@arbidocs/blocks 0.5.38 → 0.5.39

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 (147) hide show
  1. package/README.md +10 -0
  2. package/dist/{ConnectedCallDock-V7DPSE6X.cjs → ConnectedCallDock-NGHSDLJS.cjs} +4 -4
  3. package/dist/{ConnectedCallDock-V7DPSE6X.cjs.map → ConnectedCallDock-NGHSDLJS.cjs.map} +1 -1
  4. package/dist/{ConnectedCallDock-CT3D6LLI.js → ConnectedCallDock-YJSO52N4.js} +4 -4
  5. package/dist/{ConnectedCallDock-CT3D6LLI.js.map → ConnectedCallDock-YJSO52N4.js.map} +1 -1
  6. package/dist/{ConnectedCallRoom-TNOCSTX2.cjs → ConnectedCallRoom-4XGFFYHE.cjs} +4 -4
  7. package/dist/{ConnectedCallRoom-TNOCSTX2.cjs.map → ConnectedCallRoom-4XGFFYHE.cjs.map} +1 -1
  8. package/dist/{ConnectedCallRoom-A27AM7IQ.js → ConnectedCallRoom-T6NS2MY4.js} +4 -4
  9. package/dist/{ConnectedCallRoom-A27AM7IQ.js.map → ConnectedCallRoom-T6NS2MY4.js.map} +1 -1
  10. package/dist/{ConnectedNativeDocxComparison-RWKFPJPJ.js → ConnectedNativeDocxComparison-52KQKJGY.js} +7 -7
  11. package/dist/{ConnectedNativeDocxComparison-RWKFPJPJ.js.map → ConnectedNativeDocxComparison-52KQKJGY.js.map} +1 -1
  12. package/dist/{ConnectedNativeDocxComparison-H2OZMWHT.cjs → ConnectedNativeDocxComparison-UVLZGS2V.cjs} +8 -8
  13. package/dist/{ConnectedNativeDocxComparison-H2OZMWHT.cjs.map → ConnectedNativeDocxComparison-UVLZGS2V.cjs.map} +1 -1
  14. package/dist/{ConnectedNativeDocxEditor-43BI5LN6.js → ConnectedNativeDocxEditor-BRBL3MOV.js} +6 -6
  15. package/dist/{ConnectedNativeDocxEditor-43BI5LN6.js.map → ConnectedNativeDocxEditor-BRBL3MOV.js.map} +1 -1
  16. package/dist/{ConnectedNativeDocxEditor-6DQEM6SD.cjs → ConnectedNativeDocxEditor-KHR5I7W6.cjs} +8 -8
  17. package/dist/{ConnectedNativeDocxEditor-6DQEM6SD.cjs.map → ConnectedNativeDocxEditor-KHR5I7W6.cjs.map} +1 -1
  18. package/dist/{ConnectedStreamedWordArtifact-3VKYIG6C.cjs → ConnectedStreamedWordArtifact-DSVFI7BX.cjs} +8 -8
  19. package/dist/ConnectedStreamedWordArtifact-DSVFI7BX.cjs.map +1 -0
  20. package/dist/{ConnectedStreamedWordArtifact-TEB332E3.js → ConnectedStreamedWordArtifact-EQUE6WT5.js} +7 -7
  21. package/dist/ConnectedStreamedWordArtifact-EQUE6WT5.js.map +1 -0
  22. package/dist/{WorkspaceTableView-KG546U7M.cjs → WorkspaceTableView-2CGEO5KK.cjs} +6 -6
  23. package/dist/{WorkspaceTableView-KG546U7M.cjs.map → WorkspaceTableView-2CGEO5KK.cjs.map} +1 -1
  24. package/dist/{WorkspaceTableView-OSFIWJ5C.js → WorkspaceTableView-3ARFQYNO.js} +4 -4
  25. package/dist/{WorkspaceTableView-OSFIWJ5C.js.map → WorkspaceTableView-3ARFQYNO.js.map} +1 -1
  26. package/dist/agents/index.cjs +376 -376
  27. package/dist/agents/index.js +2 -2
  28. package/dist/calls/index.cjs +35 -35
  29. package/dist/calls/index.js +7 -7
  30. package/dist/chat/index.cjs +89 -89
  31. package/dist/chat/index.js +2 -2
  32. package/dist/{chunk-BRYRZOS3.cjs → chunk-3YZ3RUSB.cjs} +4 -4
  33. package/dist/{chunk-BRYRZOS3.cjs.map → chunk-3YZ3RUSB.cjs.map} +1 -1
  34. package/dist/{chunk-VPWCARVO.js → chunk-4DDPMLGU.js} +4 -4
  35. package/dist/{chunk-VPWCARVO.js.map → chunk-4DDPMLGU.js.map} +1 -1
  36. package/dist/{chunk-24H5WTGM.js → chunk-4U4NXFV5.js} +4 -4
  37. package/dist/{chunk-24H5WTGM.js.map → chunk-4U4NXFV5.js.map} +1 -1
  38. package/dist/{chunk-6EQSP77K.cjs → chunk-5ZHAHJ4H.cjs} +5 -5
  39. package/dist/{chunk-6EQSP77K.cjs.map → chunk-5ZHAHJ4H.cjs.map} +1 -1
  40. package/dist/{chunk-BIWPXSGS.cjs → chunk-6AJJJ5HR.cjs} +7 -7
  41. package/dist/{chunk-BIWPXSGS.cjs.map → chunk-6AJJJ5HR.cjs.map} +1 -1
  42. package/dist/{chunk-2YCCCXYV.js → chunk-7LN3ISPG.js} +3 -3
  43. package/dist/{chunk-2YCCCXYV.js.map → chunk-7LN3ISPG.js.map} +1 -1
  44. package/dist/{chunk-5NTSJV5H.cjs → chunk-BY2EW2QU.cjs} +16 -91
  45. package/dist/chunk-BY2EW2QU.cjs.map +1 -0
  46. package/dist/{chunk-FHB4G77H.js → chunk-CEO7YI7I.js} +3 -3
  47. package/dist/{chunk-FHB4G77H.js.map → chunk-CEO7YI7I.js.map} +1 -1
  48. package/dist/{chunk-LTO4JYU3.cjs → chunk-DWWRLKEZ.cjs} +188 -2
  49. package/dist/chunk-DWWRLKEZ.cjs.map +1 -0
  50. package/dist/chunk-E3IEZMRK.cjs +507 -0
  51. package/dist/chunk-E3IEZMRK.cjs.map +1 -0
  52. package/dist/{chunk-MLHOG7YH.js → chunk-EFDZRAW6.js} +3 -3
  53. package/dist/{chunk-MLHOG7YH.js.map → chunk-EFDZRAW6.js.map} +1 -1
  54. package/dist/chunk-FOIDBAZB.js +497 -0
  55. package/dist/chunk-FOIDBAZB.js.map +1 -0
  56. package/dist/{chunk-MB3S2ETI.cjs → chunk-G2BKHCI2.cjs} +2 -2
  57. package/dist/chunk-G2BKHCI2.cjs.map +1 -0
  58. package/dist/{chunk-EFSL4O3B.cjs → chunk-GT5FCYV5.cjs} +7 -7
  59. package/dist/{chunk-EFSL4O3B.cjs.map → chunk-GT5FCYV5.cjs.map} +1 -1
  60. package/dist/{chunk-QWKT4DO6.cjs → chunk-GX5MKJ3F.cjs} +433 -2
  61. package/dist/chunk-GX5MKJ3F.cjs.map +1 -0
  62. package/dist/{chunk-C3YIVBTU.cjs → chunk-HDEOORSV.cjs} +9 -9
  63. package/dist/{chunk-C3YIVBTU.cjs.map → chunk-HDEOORSV.cjs.map} +1 -1
  64. package/dist/{chunk-T4P237N6.js → chunk-ILBBV2ZY.js} +2 -2
  65. package/dist/chunk-ILBBV2ZY.js.map +1 -0
  66. package/dist/{chunk-XFSEPGF7.cjs → chunk-K53QRFPJ.cjs} +4 -4
  67. package/dist/{chunk-XFSEPGF7.cjs.map → chunk-K53QRFPJ.cjs.map} +1 -1
  68. package/dist/{chunk-NOKTUWTN.cjs → chunk-K7S5BMAB.cjs} +7 -7
  69. package/dist/{chunk-NOKTUWTN.cjs.map → chunk-K7S5BMAB.cjs.map} +1 -1
  70. package/dist/{chunk-FY4C7HU5.cjs → chunk-O3MRE2HL.cjs} +2233 -8
  71. package/dist/chunk-O3MRE2HL.cjs.map +1 -0
  72. package/dist/{chunk-N3HVTMQK.js → chunk-OPZBIGW4.js} +3 -3
  73. package/dist/{chunk-N3HVTMQK.js.map → chunk-OPZBIGW4.js.map} +1 -1
  74. package/dist/{chunk-JVXHVFUA.cjs → chunk-P6HVJP6Z.cjs} +4 -4
  75. package/dist/{chunk-JVXHVFUA.cjs.map → chunk-P6HVJP6Z.cjs.map} +1 -1
  76. package/dist/{chunk-PXYP3DM5.js → chunk-PD4AKBYZ.js} +432 -6
  77. package/dist/chunk-PD4AKBYZ.js.map +1 -0
  78. package/dist/{chunk-VKY4SQMH.js → chunk-REHG7VRQ.js} +5 -5
  79. package/dist/{chunk-VKY4SQMH.js.map → chunk-REHG7VRQ.js.map} +1 -1
  80. package/dist/{chunk-M4MZPH2S.js → chunk-SEZEEHLU.js} +190 -6
  81. package/dist/chunk-SEZEEHLU.js.map +1 -0
  82. package/dist/{chunk-5JEM3BWT.js → chunk-SYP2A4GQ.js} +4 -4
  83. package/dist/{chunk-5JEM3BWT.js.map → chunk-SYP2A4GQ.js.map} +1 -1
  84. package/dist/{chunk-QFYRXQTD.js → chunk-TTPXMCJL.js} +6 -80
  85. package/dist/chunk-TTPXMCJL.js.map +1 -0
  86. package/dist/{chunk-VMLEISRZ.cjs → chunk-UZVXVTTB.cjs} +17 -17
  87. package/dist/{chunk-VMLEISRZ.cjs.map → chunk-UZVXVTTB.cjs.map} +1 -1
  88. package/dist/{chunk-YDY4GIC2.cjs → chunk-V7JDMKNQ.cjs} +4 -4
  89. package/dist/{chunk-YDY4GIC2.cjs.map → chunk-V7JDMKNQ.cjs.map} +1 -1
  90. package/dist/{chunk-YPR4FSDJ.js → chunk-VA3YYR7R.js} +8 -192
  91. package/dist/chunk-VA3YYR7R.js.map +1 -0
  92. package/dist/{chunk-NUV5F6MM.js → chunk-WAIHNFUH.js} +3 -3
  93. package/dist/{chunk-NUV5F6MM.js.map → chunk-WAIHNFUH.js.map} +1 -1
  94. package/dist/{chunk-H5BFOVVL.cjs → chunk-WRERJFEV.cjs} +2 -188
  95. package/dist/chunk-WRERJFEV.cjs.map +1 -0
  96. package/dist/{chunk-4DKI37QQ.js → chunk-YAGSGBVM.js} +2213 -13
  97. package/dist/chunk-YAGSGBVM.js.map +1 -0
  98. package/dist/{chunk-K6W2GWCN.js → chunk-ZAYUJFPI.js} +3 -3
  99. package/dist/{chunk-K6W2GWCN.js.map → chunk-ZAYUJFPI.js.map} +1 -1
  100. package/dist/connect/docx.cjs +10 -10
  101. package/dist/connect/docx.js +6 -6
  102. package/dist/connect/index.cjs +1237 -591
  103. package/dist/connect/index.cjs.map +1 -1
  104. package/dist/connect/index.d.ts +3 -0
  105. package/dist/connect/index.js +665 -23
  106. package/dist/connect/index.js.map +1 -1
  107. package/dist/connect/viewer.cjs +27 -27
  108. package/dist/connect/viewer.js +10 -10
  109. package/dist/connection/panels/ConnectedPanelHost.d.ts +48 -0
  110. package/dist/connection/panels/useSessionPanelMode.d.ts +18 -0
  111. package/dist/connection/threads-page/ConnectedThreadsPage.d.ts +14 -0
  112. package/dist/connection/threads-page/ThreadSearch.d.ts +24 -0
  113. package/dist/connection/workflows/index.d.ts +1 -0
  114. package/dist/connection/workflows/useWorkflowsPageState.d.ts +134 -0
  115. package/dist/index.cjs +601 -585
  116. package/dist/index.js +8 -8
  117. package/dist/provider/host.d.ts +3 -0
  118. package/dist/shell/PanelPortal.d.ts +30 -0
  119. package/dist/shell/index.cjs +78 -61
  120. package/dist/shell/index.d.ts +3 -0
  121. package/dist/shell/index.js +3 -2
  122. package/dist/shell/panel-host.d.ts +8 -0
  123. package/dist/shell/panel-windows.d.ts +33 -0
  124. package/dist/studio/index.cjs +5 -5
  125. package/dist/studio/index.js +3 -3
  126. package/dist/workflow-canvas/index.cjs +21 -21
  127. package/dist/workflow-canvas/index.js +5 -5
  128. package/node_modules/@arbidocs/coedit/package.json +1 -1
  129. package/package.json +5 -5
  130. package/dist/ConnectedStreamedWordArtifact-3VKYIG6C.cjs.map +0 -1
  131. package/dist/ConnectedStreamedWordArtifact-TEB332E3.js.map +0 -1
  132. package/dist/chunk-4DKI37QQ.js.map +0 -1
  133. package/dist/chunk-5NTSJV5H.cjs.map +0 -1
  134. package/dist/chunk-EZSYYENN.js +0 -2700
  135. package/dist/chunk-EZSYYENN.js.map +0 -1
  136. package/dist/chunk-FY4C7HU5.cjs.map +0 -1
  137. package/dist/chunk-H5BFOVVL.cjs.map +0 -1
  138. package/dist/chunk-LTO4JYU3.cjs.map +0 -1
  139. package/dist/chunk-M4MZPH2S.js.map +0 -1
  140. package/dist/chunk-MB3S2ETI.cjs.map +0 -1
  141. package/dist/chunk-PUX4M22Q.cjs +0 -2735
  142. package/dist/chunk-PUX4M22Q.cjs.map +0 -1
  143. package/dist/chunk-PXYP3DM5.js.map +0 -1
  144. package/dist/chunk-QFYRXQTD.js.map +0 -1
  145. package/dist/chunk-QWKT4DO6.cjs.map +0 -1
  146. package/dist/chunk-T4P237N6.js.map +0 -1
  147. package/dist/chunk-YPR4FSDJ.js.map +0 -1
@@ -4,13 +4,19 @@
4
4
  var chunkRFIBUWLF_cjs = require('./chunk-RFIBUWLF.cjs');
5
5
  var chunk2QDNQM63_cjs = require('./chunk-2QDNQM63.cjs');
6
6
  var chunk3ZLNI7ZA_cjs = require('./chunk-3ZLNI7ZA.cjs');
7
+ var chunkAQPZ4QMV_cjs = require('./chunk-AQPZ4QMV.cjs');
7
8
  var chunkSIB6C7P7_cjs = require('./chunk-SIB6C7P7.cjs');
9
+ var chunkDVUZTGVL_cjs = require('./chunk-DVUZTGVL.cjs');
10
+ var chunkV4ISCZJ7_cjs = require('./chunk-V4ISCZJ7.cjs');
8
11
  var chunkAHDJXIUB_cjs = require('./chunk-AHDJXIUB.cjs');
12
+ var chunk2EI7NCUA_cjs = require('./chunk-2EI7NCUA.cjs');
9
13
  var chunkX6MGM3LH_cjs = require('./chunk-X6MGM3LH.cjs');
10
14
  var chunkLKK52DEY_cjs = require('./chunk-LKK52DEY.cjs');
11
15
  var chunkMEMWZ72Y_cjs = require('./chunk-MEMWZ72Y.cjs');
16
+ var chunkZW6FPIFC_cjs = require('./chunk-ZW6FPIFC.cjs');
12
17
  var chunkEZLZ3MDU_cjs = require('./chunk-EZLZ3MDU.cjs');
13
18
  var chunk76L6LOP3_cjs = require('./chunk-76L6LOP3.cjs');
