Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 74 additions & 2 deletions apps/mesh/src/web/components/chat/side-panel-tasks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ import { Page } from "@/web/components/page";
import { getIconComponent, parseIconString } from "../agent-icon";

import { usePanelActions } from "@/web/layouts/shell-layout";
import { Edit05, LayoutLeft, Loading01, Settings02 } from "@untitledui/icons";
import {
Edit05,
File06,
LayoutLeft,
Loading01,
Settings02,
} from "@untitledui/icons";
import { useVirtualMCPActions, useVirtualMCP } from "@decocms/mesh-sdk";
import type { VirtualMCPEntity } from "@decocms/mesh-sdk/types";
import { Suspense, useEffect, useRef, useState, useTransition } from "react";
Expand All @@ -28,6 +34,10 @@ import {
} from "@deco/ui/components/tooltip.tsx";
import { IconPicker } from "@/web/components/icon-picker.tsx";
import { useInsetContext } from "@/web/layouts/agent-shell-layout";
import {
PageSectionsSidebar,
getDecoConnectionId,
} from "@/web/views/pages/index";

// ────────────────────────────────────────
// Shared nav item style — used by New session and view buttons
Expand Down Expand Up @@ -117,17 +127,36 @@ function ProjectViewsSection({ project }: { project: VirtualMCPEntity }) {
icon: string | null;
}> | null) ?? [];

if (pinnedViews.length === 0) return null;
// Deco projects have a file_explorer pinned view
const isDecoProject = pinnedViews.some((v) => v.toolName === "file_explorer");

if (pinnedViews.length === 0 && !isDecoProject) return null;

// Determine which pinned view is currently active
const currentMain = virtualMcpCtx?.mainView;
const isPagesActive = currentMain?.type === "pages";
const isExtAppActive = (view: { connectionId: string; toolName: string }) =>
currentMain?.type === "ext-apps" &&
currentMain.id === view.connectionId &&
currentMain.toolName === view.toolName;

return (
<>
{isDecoProject && (
<button
type="button"
onClick={() =>
isPagesActive ? openMainView("default") : openMainView("pages")
}
className={cn(
navItemClass,
isPagesActive && "bg-accent text-foreground",
)}
>
<File06 size={16} className="shrink-0 text-muted-foreground" />
<span className="truncate text-foreground">Pages</span>
</button>
)}
{pinnedViews.map((view) => (
<button
key={`${view.connectionId}-${view.toolName}`}
Expand Down Expand Up @@ -273,6 +302,49 @@ function TasksPanelContent({

const virtualMcp = useVirtualMCP(virtualMcpId);

// When a page is selected, take over the sidebar with sections panel
const mainView = virtualMcpCtx?.mainView;
const pageKey =
mainView?.type === "pages"
? (mainView as { type: "pages"; pageKey?: string }).pageKey
: undefined;

const decoConnectionId = getDecoConnectionId(virtualMcp ?? null);

if (pageKey && decoConnectionId) {
return (
<ErrorBoundary
fallback={
<div className="flex items-center justify-center h-32">
<p className="text-xs text-muted-foreground">
Failed to load sections.
</p>
</div>
}
>
<Suspense
fallback={
<div className="flex flex-col h-full">
<div className="shrink-0 flex items-center gap-2 px-3 h-11 border-b border-border/50">
<Skeleton className="h-4 w-20" />
</div>
<div className="flex flex-col gap-2 p-3">
{[1, 2, 3, 4].map((i) => (
<Skeleton key={i} className="h-10 w-full rounded-md" />
))}
</div>
</div>
}
>
<PageSectionsSidebar
connectionId={decoConnectionId}
pageKey={pageKey}
/>
</Suspense>
</ErrorBoundary>
);
}

const handleNewTask = () => {
startTransition(() => {
createNewTask();
Expand Down
10 changes: 9 additions & 1 deletion apps/mesh/src/web/layouts/agent-shell-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,19 @@ import {
// Types & Context
// ---------------------------------------------------------------------------

export type MainViewType = "chat" | "settings" | "automation" | "ext-apps";
export type MainViewType =
| "chat"
| "settings"
| "automation"
| "ext-apps"
| "pages";

export type MainView =
| { type: "chat" }
| { type: "settings" }
| { type: "automation"; id: string }
| { type: "ext-apps"; id: string; toolName?: string; [key: string]: unknown }
| { type: "pages"; pageKey?: string }
| null;

export interface InsetContextValue {
Expand Down Expand Up @@ -409,6 +415,8 @@ function AgentInsetProvider() {
mainView = id
? { type: "ext-apps", id, toolName: search.toolName }
: { type: "settings" };
} else if (search.main === "pages") {
mainView = { type: "pages", pageKey: search.id };
} else {
mainView = null;
}
Expand Down
12 changes: 10 additions & 2 deletions apps/mesh/src/web/layouts/shell-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,16 @@ export function usePanelActions() {
main: view,
mainOpen: 1,
};
if (opts?.id) next.id = opts.id;
if (opts?.toolName) next.toolName = opts.toolName;
if (opts?.id) {
next.id = opts.id;
} else {
delete next.id;
}
if (opts?.toolName) {
next.toolName = opts.toolName;
} else {
delete next.toolName;
}
return next;
});
};
Expand Down
Loading
Loading