@mcp-b/react-components 0.44.1 → 0.46.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.
Files changed (170) hide show
  1. package/dist/{AgentChat-Bibfj7u1.d.ts → AgentChat-BLmQghkt.d.ts} +2 -2
  2. package/dist/{AgentToolRunsContext-daY67hFM.d.ts → AgentToolRunsContext-jtmveaRE.d.ts} +8 -7
  3. package/dist/{CodeBlock-Dl7a3Wqo.js → CodeBlock-BpooTofO.js} +1 -1
  4. package/dist/{FileTree-Uu3ZnW1u.js → FileTree-CAXWXH63.js} +1 -1
  5. package/dist/{McpConnectorForm-MRm1r59e.d.ts → McpConnectorForm-BETdVBRk.d.ts} +1 -1
  6. package/dist/{McpPluginCatalog-mbGw8FTu.d.ts → McpPluginCatalog-C6ip9IvL.d.ts} +2 -2
  7. package/dist/{PromptInput-BRX7FhjH.d.ts → PromptInput-DtJHyp0S.d.ts} +27 -22
  8. package/dist/{ResponsiveSidebarShell-DOXd5T-d.d.ts → ResponsiveSidebarShell-BTVPxLJK.d.ts} +12 -0
  9. package/dist/{SetupChecklist-DOp-zqjh.js → SetupChecklist-DyPZWzK2.js} +2 -2
  10. package/dist/{ThinkChat-BES_3Mb-.js → ThinkChat-qztQ6Clo.js} +7 -22
  11. package/dist/{ThinkChatActivity-CgvmTXXB.d.ts → ThinkChatActivity-B3lGVS-6.d.ts} +1 -1
  12. package/dist/{WorkspaceFileView-BublZXky.js → WorkspaceFileView-BvDbKM2c.js} +3 -3
  13. package/dist/components/agents-sdk/AgentActivity.js +1 -1
  14. package/dist/components/agents-sdk/AgentChat.d.ts +1 -1
  15. package/dist/components/agents-sdk/AgentChat.js +44 -40
  16. package/dist/components/agents-sdk/AgentEvent.d.ts +42 -0
  17. package/dist/components/agents-sdk/AgentEvent.js +96 -0
  18. package/dist/components/agents-sdk/AgentToolRunsContext.d.ts +1 -1
  19. package/dist/components/agents-sdk/AgentToolRunsContext.js +11 -7
  20. package/dist/components/agents-sdk/BrowserLiveScreen.js +1 -1
  21. package/dist/components/agents-sdk/BrowserLiveView.js +1 -1
  22. package/dist/components/agents-sdk/BrowserReplay.js +2 -2
  23. package/dist/components/agents-sdk/BrowserRunPanel.js +1 -1
  24. package/dist/components/agents-sdk/ManagerOffice.d.ts +106 -11
  25. package/dist/components/agents-sdk/ManagerOffice.js +1193 -151
  26. package/dist/components/agents-sdk/McpConnectionRequest.d.ts +1 -1
  27. package/dist/components/agents-sdk/McpConnectionRequest.js +11 -5
  28. package/dist/components/agents-sdk/McpConnectorForm.d.ts +1 -1
  29. package/dist/components/agents-sdk/McpConnectorForm.js +1 -1
  30. package/dist/components/agents-sdk/McpPluginCatalog.d.ts +1 -1
  31. package/dist/components/agents-sdk/McpPluginCatalog.js +11 -7
  32. package/dist/components/agents-sdk/McpServerPicker.d.ts +2 -2
  33. package/dist/components/agents-sdk/McpServerPicker.js +4 -4
  34. package/dist/components/agents-sdk/ModelSelector.js +5 -5
  35. package/dist/components/agents-sdk/PromptInputApproval.js +1 -1
  36. package/dist/components/agents-sdk/PromptInputCommands.d.ts +5 -2
  37. package/dist/components/agents-sdk/PromptInputCommands.js +81 -3
  38. package/dist/components/agents-sdk/SubagentRunDetails.js +1 -1
  39. package/dist/components/agents-sdk/SubagentRunIndicator.d.ts +21 -3
  40. package/dist/components/agents-sdk/SubagentRunIndicator.js +56 -6
  41. package/dist/components/agents-sdk/SubagentRunSelector.js +5 -12
  42. package/dist/components/agents-sdk/ThinkChat.d.ts +4 -5
  43. package/dist/components/agents-sdk/ThinkChat.js +1 -1
  44. package/dist/components/agents-sdk/ThinkChatActivity.d.ts +1 -1
  45. package/dist/components/agents-sdk/ThinkChatActivity.js +3 -3
  46. package/dist/components/agents-sdk/ThinkChatActivitySummary.js +1 -1
  47. package/dist/components/agents-sdk/ThinkChatToolPanels.js +2 -2
  48. package/dist/components/agents-sdk/ThinkExecutionDetail.js +3 -3
  49. package/dist/components/agents-sdk/ThinkExecutionRun.js +1 -1
  50. package/dist/components/agents-sdk/ThinkExecutionStatus.js +1 -1
  51. package/dist/components/agents-sdk/ThinkExecutionWorkbench.js +3 -3
  52. package/dist/components/agents-sdk/ThinkFullApp.d.ts +14 -4
  53. package/dist/components/agents-sdk/ThinkFullApp.js +51 -5
  54. package/dist/components/agents-sdk/ThinkFullAppViewSwitch.js +1 -1
  55. package/dist/components/agents-sdk/ThinkPendingApproval.js +1 -1
  56. package/dist/components/agents-sdk/ThinkRecoveryNotice.js +1 -1
  57. package/dist/components/agents-sdk/ThinkRoutineBrowser.js +3 -3
  58. package/dist/components/agents-sdk/ThinkRoutineDetail.js +1 -1
  59. package/dist/components/agents-sdk/ThinkRoutineForm.js +4 -4
  60. package/dist/components/agents-sdk/ThinkRoutineLibrary.d.ts +1 -1
  61. package/dist/components/agents-sdk/ThinkRoutineLibrary.js +4 -4
  62. package/dist/components/agents-sdk/ThinkRoutineRuns.js +1 -1
  63. package/dist/components/agents-sdk/ThinkSidepanel.d.ts +22 -4
  64. package/dist/components/agents-sdk/ThinkSidepanel.js +87 -35
  65. package/dist/components/agents-sdk/ThinkThreadPicker.js +5 -5
  66. package/dist/components/agents-sdk/Workspace.js +1 -1
  67. package/dist/components/agents-sdk/WorkspaceBrowser.js +1 -1
  68. package/dist/components/agents-sdk/WorkspaceExplorer.js +1 -1
  69. package/dist/components/agents-sdk/WorkspaceFileView.js +1 -1
  70. package/dist/components/agents-sdk/WorkspaceHeader.js +1 -1
  71. package/dist/components/agents-sdk/WorkspaceMountManager.js +4 -21
  72. package/dist/components/ai-sdk/Activity.js +1 -1
  73. package/dist/components/ai-sdk/AgentChatStartScreen.js +1 -1
  74. package/dist/components/ai-sdk/Approval.js +2 -2
  75. package/dist/components/ai-sdk/Artifact.js +1 -1
  76. package/dist/components/ai-sdk/ChainOfThought.d.ts +1 -1
  77. package/dist/components/ai-sdk/ChainOfThought.js +1 -1
  78. package/dist/components/ai-sdk/Checkpoint.js +1 -1
  79. package/dist/components/ai-sdk/CodeBlock.js +1 -1
  80. package/dist/components/ai-sdk/ComposerLink.d.ts +27 -0
  81. package/dist/components/ai-sdk/ComposerLink.js +111 -0
  82. package/dist/components/ai-sdk/ConnectedAppCards.js +3 -3
  83. package/dist/components/ai-sdk/Context.js +1 -1
  84. package/dist/components/ai-sdk/Conversation.js +1 -1
  85. package/dist/components/ai-sdk/Goal.js +2 -2
  86. package/dist/components/ai-sdk/InlineCitation.js +1 -1
  87. package/dist/components/ai-sdk/MediaPreviewCard.js +1 -1
  88. package/dist/components/ai-sdk/Message.js +19 -3
  89. package/dist/components/ai-sdk/MessageScroller.js +1 -1
  90. package/dist/components/ai-sdk/MessageScrollerVirtual.js +1 -1
  91. package/dist/components/ai-sdk/Plan.js +2 -2
  92. package/dist/components/ai-sdk/PromptInput.d.ts +2 -2
  93. package/dist/components/ai-sdk/PromptInput.js +67 -61
  94. package/dist/components/ai-sdk/PromptInputComposerEditor.d.ts +31 -0
  95. package/dist/components/ai-sdk/PromptInputComposerEditor.js +198 -0
  96. package/dist/components/ai-sdk/Queue.js +2 -2
  97. package/dist/components/ai-sdk/Reasoning.js +2 -2
  98. package/dist/components/ai-sdk/Sources.js +1 -1
  99. package/dist/components/ai-sdk/Task.js +1 -1
  100. package/dist/components/ai-sdk/ToolInvocation.js +1 -1
  101. package/dist/components/extension/ChatGptSignInScreen.js +2 -2
  102. package/dist/components/extension/CodexModelSelector.js +2 -2
  103. package/dist/components/extension/ConversationTabPicker.js +2 -2
  104. package/dist/components/foundations/AppIcon.js +1 -1
  105. package/dist/components/foundations/Checkbox.js +1 -1
  106. package/dist/components/foundations/Collapsible.js +1 -1
  107. package/dist/components/foundations/ContextMenu.js +1 -1
  108. package/dist/components/foundations/Menubar.js +1 -1
  109. package/dist/components/foundations/SearchField.js +1 -1
  110. package/dist/components/foundations/Select.js +1 -1
  111. package/dist/components/foundations/Stepper.js +1 -1
  112. package/dist/components/foundations/Toast.js +1 -1
  113. package/dist/components/foundations/ToggleGroup.d.ts +1 -1
  114. package/dist/components/foundations/ToggleGroup.js +1 -1
  115. package/dist/components/foundations/icons.d.ts +1 -1
  116. package/dist/components/foundations/icons.js +1 -1
  117. package/dist/components/general-purpose/Commit.js +2 -2
  118. package/dist/components/general-purpose/EnvironmentVariables.js +2 -2
  119. package/dist/components/general-purpose/FileTree.js +1 -1
  120. package/dist/components/general-purpose/PricingBillingToggle.js +1 -1
  121. package/dist/components/general-purpose/PricingPlanCard.js +2 -2
  122. package/dist/components/general-purpose/PricingUsageCalculator.js +2 -2
  123. package/dist/components/general-purpose/ResizableSidePanel.js +1 -1
  124. package/dist/components/general-purpose/ResponsiveSidebarShell.d.ts +1 -1
  125. package/dist/components/general-purpose/ResponsiveSidebarShell.js +72 -22
  126. package/dist/components/general-purpose/SettingsFormDialog.js +2 -2
  127. package/dist/components/general-purpose/SetupChecklist.js +1 -1
  128. package/dist/components/general-purpose/Terminal.js +2 -2
  129. package/dist/components/general-purpose/TestResults.js +1 -1
  130. package/dist/components/general-purpose/ThemeModeControl.js +2 -2
  131. package/dist/components/general-purpose/WebPreview.js +3 -3
  132. package/dist/components/nanites/AgentConnection.js +2 -2
  133. package/dist/components/nanites/AgentToolDetail.js +4 -4
  134. package/dist/{copy-button-DHhf-J1d.js → copy-button-D7ySsRRo.js} +1 -1
  135. package/dist/{format-DB2mX9DA.js → format-COCyV98Z.js} +23 -1
  136. package/dist/{icons-Dw-im7lg.js → icons-BNEY4gO5.js} +44 -4
  137. package/dist/{icons-6ZnyZJiR.d.ts → icons-D0Pd2P9v.d.ts} +9 -4
  138. package/dist/{mcp-server-SD_S-IpB.js → mcp-server-7NR24ASj.js} +31 -4
  139. package/dist/{mcp-server-catalog-CCj2ItkV.d.ts → mcp-server-catalog-Cbu483Zb.d.ts} +9 -9
  140. package/dist/{progress-ring-BEocM1e3.js → progress-ring-Cgii90dC.js} +1 -1
  141. package/dist/{provider-logos-zjZycgV6.js → provider-logos-DWYY8wNz.js} +31 -6
  142. package/dist/styles/action-guide.css +4 -0
  143. package/dist/styles/agent-attention.css +5 -1
  144. package/dist/styles/agent-chat.css +21 -18
  145. package/dist/styles/agent-event.css +14 -0
  146. package/dist/styles/app-icon.css +21 -0
  147. package/dist/styles/avatar.css +2 -1
  148. package/dist/styles/base.css +4 -0
  149. package/dist/styles/brand-marks.css +22 -0
  150. package/dist/styles/button.css +10 -0
  151. package/dist/styles/composer-link.css +99 -0
  152. package/dist/styles/connected-app-card.css +9 -0
  153. package/dist/styles/github-motion-mark.css +8 -1
  154. package/dist/styles/index.css +3 -0
  155. package/dist/styles/manager-office.css +1313 -73
  156. package/dist/styles/mcp-plugin-catalog.css +4 -0
  157. package/dist/styles/mcp-server-picker.css +2 -0
  158. package/dist/styles/message-scroller.css +5 -0
  159. package/dist/styles/prompt-input.css +14 -53
  160. package/dist/styles/responsive-sidebar-shell.css +47 -0
  161. package/dist/styles/subagent-run.css +29 -19
  162. package/dist/styles/think-full-app.css +139 -4
  163. package/dist/styles/think-sidepanel.css +9 -5
  164. package/dist/styles/think-thread-picker.css +13 -12
  165. package/dist/styles/workspace-mount-manager.css +0 -22
  166. package/dist/utils/composer-link.d.ts +59 -0
  167. package/dist/utils/composer-link.js +203 -0
  168. package/dist/utils/mcp-server-catalog.d.ts +1 -1
  169. package/dist/utils/mcp-server-catalog.js +9 -9
  170. package/package.json +8 -8