19
+ var chunkFX3K6LNZ_cjs = require('./chunk-FX3K6LNZ.cjs');
14
20
  var chunkCQ2YSHIF_cjs = require('./chunk-CQ2YSHIF.cjs');
15
21
  var chunkB3NYBMDR_cjs = require('./chunk-B3NYBMDR.cjs');
16
22
  var chunkULWRNGGE_cjs = require('./chunk-ULWRNGGE.cjs');
@@ -4622,6 +4628,215 @@ function TaskPlan({
4622
4628
  );
4623
4629
  }
4624
4630
 
4631
+ // src/agents/tasks/elapsed.ts
4632
+ function formatElapsed2(startTime, endTime) {
4633
+ const elapsedMs = (endTime || Date.now()) - startTime;
4634
+ if (elapsedMs < 1e3) return `${Math.round(elapsedMs)}ms`;
4635
+ if (elapsedMs < 6e4) return `${Math.round(elapsedMs / 1e3)}s`;
4636
+ if (elapsedMs < 36e5) {
4637
+ const minutes2 = Math.floor(elapsedMs / 6e4);
4638
+ const seconds = Math.round(elapsedMs % 6e4 / 1e3);
4639
+ return seconds > 0 ? `${minutes2}m ${seconds}s` : `${minutes2}m`;
4640
+ }
4641
+ const hours = Math.floor(elapsedMs / 36e5);
4642
+ const minutes = Math.round(elapsedMs % 36e5 / 6e4);
4643
+ return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
4644
+ }
4645
+ var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["parsing", "encrypting", "indexing", "analysing"]);
4646
+ var RUNNING_STATUSES = /* @__PURE__ */ new Set(["queued", ...ACTIVE_STATUSES]);
4647
+ var TONES = {
4648
+ completed: { text: "text-green-text", bar: "bg-green-text/90", Icon: lucideReact.Check },
4649
+ failed: { text: "text-red-text", bar: "bg-red-text/90", Icon: lucideReact.X },
4650
+ parsing: { text: "text-blue-text", bar: "bg-blue-text/90", Icon: lucideReact.Loader2 },
4651
+ encrypting: { text: "text-blue-text", bar: "bg-blue-text/90", Icon: lucideReact.Loader2 },
4652
+ indexing: { text: "text-blue-text", bar: "bg-blue-text/90", Icon: lucideReact.Loader2 },
4653
+ analysing: { text: "text-blue-text", bar: "bg-blue-text/90", Icon: lucideReact.Loader2 },
4654
+ queued: { text: "text-yellow-text", bar: "bg-yellow-text/90", Icon: lucideReact.Loader2 },
4655
+ skipped: { text: "text-gray-text", bar: "bg-gray-text/90", Icon: lucideReact.SkipForward },
4656
+ empty: { text: "text-yellow-text", bar: "bg-yellow-text/90", Icon: lucideReact.FileX },
4657
+ "low-content": { text: "text-yellow-text", bar: "bg-yellow-text/90", Icon: lucideReact.AlertTriangle }
4658
+ };
4659
+ var DEFAULT_TONE = { text: "text-gray-text", bar: "bg-blue-text/90", Icon: lucideReact.Loader2 };
4660
+ var DEFAULT_UPLOAD_TASK_ITEM_LABELS = {
4661
+ delete: "Delete",
4662
+ deleteTitle: "Delete file",
4663
+ progress: (fileName) => `${fileName} progress`,
4664
+ status: (status, percent) => `${status.charAt(0).toUpperCase() + status.slice(1)} - ${percent}%`
4665
+ };
4666
+ function UploadTaskItem({
4667
+ taskId,
4668
+ fileName,
4669
+ status,
4670
+ progress,
4671
+ startTime,
4672
+ endTime,
4673
+ fileIcon,
4674
+ onDelete,
4675
+ testIds,
4676
+ labels,
4677
+ className
4678
+ }) {
4679
+ const l = { ...DEFAULT_UPLOAD_TASK_ITEM_LABELS, ...labels };
4680
+ const [elapsed, setElapsed] = react.useState("");
4681
+ react.useEffect(() => {
4682
+ if (!startTime) {
4683
+ setElapsed("");
4684
+ return;
4685
+ }
4686
+ if (RUNNING_STATUSES.has(status)) {
4687
+ const tick = () => setElapsed(formatElapsed2(startTime));
4688
+ tick();
4689
+ const interval = setInterval(tick, 1e3);
4690
+ return () => clearInterval(interval);
4691
+ }
4692
+ setElapsed(formatElapsed2(startTime, endTime));
4693
+ }, [startTime, endTime, status]);
4694
+ const percent = progress > 1 ? progress : progress * 100;
4695
+ const tone = TONES[status] ?? DEFAULT_TONE;
4696
+ const StatusIcon2 = tone.Icon;
4697
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4698
+ "div",
4699
+ {
4700
+ className: ui.cn(
4701
+ "mb-2 w-full max-w-full overflow-hidden rounded-md bg-muted p-2 box-border",
4702
+ className
4703
+ ),
4704
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.item?.(taskId), { testId: `task-item-${taskId}` }),
4705
+ "data-slot": "upload-task-item",
4706
+ children: [
4707
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-1 flex w-full max-w-full items-center gap-2 overflow-hidden", children: [
4708
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: ui.cn("shrink-0", tone.text), children: /* @__PURE__ */ jsxRuntime.jsx(StatusIcon2, { className: ui.cn("size-4", ACTIVE_STATUSES.has(status) && "animate-spin") }) }),
4709
+ fileIcon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: fileIcon }),
4710
+ /* @__PURE__ */ jsxRuntime.jsx(
4711
+ "div",
4712
+ {
4713
+ className: "min-w-0 flex-1 truncate text-sm font-medium",
4714
+ title: fileName,
4715
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.fileName?.(taskId), { testId: `task-filename-${taskId}` }),
4716
+ children: fileName
4717
+ }
4718
+ )
4719
+ ] }),
4720
+ /* @__PURE__ */ jsxRuntime.jsx(
4721
+ "div",
4722
+ {
4723
+ className: "mb-1 h-2 w-full max-w-full overflow-hidden rounded-md bg-background",
4724
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.progressBar?.(taskId), {
4725
+ testId: `task-progress-bar-${taskId}`
4726
+ }),
4727
+ role: "progressbar",
4728
+ "aria-valuemin": 0,
4729
+ "aria-valuemax": 100,
4730
+ "aria-valuenow": Math.round(percent),
4731
+ "aria-label": l.progress(fileName),
4732
+ children: /* @__PURE__ */ jsxRuntime.jsx(
4733
+ "div",
4734
+ {
4735
+ className: ui.cn("h-2 rounded-md transition-all duration-300 ease-in-out", tone.bar),
4736
+ style: { width: `${percent}%` }
4737
+ }
4738
+ )
4739
+ }
4740
+ ),
4741
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full max-w-full items-center justify-between overflow-hidden text-sm", children: [
4742
+ /* @__PURE__ */ jsxRuntime.jsxs(
4743
+ "span",
4744
+ {
4745
+ className: "truncate text-gray-text",
4746
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.status?.(taskId), { testId: `task-status-${taskId}` }),
4747
+ children: [
4748
+ l.status(status, Math.round(percent)),
4749
+ elapsed && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-2 text-muted-foreground", children: [
4750
+ "(",
4751
+ elapsed,
4752
+ ")"
4753
+ ] })
4754
+ ]
4755
+ }
4756
+ ),
4757
+ status === "failed" && onDelete && /* @__PURE__ */ jsxRuntime.jsx(
4758
+ "button",
4759
+ {
4760
+ type: "button",
4761
+ onClick: () => onDelete(taskId),
4762
+ className: "shrink-0 text-sm text-red-text hover:text-red-text/80 pointer-coarse:min-h-11 pointer-coarse:px-3",
4763
+ title: l.deleteTitle,
4764
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.delete?.(taskId), { testId: `delete-task-${taskId}` }),
4765
+ children: l.delete
4766
+ }
4767
+ )
4768
+ ] })
4769
+ ]
4770
+ }
4771
+ );
4772
+ }
4773
+ var DEFAULT_UPLOAD_TASK_LIST_LABELS = {
4774
+ title: "Active Tasks",
4775
+ empty: "No documents in this category"
4776
+ };
4777
+ function UploadTaskList({
4778
+ tasks,
4779
+ filter,
4780
+ title,
4781
+ onDelete,
4782
+ renderFileIcon,
4783
+ showEmptyState = true,
4784
+ testIds,
4785
+ labels,
4786
+ itemLabels,
4787
+ className
4788
+ }) {
4789
+ const l = { ...DEFAULT_UPLOAD_TASK_LIST_LABELS, ...labels };
4790
+ const heading = title ?? l.title;
4791
+ const safeTasks = typeof tasks === "object" && tasks !== null ? tasks : {};
4792
+ let entries = Object.entries(safeTasks);
4793
+ if (filter) entries = entries.filter(([id, task]) => filter(id, task));
4794
+ if (entries.length === 0) {
4795
+ return showEmptyState ? /* @__PURE__ */ jsxRuntime.jsx(
4796
+ "div",
4797
+ {
4798
+ className: "text-sm italic text-muted-foreground",
4799
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.empty, { testId: "task-list-empty-state" }),
4800
+ children: l.empty
4801
+ }
4802
+ ) : null;
4803
+ }
4804
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4805
+ "div",
4806
+ {
4807
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.root, { testId: "task-status-list" }),
4808
+ "data-slot": "upload-task-list",
4809
+ className: ui.cn("box-border w-full max-w-full", className),
4810
+ children: [
4811
+ heading && /* @__PURE__ */ jsxRuntime.jsx(
4812
+ "h3",
4813
+ {
4814
+ className: "mb-2 truncate text-sm font-semibold",
4815
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.title, { testId: "task-list-title" }),
4816
+ children: heading
4817
+ }
4818
+ ),
4819
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "box-border w-full max-w-full overflow-hidden", children: entries.map(([taskId, task]) => /* @__PURE__ */ jsxRuntime.jsx(
4820
+ UploadTaskItem,
4821
+ {
4822
+ taskId,
4823
+ fileName: task.fileName,
4824
+ status: task.status,
4825
+ progress: task.progress,
4826
+ startTime: task.startTime,
4827
+ endTime: task.endTime,
4828
+ fileIcon: renderFileIcon?.(task.fileName),
4829
+ onDelete,
4830
+ labels: itemLabels,
4831
+ className: "box-border max-w-full"
4832
+ },
4833
+ taskId
4834
+ )) })
4835
+ ]
4836
+ }
4837
+ );
4838
+ }
4839
+
4625
4840
  // src/agents/tasks/rrule.ts
4626
4841
  var WEEKDAYS = ["MO", "TU", "WE", "TH", "FR", "SA", "SU"];
