diff --git a/packages/app/src/components/split-container.tsx b/packages/app/src/components/split-container.tsx
index f596e36a0..75c56ebd0 100644
--- a/packages/app/src/components/split-container.tsx
+++ b/packages/app/src/components/split-container.tsx
@@ -41,7 +41,7 @@ import {
type WorkspaceDesktopTabRowItem,
} from "@/screens/workspace/workspace-desktop-tabs-row";
import {
- useWorkspaceTabPresentation,
+ WorkspaceTabPresentationResolver,
WorkspaceTabIcon,
} from "@/screens/workspace/workspace-tab-presentation";
import type { WorkspaceTabDescriptor } from "@/screens/workspace/workspace-tabs-types";
@@ -489,35 +489,41 @@ function DragOverlayTabChipInner({
normalizedWorkspaceId: string;
}) {
const { theme } = useUnistyles();
- const presentation = useWorkspaceTabPresentation({
- tab,
- serverId: normalizedServerId,
- workspaceId: normalizedWorkspaceId,
- });
- const label =
- presentation.titleState === "loading" ? "Loading..." : presentation.label;
return (
-
-
-
- {label}
-
-
+ {(presentation) => {
+ const label =
+ presentation.titleState === "loading" ? "Loading..." : presentation.label;
+
+ return (
+
+
+
+ {label}
+
+
+ );
+ }}
+
);
}
diff --git a/packages/app/src/screens/workspace/workspace-desktop-tabs-row.tsx b/packages/app/src/screens/workspace/workspace-desktop-tabs-row.tsx
index f06c42320..6370cef31 100644
--- a/packages/app/src/screens/workspace/workspace-desktop-tabs-row.tsx
+++ b/packages/app/src/screens/workspace/workspace-desktop-tabs-row.tsx
@@ -15,7 +15,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip
import { WORKSPACE_SECONDARY_HEADER_HEIGHT } from "@/constants/layout";
import { useWorkspaceTabLayout } from "@/screens/workspace/use-workspace-tab-layout";
import {
- useWorkspaceTabPresentation,
+ WorkspaceTabPresentationResolver,
WorkspaceTabIcon,
type WorkspaceTabPresentation,
} from "@/screens/workspace/workspace-tab-presentation";
@@ -546,13 +546,6 @@ function ResolvedDesktopTabChip({
showDropIndicatorBefore: boolean;
showDropIndicatorAfter: boolean;
}) {
- const presentation = useWorkspaceTabPresentation({
- tab: item.tab,
- serverId: normalizedServerId,
- workspaceId: normalizedWorkspaceId,
- });
- const tooltipLabel =
- presentation.titleState === "loading" ? "Loading agent title" : presentation.label;
const resolvedTab = useMemo(
() =>
buildWorkspaceDesktopTabActions({
@@ -580,33 +573,46 @@ function ResolvedDesktopTabChip({
);
return (
-
- {showDropIndicatorBefore ? (
-
- ) : null}
-
- {showDropIndicatorAfter ? (
-
- ) : null}
-
+
+ {(presentation) => {
+ const tooltipLabel =
+ presentation.titleState === "loading" ? "Loading agent title" : presentation.label;
+
+ return (
+
+ {showDropIndicatorBefore ? (
+
+ ) : null}
+
+ {showDropIndicatorAfter ? (
+
+ ) : null}
+
+ );
+ }}
+
);
}
diff --git a/packages/app/src/screens/workspace/workspace-screen.tsx b/packages/app/src/screens/workspace/workspace-screen.tsx
index 3195edeaa..5254a2d6c 100644
--- a/packages/app/src/screens/workspace/workspace-screen.tsx
+++ b/packages/app/src/screens/workspace/workspace-screen.tsx
@@ -83,7 +83,7 @@ import { useArchiveAgent } from "@/hooks/use-archive-agent";
import { buildProviderCommand } from "@/utils/provider-command-templates";
import { generateDraftId } from "@/stores/draft-keys";
import {
- useWorkspaceTabPresentation,
+ WorkspaceTabPresentationResolver,
WorkspaceTabIcon,
WorkspaceTabOptionRow,
} from "@/screens/workspace/workspace-tab-presentation";
@@ -226,22 +226,24 @@ function ResolvedMobileActiveTabTrigger({
normalizedServerId: string;
normalizedWorkspaceId: string;
}) {
- const presentation = useWorkspaceTabPresentation({
- tab: activeTab,
- serverId: normalizedServerId,
- workspaceId: normalizedWorkspaceId,
- });
-
return (
- <>
-
-
-
+
+ {(presentation) => (
+ <>
+
+
+
-
- {presentation.titleState === "loading" ? "Loading..." : presentation.label}
-
- >
+
+ {presentation.titleState === "loading" ? "Loading..." : presentation.label}
+
+ >
+ )}
+
);
}
@@ -277,11 +279,6 @@ function MobileWorkspaceTabOption({
onCloseOtherTabs: (tabId: string) => Promise | void;
}) {
const { theme } = useUnistyles();
- const presentation = useWorkspaceTabPresentation({
- tab,
- serverId: normalizedServerId,
- workspaceId: normalizedWorkspaceId,
- });
const menuTestIDBase = `workspace-tab-menu-${tab.key}`;
const menuEntries = buildWorkspaceTabMenuEntries({
surface: "mobile",
@@ -298,53 +295,61 @@ function MobileWorkspaceTabOption({
});
return (
-
- [
- styles.mobileTabMenuTrigger,
- (open || pressed) && styles.mobileTabMenuTriggerActive,
- ]}
- >
-
-
-
- {menuEntries.map((entry) =>
- entry.kind === "separator" ? (
-
- ) : (
-
- {entry.label}
-
- )
- )}
-
-
- }
- />
+
+ {(presentation) => (
+
+ [
+ styles.mobileTabMenuTrigger,
+ (open || pressed) && styles.mobileTabMenuTriggerActive,
+ ]}
+ >
+
+
+
+ {menuEntries.map((entry) =>
+ entry.kind === "separator" ? (
+
+ ) : (
+
+ {entry.label}
+
+ )
+ )}
+
+
+ }
+ />
+ )}
+
);
}
diff --git a/packages/app/src/screens/workspace/workspace-tab-presentation.tsx b/packages/app/src/screens/workspace/workspace-tab-presentation.tsx
index 550087b82..d0c821ff1 100644
--- a/packages/app/src/screens/workspace/workspace-tab-presentation.tsx
+++ b/packages/app/src/screens/workspace/workspace-tab-presentation.tsx
@@ -21,23 +21,56 @@ export interface WorkspaceTabPresentation {
statusBucket: SidebarStateBucket | null;
}
-export function useWorkspaceTabPresentation(input: {
+type WorkspaceTabPresentationResolverProps = {
tab: WorkspaceTabDescriptor;
serverId: string;
workspaceId: string;
-}): WorkspaceTabPresentation {
+ children: (presentation: WorkspaceTabPresentation) => ReactNode;
+};
+
+type WorkspaceTabPresentationResolverInnerProps = WorkspaceTabPresentationResolverProps & {
+ registration: NonNullable>;
+};
+
+export function WorkspaceTabPresentationResolver({
+ tab,
+ serverId,
+ workspaceId,
+ children,
+}: WorkspaceTabPresentationResolverProps): ReactElement {
ensurePanelsRegistered();
- const registration = getPanelRegistration(input.tab.kind);
- invariant(registration, `No panel registration for kind: ${input.tab.kind}`);
- const descriptor = registration.useDescriptor(input.tab.target, {
- serverId: input.serverId,
- workspaceId: input.workspaceId,
+ const registration = getPanelRegistration(tab.kind);
+ invariant(registration, `No panel registration for kind: ${tab.kind}`);
+
+ return (
+
+ {children}
+
+ );
+}
+
+function WorkspaceTabPresentationResolverInner({
+ registration,
+ tab,
+ serverId,
+ workspaceId,
+ children,
+}: WorkspaceTabPresentationResolverInnerProps): ReactElement {
+ const descriptor = registration.useDescriptor(tab.target as never, {
+ serverId,
+ workspaceId,
});
- return useMemo(
+ const presentation = useMemo(
() => ({
- key: input.tab.key,
- kind: input.tab.kind,
+ key: tab.key,
+ kind: tab.kind,
label: descriptor.label,
subtitle: descriptor.subtitle,
titleState: descriptor.titleState,
@@ -50,10 +83,12 @@ export function useWorkspaceTabPresentation(input: {
descriptor.statusBucket,
descriptor.subtitle,
descriptor.titleState,
- input.tab.key,
- input.tab.kind,
+ tab.key,
+ tab.kind,
]
);
+
+ return <>{children(presentation)}>;
}
type WorkspaceTabIconProps = {