@@ -1,12 +1,16 @@
1
+ import { getMcpServerIconSrc } from "../../utils/mcp-server-catalog.js";
1
2
  import { t as cx } from "../../class-names-BiMDVpUo.js";
2
- import { C as FolderIcon, D as LinkIcon, P as MonitorIcon, R as PauseIcon, T as InfoIcon, U as RefreshIcon, V as PlusIcon, _ as DotIcon, a as ArrowUpIcon, d as CheckIcon, et as WarningIcon, f as ChevronDownIcon, j as MessageSquareIcon, n as ArrowDownIcon, nt as XIcon, p as ChevronRightIcon, q as SpinnerIcon, u as CalendarIcon, z as PencilIcon } from "../../icons-Dw-im7lg.js";
3
- import { Button } from "../foundations/Button.js";
4
- import { Tooltip } from "../foundations/Tooltip.js";
5
3
  import { Collapsible } from "../foundations/Collapsible.js";
6
- import { EmptyState } from "../foundations/EmptyState.js";
4
+ import { B as PlayIcon, C as FolderIcon, D as LinkIcon, P as MonitorIcon, R as PauseIcon, T as InfoIcon, U as RefreshIcon, V as PlusIcon, _ as DotIcon, a as ArrowUpIcon, b as EyeIcon, d as CheckIcon, et as WarningIcon, f as ChevronDownIcon, j as MessageSquareIcon, n as ArrowDownIcon, nt as XIcon, p as ChevronRightIcon, q as SpinnerIcon, u as CalendarIcon, v as DownloadIcon, z as PencilIcon } from "../../icons-BNEY4gO5.js";
5
+ import { Button } from "../foundations/Button.js";
7
6
  import { AgentAttention, AgentAttentionActions, AgentAttentionBody, AgentAttentionHeader } from "../ai-sdk/AgentAttention.js";
7
+ import { Tooltip } from "../foundations/Tooltip.js";
8
+ import { Menu } from "../foundations/Menu.js";
8
9
  import { Avatar } from "../foundations/Avatar.js";
9
10
  import { AppIcon } from "../foundations/AppIcon.js";
11
+ import { n as findCatalogMcpServerCard } from "../../mcp-server-7NR24ASj.js";
12
+ import { Select } from "../foundations/Select.js";
13
+ import { EmptyState } from "../foundations/EmptyState.js";
10
14
  import { LinkButton } from "../foundations/LinkButton.js";
11
15
  import "../foundations/icons.js";
12
16
  import { AppTopBar } from "../general-purpose/AppTopBar.js";
@@ -86,10 +90,10 @@ function chromeProfileColor(seed, taken) {
86
90
  //#endregion
87
91
  //#region src/components/agents-sdk/ManagerOffice.tsx
88
92
  const statusLabels = {
89
- "needs-you": "Needs you",
93
+ "needs-you": "Waiting on you",
90
94
  working: "Working",
91
95
  idle: "Idle",
92
- issue: "Issue",
96
+ issue: "Waiting on you",
93
97
  offline: "Offline",
94
98
  connecting: "Connecting…",
95
99
  unavailable: "Unavailable"
@@ -119,6 +123,27 @@ function employeeStatusText(employee) {
119
123
  const label = statusLabels[employee.status];
120
124
  return count ? `${label} · ${count} handoff${count === 1 ? "" : "s"}` : label;
121
125
  }
126
+ function statusIcon(status) {
127
+ if (status === "needs-you" || status === "issue") return /* @__PURE__ */ jsx(WarningIcon, {});
128
+ if (status === "unavailable") return /* @__PURE__ */ jsx(XIcon, {});
129
+ if (status === "working" || status === "connecting") return /* @__PURE__ */ jsx(SpinnerIcon, {});
130
+ if (status === "offline") return /* @__PURE__ */ jsx(MonitorIcon, {});
131
+ return /* @__PURE__ */ jsx(PauseIcon, {});
132
+ }
133
+ function EmployeePresence({ employee }) {
134
+ const label = employeeStatusText(employee);
135
+ return /* @__PURE__ */ jsxs(Tooltip.Root, { children: [/* @__PURE__ */ jsx(Tooltip.Trigger, { render: /* @__PURE__ */ jsx("span", {
136
+ className: "manager-office__nav-status",
137
+ "data-status": employee.status,
138
+ role: "img",
139
+ "aria-label": label,
140
+ children: statusIcon(employee.status)
141
+ }) }), /* @__PURE__ */ jsx(Tooltip.Portal, { children: /* @__PURE__ */ jsx(Tooltip.Positioner, {
142
+ side: "top",
143
+ sideOffset: 6,
144
+ children: /* @__PURE__ */ jsx(Tooltip.Popup, { children: label })
145
+ }) })] });
146
+ }
122
147
  /**
123
148
  * Each employee is a Chrome profile, so the bubble wears its profile color —
124
149
  * the same palette Chrome assigns profiles from. Chrome's pick is per-machine
@@ -136,52 +161,174 @@ function rosterProfileColors(employees) {
136
161
  }
137
162
  return colors;
138
163
  }
139
- function EmployeeAvatar({ color, employee, size = "sm" }) {
164
+ function EmployeeAvatar({ color, employee, index = 0, size = "sm" }) {
165
+ const variant = index % 4;
140
166
  return /* @__PURE__ */ jsx(Avatar.Root, {
141
167
  size,
142
168
  shape: "rounded",
169
+ className: "manager-office__employee-character",
143
170
  "aria-hidden": "true",
144
- children: /* @__PURE__ */ jsx(Avatar.Fallback, {
171
+ children: /* @__PURE__ */ jsxs(Avatar.Fallback, {
172
+ className: "manager-office__employee-character-fallback",
145
173
  style: {
146
174
  color: color.fg,
147
- backgroundColor: color.bg
175
+ backgroundColor: "transparent"
148
176
  },
149
- children: employee.initials
177
+ children: [/* @__PURE__ */ jsxs("svg", {
178
+ viewBox: "0 0 36 36",
179
+ focusable: "false",
180
+ role: "presentation",
181
+ style: { fill: color.bg },
182
+ children: [
183
+ /* @__PURE__ */ jsx("rect", {
184
+ x: "5",
185
+ y: "6",
186
+ width: "26",
187
+ height: "25",
188
+ rx: "7"
189
+ }),
190
+ /* @__PURE__ */ jsx("rect", {
191
+ x: "8",
192
+ y: "28",
193
+ width: "8",
194
+ height: "5",
195
+ rx: "2.5",
196
+ opacity: "0.78"
197
+ }),
198
+ /* @__PURE__ */ jsx("rect", {
199
+ x: "20",
200
+ y: "28",
201
+ width: "8",
202
+ height: "5",
203
+ rx: "2.5",
204
+ opacity: "0.78"
205
+ }),
206
+ variant === 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("path", { d: "M10 7c.6-3 3.2-5 6.2-5h3.6c3 0 5.6 2 6.2 5Z" }), /* @__PURE__ */ jsx("circle", {
207
+ cx: "18",
208
+ cy: "3",
209
+ r: "1.8"
210
+ })] }) : variant === 1 ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("rect", {
211
+ x: "2.5",
212
+ y: "13",
213
+ width: "4",
214
+ height: "10",
215
+ rx: "2"
216
+ }), /* @__PURE__ */ jsx("rect", {
217
+ x: "29.5",
218
+ y: "13",
219
+ width: "4",
220
+ height: "10",
221
+ rx: "2"
222
+ })] }) : variant === 2 ? /* @__PURE__ */ jsx("path", {
223
+ d: "M11 6V3.5h14V6M15 3.5V1.5h6v2",
224
+ fill: "none",
225
+ stroke: color.bg,
226
+ strokeWidth: "2",
227
+ strokeLinecap: "round",
228
+ strokeLinejoin: "round"
229
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("path", { d: "M12 7V3l4 3 4-4 4 5Z" }), /* @__PURE__ */ jsx("circle", {
230
+ cx: "26.5",
231
+ cy: "7",
232
+ r: "2"
233
+ })] }),
234
+ /* @__PURE__ */ jsx("g", {
235
+ className: "manager-office__employee-character-face",
236
+ fill: color.fg,
237
+ children: variant === 1 ? /* @__PURE__ */ jsxs(Fragment, { children: [
238
+ /* @__PURE__ */ jsx("rect", {
239
+ className: "manager-office__employee-character-visor",
240
+ x: "10",
241
+ y: "14",
242
+ width: "16",
243
+ height: "8",
244
+ rx: "4",
245
+ opacity: "0.94"
246
+ }),
247
+ /* @__PURE__ */ jsx("circle", {
248
+ cx: "14",
249
+ cy: "18",
250
+ r: "1.5",
251
+ fill: color.bg
252
+ }),
253
+ /* @__PURE__ */ jsx("circle", {
254
+ cx: "22",
255
+ cy: "18",
256
+ r: "1.5",
257
+ fill: color.bg
258
+ })
259
+ ] }) : variant === 3 ? /* @__PURE__ */ jsxs("g", {
260
+ className: "manager-office__employee-character-glasses",
261
+ children: [
262
+ /* @__PURE__ */ jsx("circle", {
263
+ className: "manager-office__employee-character-lens",
264
+ cx: "13.5",
265
+ cy: "17",
266
+ r: "3"
267
+ }),
268
+ /* @__PURE__ */ jsx("circle", {
269
+ className: "manager-office__employee-character-lens",
270
+ cx: "22.5",
271
+ cy: "17",
272
+ r: "3"
273
+ }),
274
+ /* @__PURE__ */ jsx("path", {
275
+ className: "manager-office__employee-character-bridge",
276
+ d: "M16.5 17h3"
277
+ })
278
+ ]
279
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [
280
+ /* @__PURE__ */ jsx("circle", {
281
+ cx: "13.5",
282
+ cy: "17",
283
+ r: "3.2"
284
+ }),
285
+ /* @__PURE__ */ jsx("circle", {
286
+ cx: "22.5",
287
+ cy: "17",
288
+ r: "3.2"
289
+ }),
290
+ /* @__PURE__ */ jsx("circle", {
291
+ cx: "14.5",
292
+ cy: "16",
293
+ r: "1",
294
+ fill: color.bg,
295
+ opacity: "0.72"
296
+ }),
297
+ /* @__PURE__ */ jsx("circle", {
298
+ cx: "23.5",
299
+ cy: "16",
300
+ r: "1",
301
+ fill: color.bg,
302
+ opacity: "0.72"
303
+ })
304
+ ] })
305
+ }),
306
+ /* @__PURE__ */ jsx("path", {
307
+ className: "manager-office__employee-character-shine",
308
+ d: "M9 11c2-2 4.7-3 7.7-3",
309
+ fill: "none",
310
+ stroke: color.fg,
311
+ strokeWidth: "1.5",
312
+ strokeLinecap: "round"
313
+ })
314
+ ]
315
+ }), /* @__PURE__ */ jsx("span", {
316
+ className: "sigvelo-visually-hidden",
317
+ children: employee.initials
318
+ })]
150
319
  })