4627
4842
  var WEEKDAY_LABELS = {
@@ -4904,6 +5119,322 @@ function goalProgress(task) {
4904
5119
  if (!gs || gs.criteria_total == null) return null;
4905
5120
  return { met: gs.criteria_met ?? 0, total: gs.criteria_total, done: gs.done === true };
4906
5121
  }
5122
+ var DEFAULT_TASK_OUTPUTS_CELL_LABELS = {
5123
+ none: "\u2014",
5124
+ open: (count) => `${count} ${count === 1 ? "output" : "outputs"}`,
5125
+ more: (count) => `+${count}`
5126
+ };
5127
+ function TaskOutputsCell({ id, outputs, onOpen, testId, labels }) {
5128
+ const l = { ...DEFAULT_TASK_OUTPUTS_CELL_LABELS, ...labels };
5129
+ const base = chunkMHVNT4J3_cjs.testIdOr(testId, { testId: `task-outputs-${id}` });
5130
+ if (!outputs || outputs.length === 0) {
5131
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", "data-testid": base, "data-state": "none", children: l.none });
5132
+ }
5133
+ const [first] = outputs;
5134
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
5135
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
5136
+ ui.Button,
5137
+ {
5138
+ variant: "ghost",
5139
+ size: "sm",
5140
+ className: "h-7 max-w-full gap-1.5 px-2 text-xs",
5141
+ "aria-label": l.open(outputs.length),
5142
+ "data-testid": base,
5143
+ "data-count": outputs.length,
5144
+ children: [
5145
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "size-3.5 shrink-0", "aria-hidden": true }),
5146
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: first.name }),
5147
+ outputs.length > 1 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: l.more(outputs.length - 1) })
5148
+ ]
5149
+ }
5150
+ ) }),
5151
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuContent, { align: "start", children: outputs.map((o) => /* @__PURE__ */ jsxRuntime.jsxs(
5152
+ ui.DropdownMenuItem,
5153
+ {
5154
+ onSelect: () => onOpen(o.id),
5155
+ "data-testid": `task-output-${id}-${o.id}`,
5156
+ children: [
5157
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "mr-2 size-4", "aria-hidden": true }),
5158
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: o.name })
5159
+ ]
5160
+ },
5161
+ o.id
5162
+ )) })
5163
+ ] });
5164
+ }
5165
+ function TaskMoveDialog({
5166
+ open,
5167
+ onOpenChange,
5168
+ options,
5169
+ currentParentId,
5170
+ onPick,
5171
+ labels,
5172
+ testId
5173
+ }) {
5174
+ const [query, setQuery] = react.useState("");
5175
+ const id = chunkMHVNT4J3_cjs.testIdOr(testId, { testId: "task-move" });
5176
+ const q = query.trim().toLowerCase();
5177
+ const shown = q ? options.filter((o) => o.label.toLowerCase().includes(q)) : options;
5178
+ const pick = (parentId) => {
5179
+ onPick(parentId);
5180
+ onOpenChange(false);
5181
+ };
5182
+ return /* @__PURE__ */ jsxRuntime.jsx(
5183
+ ui.Dialog,
5184
+ {
5185
+ open,
5186
+ onOpenChange: (next) => {
5187
+ if (!next) setQuery("");
5188
+ onOpenChange(next);
5189
+ },
5190
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogContent, { presentation: "sheet", className: "max-h-[80dvh] sm:max-w-md", "data-testid": id, children: [
5191
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogHeader, { children: [
5192
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DialogTitle, { children: labels.title }),
5193
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DialogDescription, { className: "sr-only", children: labels.title })
5194
+ ] }),
5195
+ /* @__PURE__ */ jsxRuntime.jsx(
5196
+ ui.Input,
5197
+ {
5198
+ value: query,
5199
+ placeholder: labels.search,
5200
+ "aria-label": labels.search,
5201
+ onChange: (e) => setQuery(e.target.value),
5202
+ "data-testid": `${id}-search`
5203
+ }
5204
+ ),
5205
+ /* @__PURE__ */ jsxRuntime.jsxs(
5206
+ "ul",
5207
+ {
5208
+ className: "flex max-h-[50dvh] flex-col gap-1 overflow-y-auto",
5209
+ "data-testid": `${id}-list`,
5210
+ children: [
5211
+ !q && /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
5212
+ ui.Button,
5213
+ {
5214
+ variant: "ghost",
5215
+ className: "h-9 w-full justify-start gap-2 pointer-coarse:h-11",
5216
+ disabled: !currentParentId,
5217
+ onClick: () => pick(null),
5218
+ "data-testid": `${id}-none`,
5219
+ children: labels.none
5220
+ }
5221
+ ) }),
5222
+ shown.map((o) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs(
5223
+ ui.Button,
5224
+ {
5225
+ variant: "ghost",
5226
+ className: "h-9 w-full justify-start gap-2 pointer-coarse:h-11",
5227
+ disabled: o.id === currentParentId,
5228
+ onClick: () => pick(o.id),
5229
+ "data-testid": `${id}-option-${o.id}`,
5230
+ children: [
5231
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CornerDownRight, { className: "size-3.5 shrink-0", "aria-hidden": true }),
5232
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: o.label })
5233
+ ]
5234
+ }
5235
+ ) }, o.id)),
5236
+ shown.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("li", { className: "px-2 py-4 text-center text-sm text-muted-foreground", children: labels.empty })
5237
+ ]
5238
+ }
5239
+ ),
5240
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "outline", onClick: () => onOpenChange(false), children: labels.cancel }) })
5241
+ ] })
5242
+ }
5243
+ );
5244
+ }
5245
+ var DEFAULT_TASK_STATUS_PILL_LABELS = {
5246
+ waitingForAccess: "Waiting for access",
5247
+ lastRunFailed: "Last run failed",
5248
+ failed: "Failed"
5249
+ };
5250
+ var ICON = "size-3";
5251
+ function StatusIcon({ status }) {
5252
+ switch (status) {
5253
+ case "generating":
5254
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: `${ICON} animate-spin`, "aria-hidden": true });
5255
+ case "done":
5256
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: ICON, "aria-hidden": true });
5257
+ case "chat":
5258
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: ICON, "aria-hidden": true });
5259
+ default:
5260
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleDashed, { className: ICON, "aria-hidden": true });
5261
+ }
5262
+ }
5263
+ function useNow(active) {
5264
+ const [now, setNow] = react.useState(() => Date.now());
5265
+ react.useEffect(() => {
5266
+ if (!active) return;
5267
+ const timer = setInterval(() => setNow(Date.now()), 1e3);
5268
+ return () => clearInterval(timer);
5269
+ }, [active]);
5270
+ return now;
5271
+ }
5272
+ function TaskStatusPill({
5273
+ id,
5274
+ status,
5275
+ runStartedAt,
5276
+ lastError,
5277
+ awaitingAccess = false,
5278
+ testId,
5279
+ labels,
5280
+ hint
5281
+ }) {
5282
+ const l = { ...DEFAULT_TASK_STATUS_PILL_LABELS, ...labels };
5283
+ const key = asTaskStatus(status);
5284
+ const generating = key === "generating";
5285
+ const now = useNow(generating && Boolean(runStartedAt));
5286
+ const started = runStartedAt ? Date.parse(runStartedAt) : NaN;
5287
+ let text2 = STATUS_LABELS[key];
5288
+ let tone = STATUS_TONE[key];
5289
+ if (awaitingAccess) {
5290
+ text2 = l.waitingForAccess;
5291
+ tone = "danger";
5292
+ }
5293
+ const elapsed = generating && !Number.isNaN(started) ? formatElapsed2(started, now) : null;
5294
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5", "data-slot": "task-status", title: hint, children: [
5295
+ /* @__PURE__ */ jsxRuntime.jsxs(
5296
+ chunkDVUZTGVL_cjs.ToneBadge,
5297
+ {
5298
+ tone,
5299
+ icon: /* @__PURE__ */ jsxRuntime.jsx(StatusIcon, { status: key }),
5300
+ "data-status": key,
5301
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testId, { testId: `task-status-${id}` }),
5302
+ children: [
5303
+ text2,
5304
+ elapsed && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "tabular-nums opacity-70", children: [
5305
+ "\xB7 ",
5306
+ elapsed
5307
+ ] })
5308
+ ]
5309
+ }
5310
+ ),
5311
+ lastError && !generating && /* @__PURE__ */ jsxRuntime.jsxs(
5312
+ "span",
5313
+ {
5314
+ role: "img",
5315
+ "aria-label": l.lastRunFailed,
5316
+ title: `${l.lastRunFailed}: ${lastError}`,
5317
+ className: "inline-flex shrink-0 items-center gap-1 text-xs font-medium text-red-text",
5318
+ "data-testid": `task-error-${id}`,
5319
+ children: [
5320
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "size-3.5", "aria-hidden": true }),
5321
+ l.failed
5322
+ ]
5323
+ }
5324
+ )
5325
+ ] });
5326
+ }
5327
+
5328
+ // src/agents/tasks/taskColumns.tsx
5329
+ var ACTIONS_WIDTH = 160;
5330
+ var NARROW_ACTIONS_WIDTH = 56;
5331
+ var TASK_COLUMN_ORDER = [
5332
+ "name",
5333
+ "owner",
5334
+ "due",
5335
+ "status",
5336
+ "outputs",
5337
+ "shared",
5338
+ "actions"
5339
+ ];
5340
+ var keepOrder = () => 0;
5341
+ function cell(render) {
5342
+ return (params) => params.data ? render(params.data) : null;
5343
+ }
5344
+ function createTaskColumns(o) {
5345
+ const l = o.labels;
5346
+ const sortable = {
5347
+ sortable: true,
5348
+ comparator: keepOrder,
5349
+ sortingOrder: ["asc", "desc", null]
5350
+ };
5351
+ const base = {
5352
+ sortable: false,
5353
+ suppressMovable: true,
5354
+ // Keyboard focus lands on the name cell only (arrow keys expand and collapse sub-tasks there).
5355
+ suppressNavigable: true,
5356
+ cellStyle: { display: "flex", alignItems: "center" }
5357
+ };
5358
+ const name = {
5359
+ ...base,
5360
+ colId: "name",
5361
+ ...sortable,
5362
+ suppressNavigable: false,
5363
+ headerName: l.colTask,
5364
+ flex: 3,
5365
+ minWidth: 200,
5366
+ cellRenderer: cell(o.renderName)
5367
+ };
5368
+ const shared = {
5369
+ ...base,
5370
+ colId: "shared",
5371
+ headerName: l.colShared,
5372
+ headerTooltip: l.shared,
5373
+ width: 90,
5374
+ cellStyle: { display: "flex", alignItems: "center", justifyContent: "center" },
5375
+ valueGetter: (p) => p.data?.task.is_shared ?? false,
5376
+ cellRenderer: cell(o.renderShared)
5377
+ };
5378
+ const actions = () => ({
5379
+ ...base,
5380
+ colId: "actions",
5381
+ headerName: "",
5382
+ // Always in view, even if the rest has to scroll.
5383
+ pinned: "right",
5384
+ lockPinned: true,
5385
+ width: o.narrow ? NARROW_ACTIONS_WIDTH : ACTIONS_WIDTH,
5386
+ minWidth: NARROW_ACTIONS_WIDTH,
5387
+ cellStyle: { display: "flex", alignItems: "center", justifyContent: "flex-end" },
5388
+ cellRenderer: cell(o.renderActions)
5389
+ });
5390
+ return [
5391
+ name,
5392
+ {
5393
+ ...base,
5394
+ colId: "owner",
5395
+ ...sortable,
5396
+ headerName: l.colOwner,
5397
+ headerTooltip: l.ownerHint,
5398
+ flex: 1.4,
5399
+ minWidth: 150,
5400
+ valueGetter: (p) => p.data ? o.getOwnerName(p.data) : "",
5401
+ cellRenderer: cell(o.renderOwner)
5402
+ },
5403
+ {
5404
+ ...base,
5405
+ colId: "due",
5406
+ ...sortable,
5407
+ headerName: l.colDue,
5408
+ flex: 1,
5409
+ minWidth: 140,
5410
+ valueGetter: (p) => p.data?.task.due_at ?? "",
5411
+ cellRenderer: cell(o.renderDue)
5412
+ },
5413
+ {
5414
+ ...base,
5415
+ colId: "status",
5416
+ ...sortable,
5417
+ headerName: l.colStatus,
5418
+ // Wide enough for "Generating" and "Waiting for access" in full, with the elapsed time.
5419
+ flex: 1.3,
5420
+ minWidth: 170,
5421
+ valueGetter: (p) => p.data?.task.status ?? "",
5422
+ cellRenderer: cell(o.renderStatus)
5423
+ },
5424
+ ...o.showOutputs ? [
5425
+ {
5426
+ ...base,
5427
+ colId: "outputs",
5428
+ headerName: l.colOutputs,
5429
+ flex: 1.2,
5430
+ minWidth: 130,
5431
+ cellRenderer: cell(o.renderOutputs)
5432
+ }
5433
+ ] : [],
5434
+ shared,
5435
+ actions()
5436
+ ];
5437
+ }
4907
5438
 
4908
5439
  // src/agents/tasks/taskRows.ts
4909
5440
  var MAX_TASK_DEPTH = 5;
@@ -5035,12 +5566,1219 @@ function buildTaskRows(tasks, filter, collapsed, compare, options = {}) {
5035
5566
  node.children.forEach((child, i) => walk(child, id, node.children.length, i + 1));
5036
5567
  }
5037
5568
  };
