@athenaintel/react 0.36.1 → 0.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -2
- package/dist/assets/AthenaLayout.cjs +9 -2
- package/dist/assets/AthenaLayout.cjs.map +1 -1
- package/dist/assets/AthenaLayout.d.ts +6 -1
- package/dist/assets/AthenaLayout.js +9 -2
- package/dist/assets/AthenaLayout.js.map +1 -1
- package/dist/auth/AthenaSSOProvider.cjs +202 -103
- package/dist/auth/AthenaSSOProvider.cjs.map +1 -1
- package/dist/auth/AthenaSSOProvider.d.ts +35 -4
- package/dist/auth/AthenaSSOProvider.js +202 -103
- package/dist/auth/AthenaSSOProvider.js.map +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/diagnostics/athena-diagnostics.cjs.map +1 -1
- package/dist/diagnostics/athena-diagnostics.d.ts +1 -1
- package/dist/diagnostics/athena-diagnostics.js.map +1 -1
- package/dist/diagnostics/errors.cjs +7 -0
- package/dist/diagnostics/errors.cjs.map +1 -1
- package/dist/diagnostics/errors.d.ts +7 -0
- package/dist/diagnostics/errors.js +7 -0
- package/dist/diagnostics/errors.js.map +1 -1
- package/dist/react/package.json.cjs +1 -1
- package/dist/react/package.json.js +1 -1
- package/dist/workbench/SessionWorkbench.cjs +13 -3
- package/dist/workbench/SessionWorkbench.cjs.map +1 -1
- package/dist/workbench/SessionWorkbench.d.ts +5 -3
- package/dist/workbench/SessionWorkbench.js +14 -4
- package/dist/workbench/SessionWorkbench.js.map +1 -1
- package/dist/workbench/workbench-layout-context.cjs.map +1 -1
- package/dist/workbench/workbench-layout-context.d.ts +2 -0
- package/dist/workbench/workbench-layout-context.js.map +1 -1
- package/package.json +1 -1
|
@@ -85,6 +85,15 @@ const SessionWorkbenchInner = ({
|
|
|
85
85
|
}, [defaultOpenPaneIds, panes]);
|
|
86
86
|
const [tabsState, dispatchTabs] = react.useReducer(sessionWorkbenchModel.workbenchTabsReducer, {});
|
|
87
87
|
const threadKey = threadId ?? "";
|
|
88
|
+
const defaultCollapsed = (layout == null ? void 0 : layout.defaultCollapsed) ?? false;
|
|
89
|
+
const collapsedByThread = react.useRef(/* @__PURE__ */ new Map());
|
|
90
|
+
const setThreadCollapsed = (next) => {
|
|
91
|
+
collapsedByThread.current.set(threadKey, next);
|
|
92
|
+
setCollapsed(next);
|
|
93
|
+
};
|
|
94
|
+
react.useLayoutEffect(() => {
|
|
95
|
+
setCollapsed(collapsedByThread.current.get(threadKey) ?? defaultCollapsed);
|
|
96
|
+
}, [threadKey, defaultCollapsed, setCollapsed]);
|
|
88
97
|
let tabs = sessionWorkbenchModel.visibleThreadTabs(sessionWorkbenchModel.threadTabs(tabsState, threadKey, defaults), paneIds);
|
|
89
98
|
if (paneIds.has(SESSION_WORKBENCH_ASSETS_PANE_ID) && !tabs.open.includes(SESSION_WORKBENCH_ASSETS_PANE_ID)) {
|
|
90
99
|
tabs = {
|
|
@@ -105,6 +114,7 @@ const SessionWorkbenchInner = ({
|
|
|
105
114
|
paneId: SESSION_WORKBENCH_ASSETS_PANE_ID,
|
|
106
115
|
defaults: latest.current.defaults
|
|
107
116
|
});
|
|
117
|
+
collapsedByThread.current.set(latest.current.threadKey, false);
|
|
108
118
|
latest.current.setCollapsed(false);
|
|
109
119
|
});
|
|
110
120
|
}, [hostsAssetPanel]);
|
|
@@ -147,7 +157,7 @@ const SessionWorkbenchInner = ({
|
|
|
147
157
|
type: "button",
|
|
148
158
|
"aria-label": "Expand workspace",
|
|
149
159
|
title: "Expand workspace",
|
|
150
|
-
onClick: () =>
|
|
160
|
+
onClick: () => setThreadCollapsed(false),
|
|
151
161
|
className: ICON_BUTTON_CLASS,
|
|
152
162
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelRightOpenIcon, { className: "size-4" })
|
|
153
163
|
}
|
|
@@ -164,7 +174,7 @@ const SessionWorkbenchInner = ({
|
|
|
164
174
|
title: pane.title,
|
|
165
175
|
onClick: () => {
|
|
166
176
|
activatePane(paneId);
|
|
167
|
-
|
|
177
|
+
setThreadCollapsed(false);
|
|
168
178
|
},
|
|
169
179
|
className: cnfast.cn(
|
|
170
180
|
ICON_BUTTON_CLASS,
|
|
@@ -255,7 +265,7 @@ const SessionWorkbenchInner = ({
|
|
|
255
265
|
type: "button",
|
|
256
266
|
"aria-label": "Collapse workspace",
|
|
257
267
|
title: "Collapse workspace",
|
|
258
|
-
onClick: () =>
|
|
268
|
+
onClick: () => setThreadCollapsed(true),
|
|
259
269
|
className: ICON_BUTTON_CLASS,
|
|
260
270
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelRightCloseIcon, { className: "size-4" })
|
|
261
271
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionWorkbench.cjs","sources":["../../src/workbench/SessionWorkbench.tsx"],"sourcesContent":["\"use client\";\n\nimport { useAuiState } from '@assistant-ui/react';\nimport { readDeepAgentStreamValues } from '@athenaintel/agent-runtime';\nimport { QueryClientProvider, useQueryClient } from '@tanstack/react-query';\nimport {\n LayersIcon,\n Maximize2Icon,\n Minimize2Icon,\n PanelRightCloseIcon,\n PanelRightOpenIcon,\n PlusIcon,\n SearchIcon,\n XIcon,\n} from 'lucide-react';\nimport {\n type FC,\n type KeyboardEvent,\n useContext,\n useEffect,\n useId,\n useMemo,\n useReducer,\n useRef,\n useState,\n} from 'react';\nimport { useAssetPanelStore } from '../assets/asset-panel-store';\nimport { AssetPanel } from '../assets/AssetPanel';\nimport { useAthenaQueryClient } from '../lib/use-athena-rest-query';\nimport { cn } from '../lib/utils';\nimport { useAthenaStatewireThreadList } from '../threads/statewire-thread-list';\nimport { AthenaStatewireThreadIdContext } from '../threads/thread-id-context';\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';\nimport {\n type SessionWorkbenchPane,\n type SessionWorkbenchPaneContext,\n SessionWorkbenchContext,\n} from './session-workbench-context';\nimport {\n filterWorkbenchPanes,\n threadTabs,\n visibleThreadTabs,\n type WorkbenchThreadTabs,\n workbenchTabsReducer,\n} from './session-workbench-model';\nimport {\n DEFAULT_SESSION_WORKBENCH_OPEN_PANE_IDS,\n DEFAULT_SESSION_WORKBENCH_PANES,\n} from './session-workbench-panes';\nimport { SESSION_WORKSPACE_QUERY_KEY } from './use-session-workspace';\nimport { useWorkbenchLayout } from './workbench-layout-context';\n\n/** The tab `AthenaLayout`'s workbench shows the open assets in. */\nexport const SESSION_WORKBENCH_ASSETS_PANE_ID = 'open-assets';\n\nconst OPEN_ASSETS_PANE: SessionWorkbenchPane = {\n id: SESSION_WORKBENCH_ASSETS_PANE_ID,\n title: 'Open assets',\n description: 'The documents, sheets and decks open in this session',\n icon: LayersIcon,\n render: () => <AssetPanel manageAssetPanelHostRegistration={false} />,\n};\n\nexport interface SessionWorkbenchProps {\n /**\n * The panes the \"+\" menu offers, in order. Defaults to the built-in Tasks,\n * Shell, Computer, Pull requests and Attachments\n * (`DEFAULT_SESSION_WORKBENCH_PANES`); spread it to add your own.\n */\n panes?: readonly SessionWorkbenchPane[];\n /**\n * The panes a thread opens with until the person changes its tabs (ids from\n * `panes`; unknown ids are ignored). Defaults to Tasks, Shell and Computer.\n */\n defaultOpenPaneIds?: readonly string[];\n className?: string;\n}\n\nconst ICON_BUTTON_CLASS =\n 'inline-flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring/60';\n\n/**\n * A Devin-style workspace pane for the active session: a tab strip of panes\n * (Tasks, Shell, Computer, Pull requests, Attachments — and any the host\n * adds), a \"+\" menu to open more, closable tabs, and a collapse to a rail.\n *\n * Mount it inside `<AthenaProvider>` — as `AthenaLayout`'s `workbench` for a\n * resizable right-hand column, or anywhere in your own layout. Each thread\n * keeps its own open tabs while the workbench stays mounted (in memory only);\n * a thread it has not seen opens `defaultOpenPaneIds`. In `AthenaLayout`, the\n * assets the agent or the person opens show here too, as an \"Open assets\" tab.\n */\nexport const SessionWorkbench: FC<SessionWorkbenchProps> = (props) => {\n // One client for every pane, so the workspace read several panes share is\n // fetched once even when the host provides no QueryClient.\n const queryClient = useAthenaQueryClient();\n return (\n <QueryClientProvider client={queryClient}>\n <SessionWorkbenchInner {...props} />\n </QueryClientProvider>\n );\n};\n\nconst SessionWorkbenchInner: FC<SessionWorkbenchProps> = ({\n panes = DEFAULT_SESSION_WORKBENCH_PANES,\n defaultOpenPaneIds = DEFAULT_SESSION_WORKBENCH_OPEN_PANE_IDS,\n className,\n}) => {\n const layout = useWorkbenchLayout();\n const [ownCollapsed, setOwnCollapsed] = useState(false);\n const collapsed = layout ? layout.collapsed : ownCollapsed;\n const setCollapsed = layout ? layout.setCollapsed : setOwnCollapsed;\n // Only a hosting layout can give the workbench the chat's width.\n const maximized = layout?.maximized ?? false;\n const setMaximized = layout?.setMaximized;\n const hostsAssetPanel = layout?.hostsAssetPanel ?? false;\n\n const threadId = useContext(AthenaStatewireThreadIdContext);\n const threadList = useAthenaStatewireThreadList();\n const hasMessages = useAuiState((state) => state.thread.messages.length > 0);\n // The attach snapshot says whether the backend minted the thread's session\n // (`sessionPersisted`) — true for an existing thread before any message.\n const sessionPersisted = useAuiState(\n (state) =>\n readDeepAgentStreamValues((state.thread.extras as { state?: unknown } | undefined)?.state)\n .sessionPersisted,\n );\n const isRunning = useAuiState(\n (state) => (state.thread.extras as { status?: unknown } | undefined)?.status === 'running',\n );\n // In thread-list mode the list knows whether the backend has the thread; a\n // single-thread provider's thread is known once the host says its session\n // exists, or once it has history (a host that predates the flag).\n const isPersisted = threadList\n ? !threadList.isNewChat\n : sessionPersisted === true || hasMessages;\n const paneContext = useMemo<SessionWorkbenchPaneContext>(\n () => ({ threadId, isPersisted, isRunning }),\n [threadId, isPersisted, isRunning],\n );\n\n // Polling stops with the run; read the workspace once more as it settles so\n // what the run's last steps created shows without waiting for a refocus.\n const queryClient = useQueryClient();\n const wasRunning = useRef(isRunning);\n useEffect(() => {\n if (wasRunning.current && !isRunning) {\n void queryClient.invalidateQueries({ queryKey: SESSION_WORKSPACE_QUERY_KEY });\n }\n wasRunning.current = isRunning;\n }, [isRunning, queryClient]);\n\n const assetPanelOpen = useAssetPanelStore((state) => state.isOpen);\n const closeAssetPanel = useAssetPanelStore((state) => state.closePanel);\n const allPanes = useMemo<readonly SessionWorkbenchPane[]>(\n () => (hostsAssetPanel && assetPanelOpen ? [...panes, OPEN_ASSETS_PANE] : panes),\n [assetPanelOpen, hostsAssetPanel, panes],\n );\n const paneById = useMemo(() => new Map(allPanes.map((pane) => [pane.id, pane])), [allPanes]);\n const paneIds = useMemo(() => new Set(paneById.keys()), [paneById]);\n\n const defaults = useMemo<WorkbenchThreadTabs>(() => {\n const open = defaultOpenPaneIds.filter((id) => panes.some((pane) => pane.id === id));\n return { open, active: open[0] ?? null };\n }, [defaultOpenPaneIds, panes]);\n const [tabsState, dispatchTabs] = useReducer(workbenchTabsReducer, {});\n const threadKey = threadId ?? '';\n let tabs = visibleThreadTabs(threadTabs(tabsState, threadKey, defaults), paneIds);\n // Assets already open when the workbench mounts (or when a thread with open\n // assets comes back) show their tab without an opening to react to.\n if (\n paneIds.has(SESSION_WORKBENCH_ASSETS_PANE_ID) &&\n !tabs.open.includes(SESSION_WORKBENCH_ASSETS_PANE_ID)\n ) {\n tabs = {\n open: [...tabs.open, SESSION_WORKBENCH_ASSETS_PANE_ID],\n active: tabs.active ?? SESSION_WORKBENCH_ASSETS_PANE_ID,\n };\n }\n\n // An asset opening (a tool card, a citation, the Attachments pane) brings\n // the \"Open assets\" tab forward and the workbench out of its rail. A thread\n // switch restoring that thread's open assets (`setCurrentThread`) is not an\n // opening: the thread keeps the pane it had selected. Read through refs:\n // the store notifies outside React's render.\n const latest = useRef({ threadKey, defaults, setCollapsed });\n latest.current = { threadKey, defaults, setCollapsed };\n useEffect(() => {\n if (!hostsAssetPanel) return undefined;\n return useAssetPanelStore.subscribe((state, previous) => {\n if (state.currentThreadId !== previous.currentThreadId) return;\n // Every open request, a repeat click on the asset already showing too.\n if (!state.isOpen || state.openRequestSeq === previous.openRequestSeq) return;\n dispatchTabs({\n type: 'open',\n threadKey: latest.current.threadKey,\n paneId: SESSION_WORKBENCH_ASSETS_PANE_ID,\n defaults: latest.current.defaults,\n });\n latest.current.setCollapsed(false);\n });\n }, [hostsAssetPanel]);\n\n // Showing a tab the strip renders is an `open`: it activates a stored tab\n // and records one the strip only derived (the \"Open assets\" tab above).\n const openPane = (paneId: string) =>\n dispatchTabs({ type: 'open', threadKey, paneId, defaults });\n const activatePane = openPane;\n const closePane = (paneId: string) => {\n if (paneId === SESSION_WORKBENCH_ASSETS_PANE_ID) closeAssetPanel();\n dispatchTabs({ type: 'close', threadKey, paneId, defaults });\n };\n\n const baseId = useId();\n const tabId = (paneId: string) => `${baseId}-tab-${paneId}`;\n const panelId = `${baseId}-panel`;\n\n const onTabKeyDown = (event: KeyboardEvent<HTMLButtonElement>, index: number) => {\n const step = event.key === 'ArrowRight' ? 1 : event.key === 'ArrowLeft' ? -1 : 0;\n if (step === 0 || tabs.open.length === 0) return;\n event.preventDefault();\n const nextId = tabs.open[(index + step + tabs.open.length) % tabs.open.length];\n if (!nextId) return;\n activatePane(nextId);\n event.currentTarget.ownerDocument.getElementById(tabId(nextId))?.focus();\n };\n\n const activePane = tabs.active ? paneById.get(tabs.active) : undefined;\n const assetsPane = paneById.get(SESSION_WORKBENCH_ASSETS_PANE_ID);\n const assetsActive = activePane?.id === SESSION_WORKBENCH_ASSETS_PANE_ID;\n\n // One tree for both states: the panel stays mounted (hidden) while the\n // workbench is a rail, and the open assets stay mounted (hidden) while\n // another pane shows — their iframes keep their editing session, as the\n // asset panel's own tabs do.\n return (\n <SessionWorkbenchContext.Provider value={paneContext}>\n <aside\n aria-label=\"Session workspace\"\n className={cn(\n 'athena-sdk-chrome flex h-full flex-col border-border border-l bg-background',\n collapsed ? 'w-10 shrink-0 items-center gap-1 py-2' : 'min-h-0 w-full min-w-0',\n className,\n )}\n >\n {collapsed ? (\n <>\n <button\n type=\"button\"\n aria-label=\"Expand workspace\"\n title=\"Expand workspace\"\n onClick={() => setCollapsed(false)}\n className={ICON_BUTTON_CLASS}\n >\n <PanelRightOpenIcon className=\"size-4\" />\n </button>\n {tabs.open.map((paneId) => {\n const pane = paneById.get(paneId);\n if (!pane) return null;\n const Icon = pane.icon ?? LayersIcon;\n return (\n <button\n key={paneId}\n type=\"button\"\n aria-label={`Show ${pane.title}`}\n title={pane.title}\n onClick={() => {\n activatePane(paneId);\n setCollapsed(false);\n }}\n className={cn(\n ICON_BUTTON_CLASS,\n paneId === tabs.active && 'bg-muted text-foreground',\n )}\n >\n <Icon className=\"size-4\" />\n </button>\n );\n })}\n </>\n ) : (\n <div className=\"flex h-11 w-full shrink-0 items-center gap-1 border-border border-b pr-1.5 pl-2\">\n <div\n role=\"tablist\"\n aria-label=\"Workspace panes\"\n className=\"flex min-w-0 items-center gap-1 overflow-x-auto [scrollbar-width:none]\"\n >\n {tabs.open.map((paneId, index) => {\n const pane = paneById.get(paneId);\n if (!pane) return null;\n const Icon = pane.icon;\n const selected = paneId === tabs.active;\n return (\n <div\n key={paneId}\n data-selected={selected ? '' : undefined}\n className={cn(\n 'group/tab flex h-7 shrink-0 items-center rounded-md text-[13px] transition-colors',\n selected\n ? 'bg-foreground/[0.06] text-foreground'\n : 'text-muted-foreground hover:bg-foreground/[0.04] hover:text-foreground',\n )}\n >\n <button\n type=\"button\"\n role=\"tab\"\n id={tabId(paneId)}\n aria-selected={selected}\n aria-controls={panelId}\n tabIndex={selected ? 0 : -1}\n onClick={() => activatePane(paneId)}\n onKeyDown={(event) => onTabKeyDown(event, index)}\n className=\"flex h-full items-center gap-1.5 rounded-md pr-1 pl-2 outline-none focus-visible:ring-2 focus-visible:ring-ring/60\"\n >\n {Icon ? <Icon className=\"size-3.5\" /> : null}\n {pane.title}\n </button>\n {/* Quiet until the tab is hovered, focused or selected, as in Devin's strip. */}\n <button\n type=\"button\"\n aria-label={`Close ${pane.title}`}\n title={`Close ${pane.title}`}\n onClick={() => closePane(paneId)}\n className={cn(\n 'mr-1 rounded p-0.5 transition-opacity hover:bg-background hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/60',\n selected ? 'opacity-60' : 'opacity-0 group-hover/tab:opacity-60',\n )}\n >\n <XIcon className=\"size-3\" />\n </button>\n </div>\n );\n })}\n </div>\n <AddPaneMenu panes={allPanes} openIds={tabs.open} onOpen={openPane} />\n <div className=\"min-w-0 flex-1\" />\n {setMaximized ? (\n <button\n type=\"button\"\n aria-label={maximized ? 'Restore workspace' : 'Maximize workspace'}\n title={maximized ? 'Restore workspace' : 'Maximize workspace'}\n aria-pressed={maximized}\n onClick={() => setMaximized(!maximized)}\n className={ICON_BUTTON_CLASS}\n >\n {maximized ? <Minimize2Icon className=\"size-4\" /> : <Maximize2Icon className=\"size-4\" />}\n </button>\n ) : null}\n <button\n type=\"button\"\n aria-label=\"Collapse workspace\"\n title=\"Collapse workspace\"\n onClick={() => setCollapsed(true)}\n className={ICON_BUTTON_CLASS}\n >\n <PanelRightCloseIcon className=\"size-4\" />\n </button>\n </div>\n )}\n <div\n role=\"tabpanel\"\n id={panelId}\n aria-labelledby={activePane ? tabId(activePane.id) : undefined}\n className={cn(\n 'min-h-0 w-full flex-1',\n assetsActive ? 'flex flex-col' : 'overflow-y-auto',\n collapsed && 'hidden',\n )}\n >\n {assetsActive ? null : activePane ? (\n activePane.render(paneContext)\n ) : (\n <NoOpenPane panes={allPanes} onOpen={openPane} />\n )}\n {assetsPane ? (\n <div\n key={SESSION_WORKBENCH_ASSETS_PANE_ID}\n data-workbench-assets=\"\"\n className={cn(assetsActive ? 'flex min-h-0 flex-1 flex-col' : 'hidden')}\n >\n {assetsPane.render(paneContext)}\n </div>\n ) : null}\n </div>\n </aside>\n </SessionWorkbenchContext.Provider>\n );\n};\n\nconst PaneMenuItems: FC<{\n panes: readonly SessionWorkbenchPane[];\n openIds: readonly string[];\n onOpen: (paneId: string) => void;\n}> = ({ panes, openIds, onOpen }) => (\n <ul className=\"flex flex-col\">\n {panes.map((pane) => {\n const Icon = pane.icon ?? LayersIcon;\n const isOpen = openIds.includes(pane.id);\n return (\n <li key={pane.id}>\n <button\n type=\"button\"\n title={pane.description}\n onClick={() => onOpen(pane.id)}\n className=\"flex h-[30px] w-full items-center gap-2 rounded-md px-2 text-left text-[13px] transition-colors hover:bg-muted focus-visible:bg-muted focus-visible:outline-none\"\n >\n <Icon className=\"size-4 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1 truncate\">{pane.title}</span>\n {isOpen ? <span className=\"text-[11px] text-muted-foreground\">Open</span> : null}\n </button>\n </li>\n );\n })}\n </ul>\n);\n\nconst AddPaneMenu: FC<{\n panes: readonly SessionWorkbenchPane[];\n openIds: readonly string[];\n onOpen: (paneId: string) => void;\n}> = ({ panes, openIds, onOpen }) => {\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const shown = filterWorkbenchPanes(panes, query);\n const choose = (paneId: string) => {\n onOpen(paneId);\n setOpen(false);\n setQuery('');\n };\n return (\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setQuery('');\n }}\n >\n <PopoverTrigger asChild>\n <button type=\"button\" aria-label=\"Open a pane\" title=\"Open a pane\" className={ICON_BUTTON_CLASS}>\n <PlusIcon className=\"size-4\" />\n </button>\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-56 p-1\" aria-label=\"Panes\">\n <div className=\"flex items-center gap-2 border-border border-b px-2 pb-1.5 pt-1\">\n <SearchIcon className=\"size-3.5 shrink-0 text-muted-foreground\" aria-hidden />\n <input\n // biome-ignore lint/a11y/noAutofocus: the menu opens to type into, as a command menu does.\n autoFocus\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onKeyDown={(event) => {\n const first = shown[0];\n if (event.key === 'Enter' && first) {\n event.preventDefault();\n choose(first.id);\n }\n }}\n placeholder=\"Search\"\n aria-label=\"Search panes\"\n className=\"h-7 min-w-0 flex-1 bg-transparent text-[13px] outline-none placeholder:text-muted-foreground\"\n />\n </div>\n <div className=\"pt-1\">\n {shown.length > 0 ? (\n <PaneMenuItems panes={shown} openIds={openIds} onOpen={choose} />\n ) : (\n <p className=\"px-2 py-1.5 text-[13px] text-muted-foreground\">No pane matches.</p>\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n};\n\n/** Nothing open: every pane the \"+\" menu offers, with what each shows, centred in the column. */\nconst NoOpenPane: FC<{\n panes: readonly SessionWorkbenchPane[];\n onOpen: (paneId: string) => void;\n}> = ({ panes, onOpen }) => (\n <div className=\"flex min-h-full items-center justify-center p-6\">\n <ul aria-label=\"Available panes\" className=\"flex w-full max-w-xs flex-col gap-1\">\n {panes.map((pane) => {\n const Icon = pane.icon ?? LayersIcon;\n return (\n <li key={pane.id}>\n <button\n type=\"button\"\n onClick={() => onOpen(pane.id)}\n className=\"flex w-full items-start gap-3 rounded-lg px-3 py-2 text-left transition-colors hover:bg-muted focus-visible:bg-muted focus-visible:outline-none\"\n >\n <Icon className=\"mt-0.5 size-4 shrink-0 text-muted-foreground\" />\n <span className=\"flex min-w-0 flex-col\">\n <span className=\"text-[13px] text-foreground\">{pane.title}</span>\n {pane.description ? (\n <span className=\"text-muted-foreground text-xs\">{pane.description}</span>\n ) : null}\n </span>\n </button>\n </li>\n );\n })}\n </ul>\n </div>\n);\n"],"names":["LayersIcon","jsx","AssetPanel","useAthenaQueryClient","QueryClientProvider","DEFAULT_SESSION_WORKBENCH_PANES","DEFAULT_SESSION_WORKBENCH_OPEN_PANE_IDS","useWorkbenchLayout","useState","useContext","AthenaStatewireThreadIdContext","useAthenaStatewireThreadList","useAuiState","readDeepAgentStreamValues","useMemo","useQueryClient","useRef","useEffect","SESSION_WORKSPACE_QUERY_KEY","useAssetPanelStore","useReducer","workbenchTabsReducer","visibleThreadTabs","threadTabs","useId","SessionWorkbenchContext","jsxs","cn","Fragment","PanelRightOpenIcon","XIcon","Minimize2Icon","Maximize2Icon","PanelRightCloseIcon","filterWorkbenchPanes","Popover","PopoverTrigger","PlusIcon","PopoverContent","SearchIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SessionWorkbench.cjs","sources":["../../src/workbench/SessionWorkbench.tsx"],"sourcesContent":["\"use client\";\n\nimport { useAuiState } from '@assistant-ui/react';\nimport { readDeepAgentStreamValues } from '@athenaintel/agent-runtime';\nimport { QueryClientProvider, useQueryClient } from '@tanstack/react-query';\nimport {\n LayersIcon,\n Maximize2Icon,\n Minimize2Icon,\n PanelRightCloseIcon,\n PanelRightOpenIcon,\n PlusIcon,\n SearchIcon,\n XIcon,\n} from 'lucide-react';\nimport {\n type FC,\n type KeyboardEvent,\n useContext,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useReducer,\n useRef,\n useState,\n} from 'react';\nimport { useAssetPanelStore } from '../assets/asset-panel-store';\nimport { AssetPanel } from '../assets/AssetPanel';\nimport { useAthenaQueryClient } from '../lib/use-athena-rest-query';\nimport { cn } from '../lib/utils';\nimport { useAthenaStatewireThreadList } from '../threads/statewire-thread-list';\nimport { AthenaStatewireThreadIdContext } from '../threads/thread-id-context';\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';\nimport {\n type SessionWorkbenchPane,\n type SessionWorkbenchPaneContext,\n SessionWorkbenchContext,\n} from './session-workbench-context';\nimport {\n filterWorkbenchPanes,\n threadTabs,\n visibleThreadTabs,\n type WorkbenchThreadTabs,\n workbenchTabsReducer,\n} from './session-workbench-model';\nimport {\n DEFAULT_SESSION_WORKBENCH_OPEN_PANE_IDS,\n DEFAULT_SESSION_WORKBENCH_PANES,\n} from './session-workbench-panes';\nimport { SESSION_WORKSPACE_QUERY_KEY } from './use-session-workspace';\nimport { useWorkbenchLayout } from './workbench-layout-context';\n\n/** The tab `AthenaLayout`'s workbench shows the open assets in. */\nexport const SESSION_WORKBENCH_ASSETS_PANE_ID = 'open-assets';\n\nconst OPEN_ASSETS_PANE: SessionWorkbenchPane = {\n id: SESSION_WORKBENCH_ASSETS_PANE_ID,\n title: 'Open assets',\n description: 'The documents, sheets and decks open in this session',\n icon: LayersIcon,\n render: () => <AssetPanel manageAssetPanelHostRegistration={false} />,\n};\n\nexport interface SessionWorkbenchProps {\n /**\n * The panes the \"+\" menu offers, in order. Defaults to the built-in Tasks,\n * Shell, Computer, Pull requests and Attachments\n * (`DEFAULT_SESSION_WORKBENCH_PANES`); spread it to add your own.\n */\n panes?: readonly SessionWorkbenchPane[];\n /**\n * The panes a thread opens with until the person changes its tabs (ids from\n * `panes`; unknown ids are ignored). Defaults to Tasks, Shell and Computer.\n */\n defaultOpenPaneIds?: readonly string[];\n className?: string;\n}\n\nconst ICON_BUTTON_CLASS =\n 'inline-flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring/60';\n\n/**\n * A Devin-style workspace pane for the active session: a tab strip of panes\n * (Tasks, Shell, Computer, Pull requests, Attachments — and any the host\n * adds), a \"+\" menu to open more, closable tabs, and a collapse to a rail.\n *\n * Mount it inside `<AthenaProvider>` — as `AthenaLayout`'s `workbench` for a\n * resizable right-hand column, or anywhere in your own layout. Each thread\n * keeps its own open tabs, and whether the workspace is open or collapsed,\n * while the workbench stays mounted (in memory only); a thread it has not seen\n * opens `defaultOpenPaneIds`, collapsed when the layout's\n * `defaultWorkbenchCollapsed` says so. In `AthenaLayout`, the assets the agent\n * or the person opens show here too, as an \"Open assets\" tab.\n */\nexport const SessionWorkbench: FC<SessionWorkbenchProps> = (props) => {\n // One client for every pane, so the workspace read several panes share is\n // fetched once even when the host provides no QueryClient.\n const queryClient = useAthenaQueryClient();\n return (\n <QueryClientProvider client={queryClient}>\n <SessionWorkbenchInner {...props} />\n </QueryClientProvider>\n );\n};\n\nconst SessionWorkbenchInner: FC<SessionWorkbenchProps> = ({\n panes = DEFAULT_SESSION_WORKBENCH_PANES,\n defaultOpenPaneIds = DEFAULT_SESSION_WORKBENCH_OPEN_PANE_IDS,\n className,\n}) => {\n const layout = useWorkbenchLayout();\n const [ownCollapsed, setOwnCollapsed] = useState(false);\n const collapsed = layout ? layout.collapsed : ownCollapsed;\n const setCollapsed = layout ? layout.setCollapsed : setOwnCollapsed;\n // Only a hosting layout can give the workbench the chat's width.\n const maximized = layout?.maximized ?? false;\n const setMaximized = layout?.setMaximized;\n const hostsAssetPanel = layout?.hostsAssetPanel ?? false;\n\n const threadId = useContext(AthenaStatewireThreadIdContext);\n const threadList = useAthenaStatewireThreadList();\n const hasMessages = useAuiState((state) => state.thread.messages.length > 0);\n // The attach snapshot says whether the backend minted the thread's session\n // (`sessionPersisted`) — true for an existing thread before any message.\n const sessionPersisted = useAuiState(\n (state) =>\n readDeepAgentStreamValues((state.thread.extras as { state?: unknown } | undefined)?.state)\n .sessionPersisted,\n );\n const isRunning = useAuiState(\n (state) => (state.thread.extras as { status?: unknown } | undefined)?.status === 'running',\n );\n // In thread-list mode the list knows whether the backend has the thread; a\n // single-thread provider's thread is known once the host says its session\n // exists, or once it has history (a host that predates the flag).\n const isPersisted = threadList\n ? !threadList.isNewChat\n : sessionPersisted === true || hasMessages;\n const paneContext = useMemo<SessionWorkbenchPaneContext>(\n () => ({ threadId, isPersisted, isRunning }),\n [threadId, isPersisted, isRunning],\n );\n\n // Polling stops with the run; read the workspace once more as it settles so\n // what the run's last steps created shows without waiting for a refocus.\n const queryClient = useQueryClient();\n const wasRunning = useRef(isRunning);\n useEffect(() => {\n if (wasRunning.current && !isRunning) {\n void queryClient.invalidateQueries({ queryKey: SESSION_WORKSPACE_QUERY_KEY });\n }\n wasRunning.current = isRunning;\n }, [isRunning, queryClient]);\n\n const assetPanelOpen = useAssetPanelStore((state) => state.isOpen);\n const closeAssetPanel = useAssetPanelStore((state) => state.closePanel);\n const allPanes = useMemo<readonly SessionWorkbenchPane[]>(\n () => (hostsAssetPanel && assetPanelOpen ? [...panes, OPEN_ASSETS_PANE] : panes),\n [assetPanelOpen, hostsAssetPanel, panes],\n );\n const paneById = useMemo(() => new Map(allPanes.map((pane) => [pane.id, pane])), [allPanes]);\n const paneIds = useMemo(() => new Set(paneById.keys()), [paneById]);\n\n const defaults = useMemo<WorkbenchThreadTabs>(() => {\n const open = defaultOpenPaneIds.filter((id) => panes.some((pane) => pane.id === id));\n return { open, active: open[0] ?? null };\n }, [defaultOpenPaneIds, panes]);\n const [tabsState, dispatchTabs] = useReducer(workbenchTabsReducer, {});\n const threadKey = threadId ?? '';\n\n // Whether the workspace is open is kept per thread, like its tabs: a thread\n // the person has not opened or collapsed it in shows the layout's default (a\n // new session, or one switched to), so one session's open workspace never\n // follows the person into the next. Applied before paint, so a switch never\n // flashes the previous thread's state.\n const defaultCollapsed = layout?.defaultCollapsed ?? false;\n const collapsedByThread = useRef(new Map<string, boolean>());\n const setThreadCollapsed = (next: boolean) => {\n collapsedByThread.current.set(threadKey, next);\n setCollapsed(next);\n };\n useLayoutEffect(() => {\n setCollapsed(collapsedByThread.current.get(threadKey) ?? defaultCollapsed);\n }, [threadKey, defaultCollapsed, setCollapsed]);\n let tabs = visibleThreadTabs(threadTabs(tabsState, threadKey, defaults), paneIds);\n // Assets already open when the workbench mounts (or when a thread with open\n // assets comes back) show their tab without an opening to react to.\n if (\n paneIds.has(SESSION_WORKBENCH_ASSETS_PANE_ID) &&\n !tabs.open.includes(SESSION_WORKBENCH_ASSETS_PANE_ID)\n ) {\n tabs = {\n open: [...tabs.open, SESSION_WORKBENCH_ASSETS_PANE_ID],\n active: tabs.active ?? SESSION_WORKBENCH_ASSETS_PANE_ID,\n };\n }\n\n // An asset opening (a tool card, a citation, the Attachments pane) brings\n // the \"Open assets\" tab forward and the workbench out of its rail. A thread\n // switch restoring that thread's open assets (`setCurrentThread`) is not an\n // opening: the thread keeps the pane it had selected. Read through refs:\n // the store notifies outside React's render.\n const latest = useRef({ threadKey, defaults, setCollapsed });\n latest.current = { threadKey, defaults, setCollapsed };\n useEffect(() => {\n if (!hostsAssetPanel) return undefined;\n return useAssetPanelStore.subscribe((state, previous) => {\n if (state.currentThreadId !== previous.currentThreadId) return;\n // Every open request, a repeat click on the asset already showing too.\n if (!state.isOpen || state.openRequestSeq === previous.openRequestSeq) return;\n dispatchTabs({\n type: 'open',\n threadKey: latest.current.threadKey,\n paneId: SESSION_WORKBENCH_ASSETS_PANE_ID,\n defaults: latest.current.defaults,\n });\n collapsedByThread.current.set(latest.current.threadKey, false);\n latest.current.setCollapsed(false);\n });\n }, [hostsAssetPanel]);\n\n // Showing a tab the strip renders is an `open`: it activates a stored tab\n // and records one the strip only derived (the \"Open assets\" tab above).\n const openPane = (paneId: string) =>\n dispatchTabs({ type: 'open', threadKey, paneId, defaults });\n const activatePane = openPane;\n const closePane = (paneId: string) => {\n if (paneId === SESSION_WORKBENCH_ASSETS_PANE_ID) closeAssetPanel();\n dispatchTabs({ type: 'close', threadKey, paneId, defaults });\n };\n\n const baseId = useId();\n const tabId = (paneId: string) => `${baseId}-tab-${paneId}`;\n const panelId = `${baseId}-panel`;\n\n const onTabKeyDown = (event: KeyboardEvent<HTMLButtonElement>, index: number) => {\n const step = event.key === 'ArrowRight' ? 1 : event.key === 'ArrowLeft' ? -1 : 0;\n if (step === 0 || tabs.open.length === 0) return;\n event.preventDefault();\n const nextId = tabs.open[(index + step + tabs.open.length) % tabs.open.length];\n if (!nextId) return;\n activatePane(nextId);\n event.currentTarget.ownerDocument.getElementById(tabId(nextId))?.focus();\n };\n\n const activePane = tabs.active ? paneById.get(tabs.active) : undefined;\n const assetsPane = paneById.get(SESSION_WORKBENCH_ASSETS_PANE_ID);\n const assetsActive = activePane?.id === SESSION_WORKBENCH_ASSETS_PANE_ID;\n\n // One tree for both states: the panel stays mounted (hidden) while the\n // workbench is a rail, and the open assets stay mounted (hidden) while\n // another pane shows — their iframes keep their editing session, as the\n // asset panel's own tabs do.\n return (\n <SessionWorkbenchContext.Provider value={paneContext}>\n <aside\n aria-label=\"Session workspace\"\n className={cn(\n 'athena-sdk-chrome flex h-full flex-col border-border border-l bg-background',\n collapsed ? 'w-10 shrink-0 items-center gap-1 py-2' : 'min-h-0 w-full min-w-0',\n className,\n )}\n >\n {collapsed ? (\n <>\n <button\n type=\"button\"\n aria-label=\"Expand workspace\"\n title=\"Expand workspace\"\n onClick={() => setThreadCollapsed(false)}\n className={ICON_BUTTON_CLASS}\n >\n <PanelRightOpenIcon className=\"size-4\" />\n </button>\n {tabs.open.map((paneId) => {\n const pane = paneById.get(paneId);\n if (!pane) return null;\n const Icon = pane.icon ?? LayersIcon;\n return (\n <button\n key={paneId}\n type=\"button\"\n aria-label={`Show ${pane.title}`}\n title={pane.title}\n onClick={() => {\n activatePane(paneId);\n setThreadCollapsed(false);\n }}\n className={cn(\n ICON_BUTTON_CLASS,\n paneId === tabs.active && 'bg-muted text-foreground',\n )}\n >\n <Icon className=\"size-4\" />\n </button>\n );\n })}\n </>\n ) : (\n <div className=\"flex h-11 w-full shrink-0 items-center gap-1 border-border border-b pr-1.5 pl-2\">\n <div\n role=\"tablist\"\n aria-label=\"Workspace panes\"\n className=\"flex min-w-0 items-center gap-1 overflow-x-auto [scrollbar-width:none]\"\n >\n {tabs.open.map((paneId, index) => {\n const pane = paneById.get(paneId);\n if (!pane) return null;\n const Icon = pane.icon;\n const selected = paneId === tabs.active;\n return (\n <div\n key={paneId}\n data-selected={selected ? '' : undefined}\n className={cn(\n 'group/tab flex h-7 shrink-0 items-center rounded-md text-[13px] transition-colors',\n selected\n ? 'bg-foreground/[0.06] text-foreground'\n : 'text-muted-foreground hover:bg-foreground/[0.04] hover:text-foreground',\n )}\n >\n <button\n type=\"button\"\n role=\"tab\"\n id={tabId(paneId)}\n aria-selected={selected}\n aria-controls={panelId}\n tabIndex={selected ? 0 : -1}\n onClick={() => activatePane(paneId)}\n onKeyDown={(event) => onTabKeyDown(event, index)}\n className=\"flex h-full items-center gap-1.5 rounded-md pr-1 pl-2 outline-none focus-visible:ring-2 focus-visible:ring-ring/60\"\n >\n {Icon ? <Icon className=\"size-3.5\" /> : null}\n {pane.title}\n </button>\n {/* Quiet until the tab is hovered, focused or selected, as in Devin's strip. */}\n <button\n type=\"button\"\n aria-label={`Close ${pane.title}`}\n title={`Close ${pane.title}`}\n onClick={() => closePane(paneId)}\n className={cn(\n 'mr-1 rounded p-0.5 transition-opacity hover:bg-background hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/60',\n selected ? 'opacity-60' : 'opacity-0 group-hover/tab:opacity-60',\n )}\n >\n <XIcon className=\"size-3\" />\n </button>\n </div>\n );\n })}\n </div>\n <AddPaneMenu panes={allPanes} openIds={tabs.open} onOpen={openPane} />\n <div className=\"min-w-0 flex-1\" />\n {setMaximized ? (\n <button\n type=\"button\"\n aria-label={maximized ? 'Restore workspace' : 'Maximize workspace'}\n title={maximized ? 'Restore workspace' : 'Maximize workspace'}\n aria-pressed={maximized}\n onClick={() => setMaximized(!maximized)}\n className={ICON_BUTTON_CLASS}\n >\n {maximized ? <Minimize2Icon className=\"size-4\" /> : <Maximize2Icon className=\"size-4\" />}\n </button>\n ) : null}\n <button\n type=\"button\"\n aria-label=\"Collapse workspace\"\n title=\"Collapse workspace\"\n onClick={() => setThreadCollapsed(true)}\n className={ICON_BUTTON_CLASS}\n >\n <PanelRightCloseIcon className=\"size-4\" />\n </button>\n </div>\n )}\n <div\n role=\"tabpanel\"\n id={panelId}\n aria-labelledby={activePane ? tabId(activePane.id) : undefined}\n className={cn(\n 'min-h-0 w-full flex-1',\n assetsActive ? 'flex flex-col' : 'overflow-y-auto',\n collapsed && 'hidden',\n )}\n >\n {assetsActive ? null : activePane ? (\n activePane.render(paneContext)\n ) : (\n <NoOpenPane panes={allPanes} onOpen={openPane} />\n )}\n {assetsPane ? (\n <div\n key={SESSION_WORKBENCH_ASSETS_PANE_ID}\n data-workbench-assets=\"\"\n className={cn(assetsActive ? 'flex min-h-0 flex-1 flex-col' : 'hidden')}\n >\n {assetsPane.render(paneContext)}\n </div>\n ) : null}\n </div>\n </aside>\n </SessionWorkbenchContext.Provider>\n );\n};\n\nconst PaneMenuItems: FC<{\n panes: readonly SessionWorkbenchPane[];\n openIds: readonly string[];\n onOpen: (paneId: string) => void;\n}> = ({ panes, openIds, onOpen }) => (\n <ul className=\"flex flex-col\">\n {panes.map((pane) => {\n const Icon = pane.icon ?? LayersIcon;\n const isOpen = openIds.includes(pane.id);\n return (\n <li key={pane.id}>\n <button\n type=\"button\"\n title={pane.description}\n onClick={() => onOpen(pane.id)}\n className=\"flex h-[30px] w-full items-center gap-2 rounded-md px-2 text-left text-[13px] transition-colors hover:bg-muted focus-visible:bg-muted focus-visible:outline-none\"\n >\n <Icon className=\"size-4 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1 truncate\">{pane.title}</span>\n {isOpen ? <span className=\"text-[11px] text-muted-foreground\">Open</span> : null}\n </button>\n </li>\n );\n })}\n </ul>\n);\n\nconst AddPaneMenu: FC<{\n panes: readonly SessionWorkbenchPane[];\n openIds: readonly string[];\n onOpen: (paneId: string) => void;\n}> = ({ panes, openIds, onOpen }) => {\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const shown = filterWorkbenchPanes(panes, query);\n const choose = (paneId: string) => {\n onOpen(paneId);\n setOpen(false);\n setQuery('');\n };\n return (\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setQuery('');\n }}\n >\n <PopoverTrigger asChild>\n <button type=\"button\" aria-label=\"Open a pane\" title=\"Open a pane\" className={ICON_BUTTON_CLASS}>\n <PlusIcon className=\"size-4\" />\n </button>\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-56 p-1\" aria-label=\"Panes\">\n <div className=\"flex items-center gap-2 border-border border-b px-2 pb-1.5 pt-1\">\n <SearchIcon className=\"size-3.5 shrink-0 text-muted-foreground\" aria-hidden />\n <input\n // biome-ignore lint/a11y/noAutofocus: the menu opens to type into, as a command menu does.\n autoFocus\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onKeyDown={(event) => {\n const first = shown[0];\n if (event.key === 'Enter' && first) {\n event.preventDefault();\n choose(first.id);\n }\n }}\n placeholder=\"Search\"\n aria-label=\"Search panes\"\n className=\"h-7 min-w-0 flex-1 bg-transparent text-[13px] outline-none placeholder:text-muted-foreground\"\n />\n </div>\n <div className=\"pt-1\">\n {shown.length > 0 ? (\n <PaneMenuItems panes={shown} openIds={openIds} onOpen={choose} />\n ) : (\n <p className=\"px-2 py-1.5 text-[13px] text-muted-foreground\">No pane matches.</p>\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n};\n\n/** Nothing open: every pane the \"+\" menu offers, with what each shows, centred in the column. */\nconst NoOpenPane: FC<{\n panes: readonly SessionWorkbenchPane[];\n onOpen: (paneId: string) => void;\n}> = ({ panes, onOpen }) => (\n <div className=\"flex min-h-full items-center justify-center p-6\">\n <ul aria-label=\"Available panes\" className=\"flex w-full max-w-xs flex-col gap-1\">\n {panes.map((pane) => {\n const Icon = pane.icon ?? LayersIcon;\n return (\n <li key={pane.id}>\n <button\n type=\"button\"\n onClick={() => onOpen(pane.id)}\n className=\"flex w-full items-start gap-3 rounded-lg px-3 py-2 text-left transition-colors hover:bg-muted focus-visible:bg-muted focus-visible:outline-none\"\n >\n <Icon className=\"mt-0.5 size-4 shrink-0 text-muted-foreground\" />\n <span className=\"flex min-w-0 flex-col\">\n <span className=\"text-[13px] text-foreground\">{pane.title}</span>\n {pane.description ? (\n <span className=\"text-muted-foreground text-xs\">{pane.description}</span>\n ) : null}\n </span>\n </button>\n </li>\n );\n })}\n </ul>\n </div>\n);\n"],"names":["LayersIcon","jsx","AssetPanel","useAthenaQueryClient","QueryClientProvider","DEFAULT_SESSION_WORKBENCH_PANES","DEFAULT_SESSION_WORKBENCH_OPEN_PANE_IDS","useWorkbenchLayout","useState","useContext","AthenaStatewireThreadIdContext","useAthenaStatewireThreadList","useAuiState","readDeepAgentStreamValues","useMemo","useQueryClient","useRef","useEffect","SESSION_WORKSPACE_QUERY_KEY","useAssetPanelStore","useReducer","workbenchTabsReducer","useLayoutEffect","visibleThreadTabs","threadTabs","useId","SessionWorkbenchContext","jsxs","cn","Fragment","PanelRightOpenIcon","XIcon","Minimize2Icon","Maximize2Icon","PanelRightCloseIcon","filterWorkbenchPanes","Popover","PopoverTrigger","PlusIcon","PopoverContent","SearchIcon"],"mappings":"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"}
|
|
@@ -23,8 +23,10 @@ export interface SessionWorkbenchProps {
|
|
|
23
23
|
*
|
|
24
24
|
* Mount it inside `<AthenaProvider>` — as `AthenaLayout`'s `workbench` for a
|
|
25
25
|
* resizable right-hand column, or anywhere in your own layout. Each thread
|
|
26
|
-
* keeps its own open tabs
|
|
27
|
-
* a thread it has not seen
|
|
28
|
-
*
|
|
26
|
+
* keeps its own open tabs, and whether the workspace is open or collapsed,
|
|
27
|
+
* while the workbench stays mounted (in memory only); a thread it has not seen
|
|
28
|
+
* opens `defaultOpenPaneIds`, collapsed when the layout's
|
|
29
|
+
* `defaultWorkbenchCollapsed` says so. In `AthenaLayout`, the assets the agent
|
|
30
|
+
* or the person opens show here too, as an "Open assets" tab.
|
|
29
31
|
*/
|
|
30
32
|
export declare const SessionWorkbench: FC<SessionWorkbenchProps>;
|
|
@@ -2,7 +2,7 @@ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
|
2
2
|
import { useAuiState } from "@assistant-ui/react";
|
|
3
3
|
import { QueryClientProvider, useQueryClient } from "@tanstack/react-query";
|
|
4
4
|
import { LayersIcon, PanelRightOpenIcon, XIcon, Minimize2Icon, Maximize2Icon, PanelRightCloseIcon, PlusIcon, SearchIcon } from "lucide-react";
|
|
5
|
-
import { useState, useContext, useMemo, useRef, useEffect, useReducer, useId } from "react";
|
|
5
|
+
import { useState, useContext, useMemo, useRef, useEffect, useReducer, useLayoutEffect, useId } from "react";
|
|
6
6
|
import { useAssetPanelStore } from "../assets/asset-panel-store.js";
|
|
7
7
|
import { AssetPanel } from "../assets/AssetPanel.js";
|
|
8
8
|
import { useAthenaQueryClient } from "../lib/use-athena-rest-query.js";
|
|
@@ -83,6 +83,15 @@ const SessionWorkbenchInner = ({
|
|
|
83
83
|
}, [defaultOpenPaneIds, panes]);
|
|
84
84
|
const [tabsState, dispatchTabs] = useReducer(workbenchTabsReducer, {});
|
|
85
85
|
const threadKey = threadId ?? "";
|
|
86
|
+
const defaultCollapsed = (layout == null ? void 0 : layout.defaultCollapsed) ?? false;
|
|
87
|
+
const collapsedByThread = useRef(/* @__PURE__ */ new Map());
|
|
88
|
+
const setThreadCollapsed = (next) => {
|
|
89
|
+
collapsedByThread.current.set(threadKey, next);
|
|
90
|
+
setCollapsed(next);
|
|
91
|
+
};
|
|
92
|
+
useLayoutEffect(() => {
|
|
93
|
+
setCollapsed(collapsedByThread.current.get(threadKey) ?? defaultCollapsed);
|
|
94
|
+
}, [threadKey, defaultCollapsed, setCollapsed]);
|
|
86
95
|
let tabs = visibleThreadTabs(threadTabs(tabsState, threadKey, defaults), paneIds);
|
|
87
96
|
if (paneIds.has(SESSION_WORKBENCH_ASSETS_PANE_ID) && !tabs.open.includes(SESSION_WORKBENCH_ASSETS_PANE_ID)) {
|
|
88
97
|
tabs = {
|
|
@@ -103,6 +112,7 @@ const SessionWorkbenchInner = ({
|
|
|
103
112
|
paneId: SESSION_WORKBENCH_ASSETS_PANE_ID,
|
|
104
113
|
defaults: latest.current.defaults
|
|
105
114
|
});
|
|
115
|
+
collapsedByThread.current.set(latest.current.threadKey, false);
|
|
106
116
|
latest.current.setCollapsed(false);
|
|
107
117
|
});
|
|
108
118
|
}, [hostsAssetPanel]);
|
|
@@ -145,7 +155,7 @@ const SessionWorkbenchInner = ({
|
|
|
145
155
|
type: "button",
|
|
146
156
|
"aria-label": "Expand workspace",
|
|
147
157
|
title: "Expand workspace",
|
|
148
|
-
onClick: () =>
|
|
158
|
+
onClick: () => setThreadCollapsed(false),
|
|
149
159
|
className: ICON_BUTTON_CLASS,
|
|
150
160
|
children: /* @__PURE__ */ jsx(PanelRightOpenIcon, { className: "size-4" })
|
|
151
161
|
}
|
|
@@ -162,7 +172,7 @@ const SessionWorkbenchInner = ({
|
|
|
162
172
|
title: pane.title,
|
|
163
173
|
onClick: () => {
|
|
164
174
|
activatePane(paneId);
|
|
165
|
-
|
|
175
|
+
setThreadCollapsed(false);
|
|
166
176
|
},
|
|
167
177
|
className: cn(
|
|
168
178
|
ICON_BUTTON_CLASS,
|
|
@@ -253,7 +263,7 @@ const SessionWorkbenchInner = ({
|
|
|
253
263
|
type: "button",
|
|
254
264
|
"aria-label": "Collapse workspace",
|
|
255
265
|
title: "Collapse workspace",
|
|
256
|
-
onClick: () =>
|
|
266
|
+
onClick: () => setThreadCollapsed(true),
|
|
257
267
|
className: ICON_BUTTON_CLASS,
|
|
258
268
|
children: /* @__PURE__ */ jsx(PanelRightCloseIcon, { className: "size-4" })
|
|
259
269
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionWorkbench.js","sources":["../../src/workbench/SessionWorkbench.tsx"],"sourcesContent":["\"use client\";\n\nimport { useAuiState } from '@assistant-ui/react';\nimport { readDeepAgentStreamValues } from '@athenaintel/agent-runtime';\nimport { QueryClientProvider, useQueryClient } from '@tanstack/react-query';\nimport {\n LayersIcon,\n Maximize2Icon,\n Minimize2Icon,\n PanelRightCloseIcon,\n PanelRightOpenIcon,\n PlusIcon,\n SearchIcon,\n XIcon,\n} from 'lucide-react';\nimport {\n type FC,\n type KeyboardEvent,\n useContext,\n useEffect,\n useId,\n useMemo,\n useReducer,\n useRef,\n useState,\n} from 'react';\nimport { useAssetPanelStore } from '../assets/asset-panel-store';\nimport { AssetPanel } from '../assets/AssetPanel';\nimport { useAthenaQueryClient } from '../lib/use-athena-rest-query';\nimport { cn } from '../lib/utils';\nimport { useAthenaStatewireThreadList } from '../threads/statewire-thread-list';\nimport { AthenaStatewireThreadIdContext } from '../threads/thread-id-context';\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';\nimport {\n type SessionWorkbenchPane,\n type SessionWorkbenchPaneContext,\n SessionWorkbenchContext,\n} from './session-workbench-context';\nimport {\n filterWorkbenchPanes,\n threadTabs,\n visibleThreadTabs,\n type WorkbenchThreadTabs,\n workbenchTabsReducer,\n} from './session-workbench-model';\nimport {\n DEFAULT_SESSION_WORKBENCH_OPEN_PANE_IDS,\n DEFAULT_SESSION_WORKBENCH_PANES,\n} from './session-workbench-panes';\nimport { SESSION_WORKSPACE_QUERY_KEY } from './use-session-workspace';\nimport { useWorkbenchLayout } from './workbench-layout-context';\n\n/** The tab `AthenaLayout`'s workbench shows the open assets in. */\nexport const SESSION_WORKBENCH_ASSETS_PANE_ID = 'open-assets';\n\nconst OPEN_ASSETS_PANE: SessionWorkbenchPane = {\n id: SESSION_WORKBENCH_ASSETS_PANE_ID,\n title: 'Open assets',\n description: 'The documents, sheets and decks open in this session',\n icon: LayersIcon,\n render: () => <AssetPanel manageAssetPanelHostRegistration={false} />,\n};\n\nexport interface SessionWorkbenchProps {\n /**\n * The panes the \"+\" menu offers, in order. Defaults to the built-in Tasks,\n * Shell, Computer, Pull requests and Attachments\n * (`DEFAULT_SESSION_WORKBENCH_PANES`); spread it to add your own.\n */\n panes?: readonly SessionWorkbenchPane[];\n /**\n * The panes a thread opens with until the person changes its tabs (ids from\n * `panes`; unknown ids are ignored). Defaults to Tasks, Shell and Computer.\n */\n defaultOpenPaneIds?: readonly string[];\n className?: string;\n}\n\nconst ICON_BUTTON_CLASS =\n 'inline-flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring/60';\n\n/**\n * A Devin-style workspace pane for the active session: a tab strip of panes\n * (Tasks, Shell, Computer, Pull requests, Attachments — and any the host\n * adds), a \"+\" menu to open more, closable tabs, and a collapse to a rail.\n *\n * Mount it inside `<AthenaProvider>` — as `AthenaLayout`'s `workbench` for a\n * resizable right-hand column, or anywhere in your own layout. Each thread\n * keeps its own open tabs while the workbench stays mounted (in memory only);\n * a thread it has not seen opens `defaultOpenPaneIds`. In `AthenaLayout`, the\n * assets the agent or the person opens show here too, as an \"Open assets\" tab.\n */\nexport const SessionWorkbench: FC<SessionWorkbenchProps> = (props) => {\n // One client for every pane, so the workspace read several panes share is\n // fetched once even when the host provides no QueryClient.\n const queryClient = useAthenaQueryClient();\n return (\n <QueryClientProvider client={queryClient}>\n <SessionWorkbenchInner {...props} />\n </QueryClientProvider>\n );\n};\n\nconst SessionWorkbenchInner: FC<SessionWorkbenchProps> = ({\n panes = DEFAULT_SESSION_WORKBENCH_PANES,\n defaultOpenPaneIds = DEFAULT_SESSION_WORKBENCH_OPEN_PANE_IDS,\n className,\n}) => {\n const layout = useWorkbenchLayout();\n const [ownCollapsed, setOwnCollapsed] = useState(false);\n const collapsed = layout ? layout.collapsed : ownCollapsed;\n const setCollapsed = layout ? layout.setCollapsed : setOwnCollapsed;\n // Only a hosting layout can give the workbench the chat's width.\n const maximized = layout?.maximized ?? false;\n const setMaximized = layout?.setMaximized;\n const hostsAssetPanel = layout?.hostsAssetPanel ?? false;\n\n const threadId = useContext(AthenaStatewireThreadIdContext);\n const threadList = useAthenaStatewireThreadList();\n const hasMessages = useAuiState((state) => state.thread.messages.length > 0);\n // The attach snapshot says whether the backend minted the thread's session\n // (`sessionPersisted`) — true for an existing thread before any message.\n const sessionPersisted = useAuiState(\n (state) =>\n readDeepAgentStreamValues((state.thread.extras as { state?: unknown } | undefined)?.state)\n .sessionPersisted,\n );\n const isRunning = useAuiState(\n (state) => (state.thread.extras as { status?: unknown } | undefined)?.status === 'running',\n );\n // In thread-list mode the list knows whether the backend has the thread; a\n // single-thread provider's thread is known once the host says its session\n // exists, or once it has history (a host that predates the flag).\n const isPersisted = threadList\n ? !threadList.isNewChat\n : sessionPersisted === true || hasMessages;\n const paneContext = useMemo<SessionWorkbenchPaneContext>(\n () => ({ threadId, isPersisted, isRunning }),\n [threadId, isPersisted, isRunning],\n );\n\n // Polling stops with the run; read the workspace once more as it settles so\n // what the run's last steps created shows without waiting for a refocus.\n const queryClient = useQueryClient();\n const wasRunning = useRef(isRunning);\n useEffect(() => {\n if (wasRunning.current && !isRunning) {\n void queryClient.invalidateQueries({ queryKey: SESSION_WORKSPACE_QUERY_KEY });\n }\n wasRunning.current = isRunning;\n }, [isRunning, queryClient]);\n\n const assetPanelOpen = useAssetPanelStore((state) => state.isOpen);\n const closeAssetPanel = useAssetPanelStore((state) => state.closePanel);\n const allPanes = useMemo<readonly SessionWorkbenchPane[]>(\n () => (hostsAssetPanel && assetPanelOpen ? [...panes, OPEN_ASSETS_PANE] : panes),\n [assetPanelOpen, hostsAssetPanel, panes],\n );\n const paneById = useMemo(() => new Map(allPanes.map((pane) => [pane.id, pane])), [allPanes]);\n const paneIds = useMemo(() => new Set(paneById.keys()), [paneById]);\n\n const defaults = useMemo<WorkbenchThreadTabs>(() => {\n const open = defaultOpenPaneIds.filter((id) => panes.some((pane) => pane.id === id));\n return { open, active: open[0] ?? null };\n }, [defaultOpenPaneIds, panes]);\n const [tabsState, dispatchTabs] = useReducer(workbenchTabsReducer, {});\n const threadKey = threadId ?? '';\n let tabs = visibleThreadTabs(threadTabs(tabsState, threadKey, defaults), paneIds);\n // Assets already open when the workbench mounts (or when a thread with open\n // assets comes back) show their tab without an opening to react to.\n if (\n paneIds.has(SESSION_WORKBENCH_ASSETS_PANE_ID) &&\n !tabs.open.includes(SESSION_WORKBENCH_ASSETS_PANE_ID)\n ) {\n tabs = {\n open: [...tabs.open, SESSION_WORKBENCH_ASSETS_PANE_ID],\n active: tabs.active ?? SESSION_WORKBENCH_ASSETS_PANE_ID,\n };\n }\n\n // An asset opening (a tool card, a citation, the Attachments pane) brings\n // the \"Open assets\" tab forward and the workbench out of its rail. A thread\n // switch restoring that thread's open assets (`setCurrentThread`) is not an\n // opening: the thread keeps the pane it had selected. Read through refs:\n // the store notifies outside React's render.\n const latest = useRef({ threadKey, defaults, setCollapsed });\n latest.current = { threadKey, defaults, setCollapsed };\n useEffect(() => {\n if (!hostsAssetPanel) return undefined;\n return useAssetPanelStore.subscribe((state, previous) => {\n if (state.currentThreadId !== previous.currentThreadId) return;\n // Every open request, a repeat click on the asset already showing too.\n if (!state.isOpen || state.openRequestSeq === previous.openRequestSeq) return;\n dispatchTabs({\n type: 'open',\n threadKey: latest.current.threadKey,\n paneId: SESSION_WORKBENCH_ASSETS_PANE_ID,\n defaults: latest.current.defaults,\n });\n latest.current.setCollapsed(false);\n });\n }, [hostsAssetPanel]);\n\n // Showing a tab the strip renders is an `open`: it activates a stored tab\n // and records one the strip only derived (the \"Open assets\" tab above).\n const openPane = (paneId: string) =>\n dispatchTabs({ type: 'open', threadKey, paneId, defaults });\n const activatePane = openPane;\n const closePane = (paneId: string) => {\n if (paneId === SESSION_WORKBENCH_ASSETS_PANE_ID) closeAssetPanel();\n dispatchTabs({ type: 'close', threadKey, paneId, defaults });\n };\n\n const baseId = useId();\n const tabId = (paneId: string) => `${baseId}-tab-${paneId}`;\n const panelId = `${baseId}-panel`;\n\n const onTabKeyDown = (event: KeyboardEvent<HTMLButtonElement>, index: number) => {\n const step = event.key === 'ArrowRight' ? 1 : event.key === 'ArrowLeft' ? -1 : 0;\n if (step === 0 || tabs.open.length === 0) return;\n event.preventDefault();\n const nextId = tabs.open[(index + step + tabs.open.length) % tabs.open.length];\n if (!nextId) return;\n activatePane(nextId);\n event.currentTarget.ownerDocument.getElementById(tabId(nextId))?.focus();\n };\n\n const activePane = tabs.active ? paneById.get(tabs.active) : undefined;\n const assetsPane = paneById.get(SESSION_WORKBENCH_ASSETS_PANE_ID);\n const assetsActive = activePane?.id === SESSION_WORKBENCH_ASSETS_PANE_ID;\n\n // One tree for both states: the panel stays mounted (hidden) while the\n // workbench is a rail, and the open assets stay mounted (hidden) while\n // another pane shows — their iframes keep their editing session, as the\n // asset panel's own tabs do.\n return (\n <SessionWorkbenchContext.Provider value={paneContext}>\n <aside\n aria-label=\"Session workspace\"\n className={cn(\n 'athena-sdk-chrome flex h-full flex-col border-border border-l bg-background',\n collapsed ? 'w-10 shrink-0 items-center gap-1 py-2' : 'min-h-0 w-full min-w-0',\n className,\n )}\n >\n {collapsed ? (\n <>\n <button\n type=\"button\"\n aria-label=\"Expand workspace\"\n title=\"Expand workspace\"\n onClick={() => setCollapsed(false)}\n className={ICON_BUTTON_CLASS}\n >\n <PanelRightOpenIcon className=\"size-4\" />\n </button>\n {tabs.open.map((paneId) => {\n const pane = paneById.get(paneId);\n if (!pane) return null;\n const Icon = pane.icon ?? LayersIcon;\n return (\n <button\n key={paneId}\n type=\"button\"\n aria-label={`Show ${pane.title}`}\n title={pane.title}\n onClick={() => {\n activatePane(paneId);\n setCollapsed(false);\n }}\n className={cn(\n ICON_BUTTON_CLASS,\n paneId === tabs.active && 'bg-muted text-foreground',\n )}\n >\n <Icon className=\"size-4\" />\n </button>\n );\n })}\n </>\n ) : (\n <div className=\"flex h-11 w-full shrink-0 items-center gap-1 border-border border-b pr-1.5 pl-2\">\n <div\n role=\"tablist\"\n aria-label=\"Workspace panes\"\n className=\"flex min-w-0 items-center gap-1 overflow-x-auto [scrollbar-width:none]\"\n >\n {tabs.open.map((paneId, index) => {\n const pane = paneById.get(paneId);\n if (!pane) return null;\n const Icon = pane.icon;\n const selected = paneId === tabs.active;\n return (\n <div\n key={paneId}\n data-selected={selected ? '' : undefined}\n className={cn(\n 'group/tab flex h-7 shrink-0 items-center rounded-md text-[13px] transition-colors',\n selected\n ? 'bg-foreground/[0.06] text-foreground'\n : 'text-muted-foreground hover:bg-foreground/[0.04] hover:text-foreground',\n )}\n >\n <button\n type=\"button\"\n role=\"tab\"\n id={tabId(paneId)}\n aria-selected={selected}\n aria-controls={panelId}\n tabIndex={selected ? 0 : -1}\n onClick={() => activatePane(paneId)}\n onKeyDown={(event) => onTabKeyDown(event, index)}\n className=\"flex h-full items-center gap-1.5 rounded-md pr-1 pl-2 outline-none focus-visible:ring-2 focus-visible:ring-ring/60\"\n >\n {Icon ? <Icon className=\"size-3.5\" /> : null}\n {pane.title}\n </button>\n {/* Quiet until the tab is hovered, focused or selected, as in Devin's strip. */}\n <button\n type=\"button\"\n aria-label={`Close ${pane.title}`}\n title={`Close ${pane.title}`}\n onClick={() => closePane(paneId)}\n className={cn(\n 'mr-1 rounded p-0.5 transition-opacity hover:bg-background hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/60',\n selected ? 'opacity-60' : 'opacity-0 group-hover/tab:opacity-60',\n )}\n >\n <XIcon className=\"size-3\" />\n </button>\n </div>\n );\n })}\n </div>\n <AddPaneMenu panes={allPanes} openIds={tabs.open} onOpen={openPane} />\n <div className=\"min-w-0 flex-1\" />\n {setMaximized ? (\n <button\n type=\"button\"\n aria-label={maximized ? 'Restore workspace' : 'Maximize workspace'}\n title={maximized ? 'Restore workspace' : 'Maximize workspace'}\n aria-pressed={maximized}\n onClick={() => setMaximized(!maximized)}\n className={ICON_BUTTON_CLASS}\n >\n {maximized ? <Minimize2Icon className=\"size-4\" /> : <Maximize2Icon className=\"size-4\" />}\n </button>\n ) : null}\n <button\n type=\"button\"\n aria-label=\"Collapse workspace\"\n title=\"Collapse workspace\"\n onClick={() => setCollapsed(true)}\n className={ICON_BUTTON_CLASS}\n >\n <PanelRightCloseIcon className=\"size-4\" />\n </button>\n </div>\n )}\n <div\n role=\"tabpanel\"\n id={panelId}\n aria-labelledby={activePane ? tabId(activePane.id) : undefined}\n className={cn(\n 'min-h-0 w-full flex-1',\n assetsActive ? 'flex flex-col' : 'overflow-y-auto',\n collapsed && 'hidden',\n )}\n >\n {assetsActive ? null : activePane ? (\n activePane.render(paneContext)\n ) : (\n <NoOpenPane panes={allPanes} onOpen={openPane} />\n )}\n {assetsPane ? (\n <div\n key={SESSION_WORKBENCH_ASSETS_PANE_ID}\n data-workbench-assets=\"\"\n className={cn(assetsActive ? 'flex min-h-0 flex-1 flex-col' : 'hidden')}\n >\n {assetsPane.render(paneContext)}\n </div>\n ) : null}\n </div>\n </aside>\n </SessionWorkbenchContext.Provider>\n );\n};\n\nconst PaneMenuItems: FC<{\n panes: readonly SessionWorkbenchPane[];\n openIds: readonly string[];\n onOpen: (paneId: string) => void;\n}> = ({ panes, openIds, onOpen }) => (\n <ul className=\"flex flex-col\">\n {panes.map((pane) => {\n const Icon = pane.icon ?? LayersIcon;\n const isOpen = openIds.includes(pane.id);\n return (\n <li key={pane.id}>\n <button\n type=\"button\"\n title={pane.description}\n onClick={() => onOpen(pane.id)}\n className=\"flex h-[30px] w-full items-center gap-2 rounded-md px-2 text-left text-[13px] transition-colors hover:bg-muted focus-visible:bg-muted focus-visible:outline-none\"\n >\n <Icon className=\"size-4 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1 truncate\">{pane.title}</span>\n {isOpen ? <span className=\"text-[11px] text-muted-foreground\">Open</span> : null}\n </button>\n </li>\n );\n })}\n </ul>\n);\n\nconst AddPaneMenu: FC<{\n panes: readonly SessionWorkbenchPane[];\n openIds: readonly string[];\n onOpen: (paneId: string) => void;\n}> = ({ panes, openIds, onOpen }) => {\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const shown = filterWorkbenchPanes(panes, query);\n const choose = (paneId: string) => {\n onOpen(paneId);\n setOpen(false);\n setQuery('');\n };\n return (\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setQuery('');\n }}\n >\n <PopoverTrigger asChild>\n <button type=\"button\" aria-label=\"Open a pane\" title=\"Open a pane\" className={ICON_BUTTON_CLASS}>\n <PlusIcon className=\"size-4\" />\n </button>\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-56 p-1\" aria-label=\"Panes\">\n <div className=\"flex items-center gap-2 border-border border-b px-2 pb-1.5 pt-1\">\n <SearchIcon className=\"size-3.5 shrink-0 text-muted-foreground\" aria-hidden />\n <input\n // biome-ignore lint/a11y/noAutofocus: the menu opens to type into, as a command menu does.\n autoFocus\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onKeyDown={(event) => {\n const first = shown[0];\n if (event.key === 'Enter' && first) {\n event.preventDefault();\n choose(first.id);\n }\n }}\n placeholder=\"Search\"\n aria-label=\"Search panes\"\n className=\"h-7 min-w-0 flex-1 bg-transparent text-[13px] outline-none placeholder:text-muted-foreground\"\n />\n </div>\n <div className=\"pt-1\">\n {shown.length > 0 ? (\n <PaneMenuItems panes={shown} openIds={openIds} onOpen={choose} />\n ) : (\n <p className=\"px-2 py-1.5 text-[13px] text-muted-foreground\">No pane matches.</p>\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n};\n\n/** Nothing open: every pane the \"+\" menu offers, with what each shows, centred in the column. */\nconst NoOpenPane: FC<{\n panes: readonly SessionWorkbenchPane[];\n onOpen: (paneId: string) => void;\n}> = ({ panes, onOpen }) => (\n <div className=\"flex min-h-full items-center justify-center p-6\">\n <ul aria-label=\"Available panes\" className=\"flex w-full max-w-xs flex-col gap-1\">\n {panes.map((pane) => {\n const Icon = pane.icon ?? LayersIcon;\n return (\n <li key={pane.id}>\n <button\n type=\"button\"\n onClick={() => onOpen(pane.id)}\n className=\"flex w-full items-start gap-3 rounded-lg px-3 py-2 text-left transition-colors hover:bg-muted focus-visible:bg-muted focus-visible:outline-none\"\n >\n <Icon className=\"mt-0.5 size-4 shrink-0 text-muted-foreground\" />\n <span className=\"flex min-w-0 flex-col\">\n <span className=\"text-[13px] text-foreground\">{pane.title}</span>\n {pane.description ? (\n <span className=\"text-muted-foreground text-xs\">{pane.description}</span>\n ) : null}\n </span>\n </button>\n </li>\n );\n })}\n </ul>\n </div>\n);\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SessionWorkbench.js","sources":["../../src/workbench/SessionWorkbench.tsx"],"sourcesContent":["\"use client\";\n\nimport { useAuiState } from '@assistant-ui/react';\nimport { readDeepAgentStreamValues } from '@athenaintel/agent-runtime';\nimport { QueryClientProvider, useQueryClient } from '@tanstack/react-query';\nimport {\n LayersIcon,\n Maximize2Icon,\n Minimize2Icon,\n PanelRightCloseIcon,\n PanelRightOpenIcon,\n PlusIcon,\n SearchIcon,\n XIcon,\n} from 'lucide-react';\nimport {\n type FC,\n type KeyboardEvent,\n useContext,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useReducer,\n useRef,\n useState,\n} from 'react';\nimport { useAssetPanelStore } from '../assets/asset-panel-store';\nimport { AssetPanel } from '../assets/AssetPanel';\nimport { useAthenaQueryClient } from '../lib/use-athena-rest-query';\nimport { cn } from '../lib/utils';\nimport { useAthenaStatewireThreadList } from '../threads/statewire-thread-list';\nimport { AthenaStatewireThreadIdContext } from '../threads/thread-id-context';\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';\nimport {\n type SessionWorkbenchPane,\n type SessionWorkbenchPaneContext,\n SessionWorkbenchContext,\n} from './session-workbench-context';\nimport {\n filterWorkbenchPanes,\n threadTabs,\n visibleThreadTabs,\n type WorkbenchThreadTabs,\n workbenchTabsReducer,\n} from './session-workbench-model';\nimport {\n DEFAULT_SESSION_WORKBENCH_OPEN_PANE_IDS,\n DEFAULT_SESSION_WORKBENCH_PANES,\n} from './session-workbench-panes';\nimport { SESSION_WORKSPACE_QUERY_KEY } from './use-session-workspace';\nimport { useWorkbenchLayout } from './workbench-layout-context';\n\n/** The tab `AthenaLayout`'s workbench shows the open assets in. */\nexport const SESSION_WORKBENCH_ASSETS_PANE_ID = 'open-assets';\n\nconst OPEN_ASSETS_PANE: SessionWorkbenchPane = {\n id: SESSION_WORKBENCH_ASSETS_PANE_ID,\n title: 'Open assets',\n description: 'The documents, sheets and decks open in this session',\n icon: LayersIcon,\n render: () => <AssetPanel manageAssetPanelHostRegistration={false} />,\n};\n\nexport interface SessionWorkbenchProps {\n /**\n * The panes the \"+\" menu offers, in order. Defaults to the built-in Tasks,\n * Shell, Computer, Pull requests and Attachments\n * (`DEFAULT_SESSION_WORKBENCH_PANES`); spread it to add your own.\n */\n panes?: readonly SessionWorkbenchPane[];\n /**\n * The panes a thread opens with until the person changes its tabs (ids from\n * `panes`; unknown ids are ignored). Defaults to Tasks, Shell and Computer.\n */\n defaultOpenPaneIds?: readonly string[];\n className?: string;\n}\n\nconst ICON_BUTTON_CLASS =\n 'inline-flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring/60';\n\n/**\n * A Devin-style workspace pane for the active session: a tab strip of panes\n * (Tasks, Shell, Computer, Pull requests, Attachments — and any the host\n * adds), a \"+\" menu to open more, closable tabs, and a collapse to a rail.\n *\n * Mount it inside `<AthenaProvider>` — as `AthenaLayout`'s `workbench` for a\n * resizable right-hand column, or anywhere in your own layout. Each thread\n * keeps its own open tabs, and whether the workspace is open or collapsed,\n * while the workbench stays mounted (in memory only); a thread it has not seen\n * opens `defaultOpenPaneIds`, collapsed when the layout's\n * `defaultWorkbenchCollapsed` says so. In `AthenaLayout`, the assets the agent\n * or the person opens show here too, as an \"Open assets\" tab.\n */\nexport const SessionWorkbench: FC<SessionWorkbenchProps> = (props) => {\n // One client for every pane, so the workspace read several panes share is\n // fetched once even when the host provides no QueryClient.\n const queryClient = useAthenaQueryClient();\n return (\n <QueryClientProvider client={queryClient}>\n <SessionWorkbenchInner {...props} />\n </QueryClientProvider>\n );\n};\n\nconst SessionWorkbenchInner: FC<SessionWorkbenchProps> = ({\n panes = DEFAULT_SESSION_WORKBENCH_PANES,\n defaultOpenPaneIds = DEFAULT_SESSION_WORKBENCH_OPEN_PANE_IDS,\n className,\n}) => {\n const layout = useWorkbenchLayout();\n const [ownCollapsed, setOwnCollapsed] = useState(false);\n const collapsed = layout ? layout.collapsed : ownCollapsed;\n const setCollapsed = layout ? layout.setCollapsed : setOwnCollapsed;\n // Only a hosting layout can give the workbench the chat's width.\n const maximized = layout?.maximized ?? false;\n const setMaximized = layout?.setMaximized;\n const hostsAssetPanel = layout?.hostsAssetPanel ?? false;\n\n const threadId = useContext(AthenaStatewireThreadIdContext);\n const threadList = useAthenaStatewireThreadList();\n const hasMessages = useAuiState((state) => state.thread.messages.length > 0);\n // The attach snapshot says whether the backend minted the thread's session\n // (`sessionPersisted`) — true for an existing thread before any message.\n const sessionPersisted = useAuiState(\n (state) =>\n readDeepAgentStreamValues((state.thread.extras as { state?: unknown } | undefined)?.state)\n .sessionPersisted,\n );\n const isRunning = useAuiState(\n (state) => (state.thread.extras as { status?: unknown } | undefined)?.status === 'running',\n );\n // In thread-list mode the list knows whether the backend has the thread; a\n // single-thread provider's thread is known once the host says its session\n // exists, or once it has history (a host that predates the flag).\n const isPersisted = threadList\n ? !threadList.isNewChat\n : sessionPersisted === true || hasMessages;\n const paneContext = useMemo<SessionWorkbenchPaneContext>(\n () => ({ threadId, isPersisted, isRunning }),\n [threadId, isPersisted, isRunning],\n );\n\n // Polling stops with the run; read the workspace once more as it settles so\n // what the run's last steps created shows without waiting for a refocus.\n const queryClient = useQueryClient();\n const wasRunning = useRef(isRunning);\n useEffect(() => {\n if (wasRunning.current && !isRunning) {\n void queryClient.invalidateQueries({ queryKey: SESSION_WORKSPACE_QUERY_KEY });\n }\n wasRunning.current = isRunning;\n }, [isRunning, queryClient]);\n\n const assetPanelOpen = useAssetPanelStore((state) => state.isOpen);\n const closeAssetPanel = useAssetPanelStore((state) => state.closePanel);\n const allPanes = useMemo<readonly SessionWorkbenchPane[]>(\n () => (hostsAssetPanel && assetPanelOpen ? [...panes, OPEN_ASSETS_PANE] : panes),\n [assetPanelOpen, hostsAssetPanel, panes],\n );\n const paneById = useMemo(() => new Map(allPanes.map((pane) => [pane.id, pane])), [allPanes]);\n const paneIds = useMemo(() => new Set(paneById.keys()), [paneById]);\n\n const defaults = useMemo<WorkbenchThreadTabs>(() => {\n const open = defaultOpenPaneIds.filter((id) => panes.some((pane) => pane.id === id));\n return { open, active: open[0] ?? null };\n }, [defaultOpenPaneIds, panes]);\n const [tabsState, dispatchTabs] = useReducer(workbenchTabsReducer, {});\n const threadKey = threadId ?? '';\n\n // Whether the workspace is open is kept per thread, like its tabs: a thread\n // the person has not opened or collapsed it in shows the layout's default (a\n // new session, or one switched to), so one session's open workspace never\n // follows the person into the next. Applied before paint, so a switch never\n // flashes the previous thread's state.\n const defaultCollapsed = layout?.defaultCollapsed ?? false;\n const collapsedByThread = useRef(new Map<string, boolean>());\n const setThreadCollapsed = (next: boolean) => {\n collapsedByThread.current.set(threadKey, next);\n setCollapsed(next);\n };\n useLayoutEffect(() => {\n setCollapsed(collapsedByThread.current.get(threadKey) ?? defaultCollapsed);\n }, [threadKey, defaultCollapsed, setCollapsed]);\n let tabs = visibleThreadTabs(threadTabs(tabsState, threadKey, defaults), paneIds);\n // Assets already open when the workbench mounts (or when a thread with open\n // assets comes back) show their tab without an opening to react to.\n if (\n paneIds.has(SESSION_WORKBENCH_ASSETS_PANE_ID) &&\n !tabs.open.includes(SESSION_WORKBENCH_ASSETS_PANE_ID)\n ) {\n tabs = {\n open: [...tabs.open, SESSION_WORKBENCH_ASSETS_PANE_ID],\n active: tabs.active ?? SESSION_WORKBENCH_ASSETS_PANE_ID,\n };\n }\n\n // An asset opening (a tool card, a citation, the Attachments pane) brings\n // the \"Open assets\" tab forward and the workbench out of its rail. A thread\n // switch restoring that thread's open assets (`setCurrentThread`) is not an\n // opening: the thread keeps the pane it had selected. Read through refs:\n // the store notifies outside React's render.\n const latest = useRef({ threadKey, defaults, setCollapsed });\n latest.current = { threadKey, defaults, setCollapsed };\n useEffect(() => {\n if (!hostsAssetPanel) return undefined;\n return useAssetPanelStore.subscribe((state, previous) => {\n if (state.currentThreadId !== previous.currentThreadId) return;\n // Every open request, a repeat click on the asset already showing too.\n if (!state.isOpen || state.openRequestSeq === previous.openRequestSeq) return;\n dispatchTabs({\n type: 'open',\n threadKey: latest.current.threadKey,\n paneId: SESSION_WORKBENCH_ASSETS_PANE_ID,\n defaults: latest.current.defaults,\n });\n collapsedByThread.current.set(latest.current.threadKey, false);\n latest.current.setCollapsed(false);\n });\n }, [hostsAssetPanel]);\n\n // Showing a tab the strip renders is an `open`: it activates a stored tab\n // and records one the strip only derived (the \"Open assets\" tab above).\n const openPane = (paneId: string) =>\n dispatchTabs({ type: 'open', threadKey, paneId, defaults });\n const activatePane = openPane;\n const closePane = (paneId: string) => {\n if (paneId === SESSION_WORKBENCH_ASSETS_PANE_ID) closeAssetPanel();\n dispatchTabs({ type: 'close', threadKey, paneId, defaults });\n };\n\n const baseId = useId();\n const tabId = (paneId: string) => `${baseId}-tab-${paneId}`;\n const panelId = `${baseId}-panel`;\n\n const onTabKeyDown = (event: KeyboardEvent<HTMLButtonElement>, index: number) => {\n const step = event.key === 'ArrowRight' ? 1 : event.key === 'ArrowLeft' ? -1 : 0;\n if (step === 0 || tabs.open.length === 0) return;\n event.preventDefault();\n const nextId = tabs.open[(index + step + tabs.open.length) % tabs.open.length];\n if (!nextId) return;\n activatePane(nextId);\n event.currentTarget.ownerDocument.getElementById(tabId(nextId))?.focus();\n };\n\n const activePane = tabs.active ? paneById.get(tabs.active) : undefined;\n const assetsPane = paneById.get(SESSION_WORKBENCH_ASSETS_PANE_ID);\n const assetsActive = activePane?.id === SESSION_WORKBENCH_ASSETS_PANE_ID;\n\n // One tree for both states: the panel stays mounted (hidden) while the\n // workbench is a rail, and the open assets stay mounted (hidden) while\n // another pane shows — their iframes keep their editing session, as the\n // asset panel's own tabs do.\n return (\n <SessionWorkbenchContext.Provider value={paneContext}>\n <aside\n aria-label=\"Session workspace\"\n className={cn(\n 'athena-sdk-chrome flex h-full flex-col border-border border-l bg-background',\n collapsed ? 'w-10 shrink-0 items-center gap-1 py-2' : 'min-h-0 w-full min-w-0',\n className,\n )}\n >\n {collapsed ? (\n <>\n <button\n type=\"button\"\n aria-label=\"Expand workspace\"\n title=\"Expand workspace\"\n onClick={() => setThreadCollapsed(false)}\n className={ICON_BUTTON_CLASS}\n >\n <PanelRightOpenIcon className=\"size-4\" />\n </button>\n {tabs.open.map((paneId) => {\n const pane = paneById.get(paneId);\n if (!pane) return null;\n const Icon = pane.icon ?? LayersIcon;\n return (\n <button\n key={paneId}\n type=\"button\"\n aria-label={`Show ${pane.title}`}\n title={pane.title}\n onClick={() => {\n activatePane(paneId);\n setThreadCollapsed(false);\n }}\n className={cn(\n ICON_BUTTON_CLASS,\n paneId === tabs.active && 'bg-muted text-foreground',\n )}\n >\n <Icon className=\"size-4\" />\n </button>\n );\n })}\n </>\n ) : (\n <div className=\"flex h-11 w-full shrink-0 items-center gap-1 border-border border-b pr-1.5 pl-2\">\n <div\n role=\"tablist\"\n aria-label=\"Workspace panes\"\n className=\"flex min-w-0 items-center gap-1 overflow-x-auto [scrollbar-width:none]\"\n >\n {tabs.open.map((paneId, index) => {\n const pane = paneById.get(paneId);\n if (!pane) return null;\n const Icon = pane.icon;\n const selected = paneId === tabs.active;\n return (\n <div\n key={paneId}\n data-selected={selected ? '' : undefined}\n className={cn(\n 'group/tab flex h-7 shrink-0 items-center rounded-md text-[13px] transition-colors',\n selected\n ? 'bg-foreground/[0.06] text-foreground'\n : 'text-muted-foreground hover:bg-foreground/[0.04] hover:text-foreground',\n )}\n >\n <button\n type=\"button\"\n role=\"tab\"\n id={tabId(paneId)}\n aria-selected={selected}\n aria-controls={panelId}\n tabIndex={selected ? 0 : -1}\n onClick={() => activatePane(paneId)}\n onKeyDown={(event) => onTabKeyDown(event, index)}\n className=\"flex h-full items-center gap-1.5 rounded-md pr-1 pl-2 outline-none focus-visible:ring-2 focus-visible:ring-ring/60\"\n >\n {Icon ? <Icon className=\"size-3.5\" /> : null}\n {pane.title}\n </button>\n {/* Quiet until the tab is hovered, focused or selected, as in Devin's strip. */}\n <button\n type=\"button\"\n aria-label={`Close ${pane.title}`}\n title={`Close ${pane.title}`}\n onClick={() => closePane(paneId)}\n className={cn(\n 'mr-1 rounded p-0.5 transition-opacity hover:bg-background hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/60',\n selected ? 'opacity-60' : 'opacity-0 group-hover/tab:opacity-60',\n )}\n >\n <XIcon className=\"size-3\" />\n </button>\n </div>\n );\n })}\n </div>\n <AddPaneMenu panes={allPanes} openIds={tabs.open} onOpen={openPane} />\n <div className=\"min-w-0 flex-1\" />\n {setMaximized ? (\n <button\n type=\"button\"\n aria-label={maximized ? 'Restore workspace' : 'Maximize workspace'}\n title={maximized ? 'Restore workspace' : 'Maximize workspace'}\n aria-pressed={maximized}\n onClick={() => setMaximized(!maximized)}\n className={ICON_BUTTON_CLASS}\n >\n {maximized ? <Minimize2Icon className=\"size-4\" /> : <Maximize2Icon className=\"size-4\" />}\n </button>\n ) : null}\n <button\n type=\"button\"\n aria-label=\"Collapse workspace\"\n title=\"Collapse workspace\"\n onClick={() => setThreadCollapsed(true)}\n className={ICON_BUTTON_CLASS}\n >\n <PanelRightCloseIcon className=\"size-4\" />\n </button>\n </div>\n )}\n <div\n role=\"tabpanel\"\n id={panelId}\n aria-labelledby={activePane ? tabId(activePane.id) : undefined}\n className={cn(\n 'min-h-0 w-full flex-1',\n assetsActive ? 'flex flex-col' : 'overflow-y-auto',\n collapsed && 'hidden',\n )}\n >\n {assetsActive ? null : activePane ? (\n activePane.render(paneContext)\n ) : (\n <NoOpenPane panes={allPanes} onOpen={openPane} />\n )}\n {assetsPane ? (\n <div\n key={SESSION_WORKBENCH_ASSETS_PANE_ID}\n data-workbench-assets=\"\"\n className={cn(assetsActive ? 'flex min-h-0 flex-1 flex-col' : 'hidden')}\n >\n {assetsPane.render(paneContext)}\n </div>\n ) : null}\n </div>\n </aside>\n </SessionWorkbenchContext.Provider>\n );\n};\n\nconst PaneMenuItems: FC<{\n panes: readonly SessionWorkbenchPane[];\n openIds: readonly string[];\n onOpen: (paneId: string) => void;\n}> = ({ panes, openIds, onOpen }) => (\n <ul className=\"flex flex-col\">\n {panes.map((pane) => {\n const Icon = pane.icon ?? LayersIcon;\n const isOpen = openIds.includes(pane.id);\n return (\n <li key={pane.id}>\n <button\n type=\"button\"\n title={pane.description}\n onClick={() => onOpen(pane.id)}\n className=\"flex h-[30px] w-full items-center gap-2 rounded-md px-2 text-left text-[13px] transition-colors hover:bg-muted focus-visible:bg-muted focus-visible:outline-none\"\n >\n <Icon className=\"size-4 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1 truncate\">{pane.title}</span>\n {isOpen ? <span className=\"text-[11px] text-muted-foreground\">Open</span> : null}\n </button>\n </li>\n );\n })}\n </ul>\n);\n\nconst AddPaneMenu: FC<{\n panes: readonly SessionWorkbenchPane[];\n openIds: readonly string[];\n onOpen: (paneId: string) => void;\n}> = ({ panes, openIds, onOpen }) => {\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const shown = filterWorkbenchPanes(panes, query);\n const choose = (paneId: string) => {\n onOpen(paneId);\n setOpen(false);\n setQuery('');\n };\n return (\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setQuery('');\n }}\n >\n <PopoverTrigger asChild>\n <button type=\"button\" aria-label=\"Open a pane\" title=\"Open a pane\" className={ICON_BUTTON_CLASS}>\n <PlusIcon className=\"size-4\" />\n </button>\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-56 p-1\" aria-label=\"Panes\">\n <div className=\"flex items-center gap-2 border-border border-b px-2 pb-1.5 pt-1\">\n <SearchIcon className=\"size-3.5 shrink-0 text-muted-foreground\" aria-hidden />\n <input\n // biome-ignore lint/a11y/noAutofocus: the menu opens to type into, as a command menu does.\n autoFocus\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onKeyDown={(event) => {\n const first = shown[0];\n if (event.key === 'Enter' && first) {\n event.preventDefault();\n choose(first.id);\n }\n }}\n placeholder=\"Search\"\n aria-label=\"Search panes\"\n className=\"h-7 min-w-0 flex-1 bg-transparent text-[13px] outline-none placeholder:text-muted-foreground\"\n />\n </div>\n <div className=\"pt-1\">\n {shown.length > 0 ? (\n <PaneMenuItems panes={shown} openIds={openIds} onOpen={choose} />\n ) : (\n <p className=\"px-2 py-1.5 text-[13px] text-muted-foreground\">No pane matches.</p>\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n};\n\n/** Nothing open: every pane the \"+\" menu offers, with what each shows, centred in the column. */\nconst NoOpenPane: FC<{\n panes: readonly SessionWorkbenchPane[];\n onOpen: (paneId: string) => void;\n}> = ({ panes, onOpen }) => (\n <div className=\"flex min-h-full items-center justify-center p-6\">\n <ul aria-label=\"Available panes\" className=\"flex w-full max-w-xs flex-col gap-1\">\n {panes.map((pane) => {\n const Icon = pane.icon ?? LayersIcon;\n return (\n <li key={pane.id}>\n <button\n type=\"button\"\n onClick={() => onOpen(pane.id)}\n className=\"flex w-full items-start gap-3 rounded-lg px-3 py-2 text-left transition-colors hover:bg-muted focus-visible:bg-muted focus-visible:outline-none\"\n >\n <Icon className=\"mt-0.5 size-4 shrink-0 text-muted-foreground\" />\n <span className=\"flex min-w-0 flex-col\">\n <span className=\"text-[13px] text-foreground\">{pane.title}</span>\n {pane.description ? (\n <span className=\"text-muted-foreground text-xs\">{pane.description}</span>\n ) : null}\n </span>\n </button>\n </li>\n );\n })}\n </ul>\n </div>\n);\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workbench-layout-context.cjs","sources":["../../src/workbench/workbench-layout-context.ts"],"sourcesContent":["import { createContext, useContext } from 'react';\n\n/**\n * What `AthenaLayout` tells the `SessionWorkbench` it hosts in its right-hand\n * column: whether that column is collapsed to a rail or maximized over the\n * chat (the layout owns its width), and that the open assets render inside\n * the workbench (as its \"Open assets\" tab) instead of in a column of their own.\n */\nexport interface WorkbenchLayoutState {\n collapsed: boolean;\n setCollapsed: (collapsed: boolean) => void;\n /** The column fills the layout and the chat is hidden until it is restored. */\n maximized: boolean;\n setMaximized: (maximized: boolean) => void;\n hostsAssetPanel: boolean;\n}\n\nexport const WorkbenchLayoutContext = createContext<WorkbenchLayoutState | null>(null);\n\n/** The hosting layout's state, or `null` for a workbench the host placed itself. */\nexport function useWorkbenchLayout(): WorkbenchLayoutState | null {\n return useContext(WorkbenchLayoutContext);\n}\n"],"names":["createContext","useContext"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"workbench-layout-context.cjs","sources":["../../src/workbench/workbench-layout-context.ts"],"sourcesContent":["import { createContext, useContext } from 'react';\n\n/**\n * What `AthenaLayout` tells the `SessionWorkbench` it hosts in its right-hand\n * column: whether that column is collapsed to a rail or maximized over the\n * chat (the layout owns its width), and that the open assets render inside\n * the workbench (as its \"Open assets\" tab) instead of in a column of their own.\n */\nexport interface WorkbenchLayoutState {\n collapsed: boolean;\n setCollapsed: (collapsed: boolean) => void;\n /** Whether a session the person has not opened the workspace in starts collapsed. */\n defaultCollapsed: boolean;\n /** The column fills the layout and the chat is hidden until it is restored. */\n maximized: boolean;\n setMaximized: (maximized: boolean) => void;\n hostsAssetPanel: boolean;\n}\n\nexport const WorkbenchLayoutContext = createContext<WorkbenchLayoutState | null>(null);\n\n/** The hosting layout's state, or `null` for a workbench the host placed itself. */\nexport function useWorkbenchLayout(): WorkbenchLayoutState | null {\n return useContext(WorkbenchLayoutContext);\n}\n"],"names":["createContext","useContext"],"mappings":";;;AAmBO,MAAM,yBAAyBA,MAAAA,cAA2C,IAAI;AAG9E,SAAS,qBAAkD;AAChE,SAAOC,MAAAA,WAAW,sBAAsB;AAC1C;;;"}
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
export interface WorkbenchLayoutState {
|
|
8
8
|
collapsed: boolean;
|
|
9
9
|
setCollapsed: (collapsed: boolean) => void;
|
|
10
|
+
/** Whether a session the person has not opened the workspace in starts collapsed. */
|
|
11
|
+
defaultCollapsed: boolean;
|
|
10
12
|
/** The column fills the layout and the chat is hidden until it is restored. */
|
|
11
13
|
maximized: boolean;
|
|
12
14
|
setMaximized: (maximized: boolean) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workbench-layout-context.js","sources":["../../src/workbench/workbench-layout-context.ts"],"sourcesContent":["import { createContext, useContext } from 'react';\n\n/**\n * What `AthenaLayout` tells the `SessionWorkbench` it hosts in its right-hand\n * column: whether that column is collapsed to a rail or maximized over the\n * chat (the layout owns its width), and that the open assets render inside\n * the workbench (as its \"Open assets\" tab) instead of in a column of their own.\n */\nexport interface WorkbenchLayoutState {\n collapsed: boolean;\n setCollapsed: (collapsed: boolean) => void;\n /** The column fills the layout and the chat is hidden until it is restored. */\n maximized: boolean;\n setMaximized: (maximized: boolean) => void;\n hostsAssetPanel: boolean;\n}\n\nexport const WorkbenchLayoutContext = createContext<WorkbenchLayoutState | null>(null);\n\n/** The hosting layout's state, or `null` for a workbench the host placed itself. */\nexport function useWorkbenchLayout(): WorkbenchLayoutState | null {\n return useContext(WorkbenchLayoutContext);\n}\n"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"workbench-layout-context.js","sources":["../../src/workbench/workbench-layout-context.ts"],"sourcesContent":["import { createContext, useContext } from 'react';\n\n/**\n * What `AthenaLayout` tells the `SessionWorkbench` it hosts in its right-hand\n * column: whether that column is collapsed to a rail or maximized over the\n * chat (the layout owns its width), and that the open assets render inside\n * the workbench (as its \"Open assets\" tab) instead of in a column of their own.\n */\nexport interface WorkbenchLayoutState {\n collapsed: boolean;\n setCollapsed: (collapsed: boolean) => void;\n /** Whether a session the person has not opened the workspace in starts collapsed. */\n defaultCollapsed: boolean;\n /** The column fills the layout and the chat is hidden until it is restored. */\n maximized: boolean;\n setMaximized: (maximized: boolean) => void;\n hostsAssetPanel: boolean;\n}\n\nexport const WorkbenchLayoutContext = createContext<WorkbenchLayoutState | null>(null);\n\n/** The hosting layout's state, or `null` for a workbench the host placed itself. */\nexport function useWorkbenchLayout(): WorkbenchLayoutState | null {\n return useContext(WorkbenchLayoutContext);\n}\n"],"names":[],"mappings":";AAmBO,MAAM,yBAAyB,cAA2C,IAAI;AAG9E,SAAS,qBAAkD;AAChE,SAAO,WAAW,sBAAsB;AAC1C;"}
|