151
320
  });
152
321
  }
153
322
  /**
154
- * One glyph per meaning, not one glyph per colour. Colour alone cannot carry
155
- * these apart: `forced-colors` flattens the palette, and a red/amber pair is
156
- * the most common colour-vision confusion there is. So an employee asking for
157
- * a person (`needs-you`), one that has failed (`issue`), and one that cannot be
158
- * reached at all (`unavailable`) each get a different shape.
323
+ * One glyph per manager action, not one glyph per backend state. Both an
324
+ * employee asking for a person (`needs-you`) and one blocked by an issue
325
+ * (`issue`) require the same response here, so the roster presents both as
326
+ * "Waiting on you" with the warning glyph. An unreachable employee remains a
327
+ * distinct shape because there is no work for the manager to resume yet.
159
328
  *
160
329
  * `working` and `connecting` deliberately share the spinner: both mean "in
161
330
  * motion, wait", and mistaking one for the other costs the manager nothing.
162
331
  */
163
- function statusIcon(status) {
164
- if (status === "needs-you") return /* @__PURE__ */ jsx(InfoIcon, {});
165
- if (status === "issue") return /* @__PURE__ */ jsx(WarningIcon, {});
166
- if (status === "unavailable") return /* @__PURE__ */ jsx(XIcon, {});
167
- if (status === "working" || status === "connecting") return /* @__PURE__ */ jsx(SpinnerIcon, {});
168
- if (status === "offline") return /* @__PURE__ */ jsx(MonitorIcon, {});
169
- return /* @__PURE__ */ jsx(PauseIcon, {});
170
- }
171
- /**
172
- * The glyph makes the state scannable and the unframed word keeps it readable
173
- * without hover. The employee header already provides the visual grouping.
174
- */
175
- function EmployeeStatus({ employee }) {
176
- const count = employeeAttentionCount(employee);
177
- const label = count ? `${statusLabels[employee.status]} · ${count}` : statusLabels[employee.status];
178
- return /* @__PURE__ */ jsxs("span", {
179
- className: "manager-office__status",
180
- "data-status": employee.status,
181
- "aria-label": label,
182
- children: [statusIcon(employee.status), /* @__PURE__ */ jsx("span", { children: label })]
183
- });
184
- }
185
332
  function ThreadStatusIcon({ status }) {
186
333
  return /* @__PURE__ */ jsx("span", {
187
334
  className: "manager-office__thread-status",
@@ -215,21 +362,6 @@ function Timestamp({ now, timestamp }) {
215
362
  children: relativeTime(timestamp, now)
216
363
  });
217
364
  }
218
- function RoutineEvidence({ employee }) {
219
- const { completed, finished } = employee.routines.reduce((total, routine) => ({
220
- completed: total.completed + routine.completedRuns,
221
- finished: total.finished + routine.finishedRuns
222
- }), {
223
- completed: 0,
224
- finished: 0
225
- });
226
- const label = finished === 0 ? "No runs yet" : `${completed}/${finished} runs`;
227
- return /* @__PURE__ */ jsxs("span", {
228
- className: "manager-office__evidence",
229
- "data-complete": finished > 0 && completed === finished ? "" : void 0,
230
- children: [finished === 0 ? /* @__PURE__ */ jsx(CalendarIcon, {}) : /* @__PURE__ */ jsx(CheckIcon, {}), /* @__PURE__ */ jsx("span", { children: label })]
231
- });
232
- }
233
365
  const channelDirectionLabels = {
234
366
  input: "In",
235
367
  output: "Out",
@@ -255,6 +387,28 @@ const channelStatusLabels = {
255
387
  "needs-auth": "Needs sign-in",
256
388
  error: "Error"
257
389
  };
390
+ function ChannelMark({ channel }) {
391
+ if (channel.icon) return /* @__PURE__ */ jsx("span", {
392
+ className: "manager-office__channel-mark",
393
+ children: channel.icon
394
+ });
395
+ const card = findCatalogMcpServerCard({
396
+ id: channel.id,
397
+ name: channel.name
398
+ });
399
+ const src = card ? getMcpServerIconSrc(card) : void 0;
400
+ if (src) return /* @__PURE__ */ jsx("span", {
401
+ className: "manager-office__channel-mark",
402
+ children: /* @__PURE__ */ jsx("img", {
403
+ alt: "",
404
+ className: "sigvelo-brand-mark sigvelo-brand-mark--colorful",
405
+ decoding: "async",
406
+ referrerPolicy: "no-referrer",
407
+ src
408
+ })
409
+ });
410
+ return /* @__PURE__ */ jsx(AppIcon.Fallback, { children: channel.name.slice(0, 1) });
411
+ }
258
412
  function ChannelRow({ channel }) {
259
413
  return /* @__PURE__ */ jsxs("li", {
260
414
  className: "manager-office__channel",
@@ -263,10 +417,7 @@ function ChannelRow({ channel }) {
263
417
  /* @__PURE__ */ jsx(AppIcon.Root, {
264
418
  size: "sm",
265
419
  "aria-hidden": "true",
266
- children: channel.icon ? /* @__PURE__ */ jsx("span", {
267
- className: "manager-office__channel-mark",
268
- children: channel.icon
269
- }) : /* @__PURE__ */ jsx(AppIcon.Fallback, { children: channel.name.slice(0, 1) })
420
+ children: /* @__PURE__ */ jsx(ChannelMark, { channel })
270
421
  }),
271
422
  /* @__PURE__ */ jsxs("span", {
272
423
  className: "manager-office__identity",
@@ -339,76 +490,119 @@ function HandoffCard({ employee, handoff, renderLink, now, showEmployee }) {
339
490
  ]
340
491
  });
341
492
  }
342
- function EmployeeSidebar({ closeSidebarOnCompact, employees, renderLink, officeActions, profileColors, view }) {
493
+ /** Dense nested action for an employee alert already signalled by the roster status. */
494
+ function ManagerOfficeSidebarAlert({ className, detail, title, ...props }) {
495
+ return /* @__PURE__ */ jsxs(LinkButton, {
496
+ variant: "ghost",
497
+ color: "neutral",
498
+ size: "sm",
499
+ className: cx("manager-office__sidebar-alert", className),
500
+ ...props,
501
+ children: [/* @__PURE__ */ jsxs("span", {
502
+ className: "manager-office__sidebar-alert-copy",
503
+ children: [/* @__PURE__ */ jsx("strong", { children: title }), /* @__PURE__ */ jsxs("span", {
504
+ className: "manager-office__sidebar-alert-meta",
505
+ children: [detail ? /* @__PURE__ */ jsx("small", { children: detail }) : null, /* @__PURE__ */ jsx("span", {
506
+ className: "manager-office__sidebar-alert-status",
507
+ children: "Blocked"
508
+ })]
509
+ })]
510
+ }), /* @__PURE__ */ jsx(ChevronRightIcon, {
511
+ className: "manager-office__sidebar-alert-chevron",
512
+ "aria-hidden": "true"
513
+ })]
514
+ });
515
+ }
516
+ /**
517
+ * Shared Manager Office rail. Stories and host shells may add employee-owned
518
+ * content, but the Workforce header, roster identity, status language, scrolling,
519
+ * and footer placement stay component-owned and therefore cannot drift.
520
+ */
521
+ function ManagerOfficeSidebar({ className, closeSidebarOnCompact, content, employees, renderLink, footer, officeActions, selectedEmployeeId, ...props }) {
343
522
  const rosterLabelId = React.useId();
344
- const attentionCount = employees.reduce((total, employee) => total + employeeAttentionCount(employee), 0);
345
- const selectedEmployeeId = view.kind === "employee" ? view.employeeId : null;
346
- return /* @__PURE__ */ jsxs("nav", {
347
- className: "manager-office__sidebar",
348
- "aria-label": "Manager office",
523
+ const employeeNavRef = React.useRef(null);
524
+ const [employeeNavOverflows, setEmployeeNavOverflows] = React.useState(false);
525
+ const profileColors = rosterProfileColors(employees);
526
+ React.useLayoutEffect(() => {
527
+ const employeeNav = employeeNavRef.current;
528
+ if (!employeeNav) return;
529
+ const syncOverflow = () => {
530
+ const overflows = employeeNav.scrollWidth > employeeNav.clientWidth;
531
+ setEmployeeNavOverflows((current) => current === overflows ? current : overflows);
532
+ };
533
+ syncOverflow();
534
+ if (typeof ResizeObserver === "undefined") return;
535
+ const observer = new ResizeObserver(syncOverflow);
536
+ observer.observe(employeeNav);
537
+ return () => observer.disconnect();
538
+ }, [employees]);
539
+ return /* @__PURE__ */ jsx(Tooltip.Provider, { children: /* @__PURE__ */ jsxs("nav", {
540
+ className: cx("manager-office__sidebar", className),
541
+ "aria-label": "Workforce",
542
+ ...props,
349
543
  children: [
350
544
  /* @__PURE__ */ jsxs("div", {
351
545
  className: "manager-office__sidebar-heading",
352
- children: [/* @__PURE__ */ jsx("strong", { children: "Office" }), /* @__PURE__ */ jsx("span", {
546
+ children: [/* @__PURE__ */ jsx("strong", { children: "Workforce" }), officeActions ? /* @__PURE__ */ jsx("span", {
353
547
  className: "manager-office__sidebar-actions",
354
548
  children: officeActions
355
- })]
356
- }),
357
- /* @__PURE__ */ jsxs(LinkButton, {
358
- render: renderLink({ kind: "attention" }),
359
- onClick: closeSidebarOnCompact,
360
- variant: "ghost",
361
- color: "neutral",
362
- size: "sm",
363
- className: "manager-office__attention-nav",
364
- "aria-current": view.kind === "attention" ? "page" : void 0,
365
- children: [/* @__PURE__ */ jsx(WarningIcon, {}), /* @__PURE__ */ jsx("span", { children: attentionCount ? `Needs you (${attentionCount})` : "Needs you" })]
549
+ }) : null]
366
550
  }),
367
551
  /* @__PURE__ */ jsx("p", {
368
- className: "manager-office__nav-label",
552
+ className: "manager-office__nav-label sigvelo-visually-hidden",
369
553
  id: rosterLabelId,
370
554
  children: "Employees"
371
555
  }),
372
556
  /* @__PURE__ */ jsx("ul", {
373
- className: "manager-office__employee-nav sigvelo-stack-list",
557
+ ref: employeeNavRef,
558
+ className: "manager-office__employee-nav",
374
559
  "aria-labelledby": rosterLabelId,
375
- children: employees.map((employee) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(LinkButton, {
376
- render: renderLink({
377
- kind: "employee",
378
- employee
379
- }),
380
- onClick: closeSidebarOnCompact,
381
- variant: "ghost",
382
- color: "neutral",
383
- size: "sm",
384
- className: "manager-office__employee-link",
385
- "aria-current": selectedEmployeeId === employee.id ? "page" : void 0,
386
- "aria-label": `Open ${employee.name} · ${employeeStatusText(employee)}`,
387
- children: [
388
- /* @__PURE__ */ jsx(EmployeeAvatar, {
389
- employee,
390
- color: profileColors.get(employee.id)
391
- }),
392
- /* @__PURE__ */ jsxs("span", {
393
- className: "manager-office__identity",
394
- children: [/* @__PURE__ */ jsx("strong", {
395
- className: "sigvelo-truncate",
396
- children: employee.name
397
- }), /* @__PURE__ */ jsx("small", {
398
- className: "manager-office__nav-state sigvelo-truncate",
399
- children: employeeStatusText(employee)
560
+ "data-overflowing": employeeNavOverflows ? "true" : void 0,
561
+ children: employees.map((employee, index) => {
562
+ const selected = selectedEmployeeId === employee.id;
563
+ return /* @__PURE__ */ jsx("li", {
564
+ className: "manager-office__employee-group",
565
+ children: /* @__PURE__ */ jsxs(LinkButton, {
566
+ render: renderLink({
567
+ kind: "employee",
568
+ employee
569
+ }),
570
+ onClick: closeSidebarOnCompact,
571
+ variant: "ghost",
572
+ color: "neutral",
573
+ size: "sm",
574
+ className: "manager-office__employee-link",
575
+ "aria-current": selected ? "page" : void 0,
576
+ "aria-label": `Open ${employee.name} · ${employeeStatusText(employee)}`,
577
+ title: `${employee.name} · ${employeeStatusText(employee)}`,
578
+ children: [/* @__PURE__ */ jsxs("span", {
579
+ className: "manager-office__employee-avatar",
580
+ children: [/* @__PURE__ */ jsx(EmployeeAvatar, {
581
+ employee,
582
+ color: profileColors.get(employee.id),
583
+ index
584
+ }), /* @__PURE__ */ jsx(EmployeePresence, { employee })]
585
+ }), /* @__PURE__ */ jsx("span", {
586
+ className: "manager-office__identity sigvelo-visually-hidden",
587
+ children: /* @__PURE__ */ jsx("strong", {
588
+ className: "sigvelo-truncate",
589
+ children: employee.name
590
+ })
400
591
  })]
401
- }),
402
- /* @__PURE__ */ jsx("span", {
403
- className: "manager-office__nav-status",
404
- "data-status": employee.status,
405
- children: statusIcon(employee.status)
406
592
  })
407
- ]
408
- }) }, employee.id))
409
- })
593
+ }, employee.id);
594
+ })
595
+ }),
596
+ content ? /* @__PURE__ */ jsx("div", {
597
+ className: "manager-office__sidebar-content",
598
+ children: content
599
+ }) : null,
600
+ footer ? /* @__PURE__ */ jsx("div", {
601
+ className: "manager-office__sidebar-footer",
602
+ children: footer
603
+ }) : null
410
604
  ]
411
- });
605
+ }) });
412
606
  }
413
607
  function AttentionView({ employees, renderLink, now }) {
414
608
  const rows = employees.flatMap((employee) => isConnected(employee) ? employee.handoffs.map((handoff) => ({
@@ -418,7 +612,7 @@ function AttentionView({ employees, renderLink, now }) {
418
612
  if (!rows.length) return /* @__PURE__ */ jsx("section", {
419
613
  className: "manager-office__attention",
420
614
  "data-recipe": "page",
421
- "aria-label": "Needs you",
615
+ "aria-label": "Waiting on you",
422
616
  children: /* @__PURE__ */ jsx(EmptyState, {
423
617
  icon: /* @__PURE__ */ jsx(CheckIcon, {}),
424
618
  title: "No active handoffs",
@@ -428,7 +622,7 @@ function AttentionView({ employees, renderLink, now }) {
428
622
  return /* @__PURE__ */ jsx("section", {
429
623
  className: "manager-office__attention",
430
624
  "data-recipe": "page",
431
- "aria-label": "Needs you",
625
+ "aria-label": "Waiting on you",
432
626
  children: /* @__PURE__ */ jsx("ul", {
433
627
  className: "manager-office__attention-list sigvelo-stack-list",
434
628
  children: rows.map(({ employee, handoff }) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(HandoffCard, {
@@ -441,6 +635,825 @@ function AttentionView({ employees, renderLink, now }) {
441
635
  })
442
636
  });
443
637
  }
638
+ const dashboardLanes = [
639
+ "working",
640
+ "needs-you",
641
+ "done",
642
+ "idle"
643
+ ];
644
+ const analyticsDateFormatter = new Intl.DateTimeFormat(void 0, {
645
+ day: "numeric",
646
+ month: "short"
647
+ });
648
+ function analyticsDateLabel(timestamp) {
649
+ return timestamp ? analyticsDateFormatter.format(timestamp) : "—";
650
+ }
651
+ function toggleDashboardFilter(setter, value, checked) {
652
+ setter((current) => {
653
+ const next = new Set(current);
654
+ if (checked) next.add(value);
655
+ else next.delete(value);
656
+ return next;
657
+ });
658
+ }
659
+ const dashboardLaneCopy = {
660
+ working: {
661
+ title: "In progress",
662
+ description: "Employees working now"
663
+ },
664
+ "needs-you": {
665
+ title: "Waiting on you",
666
+ description: "Blocked or waiting for you"
667
+ },
668
+ done: {
669
+ title: "Done",
670
+ description: "Fresh outcomes to review"
671
+ },
672
+ idle: {
673
+ title: "Idle",
674
+ description: "Not working — assign something now"
675
+ }
676
+ };
677
+ function dashboardCards(employees, lane) {
678
+ if (lane === "idle") return employees.flatMap((employee) => {
679
+ if (!isConnected(employee)) return [];
680
+ const hasCurrentWork = employee.work.some((work) => [
681
+ "running",
682
+ "attention",
683
+ "error",
684
+ "interrupted"
685
+ ].includes(work.status));
686
+ return employee.status === "idle" && !hasCurrentWork ? [{
687
+ employee,
688
+ lane
689
+ }] : [];
690
+ });
691
+ return employees.flatMap((employee) => {
692
+ if (!isConnected(employee)) return lane === "needs-you" ? [{
693
+ employee,
694
+ lane
695
+ }] : [];
696
+ if (lane === "working") {
697
+ const work = employee.work.find((candidate) => candidate.status === "running");
698
+ return work ? [{
699
+ employee,
700
+ lane,
701
+ work
702
+ }] : [];
703
+ }
704
+ if (lane === "done") {
705
+ const work = employee.work.find((candidate) => candidate.status === "attention");
706
+ return work ? [{
707
+ employee,
708
+ lane,
709
+ work
710
+ }] : [];
711
+ }
712
+ const handoff = employee.handoffs[0];
713
+ if (handoff) return [{
714
+ employee,
715
+ lane,
716
+ handoff,
717
+ work: employee.work.find((candidate) => candidate.id === handoff.workId)
718
+ }];
719
+ const work = employee.work.find((candidate) => ["error", "interrupted"].includes(candidate.status));
720
+ return work ? [{
721
+ employee,
722
+ lane,
723
+ work
724
+ }] : [];
725
+ });
726
+ }
727
+ function DashboardBrowserPreview({ card }) {
728
+ const connectedEmployee = isConnected(card.employee) ? card.employee : null;
729
+ const disconnectedDescription = isConnected(card.employee) ? "" : card.employee.statusDescription;
730
+ const title = connectedEmployee ? (card.lane === "done" ? card.work?.title : connectedEmployee.browserPreview?.title) ?? card.work?.title ?? "Ready for a new assignment" : "Browser is offline";
731
+ const url = connectedEmployee ? connectedEmployee.browserPreview?.url ?? "New tab" : disconnectedDescription;
732
+ const state = card.lane === "working" ? "Live" : card.lane === "needs-you" ? "Paused" : card.lane === "done" ? "Result ready" : connectedEmployee ? "Idle" : "Disconnected";
733
+ return /* @__PURE__ */ jsxs("div", {
734
+ className: "manager-office__browser-preview",
735
+ "data-lane": card.lane,
736
+ role: "img",
737
+ "aria-label": `${card.employee.name} browser preview: ${title}. ${state}.`,
738
+ children: [
739
+ /* @__PURE__ */ jsxs("div", {
740
+ className: "manager-office__browser-chrome",
741
+ "aria-hidden": "true",
742
+ children: [
743
+ /* @__PURE__ */ jsx("span", {}),
744
+ /* @__PURE__ */ jsx("span", {}),
745
+ /* @__PURE__ */ jsx("span", {}),
746
+ /* @__PURE__ */ jsx("small", { children: url })
747
+ ]
748
+ }),
749
+ /* @__PURE__ */ jsxs("div", {
750
+ className: "manager-office__browser-page",
751
+ "aria-hidden": "true",
752
+ children: [
753
+ /* @__PURE__ */ jsx("span", { className: "manager-office__browser-page-mark" }),
754
+ /* @__PURE__ */ jsxs("span", {
755
+ className: "manager-office__browser-page-copy",
756
+ children: [/* @__PURE__ */ jsx("strong", { children: title }), /* @__PURE__ */ jsx("small", { children: card.work?.title ?? card.handoff?.workTitle ?? (connectedEmployee ? url : "") })]
757
+ }),
758
+ /* @__PURE__ */ jsxs("span", {
759
+ className: "manager-office__browser-page-lines",
760
+ children: [
761
+ /* @__PURE__ */ jsx("i", {}),
762
+ /* @__PURE__ */ jsx("i", {}),
763
+ /* @__PURE__ */ jsx("i", {})
764
+ ]
765
+ }),
766
+ card.lane === "working" ? /* @__PURE__ */ jsx("span", { className: "manager-office__browser-cursor" }) : null
767
+ ]
768
+ }),
769
+ /* @__PURE__ */ jsxs("span", {
770
+ className: "manager-office__browser-state",
771
+ "aria-hidden": "true",
772
+ children: [card.lane === "working" ? /* @__PURE__ */ jsx(SpinnerIcon, {}) : card.lane === "done" ? /* @__PURE__ */ jsx(CheckIcon, {}) : null, state]
773
+ })
774
+ ]
775
+ });
776
+ }
777
+ function DashboardConnections({ employee }) {
778
+ if (!isConnected(employee)) return /* @__PURE__ */ jsx("span", {
779
+ className: "manager-office__connection-empty",
780
+ children: "Browser connection offline"
781
+ });
782
+ if (!employee.channels.length) return /* @__PURE__ */ jsx("span", {
783
+ className: "manager-office__connection-empty",
784
+ children: "No connectors yet"
785
+ });
786
+ return /* @__PURE__ */ jsx("div", {
787
+ className: "manager-office__dashboard-connections",
788
+ "aria-label": "Connections",
789
+ children: /* @__PURE__ */ jsx("span", {
790
+ className: "manager-office__connection-icons",
791
+ children: employee.channels.slice(0, 4).map((channel) => {
792
+ const statusLabel = channel.status === "connected" ? "Connected" : channel.status === "needs-auth" ? "Needs sign-in" : "Connection error";
793
+ return /* @__PURE__ */ jsxs(Tooltip.Root, { children: [/* @__PURE__ */ jsx(Tooltip.Trigger, {
794
+ "aria-label": `${channel.name}: ${statusLabel}`,
795
+ delay: 300,
796
+ render: /* @__PURE__ */ jsx(AppIcon.Root, {
797
+ size: "xs",
798
+ "data-status": channel.status
799
+ }),
800
+ role: "img",
801
+ children: /* @__PURE__ */ jsx(ChannelMark, { channel })
802
+ }), /* @__PURE__ */ jsx(Tooltip.Portal, { children: /* @__PURE__ */ jsx(Tooltip.Positioner, {
803
+ side: "top",
804
+ sideOffset: 6,
805
+ children: /* @__PURE__ */ jsxs(Tooltip.Popup, { children: [
806
+ channel.name,
807
+ " · ",
808
+ statusLabel
809
+ ] })
810
+ }) })] }, channel.id);
811
+ })
812
+ })
813
+ });
814
+ }
815
+ function dashboardCardId(card) {
816
+ return `${card.lane}:${card.employee.id}:${card.work?.id ?? card.handoff?.id ?? "employee"}`;
817
+ }
818
+ function DashboardCard({ card, collapsed, color, index, now, onToggleCollapsed, renderLink }) {
819
+ const connectedEmployee = isConnected(card.employee) ? card.employee : null;
820
+ const disconnectedDescription = isConnected(card.employee) ? "" : card.employee.statusDescription;
821
+ const title = card.handoff?.reason ?? card.work?.title ?? (connectedEmployee ? "No active work" : "Reconnect employee");
822
+ const detail = card.handoff?.request ?? (connectedEmployee ? connectedEmployee.role : disconnectedDescription);
823
+ return /* @__PURE__ */ jsxs("article", {
824
+ className: "manager-office__dashboard-card",
825
+ "data-collapsed": collapsed || void 0,
826
+ "data-lane": card.lane,
827
+ children: [/* @__PURE__ */ jsxs("header", {
828
+ className: "manager-office__dashboard-card-header",
829
+ children: [
830
+ /* @__PURE__ */ jsx(EmployeeAvatar, {
831
+ employee: card.employee,
832
+ color,
833
+ index,
834
+ size: "md"
835
+ }),
836
+ /* @__PURE__ */ jsxs("span", {
837
+ className: "manager-office__dashboard-card-owner",
838
+ children: [/* @__PURE__ */ jsx("strong", { children: card.employee.name }), /* @__PURE__ */ jsx("small", {
839
+ className: "sigvelo-truncate",
840
+ children: connectedEmployee ? connectedEmployee.role : "Employee offline"
841
+ })]
842
+ }),
843
+ /* @__PURE__ */ jsx(Button, {
844
+ "aria-expanded": !collapsed,
845
+ "aria-label": `${collapsed ? "Expand" : "Collapse"} ${card.employee.name} card`,
846
+ className: "manager-office__dashboard-card-toggle",
847
+ color: "neutral",
848
+ onClick: onToggleCollapsed,
849
+ size: "sm",
850
+ type: "button",
851
+ variant: "ghost",
852
+ children: collapsed ? /* @__PURE__ */ jsx(ChevronRightIcon, {}) : /* @__PURE__ */ jsx(ChevronDownIcon, {})
853
+ })
854
+ ]
855
+ }), !collapsed ? /* @__PURE__ */ jsxs(Fragment, { children: [
856
+ card.lane === "working" || card.lane === "needs-you" && card.handoff ? /* @__PURE__ */ jsx(DashboardBrowserPreview, { card }) : null,
857
+ card.lane === "done" && card.work ? /* @__PURE__ */ jsxs("section", {
858
+ className: "manager-office__outcome-summary",
859
+ "aria-label": "Completed outcome",
860
+ children: [
861
+ /* @__PURE__ */ jsx("strong", { children: card.work.title }),
862
+ /* @__PURE__ */ jsx("p", { children: card.work.summary ?? `${card.work.title} is complete and ready for review.` }),
863
+ /* @__PURE__ */ jsxs("span", {
864
+ className: "manager-office__dashboard-updated",
865
+ children: [
866
+ "Completed ",
867
+ /* @__PURE__ */ jsx(Timestamp, {
868
+ timestamp: card.work.updatedAt,
869
+ now
870
+ }),
871
+ " ago"
872
+ ]
873
+ })
874
+ ]
875
+ }) : /* @__PURE__ */ jsxs("div", {
876
+ className: "manager-office__dashboard-card-copy",
877
+ children: [
878
+ /* @__PURE__ */ jsx("strong", { children: title }),
879
+ /* @__PURE__ */ jsx("small", { children: detail }),
880
+ card.work ? /* @__PURE__ */ jsxs("span", {
881
+ className: "manager-office__dashboard-updated",
882
+ children: [
883
+ "Updated ",
884
+ /* @__PURE__ */ jsx(Timestamp, {
885
+ timestamp: card.work.updatedAt,
886
+ now
887
+ }),
888
+ " ago"
889
+ ]
890
+ }) : null
891
+ ]
892
+ }),
893
+ /* @__PURE__ */ jsx(DashboardConnections, { employee: card.employee }),
894
+ /* @__PURE__ */ jsx("footer", {
895
+ className: "manager-office__dashboard-card-actions",
896
+ children: connectedEmployee && card.lane === "idle" ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(LinkButton, {
897
+ render: renderLink({
898
+ kind: "new-work",
899
+ employee: connectedEmployee
900
+ }),
901
+ size: "sm",
902
+ children: [/* @__PURE__ */ jsx(PlayIcon, {}), "Assign work"]
903
+ }), /* @__PURE__ */ jsxs(LinkButton, {
904
+ render: renderLink({
905
+ kind: "new-routine",
906
+ employee: connectedEmployee
907
+ }),
908
+ variant: "ghost",
909
+ color: "neutral",
910
+ size: "sm",
911
+ children: [/* @__PURE__ */ jsx(CalendarIcon, {}), "Set routine"]
912
+ })] }) : connectedEmployee && card.handoff ? /* @__PURE__ */ jsxs(LinkButton, {
913
+ render: renderLink({
914
+ kind: "handoff",
915
+ employee: connectedEmployee,
916
+ handoff: card.handoff
917
+ }),
918
+ size: "sm",
919
+ children: [/* @__PURE__ */ jsx(EyeIcon, {}), "Help in browser"]
920
+ }) : connectedEmployee && card.work ? /* @__PURE__ */ jsxs(LinkButton, {
921
+ render: renderLink({
922
+ kind: "work",
923
+ employee: connectedEmployee,
924
+ work: card.work
925
+ }),
926
+ size: "sm",
927
+ children: [card.lane === "done" ? /* @__PURE__ */ jsx(CheckIcon, {}) : card.lane === "needs-you" ? /* @__PURE__ */ jsx(WarningIcon, {}) : /* @__PURE__ */ jsx(EyeIcon, {}), card.lane === "done" ? "Review result" : card.lane === "needs-you" ? "Open issue" : "Watch work"]
928
+ }) : /* @__PURE__ */ jsxs(LinkButton, {
929
+ render: renderLink({
930
+ kind: "employee",
931
+ employee: card.employee
932
+ }),
933
+ size: "sm",
934
+ children: [/* @__PURE__ */ jsx(RefreshIcon, {}), "Reconnect"]
935
+ })
936
+ })
937
+ ] }) : null]
938
+ });
939
+ }
940
+ function DashboardFilterMenu({ label, onToggle, options, selected }) {
941
+ return /* @__PURE__ */ jsxs(Menu.Root, { children: [/* @__PURE__ */ jsxs(Menu.Trigger, {
942
+ "aria-label": `${label} filter`,
943
+ className: "manager-office__filter-trigger",
944
+ "data-active": selected.size || void 0,
945
+ children: [
946
+ /* @__PURE__ */ jsx("span", { children: label }),
947
+ selected.size ? /* @__PURE__ */ jsx("strong", { children: selected.size }) : null,
948
+ /* @__PURE__ */ jsx(ChevronDownIcon, {})
949
+ ]
950
+ }), /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, {
951
+ sideOffset: 6,
952
+ align: "start",
953
+ children: /* @__PURE__ */ jsx(Menu.Popup, {
954
+ className: "manager-office__filter-popup",
955
+ children: /* @__PURE__ */ jsxs(Menu.Group, { children: [/* @__PURE__ */ jsx(Menu.GroupLabel, { children: label }), options.map((option) => /* @__PURE__ */ jsxs(Menu.CheckboxItem, {
956
+ checked: selected.has(option.value),
957
+ onCheckedChange: (checked) => onToggle(option.value, checked === true),
958
+ children: [/* @__PURE__ */ jsx(Menu.CheckboxItemIndicator, {}), option.label]
959
+ }, option.value))] })
960
+ })
961
+ }) })] });
962
+ }
963
+ function AssignWorkMenu({ employees, profileColors, renderLink }) {
964
+ return /* @__PURE__ */ jsxs(Menu.Root, { children: [/* @__PURE__ */ jsxs(Menu.Trigger, {
965
+ className: "manager-office__assignment-trigger",
966
+ disabled: !employees.length,
967
+ children: [/* @__PURE__ */ jsx("span", { children: "Assign work" }), /* @__PURE__ */ jsx(ChevronDownIcon, {})]
968
+ }), /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, {
969
+ align: "end",
970
+ sideOffset: 6,
971
+ children: /* @__PURE__ */ jsx(Menu.Popup, {
972
+ "aria-label": "Choose an AI employee",
973
+ className: "manager-office__assignment-popup",
974
+ children: /* @__PURE__ */ jsxs(Menu.Group, { children: [/* @__PURE__ */ jsx(Menu.GroupLabel, { children: "Choose an employee" }), employees.map((employee, index) => /* @__PURE__ */ jsxs(Menu.Item, {
975
+ "aria-label": `Assign work to ${employee.name}`,
976
+ className: "manager-office__assignment-item",
977
+ render: renderLink({
978
+ kind: "new-work",
979
+ employee
980
+ }),
981
+ children: [
982
+ /* @__PURE__ */ jsx(EmployeeAvatar, {
983
+ employee,
984
+ color: profileColors.get(employee.id),
985
+ index
986
+ }),
987
+ /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsx("strong", { children: employee.name }), /* @__PURE__ */ jsx("small", {
988
+ className: "sigvelo-truncate",
989
+ children: employee.role
990
+ })] }),
991
+ /* @__PURE__ */ jsx(ChevronRightIcon, {})
992
+ ]
993
+ }, employee.id))] })
994
+ })
995
+ }) })] });
996
+ }
997
+ function employeeMatchesUtilization(employee, selected) {
998
+ if (!selected.size) return true;
999
+ if (!isConnected(employee)) return selected.has("connector-issue");
1000
+ const matches = [];
1001
+ if (employee.browserPreview) matches.push("browser");
1002
+ if (employee.routines.length) matches.push("routines");
1003
+ else matches.push("no-routines");
1004
+ if (employee.channels.some((channel) => channel.status !== "connected")) matches.push("connector-issue");
1005
+ return matches.some((value) => selected.has(value));
1006
+ }
1007
+ function niceAxisMaximum(values) {
1008
+ const maximum = Math.max(...values, 1);
1009
+ const roughStep = maximum / 2;
1010
+ const magnitude = 10 ** Math.floor(Math.log10(roughStep));
1011
+ const normalized = roughStep / magnitude;
1012
+ const step = (normalized <= 1 ? 1 : normalized <= 2 ? 2 : normalized <= 5 ? 5 : 10) * magnitude;
1013
+ return Math.ceil(maximum / step) * step;
1014
+ }
1015
+ function chartY(value, maximum, height = 76) {
1016
+ return height - 4 - value / maximum * (height - 10);
1017
+ }
1018
+ function chartPath(values, maximum, width = 260, height = 76) {
1019
+ if (!values.length) return "";
1020
+ return values.map((value, index) => {
1021
+ const x = values.length === 1 ? width / 2 : index / (values.length - 1) * width;
1022
+ const y = chartY(value, maximum, height);
1023
+ return `${index ? "L" : "M"}${x.toFixed(1)},${y.toFixed(1)}`;
1024
+ }).join(" ");
1025
+ }
1026
+ function chartAreaPath(values, maximum, width = 260, height = 76) {
1027
+ const line = chartPath(values, maximum, width, height);
1028
+ return line ? `${line} L${width},${height - 4} L0,${height - 4} Z` : "";
1029
+ }
1030
+ function chartBars(values, maximum, width = 260, height = 76) {
1031
+ const barWidth = Math.max(2, width / Math.max(values.length, 1) - 3);
1032
+ return values.map((value, index) => {
1033
+ const barHeight = Math.max(value ? 3 : 0, value / maximum * (height - 10));
1034
+ const x = values.length === 1 ? width / 2 - barWidth / 2 : index / values.length * width;
1035
+ return /* @__PURE__ */ jsx("rect", {
1036
+ className: "manager-office__analytics-bar",
1037
+ height: barHeight,
1038
+ rx: "2",
1039
+ width: barWidth,
1040
+ x,
1041
+ y: height - 4 - barHeight
1042
+ }, index);
1043
+ });
1044
+ }
1045
+ function AnalyticsSeries({ detail, label, tone, timestamps, value, values }) {
1046
+ const axisMaximum = niceAxisMaximum(values);
1047
+ const axisValue = (axisValue) => {
1048
+ if (tone === "roi") return `${Math.round(axisValue)}×`;
1049
+ if (tone === "workload") return `${Math.round(axisValue)}h`;
1050
+ return String(Math.round(axisValue));
1051
+ };
1052
+ const middleIndex = Math.floor(Math.max(timestamps.length - 1, 0) / 2);
1053
+ return /* @__PURE__ */ jsxs("article", {
1054
+ className: "manager-office__analytics-series",
1055
+ "data-tone": tone,
1056
+ children: [/* @__PURE__ */ jsxs("span", {
1057
+ className: "manager-office__analytics-series-copy",
1058
+ children: [
1059
+ /* @__PURE__ */ jsx("small", { children: label }),
1060
+ /* @__PURE__ */ jsx("strong", { children: value }),
1061
+ /* @__PURE__ */ jsx("span", { children: detail })
1062
+ ]
1063
+ }), /* @__PURE__ */ jsxs("div", {
1064
+ className: "manager-office__analytics-chart",
1065
+ role: "img",
1066
+ "aria-label": `${label} by date over the selected period, from 0 to ${axisValue(axisMaximum)}`,
1067
+ children: [
1068
+ /* @__PURE__ */ jsxs("span", {
1069
+ className: "manager-office__analytics-y-axis",
1070
+ "aria-hidden": "true",
1071
+ children: [
1072
+ /* @__PURE__ */ jsx("span", { children: axisValue(axisMaximum) }),
1073
+ /* @__PURE__ */ jsx("span", { children: axisValue(axisMaximum / 2) }),
1074
+ /* @__PURE__ */ jsx("span", { children: axisValue(0) })
1075
+ ]
1076
+ }),
1077
+ /* @__PURE__ */ jsxs("svg", {
1078
+ viewBox: "0 0 260 76",
1079
+ "aria-hidden": "true",
1080
+ preserveAspectRatio: "none",
1081
+ children: [
1082
+ /* @__PURE__ */ jsx("path", {
1083
+ className: "manager-office__analytics-gridline",
1084
+ d: "M0 4H260M0 38H260M0 72H260"
1085
+ }),
1086
+ /* @__PURE__ */ jsx("path", {
1087
+ className: "manager-office__analytics-axis-line",
1088
+ d: "M0 4V72H260"
1089
+ }),
1090
+ tone === "outcomes" ? chartBars(values, axisMaximum) : /* @__PURE__ */ jsxs(Fragment, { children: [
1091
+ /* @__PURE__ */ jsx("path", {
1092
+ className: "manager-office__analytics-area",
1093
+ d: chartAreaPath(values, axisMaximum)
1094
+ }),
1095
+ /* @__PURE__ */ jsx("path", {
1096
+ className: "manager-office__analytics-line",
1097
+ d: chartPath(values, axisMaximum)
1098
+ }),
1099
+ values.length ? /* @__PURE__ */ jsx("circle", {
1100
+ className: "manager-office__analytics-endpoint",
1101
+ cx: "260",
1102
+ cy: chartY(values.at(-1) ?? 0, axisMaximum),
1103
+ r: "3"
1104
+ }) : null
1105
+ ] })
1106
+ ]
1107
+ }),
1108
+ /* @__PURE__ */ jsxs("span", {
1109
+ className: "manager-office__analytics-x-axis",
1110
+ "aria-hidden": "true",
1111
+ children: [
1112
+ /* @__PURE__ */ jsx("span", { children: analyticsDateLabel(timestamps[0]) }),
1113
+ /* @__PURE__ */ jsx("span", { children: analyticsDateLabel(timestamps[middleIndex]) }),
1114
+ /* @__PURE__ */ jsx("span", { children: analyticsDateLabel(timestamps.at(-1)) })
1115
+ ]
1116
+ })
1117
+ ]
1118
+ })]
1119
+ });
1120
+ }
1121
+ function aggregateAnalytics(analytics, employeeIds, now, rangeDays) {
1122
+ const cutoff = now - rangeDays * 24 * 60 * 6e4;
1123
+ const buckets = /* @__PURE__ */ new Map();
1124
+ for (const employee of analytics) {
1125
+ if (!employeeIds.has(employee.employeeId)) continue;
1126
+ for (const point of employee.points) {
1127
+ if (point.timestamp < cutoff || point.timestamp > now) continue;
1128
+ const day = new Date(point.timestamp);
1129
+ day.setHours(0, 0, 0, 0);
1130
+ const timestamp = day.getTime();
1131
+ const current = buckets.get(timestamp) ?? {
1132
+ timestamp,
1133
+ completed: 0,
1134
+ workloadHours: 0,
1135
+ estimatedCost: 0
1136
+ };
1137
+ current.completed += point.completed;
1138
+ current.workloadHours += point.workloadHours;
1139
+ current.estimatedCost += point.estimatedCost;
1140
+ buckets.set(timestamp, current);
1141
+ }
1142
+ }
1143
+ return [...buckets.values()].sort((left, right) => left.timestamp - right.timestamp);
1144
+ }
1145
+ function DashboardAnalytics({ analytics, currency, employeeIds, now, onExportReport, rangeDays, setRangeDays }) {
1146
+ const points = aggregateAnalytics(analytics, new Set(employeeIds), now, rangeDays);
1147
+ const completed = points.reduce((sum, point) => sum + point.completed, 0);
1148
+ const workload = points.reduce((sum, point) => sum + point.workloadHours, 0);
1149
+ const hourlyWageEquivalent = 45;
1150
+ const monthlyCostPerEmployee = 28;
1151
+ const monthlyAICost = employeeIds.length * monthlyCostPerEmployee;
1152
+ const selectedPeriodAICost = monthlyAICost * rangeDays / 30;
1153
+ const laborValue = workload * hourlyWageEquivalent;
1154
+ const roiMultiple = selectedPeriodAICost ? laborValue / selectedPeriodAICost : 0;
1155
+ const dailyAICost = monthlyAICost / 30;
1156
+ const roiValues = points.map((point) => dailyAICost ? point.workloadHours * hourlyWageEquivalent / dailyAICost : 0);
1157
+ const money = React.useMemo(() => new Intl.NumberFormat(void 0, {
1158
+ currency,
1159
+ maximumFractionDigits: 0,
1160
+ style: "currency"
1161
+ }), [currency]);
1162
+ return /* @__PURE__ */ jsxs("section", {
1163
+ className: "manager-office__analytics",
1164
+ "aria-labelledby": "manager-office-analytics-title",
1165
+ children: [/* @__PURE__ */ jsxs("header", {
1166
+ className: "manager-office__analytics-header",
1167
+ children: [/* @__PURE__ */ jsx("h2", {
1168
+ id: "manager-office-analytics-title",
1169
+ children: "Your workforce at a glance"
1170
+ }), /* @__PURE__ */ jsxs("span", {
1171
+ className: "manager-office__analytics-actions",
1172
+ children: [/* @__PURE__ */ jsxs(Select.Root, {
1173
+ value: String(rangeDays),
1174
+ onValueChange: (value) => setRangeDays(Number(value)),
1175
+ children: [/* @__PURE__ */ jsxs(Select.Trigger, {
1176
+ className: "manager-office__analytics-range",
1177
+ "aria-label": "Analytics time range",
1178
+ children: [
1179
+ /* @__PURE__ */ jsx(CalendarIcon, {}),
1180
+ /* @__PURE__ */ jsxs("span", { children: [
1181
+ /* @__PURE__ */ jsx("span", {
1182
+ className: "manager-office__analytics-range-prefix",
1183
+ children: "Last "
1184
+ }),
1185
+ rangeDays,
1186
+ " days"
1187
+ ] }),
1188
+ /* @__PURE__ */ jsx(Select.Icon, { children: /* @__PURE__ */ jsx(ChevronDownIcon, {}) })
1189
+ ]
1190
+ }), /* @__PURE__ */ jsx(Select.Portal, { children: /* @__PURE__ */ jsx(Select.Positioner, {
1191
+ sideOffset: 4,
1192
+ children: /* @__PURE__ */ jsx(Select.Popup, { children: /* @__PURE__ */ jsx(Select.List, { children: [
1193
+ 7,
1194
+ 30,
1195
+ 90
1196
+ ].map((days) => /* @__PURE__ */ jsxs(Select.Item, {
1197
+ value: String(days),
1198
+ children: [/* @__PURE__ */ jsx(Select.ItemIndicator, {}), /* @__PURE__ */ jsxs(Select.ItemText, { children: [
1199
+ "Last ",
1200
+ days,
1201
+ " days"
1202
+ ] })]
1203
+ }, days)) }) })
1204
+ }) })]
1205
+ }), onExportReport ? /* @__PURE__ */ jsxs(Button, {
1206
+ "aria-label": "Export report",
1207
+ className: "manager-office__analytics-export",
1208
+ title: "Export report",
1209
+ type: "button",
1210
+ size: "sm",
1211
+ variant: "outline",
1212
+ onClick: () => onExportReport({
1213
+ employeeIds,
1214
+ rangeDays
1215
+ }),
1216
+ children: [/* @__PURE__ */ jsx(DownloadIcon, {}), /* @__PURE__ */ jsxs("span", {
1217
+ className: "manager-office__analytics-export-label",
1218
+ children: ["Export", /* @__PURE__ */ jsx("span", {
1219
+ className: "manager-office__export-report-suffix",
1220
+ children: " report"
1221
+ })]
1222
+ })]
1223
+ }) : null]
1224
+ })]
1225
+ }), /* @__PURE__ */ jsxs("div", {
1226
+ className: "manager-office__analytics-series-grid",
1227
+ children: [
1228
+ /* @__PURE__ */ jsx(AnalyticsSeries, {
1229
+ detail: `${(completed / Math.max(employeeIds.length, 1)).toFixed(1)} per employee`,
1230
+ label: "Completed outcomes",
1231
+ tone: "outcomes",
1232
+ timestamps: points.map((point) => point.timestamp),
1233
+ value: String(completed),
1234
+ values: points.map((point) => point.completed)
1235
+ }),
1236
+ /* @__PURE__ */ jsx(AnalyticsSeries, {
1237
+ detail: `${(workload / Math.max(employeeIds.length, 1)).toFixed(1)}h per employee`,
1238
+ label: "Workload",
1239
+ tone: "workload",
1240
+ timestamps: points.map((point) => point.timestamp),
1241
+ value: `${Math.round(workload)}h`,
1242
+ values: points.map((point) => point.workloadHours)
1243
+ }),
1244
+ /* @__PURE__ */ jsx(AnalyticsSeries, {
1245
+ detail: `${money.format(hourlyWageEquivalent)}/hr equivalent · ${money.format(monthlyCostPerEmployee)}/employee/mo`,
1246
+ label: "Return on investment",
1247
+ tone: "roi",
1248
+ timestamps: points.map((point) => point.timestamp),
1249
+ value: `${roiMultiple.toFixed(1)}×`,
1250
+ values: roiValues
1251
+ })
1252
+ ]
1253
+ })]
1254
+ });
1255
+ }
1256
+ function DashboardView({ analytics, analyticsCurrency, employees, now, onExportReport, profileColors, renderLink }) {
1257
+ const lanes = dashboardLanes;
1258
+ const [rangeDays, setRangeDays] = React.useState(30);
1259
+ const [employeeFilters, setEmployeeFilters] = React.useState(() => /* @__PURE__ */ new Set());
1260
+ const [appFilters, setAppFilters] = React.useState(() => /* @__PURE__ */ new Set());
1261
+ const [utilizationFilters, setUtilizationFilters] = React.useState(() => /* @__PURE__ */ new Set());
1262
+ const [collapsedLanes, setCollapsedLanes] = React.useState(() => /* @__PURE__ */ new Set());
1263
+ const [collapsedCards, setCollapsedCards] = React.useState(() => /* @__PURE__ */ new Set());
1264
+ const filteredEmployees = employees.filter((employee) => {
1265
+ const connected = isConnected(employee);
1266
+ if (employeeFilters.size && !employeeFilters.has(employee.id)) return false;
1267
+ if (appFilters.size && (!connected || !employee.channels.some((channel) => appFilters.has(channel.name)))) return false;
1268
+ return employeeMatchesUtilization(employee, utilizationFilters);
1269
+ });
1270
+ const cardsByLane = new Map(lanes.map((lane) => [lane, dashboardCards(filteredEmployees, lane)]));
1271
+ const appOptions = [...new Set(employees.flatMap((employee) => isConnected(employee) ? employee.channels.map((channel) => channel.name) : []))].sort((left, right) => left.localeCompare(right)).map((name) => ({
1272
+ label: name,
1273
+ value: name
1274
+ }));
1275
+ const filtersActive = employeeFilters.size > 0 || appFilters.size > 0 || utilizationFilters.size > 0;
1276
+ const activeFilterCount = employeeFilters.size + appFilters.size + utilizationFilters.size;
1277
+ const clearFilters = () => {
1278
+ setEmployeeFilters(/* @__PURE__ */ new Set());
1279
+ setAppFilters(/* @__PURE__ */ new Set());
1280
+ setUtilizationFilters(/* @__PURE__ */ new Set());
1281
+ };
1282
+ const toggleLane = (lane) => setCollapsedLanes((current) => {
1283
+ const next = new Set(current);
1284
+ if (next.has(lane)) next.delete(lane);
1285
+ else next.add(lane);
1286
+ return next;
1287
+ });
1288
+ const toggleCard = (cardId) => setCollapsedCards((current) => {
1289
+ const next = new Set(current);
1290
+ if (next.has(cardId)) next.delete(cardId);
1291
+ else next.add(cardId);
1292
+ return next;
1293
+ });
1294
+ return /* @__PURE__ */ jsxs("div", {
1295
+ className: "manager-office__dashboard-content",
1296
+ "data-recipe": "page",
1297
+ children: [
1298
+ /* @__PURE__ */ jsxs("section", {
1299
+ className: "manager-office__dashboard-controls",
1300
+ "aria-label": "Workforce controls",
1301
+ children: [/* @__PURE__ */ jsx("div", {
1302
+ className: "manager-office__workforce-actions",
1303
+ "aria-label": "Workforce actions",
1304
+ children: /* @__PURE__ */ jsx(AssignWorkMenu, {
1305
+ employees: employees.filter(isConnected),
1306
+ profileColors,
1307
+ renderLink
1308
+ })
1309
+ }), /* @__PURE__ */ jsxs("section", {
1310
+ className: "manager-office__filters",
1311
+ "aria-label": "Filter AI employees",
1312
+ children: [/* @__PURE__ */ jsxs("div", {
1313
+ className: "manager-office__filters-main",
1314
+ children: [/* @__PURE__ */ jsxs("div", {
1315
+ className: "manager-office__filters-heading",
1316
+ children: [/* @__PURE__ */ jsx("strong", { children: "Filters" }), filtersActive ? /* @__PURE__ */ jsxs("span", { children: [activeFilterCount, " active"] }) : null]
1317
+ }), /* @__PURE__ */ jsxs("div", {
1318
+ className: "manager-office__filter-categories",
1319
+ children: [
1320
+ /* @__PURE__ */ jsx(DashboardFilterMenu, {
1321
+ label: "Employee",
1322
+ options: employees.map((employee) => ({
1323
+ label: employee.name,
1324
+ value: employee.id
1325
+ })),
1326
+ selected: employeeFilters,
1327
+ onToggle: (value, checked) => toggleDashboardFilter(setEmployeeFilters, value, checked)
1328
+ }),
1329
+ /* @__PURE__ */ jsx(DashboardFilterMenu, {
1330
+ label: "Apps",
1331
+ options: appOptions,
1332
+ selected: appFilters,
1333
+ onToggle: (value, checked) => toggleDashboardFilter(setAppFilters, value, checked)
1334
+ }),
1335
+ /* @__PURE__ */ jsx(DashboardFilterMenu, {
1336
+ label: "Utilization",
1337
+ options: [
1338
+ {
1339
+ label: "Live browser connected",
1340
+ value: "browser"
1341
+ },
1342
+ {
1343
+ label: "Has routines",
1344
+ value: "routines"
1345
+ },
1346
+ {
1347
+ label: "No routines",
1348
+ value: "no-routines"
1349
+ },
1350
+ {
1351
+ label: "Connection issue",
1352
+ value: "connector-issue"
1353
+ }
1354
+ ],
1355
+ selected: utilizationFilters,
1356
+ onToggle: (value, checked) => toggleDashboardFilter(setUtilizationFilters, value, checked)
1357
+ }),
1358
+ filtersActive ? /* @__PURE__ */ jsxs(Button, {
1359
+ className: "manager-office__filter-clear",
1360
+ type: "button",
1361
+ variant: "ghost",
1362
+ size: "sm",
1363
+ onClick: clearFilters,
1364
+ children: [/* @__PURE__ */ jsx(XIcon, {}), "Clear filters"]
1365
+ }) : null
1366
+ ]
1367
+ })]
1368
+ }), /* @__PURE__ */ jsxs("p", {
1369
+ "aria-live": "polite",
1370
+ children: [
1371
+ "Showing ",
1372
+ /* @__PURE__ */ jsx("strong", { children: filteredEmployees.length }),
1373
+ " of ",
1374
+ employees.length,
1375
+ " employees"
1376
+ ]
1377
+ })]
1378
+ })]
1379
+ }),
1380
+ analytics.length ? /* @__PURE__ */ jsx(DashboardAnalytics, {
1381
+ analytics,
1382
+ currency: analyticsCurrency,
1383
+ employeeIds: filteredEmployees.map((employee) => employee.id),
1384
+ now,
1385
+ onExportReport,
1386
+ rangeDays,
1387
+ setRangeDays
1388
+ }) : null,
1389
+ /* @__PURE__ */ jsx("div", {
1390
+ className: "manager-office__kanban",
1391
+ "aria-label": "AI employee progress board",
1392
+ style: { gridTemplateColumns: lanes.map((lane) => collapsedLanes.has(lane) ? "4rem" : "minmax(15rem, 1fr)").join(" ") },
1393
+ children: lanes.map((lane) => {
1394
+ const cards = cardsByLane.get(lane) ?? [];
1395
+ const visibleCards = cards.slice(0, 5);
1396
+ const headingId = `manager-office-lane-${lane}`;
1397
+ const collapsed = collapsedLanes.has(lane);
1398
+ return /* @__PURE__ */ jsxs("section", {
1399
+ className: "manager-office__kanban-lane",
1400
+ "data-collapsed": collapsed || void 0,
1401
+ "data-lane": lane,
1402
+ "aria-labelledby": headingId,
1403
+ children: [/* @__PURE__ */ jsxs("header", {
1404
+ className: "manager-office__kanban-lane-header",
1405
+ children: [/* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsx("h3", {
1406
+ id: headingId,
1407
+ children: dashboardLaneCopy[lane].title
1408
+ }), /* @__PURE__ */ jsx("small", { children: dashboardLaneCopy[lane].description })] }), /* @__PURE__ */ jsxs("span", {
1409
+ className: "manager-office__kanban-lane-actions",
1410
+ children: [/* @__PURE__ */ jsx("strong", {
1411
+ "aria-label": `${cards.length} items`,
1412
+ children: cards.length
1413
+ }), /* @__PURE__ */ jsx(Button, {
1414
+ "aria-expanded": !collapsed,
1415
+ "aria-label": `${collapsed ? "Expand" : "Collapse"} ${dashboardLaneCopy[lane].title} column`,
1416
+ className: "manager-office__kanban-lane-toggle",
1417
+ color: "neutral",
1418
+ onClick: () => toggleLane(lane),
1419
+ size: "sm",
1420
+ type: "button",
1421
+ variant: "ghost",
1422
+ children: collapsed ? /* @__PURE__ */ jsx(ChevronRightIcon, {}) : /* @__PURE__ */ jsx(ChevronDownIcon, {})
1423
+ })]
1424
+ })]
1425
+ }), !collapsed ? /* @__PURE__ */ jsxs("div", {
1426
+ className: "manager-office__kanban-cards",
1427
+ children: [
1428
+ visibleCards.map((card) => /* @__PURE__ */ jsx(DashboardCard, {
1429
+ card,
1430
+ collapsed: collapsedCards.has(dashboardCardId(card)),
1431
+ color: profileColors.get(card.employee.id),
1432
+ index: employees.indexOf(card.employee),
1433
+ now,
1434
+ onToggleCollapsed: () => toggleCard(dashboardCardId(card)),
1435
+ renderLink
1436
+ }, dashboardCardId(card))),
1437
+ !cards.length ? /* @__PURE__ */ jsx("p", {
1438
+ className: "manager-office__kanban-empty",
1439
+ children: "Nothing here right now."
1440
+ }) : null,
1441
+ cards.length > visibleCards.length ? /* @__PURE__ */ jsxs("p", {
1442
+ className: "manager-office__kanban-more",
1443
+ children: [
1444
+ "+",
1445
+ cards.length - visibleCards.length,
1446
+ " more match · Refine filters to narrow"
1447
+ ]
1448
+ }) : null
1449
+ ]
1450
+ }) : null]
1451
+ }, lane);
1452
+ })
1453
+ })
1454
+ ]
1455
+ });
1456
+ }
444
1457
  function EmployeeDetail({ employee, renderLink, now, profileColor }) {
445
1458
  if (!isConnected(employee)) return /* @__PURE__ */ jsx("div", {
446
1459
  "data-recipe": "page",
@@ -456,33 +1469,28 @@ function EmployeeDetail({ employee, renderLink, now, profileColor }) {
456
1469
  children: [
457
1470
  /* @__PURE__ */ jsxs("header", {
458
1471
  className: "manager-office__employee-header",
459
- children: [
460
- /* @__PURE__ */ jsx(EmployeeAvatar, {
461
- employee,
462
- color: profileColor,
463
- size: "lg"
464
- }),
465
- /* @__PURE__ */ jsxs("span", {
466
- className: "manager-office__identity",
467
- children: [/* @__PURE__ */ jsx("strong", {
468
- className: "sigvelo-truncate",
469
- children: employee.name
470
- }), /* @__PURE__ */ jsxs("small", {
471
- className: "manager-office__role sigvelo-truncate",
472
- children: [
473
- employee.email,
474
- " · ",
475
- employee.role
476
- ]
477
- })]
478
- }),
479
- /* @__PURE__ */ jsx(RoutineEvidence, { employee }),
480
- /* @__PURE__ */ jsx(EmployeeStatus, { employee })
481
- ]
1472
+ children: [/* @__PURE__ */ jsx(EmployeeAvatar, {
1473
+ employee,
1474
+ color: profileColor,
1475
+ size: "lg"
1476
+ }), /* @__PURE__ */ jsxs("span", {
1477
+ className: "manager-office__identity",
1478
+ children: [/* @__PURE__ */ jsx("strong", {
1479
+ className: "sigvelo-truncate",
1480
+ children: employee.name
1481
+ }), /* @__PURE__ */ jsxs("small", {
1482
+ className: "manager-office__role sigvelo-truncate",
1483
+ children: [
1484
+ employee.email,
1485
+ " · ",
1486
+ employee.role
1487
+ ]
1488
+ })]
1489
+ })]
482
1490
  }),
483
1491
  employee.handoffs.length ? /* @__PURE__ */ jsx("section", {
484
1492
  className: "manager-office__employee-handoffs",
485
- "aria-label": "Needs you",
1493
+ "aria-label": "Waiting on you",
486
1494
  children: employee.handoffs.map((handoff) => /* @__PURE__ */ jsx(HandoffCard, {
487
1495
  employee,
488
1496
  handoff,
@@ -582,9 +1590,9 @@ function EmployeeDetail({ employee, renderLink, now, profileColor }) {
582
1590
  children: [/* @__PURE__ */ jsx("strong", {
583
1591
  className: "sigvelo-truncate",
584
1592
  children: routine.name
585
- }), /* @__PURE__ */ jsxs("small", {
1593
+ }), /* @__PURE__ */ jsx("small", {
586
1594
  className: "sigvelo-truncate",
587
- children: [routine.enabled ? routine.schedule : `Paused · ${routine.schedule}`, routine.finishedRuns ? ` · ${routine.completedRuns}/${routine.finishedRuns}` : ""]
1595
+ children: routine.enabled ? routine.schedule : `Paused · ${routine.schedule}`
588
1596
  })]
589
1597
  }),
590
1598
  /* @__PURE__ */ jsx(ChevronRightIcon, { className: "manager-office__row-chevron" })
@@ -615,11 +1623,11 @@ function EmployeeDetail({ employee, renderLink, now, profileColor }) {
615
1623
  });
616
1624
  }
617
1625
  /**
618
- * Multi-employee manager office: aggregate handoffs, employee roster, and one
619
- * employee dossier. The consuming app owns authentication, Agent connections,
620
- * routing, and the selected employee's full work surface.
1626
+ * Multi-employee manager office: a dashboard, aggregate handoffs, employee
1627
+ * roster, and one employee dossier. The consuming app owns authentication,
1628
+ * Agent connections, routing, and the selected employee's full work surface.
621
1629
  */
622
- function ManagerOffice({ className, emptyOfficeAction, employees, renderLink, officeActions, renderEmployeeActions, style, view, ...props }) {
1630
+ function ManagerOffice({ analytics = [], analyticsCurrency = "USD", className, emptyOfficeAction, employees, renderLink, officeActions, onExportReport, renderEmployeeActions, sidebarTogglePlacement = "sidebar", style, view, ...props }) {
623
1631
  const titleId = React.useId();
624
1632
  const [now, setNow] = React.useState(Date.now);
625
1633
  React.useEffect(() => {
@@ -628,23 +1636,57 @@ function ManagerOffice({ className, emptyOfficeAction, employees, renderLink, of
628
1636
  }, []);
629
1637
  const selectedEmployee = view.kind === "employee" ? employees.find((employee) => employee.id === view.employeeId) : void 0;
630
1638
  const profileColors = rosterProfileColors(employees);
631
- const title = view.kind === "attention" ? "Needs you" : selectedEmployee?.name ?? "Employee";
1639
+ if (view.kind === "dashboard") return /* @__PURE__ */ jsx(Tooltip.Provider, { children: /* @__PURE__ */ jsxs("div", {
1640
+ className: cx("manager-office", "manager-office--dashboard", className),
1641
+ style,
1642
+ ...props,
1643
+ children: [/* @__PURE__ */ jsxs(AppTopBar.Root, {
1644
+ "aria-label": "Workforce controls",
1645
+ titleAlign: "start",
1646
+ children: [/* @__PURE__ */ jsx(AppTopBar.Title, { render: /* @__PURE__ */ jsx("h1", {
1647
+ id: titleId,
1648
+ children: "Workforce"
1649
+ }) }), officeActions ? /* @__PURE__ */ jsx(AppTopBar.Trailing, { children: officeActions }) : null]
1650
+ }), /* @__PURE__ */ jsx("main", {
1651
+ className: "manager-office__dashboard",
1652
+ "aria-labelledby": titleId,
1653
+ children: !employees.length ? /* @__PURE__ */ jsx(EmptyState, {
1654
+ icon: /* @__PURE__ */ jsx(PlusIcon, {}),
1655
+ title: "Add your first employee",
1656
+ description: "Connect another profile to manage it here.",
1657
+ children: emptyOfficeAction
1658
+ }) : /* @__PURE__ */ jsx(DashboardView, {
1659
+ analytics,
1660
+ analyticsCurrency,
1661
+ employees,
1662
+ now,
1663
+ onExportReport,
1664
+ profileColors,
1665
+ renderLink
1666
+ })
1667
+ })]
1668
+ }) });
1669
+ const title = view.kind === "attention" ? "Waiting on you" : selectedEmployee?.name ?? "Employee";
1670
+ const mainLabel = view.kind === "attention" ? "Waiting on you" : `${selectedEmployee?.name ?? "Employee"} details`;
632
1671
  return /* @__PURE__ */ jsx(Tooltip.Provider, { children: /* @__PURE__ */ jsx(ResponsiveSidebarShell, {
633
1672
  className: cx("manager-office", className),
634
1673
  style,
635
1674
  sidebarLabel: "employees",
636
- showMainLabel: "Show manager office",
637
- sidebar: ({ closeSidebarOnCompact }) => /* @__PURE__ */ jsx(EmployeeSidebar, {
1675
+ sidebarTogglePlacement,
1676
+ showMainLabel: "Show workforce",
1677
+ sidebar: ({ closeSidebarOnCompact }) => /* @__PURE__ */ jsx(ManagerOfficeSidebar, {
638
1678
  closeSidebarOnCompact,
639
1679
  employees,
640
1680
  renderLink,
641
1681
  officeActions,
642
- profileColors,
643
- view
1682
+ selectedEmployeeId: view.kind === "employee" ? view.employeeId : null
644
1683
  }),
645
1684
  bar: {
646
- label: "Manager office controls",
647
- titleRender: /* @__PURE__ */ jsx("h1", { id: titleId }),
1685
+ label: "Workforce controls",
1686
+ titleRender: /* @__PURE__ */ jsx("h1", {
1687
+ id: titleId,
1688
+ children: title
1689
+ }),
648
1690
  title,
649
1691
  actions: selectedEmployee && isConnected(selectedEmployee) ? /* @__PURE__ */ jsxs(Fragment, { children: [
650
1692
  /* @__PURE__ */ jsx(AppTopBar.Link, {
@@ -671,7 +1713,7 @@ function ManagerOffice({ className, emptyOfficeAction, employees, renderLink, of
671
1713
  ...props,
672
1714
  children: /* @__PURE__ */ jsx("main", {
673
1715
  className: "manager-office__main",
674
- "aria-labelledby": titleId,
1716
+ "aria-label": mainLabel,
675
1717
  children: !employees.length ? /* @__PURE__ */ jsx(EmptyState, {
676
1718
  icon: /* @__PURE__ */ jsx(PlusIcon, {}),
677
1719
  title: "Add your first employee",
@@ -695,4 +1737,4 @@ function ManagerOffice({ className, emptyOfficeAction, employees, renderLink, of
695
1737
  }) });
696
1738
  }
697
1739
  //#endregion
698
- export { ManagerOffice };
1740
+ export { ManagerOffice, ManagerOfficeSidebar, ManagerOfficeSidebarAlert };