5038
- const ordered = [...STATUS_ORDER, "sorted"].flatMap((s) => sections.get(s) ?? []);
5039
- ordered.forEach((node, i) => walk(node, null, ordered.length, i + 1));
5040
- if (cache2) {
5041
- for (const id of [...cache2.keys()]) if (!used.has(id)) cache2.delete(id);
5042
- }
5043
- return rows;
5569
+ const ordered = [...STATUS_ORDER, "sorted"].flatMap((s) => sections.get(s) ?? []);
5570
+ ordered.forEach((node, i) => walk(node, null, ordered.length, i + 1));
5571
+ if (cache2) {
5572
+ for (const id of [...cache2.keys()]) if (!used.has(id)) cache2.delete(id);
5573
+ }
5574
+ return rows;
5575
+ }
5576
+
5577
+ // src/agents/tasks/taskTableLabels.ts
5578
+ var DEFAULT_TASK_LIST_LABELS = {
5579
+ filterAll: "All",
5580
+ emptyTitle: "No tasks yet",
5581
+ emptyMessage: "Use New to add one: just type what you need, or add a due date. Automations that create tasks live on the Workflows page. You always decide when a task is done.",
5582
+ noMatches: "No tasks match.",
5583
+ due: (when) => when,
5584
+ overdue: (when) => `${when} \xB7 overdue`,
5585
+ agent: "Agent",
5586
+ colTask: "Task",
5587
+ colOwner: "Owner",
5588
+ ownerHint: "Who created the task. They are notified when its run finishes.",
5589
+ colOutputs: "Outputs",
5590
+ preparedBy: (agent) => `Prepared by ${agent}`,
5591
+ colDue: "Due",
5592
+ colStatus: "Status",
5593
+ me: "Me",
5594
+ someone: "Someone",
5595
+ noDue: "\u2014",
5596
+ colShared: "Shared",
5597
+ shared: "Shared with the workspace",
5598
+ sharedOwnerOnly: "Only the creator can change who can see this",
5599
+ deleteOwnerOnly: "Only the creator or workspace owner can delete this",
5600
+ goalMet: (met, total) => `${met}/${total} met`,
5601
+ subtasksDone: (done, total) => `${done}/${total} sub-tasks done`,
5602
+ expandSubtasks: "Show sub-tasks",
5603
+ collapseSubtasks: "Hide sub-tasks",
5604
+ selectAll: "Select all tasks",
5605
+ selectTask: (name) => `Select ${name}`,
5606
+ markDone: "Mark done",
5607
+ reopen: "Reopen",
5608
+ markDoneMany: "Mark done",
5609
+ markDoneManyHint: "Marks the selected tasks done.",
5610
+ deleteMany: "Delete",
5611
+ moveTo: "Move to\u2026",
5612
+ untitled: "Untitled task",
5613
+ fromWorkflow: (name) => `From \u201C${name}\u201D`,
5614
+ searchLabel: "Search tasks",
5615
+ searchPlaceholder: "Search tasks\u2026",
5616
+ expandAll: "Expand all",
5617
+ collapseAll: "Collapse all",
5618
+ moveToTitle: (name) => `Move \u201C${name}\u201D to\u2026`,
5619
+ moveToNone: "No parent (top level)",
5620
+ moveToSearch: "Search tasks\u2026",
5621
+ moveToEmpty: "No task to move it under.",
5622
+ moveToCancel: "Cancel",
5623
+ subtasksSelected: (count) => `${count} ${count === 1 ? "sub-task" : "sub-tasks"} included`,
5624
+ addSubtask: "Add sub-task",
5625
+ edit: "Edit",
5626
+ rename: "Rename",
5627
+ delete: "Delete",
5628
+ grantAccess: "Allow access and continue",
5629
+ allowAccess: "Allow access",
5630
+ moreActions: "More actions",
5631
+ activity: "Activity",
5632
+ statusHint: (status, ago) => `${status} \xB7 ${ago}`,
5633
+ status: {}
5634
+ };
5635
+ function TaskRowMenu({
5636
+ task,
5637
+ status,
5638
+ busy,
5639
+ isOwner,
5640
+ canAdmin,
5641
+ canEdit,
5642
+ labels,
5643
+ canMarkDone = canEdit,
5644
+ canReopen = canEdit,
5645
+ selected = false,
5646
+ onToggleSelected,
5647
+ onMarkDone,
5648
+ onReopen,
5649
+ onAddSubtask,
5650
+ onEdit,
5651
+ onDelete,
5652
+ onMoveTo,
5653
+ onOpenActivity,
5654
+ onToggleShared,
5655
+ onGrantAccess
5656
+ }) {
5657
+ const [open, setOpen] = react.useState(false);
5658
+ const id = task.external_id;
5659
+ const isChat = status === "chat";
5660
+ const done = status === "done";
5661
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { open, onOpenChange: setOpen, children: [
5662
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
5663
+ ui.Button,
5664
+ {
5665
+ variant: "ghost",
5666
+ size: "icon",
5667
+ className: "size-8 pointer-coarse:size-11",
5668
+ "aria-label": labels.moreActions,
5669
+ "data-testid": `task-menu-${id}`,
5670
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: "size-4", "aria-hidden": true })
5671
+ }
5672
+ ) }),
5673
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { align: "end", children: [
5674
+ onToggleSelected && /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuItem, { onSelect: onToggleSelected, "data-testid": `task-select-${id}`, children: selected ? "Deselect task" : "Select task" }),
5675
+ isOwner && onGrantAccess && task.pending_auth_request_id && /* @__PURE__ */ jsxRuntime.jsxs(
5676
+ ui.DropdownMenuItem,
5677
+ {
5678
+ onSelect: onGrantAccess,
5679
+ "data-testid": `task-grant-${id}`,
5680
+ className: "text-destructive",
5681
+ children: [
5682
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.KeyRound, { className: "mr-2 size-4", "aria-hidden": true }),
5683
+ labels.grantAccess
5684
+ ]
5685
+ }
5686
+ ),
5687
+ isChat || !canEdit ? null : done ? canReopen && /* @__PURE__ */ jsxRuntime.jsxs(
5688
+ ui.DropdownMenuItem,
5689
+ {
5690
+ disabled: busy,
5691
+ onSelect: onReopen,
5692
+ "data-testid": `task-reopen-${id}`,
5693
+ children: [
5694
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, { className: "mr-2 size-4", "aria-hidden": true }),
5695
+ labels.reopen
5696
+ ]
5697
+ }
5698
+ ) : canMarkDone && /* @__PURE__ */ jsxRuntime.jsxs(
5699
+ ui.DropdownMenuItem,
5700
+ {
5701
+ disabled: busy,
5702
+ onSelect: onMarkDone,
5703
+ "data-testid": `task-mark-done-${id}`,
5704
+ children: [
5705
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCheck, { className: "mr-2 size-4", "aria-hidden": true }),
5706
+ labels.markDone
5707
+ ]
5708
+ }
5709
+ ),
5710
+ !isChat && onOpenActivity && /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: onOpenActivity, "data-testid": `task-activity-${id}`, children: [
5711
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.History, { className: "mr-2 size-4", "aria-hidden": true }),
5712
+ labels.activity
5713
+ ] }),
5714
+ isOwner && onToggleShared && /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuItem, { disabled: busy, onSelect: onToggleShared, children: task.is_shared ? "Make private" : "Share with workspace" }),
5715
+ canEdit && onAddSubtask && /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: onAddSubtask, "data-testid": `task-add-subtask-${id}`, children: [
5716
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListPlus, { className: "mr-2 size-4", "aria-hidden": true }),
5717
+ labels.addSubtask
5718
+ ] }),
5719
+ canEdit && onMoveTo && /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: onMoveTo, "data-testid": `task-move-${id}`, children: [
5720
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CornerDownRight, { className: "mr-2 size-4", "aria-hidden": true }),
5721
+ labels.moveTo
5722
+ ] }),
5723
+ canEdit && /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: onEdit, "data-testid": `task-edit-${id}`, children: [
5724
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "mr-2 size-4", "aria-hidden": true }),
5725
+ isChat ? labels.rename : labels.edit
5726
+ ] }),
5727
+ canEdit && onDelete && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5728
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuSeparator, {}),
5729
+ /* @__PURE__ */ jsxRuntime.jsxs(
5730
+ ui.DropdownMenuItem,
5731
+ {
5732
+ disabled: busy || !canAdmin,
5733
+ onSelect: onDelete,
5734
+ title: canAdmin ? void 0 : labels.deleteOwnerOnly,
5735
+ className: "text-destructive focus:text-destructive",
5736
+ "data-testid": `task-delete-${id}`,
5737
+ children: [
5738
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "mr-2 size-4", "aria-hidden": true }),
5739
+ labels.delete
5740
+ ]
5741
+ }
5742
+ )
5743
+ ] })
5744
+ ] })
5745
+ ] });
5746
+ }
5747
+
5748
+ // src/agents/tasks/gridWidth.ts
5749
+ function applyColumnWidthRules(api, gridWidth, rules) {
5750
+ for (const rule of rules) {
5751
+ if (api.getColumn(rule.colId)) api.setColumnsVisible([rule.colId], gridWidth >= rule.minWidth);
5752
+ }
5753
+ }
5754
+ var ROW_HEIGHT = 56;
5755
+ var NARROW_ROW_HEIGHT = 76;
5756
+ var MAX_INDENT_DEPTH = 4;
5757
+ var ANIMATE_ROWS_UP_TO = 500;
5758
+ var NARROW_GRID = 640;
5759
+ var WIDTH_RULES = [
5760
+ { colId: "shared", minWidth: 1050 },
5761
+ { colId: "due", minWidth: 850 },
5762
+ { colId: "outputs", minWidth: 930 },
5763
+ { colId: "owner", minWidth: 730 },
5764
+ { colId: "status", minWidth: NARROW_GRID }
5765
+ ];
5766
+ function statusHint(task, ctx) {
5767
+ const { props: p, l } = ctx;
5768
+ if (!p.formatRelative || !task.updated_at) return void 0;
5769
+ const key = asTaskStatus(task.status);
5770
+ const pill = { ...DEFAULT_TASK_STATUS_PILL_LABELS, ...p.statusPillLabels };
5771
+ const label = task.pending_auth_request_id ? pill.waitingForAccess : STATUS_LABELS[key];
5772
+ return l.statusHint(label, p.formatRelative(task.updated_at));
5773
+ }
5774
+ function TaskTable(props) {
5775
+ const { tasks: allTasks, isLoading, busyId, header, testId } = props;
5776
+ const l = {
5777
+ ...DEFAULT_TASK_LIST_LABELS,
5778
+ ...props.labels,
5779
+ status: { ...STATUS_LABELS, ...props.labels?.status }
5780
+ };
5781
+ const [filter, setFilter] = react.useState("all");
5782
+ const [query, setQuery] = react.useState("");
5783
+ const [collapsed, setCollapsed] = react.useState(/* @__PURE__ */ new Set());
5784
+ const [selectedIds, setSelectedIds] = react.useState(/* @__PURE__ */ new Set());
5785
+ const [sort, setSort] = react.useState(null);
5786
+ const [moving, setMoving] = react.useState(null);
5787
+ const tasks = allTasks;
5788
+ const apiRef = react.useRef(null);
5789
+ const [narrow, setNarrow] = react.useState(false);
5790
+ const rowCache = react.useRef(/* @__PURE__ */ new Map());
5791
+ const tree = react.useMemo(() => indexTasks(tasks), [tasks]);
5792
+ const peopleNames = react.useMemo(
5793
+ () => new Map((props.people ?? []).map((p) => [p.id, p.label])),
5794
+ [props.people]
5795
+ );
5796
+ const nameOf = (task) => task.title?.trim() || task.workflow_ext_id && props.workflowNames?.[task.workflow_ext_id] || l.untitled;
5797
+ const owner = (task) => {
5798
+ const id = ownerExtId(task);
5799
+ const mine = task.is_owner !== false;
5800
+ return {
5801
+ id,
5802
+ label: mine ? l.me : (id && peopleNames.get(id)) ?? l.someone,
5803
+ isMe: mine
5804
+ };
5805
+ };
5806
+ const starter = (task) => {
5807
+ const id = task.created_by_ext_id ?? task.owner_ext_id;
5808
+ const mine = task.is_owner !== false;
5809
+ return {
5810
+ id,
5811
+ label: mine ? l.me : (id && peopleNames.get(id)) ?? l.someone,
5812
+ isMe: mine
5813
+ };
5814
+ };
5815
+ const renderPerson = props.renderPerson ?? ((person) => /* @__PURE__ */ jsxRuntime.jsx(chunk2QDNQM63_cjs.PersonPill, { person }));
5816
+ const q = (query.trim() || (props.filterText ?? "").trim()).toLowerCase();
5817
+ const counts = react.useMemo(() => {
5818
+ const map = new Map(STATUS_ORDER.map((s) => [s, 0]));
5819
+ let all = 0;
5820
+ for (const task of tasks) {
5821
+ const text2 = `${nameOf(task)} ${task.description ?? ""}`.toLowerCase();
5822
+ if (q && !text2.includes(q)) continue;
5823
+ all += 1;
5824
+ const s = asTaskStatus(task.status);
5825
+ map.set(s, (map.get(s) ?? 0) + 1);
5826
+ }
5827
+ map.set("all", all);
5828
+ return map;
5829
+ }, [tasks, q, props.workflowNames, l.untitled]);
5830
+ const compare = react.useMemo(() => {
5831
+ if (!sort) return void 0;
5832
+ const keys = /* @__PURE__ */ new Map();
5833
+ const compute = (t) => {
5834
+ switch (sort.colId) {
5835
+ case "name":
5836
+ return nameOf(t).toLowerCase();
5837
+ case "owner":
5838
+ return owner(t).label.toLowerCase();
5839
+ case "updated":
5840
+ return t.updated_at ? Date.parse(t.updated_at) : 0;
5841
+ case "messages":
5842
+ return t.message_count ?? 0;
5843
+ case "due":
5844
+ return t.due_at ? Date.parse(t.due_at) : Number.POSITIVE_INFINITY;
5845
+ default:
5846
+ return STATUS_ORDER.indexOf(asTaskStatus(t.status));
5847
+ }
5848
+ };
5849
+ const key = (t) => {
5850
+ let k = keys.get(t);
5851
+ if (k === void 0) {
5852
+ k = compute(t);
5853
+ keys.set(t, k);
5854
+ }
5855
+ return k;
5856
+ };
5857
+ const sign = sort.dir === "asc" ? 1 : -1;
5858
+ return (a, b) => {
5859
+ const [x, y] = [key(a), key(b)];
5860
+ if (typeof x === "number" && typeof y === "number") return (x - y) * sign;
5861
+ return String(x).localeCompare(String(y)) * sign;
5862
+ };
5863
+ }, [
5864
+ sort,
5865
+ peopleNames,
5866
+ props.agentNames,
5867
+ props.workflowNames,
5868
+ l.me,
5869
+ l.agent,
5870
+ l.someone,
5871
+ l.untitled
5872
+ ]);
5873
+ const rows = react.useMemo(
5874
+ () => buildTaskRows(tasks, filter, collapsed, compare, {
5875
+ query: query.trim() || props.filterText,
5876
+ titleOf: nameOf,
5877
+ cache: rowCache.current
5878
+ }),
5879
+ // nameOf reads the labels and workflow names the table was given.
5880
+ // eslint-disable-next-line react-hooks/exhaustive-deps
5881
+ [tasks, filter, collapsed, compare, query, props.filterText, props.workflowNames, l.untitled]
5882
+ );
5883
+ const selectedRows = react.useMemo(
5884
+ () => rows.filter((r) => selectedIds.has(r.external_id)),
5885
+ [rows, selectedIds]
5886
+ );
5887
+ const selectedTasks = react.useMemo(
5888
+ () => tasks.filter((t) => selectedIds.has(t.external_id)),
5889
+ [tasks, selectedIds]
5890
+ );
5891
+ const subtasksIncluded = react.useMemo(
5892
+ () => selectedTasks.filter((t) => {
5893
+ const parent = tree.parentOf.get(t.external_id);
5894
+ return parent !== void 0 && selectedIds.has(parent);
5895
+ }).length,
5896
+ [selectedTasks, selectedIds, tree]
5897
+ );
5898
+ const markable = selectedTasks.filter(
5899
+ (t) => t.status != null && (t.is_owner !== false || props.canEditShared) && isPlainTodo(t) && asTaskStatus(t.status) !== "done"
5900
+ );
5901
+ const deletable = selectedTasks.filter((t) => t.is_owner !== false || props.isWorkspaceOwner);
5902
+ const rowsRef = react.useRef(rows);
5903
+ rowsRef.current = rows;
5904
+ const handleSelectionChange = (picked) => {
5905
+ const visible = new Set(rowsRef.current.map((r) => r.external_id));
5906
+ const pickedIds = new Set(picked.map((r) => r.external_id));
5907
+ setSelectedIds((prev) => {
5908
+ const added = [...pickedIds].filter((id) => !prev.has(id));
5909
+ const removed = [...prev].filter((id) => visible.has(id) && !pickedIds.has(id));
5910
+ if (added.length === 0 && removed.length === 0) return prev;
5911
+ const next = new Set(prev);
5912
+ for (const id of added) {
5913
+ next.add(id);
5914
+ for (const d of descendantIds(tree, id)) next.add(d);
5915
+ }
5916
+ for (const id of removed) {
5917
+ next.delete(id);
5918
+ for (const d of descendantIds(tree, id)) next.delete(d);
5919
+ for (let at = tree.parentOf.get(id); at; at = tree.parentOf.get(at)) next.delete(at);
5920
+ }
5921
+ return next;
5922
+ });
5923
+ };
5924
+ const setExpanded = (id, expanded) => setCollapsed((prev) => {
5925
+ if (prev.has(id) === !expanded) return prev;
5926
+ const next = new Set(prev);
5927
+ if (expanded) next.delete(id);
5928
+ else next.add(id);
5929
+ return next;
5930
+ });
5931
+ const expandAll = () => setCollapsed(/* @__PURE__ */ new Set());
5932
+ const collapseAll = () => setCollapsed(new Set(tree.kids.keys()));
5933
+ const latest = react.useRef({ props, l, owner, starter, renderPerson, nameOf, setExpanded, narrow });
5934
+ latest.current = { props, l, owner, starter, renderPerson, nameOf, setExpanded, narrow };
5935
+ const showOutputs = Object.values(props.outputsByTask ?? {}).some((o) => o.length > 0);
5936
+ const columnDefs = react.useMemo(
5937
+ () => createTaskColumns({
5938
+ narrow,
5939
+ labels: l,
5940
+ getOwnerName: (row) => latest.current.owner(row.task).label,
5941
+ renderName: (row) => {
5942
+ const { l: lb, props: p, nameOf: name } = latest.current;
5943
+ const { task, depth, childStats, expanded } = row;
5944
+ const id = task.external_id;
5945
+ const status = asTaskStatus(task.status);
5946
+ const goal = goalProgress(task);
5947
+ const workflowName = task.workflow_ext_id ? p.workflowNames?.[task.workflow_ext_id] : null;
5948
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5949
+ "div",
5950
+ {
5951
+ className: "flex min-w-0 flex-1 items-center gap-1.5",
5952
+ style: depth > 0 ? { paddingLeft: `${Math.min(depth, MAX_INDENT_DEPTH) * 1.5}rem` } : void 0,
5953
+ "data-depth": depth,
5954
+ "aria-level": depth + 1,
5955
+ "aria-setsize": row.setSize,
5956
+ "aria-posinset": row.posInSet,
5957
+ "data-context": row.context || void 0,
5958
+ children: [
5959
+ childStats ? /* @__PURE__ */ jsxRuntime.jsx(
5960
+ "button",
5961
+ {
5962
+ type: "button",
5963
+ onClick: () => latest.current.setExpanded(id, !expanded),
5964
+ "aria-expanded": expanded,
5965
+ "aria-label": expanded ? lb.collapseSubtasks : lb.expandSubtasks,
5966
+ className: "flex size-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground",
5967
+ "data-testid": `task-expand-${id}`,
5968
+ children: expanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "size-4", "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "size-4", "aria-hidden": true })
5969
+ }
5970
+ ) : depth > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-5 shrink-0", "aria-hidden": true }) : null,
5971
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 leading-tight", children: [
5972
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
5973
+ /* @__PURE__ */ jsxRuntime.jsx(
5974
+ "button",
5975
+ {
5976
+ type: "button",
5977
+ onClick: () => latest.current.props.onOpenThread(id, task),
5978
+ title: task.agent_ext_id ? lb.preparedBy(p.agentNames?.[task.agent_ext_id] || lb.agent) : void 0,
5979
+ className: ui.cn(
5980
+ // The title has priority: it keeps at least 12 characters before it ellipsises.
5981
+ "min-w-[12ch] truncate text-left text-sm font-medium hover:underline focus-visible:underline focus-visible:outline-none",
5982
+ status === "done" && "text-muted-foreground line-through"
5983
+ ),
5984
+ "data-testid": `task-name-${id}`,
5985
+ children: name(task)
5986
+ }
5987
+ ),
5988
+ goal && /* @__PURE__ */ jsxRuntime.jsxs(
5989
+ chunkDVUZTGVL_cjs.ToneBadge,
5990
+ {
5991
+ tone: goal.done ? "success" : "neutral",
5992
+ "data-testid": `task-goal-progress-${id}`,
5993
+ children: [
5994
+ goal.done ? "\u2713 " : "",
5995
+ lb.goalMet(goal.met, goal.total)
5996
+ ]
5997
+ }
5998
+ )
5999
+ ] }),
6000
+ latest.current.narrow && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(
6001
+ TaskStatusPill,
6002
+ {
6003
+ id,
6004
+ status,
6005
+ runStartedAt: task.run_started_at,
6006
+ lastError: task.last_error,
6007
+ awaitingAccess: Boolean(task.pending_auth_request_id),
6008
+ labels: p.statusPillLabels
6009
+ }
6010
+ ) }),
6011
+ (task.description || workflowName || childStats) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 items-center gap-2 text-xs text-muted-foreground", children: [
6012
+ task.description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "min-w-0 truncate", children: task.description }) : workflowName ? /* @__PURE__ */ jsxRuntime.jsxs(
6013
+ "span",
6014
+ {
6015
+ className: "inline-flex min-w-0 items-center gap-1.5",
6016
+ "data-testid": `task-workflow-${id}`,
6017
+ children: [
6018
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Workflow, { className: "size-3.5 shrink-0", "aria-hidden": true }),
6019
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: lb.fromWorkflow(workflowName) })
6020
+ ]
6021
+ }
6022
+ ) : null,
6023
+ childStats && /* @__PURE__ */ jsxRuntime.jsx(
6024
+ "span",
6025
+ {
6026
+ className: "shrink-0 tabular-nums",
6027
+ "data-testid": `task-subtask-progress-${id}`,
6028
+ children: lb.subtasksDone(childStats.done, childStats.total)
6029
+ }
6030
+ )
6031
+ ] })
6032
+ ] })
6033
+ ]
6034
+ }
6035
+ );
6036
+ },
6037
+ // Who has the next step: the person pill, with the "Me" treatment. A plain chat is its starter's.
6038
+ renderOwner: (row) => /* @__PURE__ */ jsxRuntime.jsx("span", { "data-testid": `task-owner-${row.external_id}`, className: "flex min-w-0", children: latest.current.renderPerson(
6039
+ row.task.status ? latest.current.owner(row.task) : latest.current.starter(row.task)
6040
+ ) }),
6041
+ renderDue: (row) => {
6042
+ const { l: lb, props: p } = latest.current;
6043
+ const { task } = row;
6044
+ const dueMs = task.due_at ? Date.parse(task.due_at) : NaN;
6045
+ const overdue = asTaskStatus(task.status) !== "done" && !Number.isNaN(dueMs) && dueMs < Date.now();
6046
+ return /* @__PURE__ */ jsxRuntime.jsx(
6047
+ "span",
6048
+ {
6049
+ className: ui.cn(
6050
+ "truncate text-sm",
6051
+ overdue ? "font-medium text-red-text" : "text-muted-foreground"
6052
+ ),
6053
+ "data-testid": `task-due-${task.external_id}`,
6054
+ "data-overdue": overdue,
6055
+ children: task.due_at ? overdue ? lb.overdue(p.formatDate(task.due_at)) : lb.due(p.formatDate(task.due_at)) : lb.noDue
6056
+ }
6057
+ );
6058
+ },
6059
+ renderShared: (row) => {
6060
+ const { l: lb, props: p } = latest.current;
6061
+ const { task } = row;
6062
+ if (!p.onToggleShared) return null;
6063
+ return /* @__PURE__ */ jsxRuntime.jsx(
6064
+ ui.VisibilityToggle,
6065
+ {
6066
+ items: { shared: task.is_shared ?? false },
6067
+ onToggle: (shouldShare) => latest.current.props.onToggleShared?.(task, shouldShare),
6068
+ disabled: task.is_owner === false,
6069
+ disabledTooltip: lb.sharedOwnerOnly,
6070
+ showLabel: false,
6071
+ "data-testid": `task-shared-${task.external_id}`
6072
+ }
6073
+ );
6074
+ },
6075
+ showOutputs,
6076
+ renderOutputs: (row) => /* @__PURE__ */ jsxRuntime.jsx(
6077
+ TaskOutputsCell,
6078
+ {
6079
+ id: row.external_id,
6080
+ outputs: latest.current.props.outputsByTask?.[row.external_id],
6081
+ onOpen: (docId) => latest.current.props.onOpenOutput?.(docId, row.task),
6082
+ labels: latest.current.props.outputsLabels
6083
+ }
6084
+ ),
6085
+ renderStatus: (row) => /* @__PURE__ */ jsxRuntime.jsx(
6086
+ TaskStatusPill,
6087
+ {
6088
+ id: row.external_id,
6089
+ status: asTaskStatus(row.task.status),
6090
+ runStartedAt: row.task.run_started_at,
6091
+ lastError: row.task.last_error,
6092
+ awaitingAccess: Boolean(row.task.pending_auth_request_id),
6093
+ labels: latest.current.props.statusPillLabels,
6094
+ hint: statusHint(row.task, latest.current)
6095
+ }
6096
+ ),
6097
+ renderActions: (row) => {
6098
+ const { l: lb, props: p } = latest.current;
6099
+ const { task } = row;
6100
+ const id = task.external_id;
6101
+ const status = asTaskStatus(task.status);
6102
+ const busy = p.busyId === id;
6103
+ const isOwner = task.is_owner !== false;
6104
+ const canEdit = isOwner || Boolean(p.canEditShared);
6105
+ const canAdmin = isOwner || Boolean(p.isWorkspaceOwner);
6106
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-2", children: [
6107
+ !latest.current.narrow && isOwner && task.pending_auth_request_id && p.onGrantAccess && /* @__PURE__ */ jsxRuntime.jsxs(
6108
+ ui.Button,
6109
+ {
6110
+ size: "sm",
6111
+ className: "h-8 gap-1.5 pointer-coarse:h-11",
6112
+ onClick: () => p.onGrantAccess?.(task),
6113
+ "data-testid": `task-allow-access-${id}`,
6114
+ children: [
6115
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.KeyRound, { className: "size-3.5", "aria-hidden": true }),
6116
+ lb.allowAccess
6117
+ ]
6118
+ }
6119
+ ),
6120
+ /* @__PURE__ */ jsxRuntime.jsx(
6121
+ TaskRowMenu,
6122
+ {
6123
+ task,
6124
+ status,
6125
+ busy,
6126
+ isOwner,
6127
+ canAdmin,
6128
+ canEdit,
6129
+ labels: lb,
6130
+ onMarkDone: () => p.onMarkDone(task),
6131
+ onReopen: () => p.onReopen(task),
6132
+ onAddSubtask: p.onAddSubtask ? () => p.onAddSubtask?.(task) : void 0,
6133
+ onMoveTo: p.onMove ? () => setMoving(task) : void 0,
6134
+ onEdit: () => p.onEdit(task),
6135
+ onDelete: () => p.onDelete(task),
6136
+ onOpenActivity: p.onOpenActivity ? () => p.onOpenActivity?.(task) : void 0,
6137
+ onGrantAccess: p.onGrantAccess ? () => p.onGrantAccess?.(task) : void 0
6138
+ }
6139
+ )
6140
+ ] });
6141
+ }
6142
+ }),
6143
+ // Stable on purpose: only the header texts rebuild the columns (see `latest`).
6144
+ // eslint-disable-next-line react-hooks/exhaustive-deps
6145
+ [
6146
+ l.colTask,
6147
+ l.colOwner,
6148
+ l.colDue,
6149
+ l.colStatus,
6150
+ l.colShared,
6151
+ l.colOutputs,
6152
+ l.shared,
6153
+ showOutputs,
6154
+ narrow
6155
+ ]
6156
+ );
6157
+ react.useEffect(() => {
6158
+ apiRef.current?.refreshCells({ force: true });
6159
+ }, [
6160
+ busyId,
6161
+ props.people,
6162
+ props.agentNames,
6163
+ props.workflowNames,
6164
+ props.outputsByTask,
6165
+ props.renderPerson,
6166
+ props.labels,
6167
+ props.canEditShared,
6168
+ props.isWorkspaceOwner,
6169
+ narrow
6170
+ ]);
6171
+ const animate = rows.length <= ANIMATE_ROWS_UP_TO;
6172
+ const gridOptions = react.useMemo(
6173
+ () => ({
6174
+ suppressClickEdit: true,
6175
+ // Keyboard focus lives on the name column only (the others are not navigable): ArrowRight
6176
+ // opens a task's sub-tasks and ArrowLeft closes them, or steps up to the parent.
6177
+ suppressCellFocus: false,
6178
+ suppressColumnVirtualisation: true,
6179
+ animateRows: animate,
6180
+ getRowClass: (p) => p.data?.context ? "opacity-60" : void 0,
6181
+ // The grid shows and reports the sort; the table orders each level (see buildTaskRows).
6182
+ onSortChanged: (event) => {
6183
+ const sorted = event.api.getColumnState().find((c) => c.sort);
6184
+ setSort(
6185
+ sorted?.colId ? { colId: sorted.colId, dir: sorted.sort ?? "asc" } : null
6186
+ );
6187
+ },
6188
+ onGridSizeChanged: (event) => {
6189
+ applyColumnWidthRules(event.api, event.clientWidth, WIDTH_RULES);
6190
+ setNarrow(event.clientWidth < NARROW_GRID);
6191
+ },
6192
+ onCellKeyDown: (event) => {
6193
+ const row = event.data;
6194
+ const key = event.event?.key;
6195
+ if (!row || event.column.getColId() !== "name") return;
6196
+ if (key === "ArrowRight" && row.childStats && !row.expanded) {
6197
+ event.event?.preventDefault();
6198
+ latest.current.setExpanded(row.external_id, true);
6199
+ } else if (key === "ArrowLeft") {
6200
+ if (row.childStats && row.expanded) {
6201
+ event.event?.preventDefault();
6202
+ latest.current.setExpanded(row.external_id, false);
6203
+ } else if (row.parentId) {
6204
+ event.event?.preventDefault();
6205
+ const parent = event.api.getRowNode(row.parentId);
6206
+ if (parent?.rowIndex != null) {
6207
+ event.api.ensureIndexVisible(parent.rowIndex);
6208
+ event.api.setFocusedCell(parent.rowIndex, "name");
6209
+ }
6210
+ }
6211
+ }
6212
+ }
6213
+ }),
6214
+ [animate]
6215
+ );
6216
+ const clearSelection = () => setSelectedIds(/* @__PURE__ */ new Set());
6217
+ const filterKeys = ["all", ...STATUS_ORDER].filter(
6218
+ (key) => key !== "chat" || (counts.get(key) ?? 0) > 0
6219
+ );
6220
+ const hasChildren = tree.kids.size > 0;
6221
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6222
+ "div",
6223
+ {
6224
+ className: "flex min-h-0 flex-1 flex-col gap-3",
6225
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testId, { testId: "task-list" }),
6226
+ children: [
6227
+ header,
6228
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
6229
+ /* @__PURE__ */ jsxRuntime.jsx("div", { role: "tablist", "aria-label": "Filter tasks", className: "flex flex-wrap gap-1.5", children: filterKeys.map((key) => {
6230
+ const count = counts.get(key) ?? 0;
6231
+ const isSelected = filter === key;
6232
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6233
+ "button",
6234
+ {
6235
+ type: "button",
6236
+ role: "tab",
6237
+ "aria-selected": isSelected,
6238
+ onClick: () => setFilter(key),
6239
+ className: ui.cn(
6240
+ "inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:min-h-11",
6241
+ isSelected ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground hover:bg-accent"
6242
+ ),
6243
+ "data-testid": `task-filter-${key}`,
6244
+ children: [
6245
+ key === "all" ? l.filterAll : l.status[key],
6246
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums opacity-70", children: count })
6247
+ ]
6248
+ },
6249
+ key
6250
+ );
6251
+ }) }),
6252
+ /* @__PURE__ */ jsxRuntime.jsx(
6253
+ ui.Input,
6254
+ {
6255
+ type: "search",
6256
+ value: query,
6257
+ onChange: (e) => setQuery(e.target.value),
6258
+ placeholder: l.searchPlaceholder,
6259
+ "aria-label": l.searchLabel,
6260
+ className: "h-8 max-w-56 text-xs pointer-coarse:h-11",
6261
+ "data-testid": "task-search"
6262
+ }
6263
+ ),
6264
+ hasChildren && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-auto flex gap-1", children: [
6265
+ /* @__PURE__ */ jsxRuntime.jsxs(
6266
+ ui.Button,
6267
+ {
6268
+ type: "button",
6269
+ variant: "ghost",
6270
+ size: "sm",
6271
+ className: "h-8 gap-1.5 text-xs pointer-coarse:h-11",
6272
+ onClick: expandAll,
6273
+ "data-testid": "task-expand-all",
6274
+ children: [
6275
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDown, { className: "size-3.5", "aria-hidden": true }),
6276
+ l.expandAll
6277
+ ]
6278
+ }
6279
+ ),
6280
+ /* @__PURE__ */ jsxRuntime.jsxs(
6281
+ ui.Button,
6282
+ {
6283
+ type: "button",
6284
+ variant: "ghost",
6285
+ size: "sm",
6286
+ className: "h-8 gap-1.5 text-xs pointer-coarse:h-11",
6287
+ onClick: collapseAll,
6288
+ "data-testid": "task-collapse-all",
6289
+ children: [
6290
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsDownUp, { className: "size-3.5", "aria-hidden": true }),
6291
+ l.collapseAll
6292
+ ]
6293
+ }
6294
+ )
6295
+ ] })
6296
+ ] }),
6297
+ tasks.length === 0 && !isLoading ? /* @__PURE__ */ jsxRuntime.jsx(
6298
+ chunkZW6FPIFC_cjs.EmptyState,
6299
+ {
6300
+ icon: lucideReact.ListTodo,
6301
+ title: l.emptyTitle,
6302
+ description: l.emptyMessage,
6303
+ testId: "task-list-empty"
6304
+ }
6305
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
6306
+ chunkLKK52DEY_cjs.GridView,
6307
+ {
6308
+ testId: "task-grid",
6309
+ gridId: props.gridId ?? "tasks-grid-v4",
6310
+ items: rows,
6311
+ columnDefs,
6312
+ getItemId: (row) => row.external_id,
6313
+ getRowTestId: (row) => `task-row-${row.external_id}`,
6314
+ isLoading,
6315
+ showEmpty: rows.length === 0,
6316
+ emptyState: { title: l.noMatches },
6317
+ rowHeight: narrow ? NARROW_ROW_HEIGHT : ROW_HEIGHT,
6318
+ height: "100%",
6319
+ onGridReady: ({ api }) => {
6320
+ apiRef.current = api;
6321
+ },
6322
+ selection: {
6323
+ mode: "multiple",
6324
+ controlled: true,
6325
+ selected: selectedRows,
6326
+ onSelectionChange: handleSelectionChange
6327
+ },
6328
+ gridOptions
6329
+ }
6330
+ ) }),
6331
+ /* @__PURE__ */ jsxRuntime.jsx(
6332
+ chunkV4ISCZJ7_cjs.SelectionBar,
6333
+ {
6334
+ count: selectedTasks.length,
6335
+ onClear: clearSelection,
6336
+ status: selectedTasks.length > 0 && subtasksIncluded > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", "data-testid": "task-selection-subtasks", children: l.subtasksSelected(subtasksIncluded) }) : void 0,
6337
+ children: (isCompact) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6338
+ props.selectionActions?.(selectedTasks, isCompact, clearSelection),
6339
+ props.onMarkDoneMany && /* @__PURE__ */ jsxRuntime.jsx(
6340
+ chunkV4ISCZJ7_cjs.SelectionBarAction,
6341
+ {
6342
+ icon: lucideReact.CheckCheck,
6343
+ label: l.markDoneMany,
6344
+ onClick: () => {
6345
+ props.onMarkDoneMany?.(markable);
6346
+ clearSelection();
6347
+ },
6348
+ disabled: markable.length === 0,
6349
+ isCompact,
6350
+ tooltip: l.markDoneManyHint,
6351
+ testId: "task-bulk-done"
6352
+ }
6353
+ ),
6354
+ props.onDeleteMany && /* @__PURE__ */ jsxRuntime.jsx(
6355
+ chunkV4ISCZJ7_cjs.SelectionBarAction,
6356
+ {
6357
+ icon: lucideReact.Trash2,
6358
+ label: l.deleteMany,
6359
+ onClick: () => {
6360
+ props.onDeleteMany?.(deletable);
6361
+ clearSelection();
6362
+ },
6363
+ disabled: deletable.length === 0,
6364
+ isCompact,
6365
+ className: "border-red-border text-red-text hover:bg-red-bg hover:text-red-text",
6366
+ testId: "task-bulk-delete"
6367
+ }
6368
+ )
6369
+ ] })
6370
+ }
6371
+ ),
6372
+ moving && props.onMove && /* @__PURE__ */ jsxRuntime.jsx(
6373
+ TaskMoveDialog,
6374
+ {
6375
+ open: true,
6376
+ onOpenChange: (open) => !open && setMoving(null),
6377
+ options: moveTargets(tasks, moving).map((t) => ({ id: t.external_id, label: nameOf(t) })),
6378
+ currentParentId: moving.parent_conversation_ext_id,
6379
+ onPick: (parentId) => props.onMove?.(moving, parentId),
6380
+ labels: {
6381
+ title: l.moveToTitle(nameOf(moving)),
6382
+ none: l.moveToNone,
6383
+ search: l.moveToSearch,
6384
+ empty: l.moveToEmpty,
6385
+ cancel: l.moveToCancel
6386
+ }
6387
+ }
6388
+ )
6389
+ ]
6390
+ }
6391
+ );
6392
+ }
6393
+ function TaskInbox(p) {
6394
+ const [filterOpen, setFilterOpen] = react.useState(false);
6395
+ const [statusFilters, setStatusFilters] = react.useState(
6396
+ () => /* @__PURE__ */ new Map([["done", "exclude"]])
6397
+ );
6398
+ const [localQuery, setLocalQuery] = react.useState("");
6399
+ const [searchFields, setSearchFields] = react.useState(["text", "labels"]);
6400
+ const [selected, setSelected] = react.useState(/* @__PURE__ */ new Set());
6401
+ const [collapsed, setCollapsed] = react.useState(/* @__PURE__ */ new Set());
6402
+ const [moving, setMoving] = react.useState(null);
6403
+ const l = { ...DEFAULT_TASK_LIST_LABELS, ...p.labels };
6404
+ const nameOf = (t) => t.title?.trim() || t.workflow_ext_id && p.workflowNames?.[t.workflow_ext_id] || l.untitled;
6405
+ const all = p.tasks.filter((t) => t.status != null);
6406
+ const filterText = p.filterText ?? localQuery;
6407
+ const q = filterText.trim().toLowerCase();
6408
+ const included = [...statusFilters].filter(([, state]) => state === "include").map(([id]) => id);
6409
+ const statusMatches = (t) => statusFilters.get(asTaskStatus(t.status)) !== "exclude" && (!included.length || included.includes(asTaskStatus(t.status)));
6410
+ const rows = all.filter(
6411
+ (t) => statusMatches(t) && (!q || [
6412
+ searchFields.includes("text") ? `${nameOf(t)} ${t.description ?? ""}` : "",
6413
+ searchFields.includes("labels") && t.workflow_ext_id ? p.workflowNames?.[t.workflow_ext_id] ?? "" : ""
6414
+ ].join(" ").toLowerCase().includes(q))
6415
+ );
6416
+ const hasActiveFilters = !!q || [...statusFilters.values()].some((state) => state != null);
6417
+ const selectedTasks = all.filter((t) => selected.has(t.external_id));
6418
+ const canEdit = (t) => t.is_owner !== false || Boolean(p.canEditShared);
6419
+ const markable = (t) => t.status !== "done" && t.status !== "generating" && canEdit(t) && !t.in_progress;
6420
+ const markableTasks = selectedTasks.filter(markable);
6421
+ const deletableTasks = selectedTasks.filter((t) => t.is_owner !== false || p.isWorkspaceOwner);
6422
+ const clearSelection = () => setSelected(/* @__PURE__ */ new Set());
6423
+ const toggle = (set, id) => set((old) => {
6424
+ const next = new Set(old);
6425
+ if (next.has(id)) next.delete(id);
6426
+ else next.add(id);
6427
+ return next;
6428
+ });
6429
+ p.renderPerson ?? ((value) => /* @__PURE__ */ jsxRuntime.jsx(chunk2QDNQM63_cjs.PersonPill, { person: value }));
6430
+ const taskById = new Map(all.map((t) => [t.external_id, t]));
6431
+ const visible = new Set(rows.map((t) => t.external_id));
6432
+ for (const task of rows) {
6433
+ let id = task.parent_conversation_ext_id;
6434
+ const seen = /* @__PURE__ */ new Set();
6435
+ while (id && taskById.has(id) && !seen.has(id)) {
6436
+ seen.add(id);
6437
+ visible.add(id);
6438
+ id = taskById.get(id)?.parent_conversation_ext_id;
6439
+ }
6440
+ }
6441
+ const listed = all.filter((t) => visible.has(t.external_id));
6442
+ const roots = listed.filter(
6443
+ (t) => !t.parent_conversation_ext_id || !visible.has(t.parent_conversation_ext_id)
6444
+ );
6445
+ const workflows = (p.workflows ?? []).filter((w) => {
6446
+ const runs = roots.filter((t) => t.workflow_ext_id === w.external_id);
6447
+ return runs.length > 0 || !included.length && (!q || w.name.toLowerCase().includes(q));
6448
+ });
6449
+ const workflowIds = new Set(workflows.map((w) => w.external_id));
6450
+ const order = (a, b) => {
6451
+ const weight = (t) => t.pending_auth_request_id || t.last_error ? 0 : t.status === "todo" ? 1 : t.status === "generating" ? 2 : 3;
6452
+ return weight(a) - weight(b) || (b.updated_at ?? "").localeCompare(a.updated_at ?? "");
6453
+ };
6454
+ const renderTask = (task, depth = 0) => {
6455
+ const id = task.external_id;
6456
+ const status = asTaskStatus(task.status);
6457
+ const busy = p.busyId === id;
6458
+ const children = listed.filter((t) => t.parent_conversation_ext_id === id).sort(order);
6459
+ const outputs = p.outputsByTask?.[id] ?? [];
6460
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { "data-testid": `task-inbox-row-${id}`, children: [
6461
+ /* @__PURE__ */ jsxRuntime.jsxs(
6462
+ "div",
6463
+ {
6464
+ className: ui.cn(
6465
+ "relative flex cursor-pointer items-start gap-2 border-b py-3 hover:bg-muted/40",
6466
+ selected.has(id) && "bg-muted/60"
6467
+ ),
6468
+ onClick: (event) => {
6469
+ if (!event.target.closest(
6470
+ 'button, a, input, select, textarea, [role="menuitem"], [role="checkbox"], [role="combobox"]'
6471
+ )) {
6472
+ p.onOpenThread(id, task);
6473
+ }
6474
+ },
6475
+ style: { paddingLeft: `${Math.min(depth, 5) * 20}px` },
6476
+ children: [
6477
+ children.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
6478
+ ui.Button,
6479
+ {
6480
+ variant: "ghost",
6481
+ size: "icon",
6482
+ className: "size-7 shrink-0",
6483
+ "aria-label": `${collapsed.has(id) ? "Expand" : "Collapse"} ${nameOf(task)}`,
6484
+ onClick: () => toggle(setCollapsed, id),
6485
+ children: collapsed.has(id) ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "size-4" })
6486
+ }
6487
+ ),
6488
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
6489
+ /* @__PURE__ */ jsxRuntime.jsx(
6490
+ "button",
6491
+ {
6492
+ className: ui.cn(
6493
+ "block w-full text-left text-sm font-medium hover:underline",
6494
+ status === "done" && "text-muted-foreground"
6495
+ ),
6496
+ "data-testid": `task-open-${id}`,
6497
+ onClick: () => p.onOpenThread(id, task),
6498
+ children: nameOf(task)
6499
+ }
6500
+ ),
6501
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
6502
+ status !== "todo" && /* @__PURE__ */ jsxRuntime.jsx(
6503
+ TaskStatusPill,
6504
+ {
6505
+ id,
6506
+ status: task.status,
6507
+ runStartedAt: task.run_started_at,
6508
+ lastError: task.last_error,
6509
+ awaitingAccess: Boolean(task.pending_auth_request_id)
6510
+ }
6511
+ ),
6512
+ task.due_at && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
6513
+ "Due ",
6514
+ p.formatDate(task.due_at)
6515
+ ] }),
6516
+ children.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
6517
+ all.filter((t) => t.parent_conversation_ext_id === id && t.status === "done").length,
6518
+ "/",
6519
+ all.filter((t) => t.parent_conversation_ext_id === id).length,
6520
+ " steps complete"
6521
+ ] })
6522
+ ] }),
6523
+ outputs.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 flex flex-wrap gap-2", "aria-label": "Outputs", children: outputs.map((output) => /* @__PURE__ */ jsxRuntime.jsxs(
6524
+ ui.Button,
6525
+ {
6526
+ variant: "link",
6527
+ size: "sm",
6528
+ className: "h-auto max-w-full gap-1 px-0 py-1 text-xs",
6529
+ disabled: !p.onOpenOutput,
6530
+ onClick: () => p.onOpenOutput?.(output.id, task),
6531
+ "data-testid": `task-output-${id}-${output.id}`,
6532
+ children: [
6533
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "size-3.5 shrink-0" }),
6534
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: output.name })
6535
+ ]
6536
+ },
6537
+ output.id
6538
+ )) })
6539
+ ] }),
6540
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
6541
+ task.pending_auth_request_id && task.is_owner !== false && p.onGrantAccess && /* @__PURE__ */ jsxRuntime.jsx(
6542
+ ui.Button,
6543
+ {
6544
+ size: "sm",
6545
+ variant: "outline",
6546
+ disabled: busy,
6547
+ onClick: () => p.onGrantAccess?.(task),
6548
+ children: "Allow access"
6549
+ }
6550
+ ),
6551
+ /* @__PURE__ */ jsxRuntime.jsx(
6552
+ TaskRowMenu,
6553
+ {
6554
+ task,
6555
+ status,
6556
+ busy,
6557
+ isOwner: task.is_owner !== false,
6558
+ canAdmin: task.is_owner !== false || Boolean(p.isWorkspaceOwner),
6559
+ canEdit: canEdit(task),
6560
+ canMarkDone: markable(task),
6561
+ canReopen: canEdit(task),
6562
+ selected: selected.has(id),
6563
+ onToggleSelected: p.selectionActions || p.onMarkDoneMany || p.onDeleteMany ? () => toggle(setSelected, id) : void 0,
6564
+ labels: l,
6565
+ onMarkDone: () => p.onMarkDone(task),
6566
+ onNotify: p.onNotify ? () => p.onNotify?.(task) : void 0,
6567
+ onReopen: () => p.onReopen(task),
6568
+ onEdit: () => p.onEdit(task),
6569
+ onAddSubtask: p.onAddSubtask ? () => p.onAddSubtask?.(task) : void 0,
6570
+ onMoveTo: p.onMove ? () => setMoving(task) : void 0,
6571
+ onOpenActivity: p.onOpenActivity ? () => p.onOpenActivity?.(task) : void 0,
6572
+ onToggleShared: p.onToggleShared ? () => p.onToggleShared?.(task, !task.is_shared) : void 0
6573
+ }
6574
+ )
6575
+ ] })
6576
+ ]
6577
+ }
6578
+ ),
6579
+ children.length > 0 && !collapsed.has(id) && /* @__PURE__ */ jsxRuntime.jsx("ul", { children: children.map((child) => renderTask(child, depth + 1)) })
6580
+ ] }, id);
6581
+ };
6582
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 flex-col", "data-testid": p.testId ?? "task-inbox", children: [
6583
+ /* @__PURE__ */ jsxRuntime.jsx(
6584
+ chunkMEMWZ72Y_cjs.TabHeader,
6585
+ {
6586
+ testId: "tasks-tab-header",
6587
+ tabs: [
6588
+ {
6589
+ id: "tasks",
6590
+ label: "",
6591
+ count: rows.length,
6592
+ countPlacement: "leading",
6593
+ countIcon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListTodo, { className: "size-3.5" }),
6594
+ hasActiveFilters,
6595
+ testId: "tasks-tab",
6596
+ presentation: "count"
6597
+ }
6598
+ ],
6599
+ activeTabId: "tasks",
6600
+ onTabChange: () => {
6601
+ },
6602
+ firstTabContent: /* @__PURE__ */ jsxRuntime.jsx(
6603
+ chunk2EI7NCUA_cjs.FilterInput,
6604
+ {
6605
+ value: filterText,
6606
+ onChange: p.onFilterTextChange ?? setLocalQuery,
6607
+ fields: searchFields,
6608
+ onFieldsChange: setSearchFields,
6609
+ labels: { fieldNames: { text: "Task", labels: "Workflow" } },
6610
+ className: "w-44 max-w-[40vw]",
6611
+ testIds: {
6612
+ root: "tasks-filter",
6613
+ input: "tasks-filter-input",
6614
+ fieldsButton: "tasks-filter-fields"
6615
+ },
6616
+ filter: /* @__PURE__ */ jsxRuntime.jsx(
6617
+ chunkAQPZ4QMV_cjs.TriStateFilterMenu,
6618
+ {
6619
+ testId: "tasks-status-filter",
6620
+ open: filterOpen,
6621
+ onOpenChange: setFilterOpen,
6622
+ filterStates: statusFilters,
6623
+ onFiltersChange: setStatusFilters,
6624
+ options: [
6625
+ {
6626
+ id: "todo",
6627
+ label: "To do",
6628
+ count: all.filter((t) => t.status === "todo").length
6629
+ },
6630
+ {
6631
+ id: "generating",
6632
+ label: "Generating",
6633
+ count: all.filter((t) => t.status === "generating").length
6634
+ },
6635
+ {
6636
+ id: "done",
6637
+ label: "Completed",
6638
+ count: all.filter((t) => t.status === "done").length
6639
+ }
6640
+ ],
6641
+ groups: [{ label: "Status", options: ["todo", "generating", "done"] }],
6642
+ triggerClassName: "flex h-5 items-center gap-0.5 rounded px-1 text-muted-foreground hover:text-foreground pointer-coarse:h-11! pointer-coarse:min-w-11 pointer-coarse:justify-center",
6643
+ renderChevron: true,
6644
+ disableHoverOpen: true
6645
+ }
6646
+ )
6647
+ }
6648
+ ),
6649
+ rightContent: p.onCreate ? /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
6650
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { "data-testid": "new-task-button", children: [
6651
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "mr-1 size-4" }),
6652
+ "New",
6653
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "ml-1 size-3" })
6654
+ ] }) }),
6655
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { align: "end", children: [
6656
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuItem, { onSelect: p.onCreate, children: "Task" }),
6657
+ p.onCreateWorkflow && /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuItem, { onSelect: p.onCreateWorkflow, children: "Saved workflow" })
6658
+ ] })
6659
+ ] }) : p.header
6660
+ }
6661
+ ),
6662
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1 overflow-y-auto", "aria-busy": p.isLoading, children: p.isLoading ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "py-12 text-center text-sm text-muted-foreground", children: "Loading work\u2026" }) : !listed.length && !workflows.length ? /* @__PURE__ */ jsxRuntime.jsx(
6663
+ chunkZW6FPIFC_cjs.EmptyState,
6664
+ {
6665
+ title: q ? "No matches" : all.length ? "You\u2019re all caught up" : "No work here yet",
6666
+ description: "Create a task from a prompt or a saved workflow. Keep its drafts and outputs together."
6667
+ }
6668
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("ul", { children: [
6669
+ workflows.map((w) => {
6670
+ const runs = roots.filter((t) => t.workflow_ext_id === w.external_id).sort(order);
6671
+ const editable = w.is_owner !== false || p.canEditShared;
6672
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { "data-testid": `task-workflow-${w.external_id}`, children: [
6673
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 border-b py-3", children: [
6674
+ runs.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
6675
+ ui.Button,
6676
+ {
6677
+ variant: "ghost",
6678
+ size: "icon",
6679
+ className: "size-7",
6680
+ "aria-label": `${collapsed.has(w.external_id) ? "Expand" : "Collapse"} ${w.name}`,
6681
+ onClick: () => toggle(setCollapsed, w.external_id),
6682
+ children: collapsed.has(w.external_id) ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "size-4" })
6683
+ }
6684
+ ) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Workflow, { className: "mx-1 mt-1 size-4 shrink-0 text-muted-foreground" }),
6685
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
6686
+ /* @__PURE__ */ jsxRuntime.jsx(
6687
+ "button",
6688
+ {
6689
+ className: "block text-left text-sm font-medium hover:underline",
6690
+ disabled: !editable,
6691
+ onClick: () => p.onEditWorkflow?.(w.external_id),
6692
+ children: w.name
6693
+ }
6694
+ ),
6695
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-1 text-xs text-muted-foreground", children: [
6696
+ "Saved workflow \xB7 ",
6697
+ w.summary ?? "Run when needed",
6698
+ !w.active ? " \xB7 Paused" : "",
6699
+ runs.length ? ` \xB7 ${runs.length} ${runs.length === 1 ? "task" : "tasks"}` : ""
6700
+ ] }),
6701
+ w.last_error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-destructive", children: w.last_error })
6702
+ ] }),
6703
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
6704
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6705
+ ui.Button,
6706
+ {
6707
+ variant: "ghost",
6708
+ size: "icon",
6709
+ className: "size-8",
6710
+ "aria-label": `Actions for ${w.name}`,
6711
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: "size-4" })
6712
+ }
6713
+ ) }),
6714
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { align: "end", children: [
6715
+ p.onWorkflowHistory && /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuItem, { onSelect: () => p.onWorkflowHistory?.(w.external_id), children: "Run history" }),
6716
+ editable && p.onToggleWorkflow && /* @__PURE__ */ jsxRuntime.jsx(
6717
+ ui.DropdownMenuItem,
6718
+ {
6719
+ onSelect: () => p.onToggleWorkflow?.(w.external_id, !w.active),
6720
+ children: w.active ? "Pause" : "Resume"
6721
+ }
6722
+ ),
6723
+ (w.is_owner !== false || p.isWorkspaceOwner) && p.onDeleteWorkflow && /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuItem, { onSelect: () => p.onDeleteWorkflow?.(w.external_id), children: "Delete workflow" })
6724
+ ] })
6725
+ ] })
6726
+ ] }),
6727
+ !collapsed.has(w.external_id) && runs.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("ul", { children: runs.map((t) => renderTask(t, 1)) })
6728
+ ] }, w.external_id);
6729
+ }),
6730
+ roots.filter((t) => !t.workflow_ext_id || !workflowIds.has(t.workflow_ext_id)).sort(order).map((t) => renderTask(t))
6731
+ ] }) }),
6732
+ /* @__PURE__ */ jsxRuntime.jsx(chunkV4ISCZJ7_cjs.SelectionBar, { count: selectedTasks.length, onClear: clearSelection, children: (isCompact) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6733
+ p.selectionActions?.(selectedTasks, isCompact, clearSelection),
6734
+ p.onMarkDoneMany && /* @__PURE__ */ jsxRuntime.jsx(
6735
+ chunkV4ISCZJ7_cjs.SelectionBarAction,
6736
+ {
6737
+ icon: lucideReact.CheckCheck,
6738
+ label: l.markDoneMany,
6739
+ isCompact,
6740
+ disabled: !markableTasks.length,
6741
+ onClick: () => {
6742
+ p.onMarkDoneMany?.(markableTasks);
6743
+ clearSelection();
6744
+ },
6745
+ testId: "task-bulk-done"
6746
+ }
6747
+ ),
6748
+ p.onDeleteMany && /* @__PURE__ */ jsxRuntime.jsx(
6749
+ chunkV4ISCZJ7_cjs.SelectionBarAction,
6750
+ {
6751
+ icon: lucideReact.Trash2,
6752
+ label: l.deleteMany,
6753
+ isCompact,
6754
+ disabled: !deletableTasks.length,
6755
+ onClick: () => {
6756
+ p.onDeleteMany?.(deletableTasks);
6757
+ clearSelection();
6758
+ },
6759
+ className: "text-red-text hover:bg-red-bg hover:text-red-text",
6760
+ testId: "task-bulk-delete"
6761
+ }
6762
+ )
6763
+ ] }) }),
6764
+ moving && p.onMove && /* @__PURE__ */ jsxRuntime.jsx(
6765
+ TaskMoveDialog,
6766
+ {
6767
+ open: true,
6768
+ onOpenChange: (open) => !open && setMoving(null),
6769
+ options: moveTargets(all, moving).map((t) => ({ id: t.external_id, label: nameOf(t) })),
6770
+ currentParentId: moving.parent_conversation_ext_id,
6771
+ onPick: (id) => p.onMove?.(moving, id),
6772
+ labels: {
6773
+ title: l.moveToTitle(nameOf(moving)),
6774
+ none: l.moveToNone,
6775
+ search: l.moveToSearch,
6776
+ empty: l.moveToEmpty,
6777
+ cancel: l.moveToCancel
6778
+ }
6779
+ }
6780
+ )
6781
+ ] });
5044
6782
  }
