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