5045
6783
  var DEFAULT_THREAD_STATE_LABELS = {
5046
6784
  generating: "Generating",
@@ -5098,6 +6836,220 @@ function ThreadStatusLine({
5098
6836
  }
5099
6837
  );
5100
6838
  }
6839
+ function filterConversationRows(conversations, query, labelText, doneFilter = "exclude", visibilityFilters, meetingFilter = null) {
6840
+ const q = query.trim().toLowerCase();
6841
+ return [...conversations].sort(
6842
+ (a, b) => (Date.parse(b.last_message_updated_at || b.updated_at || b.created_at || "") || 0) - (Date.parse(a.last_message_updated_at || a.updated_at || a.created_at || "") || 0)
6843
+ ).filter(
6844
+ (row) => doneFilter === "exclude" ? row.status !== "done" : doneFilter === "include" ? row.status === "done" : true
6845
+ ).filter((row) => {
6846
+ const state = row.is_shared ? visibilityFilters?.workspace : visibilityFilters?.me;
6847
+ const hasIncluded = visibilityFilters?.me === "include" || visibilityFilters?.workspace === "include";
6848
+ return state !== "exclude" && (!hasIncluded || state === "include");
6849
+ }).filter(
6850
+ (row) => meetingFilter === "include" ? !!row.meeting_call_ext_id : meetingFilter === "exclude" ? !row.meeting_call_ext_id : true
6851
+ ).filter((row) => !q || `${row.title ?? ""} ${labelText?.(row) ?? ""}`.toLowerCase().includes(q));
6852
+ }
6853
+ function ConversationListView(p) {
6854
+ const liveProps = react.useRef(p);
6855
+ liveProps.current = p;
6856
+ const [query, setQuery] = react.useState("");
6857
+ const [selected, setSelected] = react.useState(/* @__PURE__ */ new Set());
6858
+ const q = `${query} ${p.filterText ?? ""}`.trim().toLowerCase();
6859
+ const isPhone = chunkFX3K6LNZ_cjs.useIsPhone();
6860
+ const rows = react.useMemo(
6861
+ () => filterConversationRows(
6862
+ p.conversations,
6863
+ q,
6864
+ p.labelText,
6865
+ p.doneFilter,
6866
+ p.visibilityFilters,
6867
+ p.meetingFilter
6868
+ ),
6869
+ [p.conversations, q, p.labelText, p.doneFilter, p.visibilityFilters, p.meetingFilter]
6870
+ );
6871
+ const selectedRows = p.conversations.filter((c) => selected.has(c.external_id));
6872
+ const hasLabels = p.conversations.some((c) => !!p.labelText?.(c));
6873
+ const columns = react.useMemo(
6874
+ () => [
6875
+ {
6876
+ colId: "name",
6877
+ headerName: "Thread",
6878
+ flex: 2,
6879
+ minWidth: 200,
6880
+ valueGetter: ({ data }) => data?.title?.trim() || "Untitled thread",
6881
+ cellRenderer: ({ data }) => data && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group flex h-full min-w-0 items-center gap-2", children: [
6882
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0", children: liveProps.current.renderThread ? liveProps.current.renderThread(data) : /* @__PURE__ */ jsxRuntime.jsx(
6883
+ EntityChip,
6884
+ {
6885
+ icon: /* @__PURE__ */ jsxRuntime.jsx(ui.ThreadVisibilityIcon, { shared: data.is_shared ?? false, className: "size-4" }),
6886
+ label: data.title?.trim() || "Untitled thread",
6887
+ pillTooltip: "Open conversation",
6888
+ labelMaxWidth: "max-w-full",
6889
+ onClick: () => liveProps.current.onOpen(data),
6890
+ testId: `thread-open-${data.external_id}`
6891
+ }
6892
+ ) }),
6893
+ (data.message_count ?? 0) > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
6894
+ "span",
6895
+ {
6896
+ className: "inline-flex h-5 shrink-0 items-center gap-0.5 self-center rounded-full bg-muted px-1.5 text-[10px] font-medium leading-none tabular-nums text-muted-foreground",
6897
+ title: `${data.message_count} ${data.message_count === 1 ? "message" : "messages"}`,
6898
+ "data-testid": `thread-messages-${data.external_id}`,
6899
+ children: [
6900
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: "size-3", "aria-hidden": true }),
6901
+ data.message_count
6902
+ ]
6903
+ }
6904
+ ),
6905
+ (data.is_owner !== false || liveProps.current.canEditShared) && /* @__PURE__ */ jsxRuntime.jsx(
6906
+ "button",
6907
+ {
6908
+ type: "button",
6909
+ "aria-label": `Rename ${data.title?.trim() || "Untitled thread"}`,
6910
+ onClick: () => liveProps.current.onRename(data),
6911
+ "data-testid": `thread-rename-${data.external_id}`,
6912
+ className: "shrink-0 pointer-coarse:flex pointer-coarse:size-11 pointer-coarse:items-center pointer-coarse:justify-center",
6913
+ children: /* @__PURE__ */ jsxRuntime.jsx(chunkSIB6C7P7_cjs.CellHoverIcon, {})
6914
+ }
6915
+ )
6916
+ ] })
6917
+ },
6918
+ // Labels only when a thread has some (an empty column only takes the names' room), and never
6919
+ // on a phone, where the status is what a row must say.
6920
+ ...liveProps.current.renderLabels && hasLabels && !isPhone ? [
6921
+ {
6922
+ colId: "labels",
6923
+ headerName: "Labels",
6924
+ flex: 0.5,
6925
+ minWidth: 100,
6926
+ valueGetter: ({ data }) => data ? liveProps.current.labelText?.(data) ?? "" : "",
6927
+ cellRenderer: ({ data }) => data && liveProps.current.renderLabels?.(data)
6928
+ }
6929
+ ] : [],
6930
+ {
6931
+ colId: "status",
6932
+ headerName: "Status",
6933
+ width: isPhone ? 170 : 240,
6934
+ valueGetter: ({ data }) => data?.status,
6935
+ cellRenderer: ({ data }) => data && (liveProps.current.renderStatus ? liveProps.current.renderStatus(data) : /* @__PURE__ */ jsxRuntime.jsx(
6936
+ ThreadStatusLine,
6937
+ {
6938
+ state: data.status === "done" ? "done" : data.status === "todo" ? "todo" : "ready"
6939
+ }
6940
+ ))
6941
+ },
6942
+ // Who spoke last (their face) and when: the two read together, at the row's end.
6943
+ ...liveProps.current.renderBy || liveProps.current.renderOwner ? [
6944
+ {
6945
+ colId: liveProps.current.renderBy ? "by" : "owner",
6946
+ headerName: liveProps.current.renderBy ? "By" : "Owner",
6947
+ width: 64,
6948
+ hide: isPhone,
6949
+ sortable: false,
6950
+ resizable: false,
6951
+ cellRenderer: ({ data }) => data && (liveProps.current.renderBy || liveProps.current.renderOwner)?.(data)
6952
+ }
6953
+ ] : [],
6954
+ {
6955
+ colId: "activity",
6956
+ initialSort: "desc",
6957
+ headerName: "Updated",
6958
+ width: 128,
6959
+ hide: isPhone,
6960
+ valueGetter: ({ data }) => data?.last_message_updated_at || data?.updated_at || data?.created_at || "",
6961
+ valueFormatter: ({ value }) => value ? liveProps.current.formatDate(value) : "\u2014",
6962
+ cellClass: "flex items-center text-xs text-muted-foreground/80"
6963
+ }
6964
+ ],
6965
+ [
6966
+ Boolean(p.renderThread),
6967
+ Boolean(p.renderLabels),
6968
+ Boolean(p.renderOwner),
6969
+ Boolean(p.renderBy),
6970
+ Boolean(p.renderStatus),
6971
+ isPhone,
6972
+ hasLabels
6973
+ ]
6974
+ );
6975
+ const centred = react.useMemo(
6976
+ () => columns.map((c) => ({ cellClass: "flex items-center", ...c })),
6977
+ [columns]
6978
+ );
6979
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 flex-col", "data-testid": "conversation-list-view", children: [
6980
+ p.showHeader !== false && /* @__PURE__ */ jsxRuntime.jsx(
6981
+ chunkMEMWZ72Y_cjs.TabHeader,
6982
+ {
6983
+ testId: "threads-tab-header",
6984
+ tabs: [
6985
+ {
6986
+ id: "threads",
6987
+ label: "",
6988
+ count: rows.length,
6989
+ countIcon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: "size-3.5" }),
6990
+ countPlacement: "leading",
6991
+ presentation: "count",
6992
+ hasActiveFilters: !!q
6993
+ }
6994
+ ],
6995
+ activeTabId: "threads",
6996
+ onTabChange: () => {
6997
+ },
6998
+ firstTabContent: /* @__PURE__ */ jsxRuntime.jsx(
6999
+ chunk2EI7NCUA_cjs.FilterInput,
7000
+ {
7001
+ value: query,
7002
+ hideFieldPicker: true,
7003
+ ariaLabel: "Search threads",
7004
+ onChange: setQuery,
7005
+ fields: ["text"],
7006
+ onFieldsChange: () => {
7007
+ },
7008
+ labels: {
7009
+ placeholder: "Find a thread\u2026",
7010
+ fieldNames: { text: "Thread" }
7011
+ },
7012
+ className: "w-44 max-w-[40vw]"
7013
+ }
7014
+ ),
7015
+ rightContent: p.header
7016
+ }
7017
+ ),
7018
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
7019
+ chunkLKK52DEY_cjs.GridView,
7020
+ {
7021
+ testId: "threads-grid",
7022
+ items: rows,
7023
+ columnDefs: centred,
7024
+ getItemId: (row) => row.external_id,
7025
+ getRowTestId: (row) => `thread-row-${row.external_id}`,
7026
+ onRowClick: p.onOpen,
7027
+ height: "100%",
7028
+ isLoading: p.isLoading,
7029
+ loadingMessage: "Loading threads\u2026",
7030
+ emptyState: {
7031
+ title: q ? "No threads match" : "No conversations yet",
7032
+ message: p.footer ? "Type below to ask ARBI, bring in people, or both." : "Use New Task to ask ARBI, bring in people, or both."
7033
+ },
7034
+ selection: p.selectionActions ? {
7035
+ mode: "multiple",
7036
+ controlled: true,
7037
+ selected: selectedRows,
7038
+ onSelectionChange: (items) => setSelected(new Set(items.map((item) => item.external_id)))
7039
+ } : void 0,
7040
+ gridOptions: {
7041
+ suppressClickEdit: true,
7042
+ onCellKeyDown: (event) => {
7043
+ if (event.event?.key === "Enter" && "column" in event && event.column.getColId() === "name" && event.data)
7044
+ p.onOpen(event.data);
7045
+ }
7046
+ }
7047
+ }
7048
+ ) }),
7049
+ p.footer,
7050
+ p.selectionActions && /* @__PURE__ */ jsxRuntime.jsx(chunkV4ISCZJ7_cjs.SelectionBar, { count: selectedRows.length, onClear: () => setSelected(/* @__PURE__ */ new Set()), children: (compact2) => p.selectionActions?.(selectedRows, compact2, () => setSelected(/* @__PURE__ */ new Set())) })
7051
+ ] });
7052
+ }
5101
7053
  var NO_PEOPLE = [];
5102
7054
  function TaskStartDialog({
5103
7055
  open,
@@ -7181,6 +9133,56 @@ function compactThreadActivity(events, stepTitleOf) {
7181
9133
  }
7182
9134
  return result;
7183
9135
  }
9136
+ var DEFAULT_TASK_THREAD_CHIP_LABELS = {
9137
+ open: "Open thread",
9138
+ watch: "Watch live",
9139
+ none: "No thread yet"
9140
+ };
9141
+ function TaskThreadChip({
9142
+ id,
9143
+ conversationId,
9144
+ generating = false,
9145
+ onOpen,
9146
+ testId,
9147
+ labels
9148
+ }) {
9149
+ const l = { ...DEFAULT_TASK_THREAD_CHIP_LABELS, ...labels };
9150
+ if (!conversationId) {
9151
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9152
+ "span",
9153
+ {
9154
+ className: "inline-flex items-center gap-1 text-xs text-muted-foreground",
9155
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testId, { testId: `task-thread-${id}` }),
9156
+ "data-state": "none",
9157
+ children: [
9158
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: "size-3.5 opacity-50", "aria-hidden": true }),
9159
+ l.none
9160
+ ]
9161
+ }
9162
+ );
9163
+ }
9164
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9165
+ ui.Button,
9166
+ {
9167
+ variant: "ghost",
9168
+ size: "sm",
9169
+ className: ui.cn(
9170
+ "h-7 gap-1.5 px-2 text-xs pointer-coarse:h-11",
9171
+ generating && "text-ai-ink hover:text-ai-ink"
9172
+ ),
9173
+ onClick: () => onOpen(conversationId),
9174
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testId, { testId: `task-thread-${id}` }),
9175
+ "data-state": generating ? "live" : "idle",
9176
+ children: [
9177
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex size-3.5 items-center justify-center", children: [
9178
+ generating && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inline-flex size-full animate-ping rounded-full bg-ai-soft" }),
9179
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: "relative size-3.5", "aria-hidden": true })
9180
+ ] }),
9181
+ generating ? l.watch : l.open
9182
+ ]
9183
+ }
9184
+ );
9185
+ }
7184
9186
  var DEFAULT_TASK_RUNS_DIALOG_LABELS = {
7185
9187
  title: (taskName) => `Run history \u2014 ${taskName}`,
7186
9188
  description: "Every time this task ran. Open a run to read or watch it in its conversation.",
@@ -7315,6 +9317,78 @@ function TaskRunsDialog({
7315
9317
  }
7316
9318
  ) });
7317
9319
  }
9320
+ var DEFAULT_TASKS_CHROME_LABELS = {
9321
+ tasksTab: "Tasks",
9322
+ newTask: "New task"
9323
+ };
9324
+ function TasksToolbar({ count, onNewTask, testIds, labels }) {
9325
+ const l = { ...DEFAULT_TASKS_CHROME_LABELS, ...labels };
9326
+ const tabs = [
9327
+ {
9328
+ id: "tasks",
9329
+ label: l.tasksTab,
9330
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListTodo, { className: "size-4" }),
9331
+ count,
9332
+ testId: chunkMHVNT4J3_cjs.testIdOr(testIds?.tab, { testId: "tasks-tab" })
9333
+ }
9334
+ ];
9335
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-10 bg-background", "data-slot": "tasks-toolbar", children: /* @__PURE__ */ jsxRuntime.jsx(
9336
+ chunkMEMWZ72Y_cjs.TabHeader,
9337
+ {
9338
+ tabs,
9339
+ activeTabId: "tasks",
9340
+ onTabChange: () => {
9341
+ },
9342
+ rightContent: /* @__PURE__ */ jsxRuntime.jsxs(
9343
+ ui.Button,
9344
+ {
9345
+ onClick: onNewTask,
9346
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.newTask, { testId: "task-new" }),
9347
+ children: [
9348
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { size: 16, className: "mr-1.5" }),
9349
+ l.newTask
9350
+ ]
9351
+ }
9352
+ )
9353
+ }
9354
+ ) });
9355
+ }
9356
+ var DEFAULT_WORKFLOWS_CHROME_LABELS = {
9357
+ workflowsTab: "Workflows",
9358
+ newWorkflow: "New workflow"
9359
+ };
9360
+ function WorkflowsToolbar({ count, onNewWorkflow, testIds, labels }) {
9361
+ const l = { ...DEFAULT_WORKFLOWS_CHROME_LABELS, ...labels };
9362
+ const tabs = [
9363
+ {
9364
+ id: "workflows",
9365
+ label: l.workflowsTab,
9366
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Workflow, { className: "size-4" }),
9367
+ count,
9368
+ testId: chunkMHVNT4J3_cjs.testIdOr(testIds?.tab, { testId: "workflows-tab" })
9369
+ }
9370
+ ];
9371
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-10 bg-background", "data-slot": "workflows-toolbar", children: /* @__PURE__ */ jsxRuntime.jsx(
9372
+ chunkMEMWZ72Y_cjs.TabHeader,
9373
+ {
9374
+ tabs,
9375
+ activeTabId: "workflows",
9376
+ onTabChange: () => {
9377
+ },
9378
+ rightContent: /* @__PURE__ */ jsxRuntime.jsxs(
9379
+ ui.Button,
9380
+ {
9381
+ onClick: onNewWorkflow,
9382
+ "data-testid": chunkMHVNT4J3_cjs.testIdOr(testIds?.newWorkflow, { testId: "workflow-new" }),
9383
+ children: [
9384
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { size: 16, className: "mr-1.5" }),
9385
+ l.newWorkflow
9386
+ ]
9387
+ }
9388
+ )
9389
+ }
9390
+ ) });
9391
+ }
7318
9392
 
7319
9393
  // src/agents/tasks/taskComposerTypes.ts
7320
9394
  var DEFAULT_TASK_COMPOSER_LABELS = {
@@ -8502,6 +10576,132 @@ function WorkTaskComposer({
8502
10576
  function TaskComposer(props) {
8503
10577
  return props.kind === "workflow" ? /* @__PURE__ */ jsxRuntime.jsx(WorkflowComposer, { ...props }) : /* @__PURE__ */ jsxRuntime.jsx(WorkTaskComposer, { ...props });
8504
10578
  }
10579
+ function ThreadNotifyDialog({
10580
+ open,
10581
+ onOpenChange,
10582
+ people,
10583
+ isShared,
10584
+ onNotify
10585
+ }) {
10586
+ const [selected, setSelected] = react.useState([]);
10587
+ const [query, setQuery] = react.useState("");
10588
+ const [busy, setBusy] = react.useState(false);
10589
+ const [error, setError] = react.useState(null);
10590
+ react.useEffect(() => {
10591
+ if (open) {
10592
+ setSelected([]);
10593
+ setQuery("");
10594
+ setError(null);
10595
+ }
10596
+ }, [open]);
10597
+ return /* @__PURE__ */ jsxRuntime.jsx(
10598
+ ui.Dialog,
10599
+ {
10600
+ open,
10601
+ onOpenChange: (value) => {
10602
+ if (!busy) onOpenChange(value);
10603
+ },
10604
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogContent, { className: "max-w-sm", "data-testid": "thread-notify-dialog", children: [
10605
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DialogTitle, { children: "Notify" }),
10606
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DialogDescription, { children: isShared ? "Ask someone to follow up in this thread." : "Notifying someone shares this thread with your workspace." }),
10607
+ /* @__PURE__ */ jsxRuntime.jsx(
10608
+ ui.Input,
10609
+ {
10610
+ "aria-label": "Find people",
10611
+ placeholder: "Find someone\u2026",
10612
+ value: query,
10613
+ onChange: (event) => setQuery(event.target.value)
10614
+ }
10615
+ ),
10616
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-h-64 overflow-y-auto space-y-1", children: [
10617
+ people.filter((person) => person.label.toLowerCase().includes(query.toLowerCase())).map((person) => /* @__PURE__ */ jsxRuntime.jsxs(
10618
+ "label",
10619
+ {
10620
+ className: "flex cursor-pointer items-center gap-2 rounded px-2 py-2 hover:bg-muted",
10621
+ children: [
10622
+ /* @__PURE__ */ jsxRuntime.jsx(
10623
+ ui.Checkbox,
10624
+ {
10625
+ disabled: busy,
10626
+ checked: selected.includes(person.id),
10627
+ onCheckedChange: (checked) => setSelected(
10628
+ (old) => checked ? [...old, person.id] : old.filter((id) => id !== person.id)
10629
+ )
10630
+ }
10631
+ ),
10632
+ person.label
10633
+ ]
10634
+ },
10635
+ person.id
10636
+ )),
10637
+ !people.length && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "No other workspace members yet." })
10638
+ ] }),
10639
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "text-sm text-destructive", children: error }),
10640
+ /* @__PURE__ */ jsxRuntime.jsx(
10641
+ ui.Button,
10642
+ {
10643
+ disabled: busy || !selected.length,
10644
+ "data-testid": "thread-notify-submit",
10645
+ onClick: async () => {
10646
+ setBusy(true);
10647
+ setError(null);
10648
+ try {
10649
+ await onNotify(selected);
10650
+ onOpenChange(false);
10651
+ } catch (failure) {
10652
+ setError(failure instanceof Error ? failure.message : "Could not notify people");
10653
+ } finally {
10654
+ setBusy(false);
10655
+ }
10656
+ },
10657
+ children: busy ? "Notifying\u2026" : "Notify"
10658
+ }
10659
+ )
10660
+ ] })
10661
+ }
10662
+ );
10663
+ }
10664
+ function ConversationTurnSpeaker({
10665
+ role,
10666
+ actor,
10667
+ currentUserId,
10668
+ colorClass,
10669
+ platformName = "ARBI",
10670
+ platformLogoSrc = ui.ARBI_MARK_SRC,
10671
+ variant = "pill"
10672
+ }) {
10673
+ if (!role) return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "\u2014" });
10674
+ if (role === "assistant" && !actor)
10675
+ return /* @__PURE__ */ jsxRuntime.jsx(
10676
+ ui.UserEntity,
10677
+ {
10678
+ size: "sm",
10679
+ variant,
10680
+ interactive: false,
10681
+ picture: platformLogoSrc,
10682
+ avatarImageClassName: "object-contain p-0.5",
10683
+ initials: platformName.charAt(0),
10684
+ displayName: platformName
10685
+ }
10686
+ );
10687
+ if (!actor) return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Unknown participant" });
10688
+ const isMe = actor.external_id === currentUserId;
10689
+ const displayName = isMe ? "You" : [actor.given_name, actor.family_name].filter(Boolean).join(" ");
10690
+ return /* @__PURE__ */ jsxRuntime.jsx(
10691
+ ui.UserEntity,
10692
+ {
10693
+ size: "sm",
10694
+ variant,
10695
+ interactive: false,
10696
+ isMe,
10697
+ isAgent: actor.external_id.startsWith("agt-"),
10698
+ displayName,
10699
+ initials: `${actor.given_name.charAt(0)}${actor.family_name?.charAt(0) ?? ""}`.toUpperCase(),
10700
+ picture: actor.picture,
10701
+ colorClass
10702
+ }
10703
+ );
10704
+ }
8505
10705
  var STEP_ICON_MAP = {
8506
10706
  goal: lucideReact.Target,
8507
10707
  interjection: lucideReact.CornerDownRight,
@@ -10476,6 +12676,8 @@ exports.ConsentPermissionList = ConsentPermissionList;
10476
12676
  exports.ConsentSection = ConsentSection;
10477
12677
  exports.ConsentStrong = ConsentStrong;
10478
12678
  exports.ConsentText = ConsentText;
12679
+ exports.ConversationListView = ConversationListView;
12680
+ exports.ConversationTurnSpeaker = ConversationTurnSpeaker;
10479
12681
  exports.CopyableUrl = CopyableUrl;
10480
12682
  exports.DASHBOARD_OPERATIONS = DASHBOARD_OPERATIONS;
10481
12683
  exports.DASHBOARD_PINNED = DASHBOARD_PINNED;
@@ -10504,13 +12706,21 @@ exports.DEFAULT_SKILL_GLOBAL_BADGE_LABELS = DEFAULT_SKILL_GLOBAL_BADGE_LABELS;
10504
12706
  exports.DEFAULT_SKILL_VIEW_TOGGLE_LABELS = DEFAULT_SKILL_VIEW_TOGGLE_LABELS;
10505
12707
  exports.DEFAULT_STEP_BAR_LABELS = DEFAULT_STEP_BAR_LABELS;
10506
12708
  exports.DEFAULT_SUBAGENT_ROSTER_LABELS = DEFAULT_SUBAGENT_ROSTER_LABELS;
12709
+ exports.DEFAULT_TASKS_CHROME_LABELS = DEFAULT_TASKS_CHROME_LABELS;
10507
12710
  exports.DEFAULT_TASK_ACTIVITY_LABELS = DEFAULT_TASK_ACTIVITY_LABELS;
10508
12711
  exports.DEFAULT_TASK_COMPOSER_LABELS = DEFAULT_TASK_COMPOSER_LABELS;
12712
+ exports.DEFAULT_TASK_LIST_LABELS = DEFAULT_TASK_LIST_LABELS;
12713
+ exports.DEFAULT_TASK_OUTPUTS_CELL_LABELS = DEFAULT_TASK_OUTPUTS_CELL_LABELS;
10509
12714
  exports.DEFAULT_TASK_PLAN_LABELS = DEFAULT_TASK_PLAN_LABELS;
10510
12715
  exports.DEFAULT_TASK_RUNS_DIALOG_LABELS = DEFAULT_TASK_RUNS_DIALOG_LABELS;
12716
+ exports.DEFAULT_TASK_STATUS_PILL_LABELS = DEFAULT_TASK_STATUS_PILL_LABELS;
12717
+ exports.DEFAULT_TASK_THREAD_CHIP_LABELS = DEFAULT_TASK_THREAD_CHIP_LABELS;
10511
12718
  exports.DEFAULT_THREAD_LAUNCHER_LABELS = DEFAULT_THREAD_LAUNCHER_LABELS;
10512
12719
  exports.DEFAULT_THREAD_STATE_LABELS = DEFAULT_THREAD_STATE_LABELS;
10513
12720
  exports.DEFAULT_TUPLE_ARRAY_FIELD_LABELS = DEFAULT_TUPLE_ARRAY_FIELD_LABELS;
12721
+ exports.DEFAULT_UPLOAD_TASK_ITEM_LABELS = DEFAULT_UPLOAD_TASK_ITEM_LABELS;
12722
+ exports.DEFAULT_UPLOAD_TASK_LIST_LABELS = DEFAULT_UPLOAD_TASK_LIST_LABELS;
12723
+ exports.DEFAULT_WORKFLOWS_CHROME_LABELS = DEFAULT_WORKFLOWS_CHROME_LABELS;
10514
12724
  exports.DEFAULT_WORKFLOW_RUNNER_LABELS = DEFAULT_WORKFLOW_RUNNER_LABELS;
10515
12725
  exports.DEFAULT_WORKFLOW_RUN_STATUS_LABELS = DEFAULT_WORKFLOW_RUN_STATUS_LABELS;
10516
12726
  exports.DEFAULT_WORKFLOW_STEP_PARTS_LABELS = DEFAULT_WORKFLOW_STEP_PARTS_LABELS;
@@ -10567,6 +12777,7 @@ exports.SubAgentLane = SubAgentLane;
10567
12777
  exports.SubStepGroup = SubStepGroup;
10568
12778
  exports.SubagentRoster = SubagentRoster;
10569
12779
  exports.TAG_ICONS = TAG_ICONS;
12780
+ exports.TASK_COLUMN_ORDER = TASK_COLUMN_ORDER;
10570
12781
  exports.TIMELINE = TIMELINE;
10571
12782
  exports.TIMELINE_ID = TIMELINE_ID;
10572
12783
  exports.TIMELINE_PROMPT = TIMELINE_PROMPT;
@@ -10580,13 +12791,23 @@ exports.TaskActivityTimeline = TaskActivityTimeline;
10580
12791
  exports.TaskComposer = TaskComposer;
10581
12792
  exports.TaskEmptyState = TaskEmptyState;
10582
12793
  exports.TaskFlow = TaskFlow;
12794
+ exports.TaskInbox = TaskInbox;
12795
+ exports.TaskMoveDialog = TaskMoveDialog;
12796
+ exports.TaskOutputsCell = TaskOutputsCell;
10583
12797
  exports.TaskPlan = TaskPlan;
10584
12798
  exports.TaskRunsDialog = TaskRunsDialog;
10585
12799
  exports.TaskStartDialog = TaskStartDialog;
12800
+ exports.TaskStatusPill = TaskStatusPill;
12801
+ exports.TaskTable = TaskTable;
12802
+ exports.TaskThreadChip = TaskThreadChip;
12803
+ exports.TasksToolbar = TasksToolbar;
10586
12804
  exports.ThreadActivity = ThreadActivity;
10587
12805
  exports.ThreadLauncher = ThreadLauncher;
12806
+ exports.ThreadNotifyDialog = ThreadNotifyDialog;
10588
12807
  exports.ThreadStatusLine = ThreadStatusLine;
10589
12808
  exports.TupleArrayField = TupleArrayField;
12809
+ exports.UploadTaskItem = UploadTaskItem;
12810
+ exports.UploadTaskList = UploadTaskList;
10590
12811
  exports.WEB_WORKFLOWS = WEB_WORKFLOWS;
10591
12812
  exports.WEEKDAYS = WEEKDAYS;
10592
12813
  exports.WORD_ASK = WORD_ASK;
@@ -10605,6 +12826,7 @@ exports.WorkflowStepAction = WorkflowStepAction;
10605
12826
  exports.WorkflowStepBar = WorkflowStepBar;
10606
12827
  exports.WorkflowThreadStartedBy = WorkflowThreadStartedBy;
10607
12828
  exports.WorkflowThreadStrip = WorkflowThreadStrip;
12829
+ exports.WorkflowsToolbar = WorkflowsToolbar;
10608
12830
  exports.activateOnKey = activateOnKey;
10609
12831
  exports.activeStepId = activeStepId;
10610
12832
  exports.agentConfigSectionToValues = agentConfigSectionToValues;
@@ -10622,6 +12844,7 @@ exports.composerToTaskQuery = composerToTaskQuery;
10622
12844
  exports.composerToWorkRequest = composerToWorkRequest;
10623
12845
  exports.composerToWorkflowRequest = composerToWorkflowRequest;
10624
12846
  exports.composerToWorkflowUpdate = composerToWorkflowUpdate;
12847
+ exports.createTaskColumns = createTaskColumns;
10625
12848
  exports.createsWork = createsWork;
10626
12849
  exports.defaultScopeRenderer = defaultScopeRenderer;
10627
12850
  exports.defaultTaskComposerValues = defaultTaskComposerValues;
@@ -10631,8 +12854,10 @@ exports.deriveWorkflowName = deriveWorkflowName;
10631
12854
  exports.descendantIds = descendantIds;
10632
12855
  exports.describeRRule = describeRRule;
10633
12856
  exports.describeTrigger = describeTrigger;
12857
+ exports.filterConversationRows = filterConversationRows;
10634
12858
  exports.filterLibrarySkills = filterLibrarySkills;
10635
12859
  exports.firstWords = firstWords;
12860
+ exports.formatElapsed = formatElapsed2;
10636
12861
  exports.fromPlanAssignee = fromPlanAssignee;
10637
12862
  exports.fromPlanDocumentRef = fromPlanDocumentRef;
10638
12863
  exports.fromPlanSteps = fromPlanSteps;
@@ -10701,5 +12926,5 @@ exports.workflowTaskFields = workflowTaskFields;
10701
12926
  exports.workflowToComposerValues = workflowToComposerValues;
10702
12927
  exports.workflowToSkillMarkdown = workflowToSkillMarkdown;
10703
12928
  exports.workflowWhen = workflowWhen;
10704
- //# sourceMappingURL=chunk-FY4C7HU5.cjs.map
10705
- //# sourceMappingURL=chunk-FY4C7HU5.cjs.map
12929
+ //# sourceMappingURL=chunk-O3MRE2HL.cjs.map
12930
+ //# sourceMappingURL=chunk-O3MRE2HL.cjs.map