@arbidocs/blocks 0.5.43 → 0.5.45

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 (45) hide show
  1. package/README.md +14 -0
  2. package/dist/agents/definitions/agentTasks.d.ts +4 -0
  3. package/dist/agents/definitions/index.d.ts +1 -0
  4. package/dist/agents/index.cjs +14 -10
  5. package/dist/agents/index.js +1 -1
  6. package/dist/calls/index.cjs +73 -696
  7. package/dist/calls/index.cjs.map +1 -1
  8. package/dist/calls/index.js +10 -666
  9. package/dist/calls/index.js.map +1 -1
  10. package/dist/{chunk-6AJJJ5HR.cjs → chunk-5R256EMF.cjs} +671 -3
  11. package/dist/chunk-5R256EMF.cjs.map +1 -0
  12. package/dist/{chunk-E3IEZMRK.cjs → chunk-ET42AFEJ.cjs} +15 -2
  13. package/dist/chunk-ET42AFEJ.cjs.map +1 -0
  14. package/dist/{chunk-FOIDBAZB.js → chunk-OQMWTEM2.js} +15 -3
  15. package/dist/chunk-OQMWTEM2.js.map +1 -0
  16. package/dist/{chunk-4U4NXFV5.js → chunk-TKTNXFAB.js} +666 -9
  17. package/dist/chunk-TKTNXFAB.js.map +1 -0
  18. package/dist/connect/index.cjs +1736 -482
  19. package/dist/connect/index.cjs.map +1 -1
  20. package/dist/connect/index.d.ts +2 -0
  21. package/dist/connect/index.js +1729 -479
  22. package/dist/connect/index.js.map +1 -1
  23. package/dist/connection/ConnectedFilterDropdown.d.ts +6 -0
  24. package/dist/connection/agents/useConnectedAgentManagement.d.ts +60 -0
  25. package/dist/connection/conversation/ConnectedConversation.d.ts +7 -9
  26. package/dist/connection/conversation/ConnectedConversationPage.d.ts +30 -0
  27. package/dist/connection/conversation/SemanticSearchButton.d.ts +12 -0
  28. package/dist/connection/files/imports/ConnectedAccountsImport.d.ts +16 -0
  29. package/dist/connection/files/imports/DriveImportPanel.d.ts +10 -0
  30. package/dist/connection/files/imports/EmailImportPanel.d.ts +21 -0
  31. package/dist/connection/files/imports/ImportHandoff.d.ts +24 -0
  32. package/dist/connection/files/imports/useDriveSyncTrigger.d.ts +11 -0
  33. package/dist/connection/files/imports/useEmailSyncTrigger.d.ts +11 -0
  34. package/dist/connection/files/imports/useImportHandoff.d.ts +20 -0
  35. package/dist/connection/files/index.d.ts +1 -0
  36. package/dist/index.cjs +14 -10
  37. package/dist/index.js +1 -1
  38. package/dist/workflow-canvas/index.cjs +2 -2
  39. package/dist/workflow-canvas/index.js +1 -1
  40. package/node_modules/@arbidocs/coedit/package.json +1 -1
  41. package/package.json +5 -5
  42. package/dist/chunk-4U4NXFV5.js.map +0 -1
  43. package/dist/chunk-6AJJJ5HR.cjs.map +0 -1
  44. package/dist/chunk-E3IEZMRK.cjs.map +0 -1
  45. package/dist/chunk-FOIDBAZB.js.map +0 -1
@@ -62,7 +62,7 @@ var chunkCG757WKY_cjs = require('../chunk-CG757WKY.cjs');
62
62
  var chunkW3PSIIMN_cjs = require('../chunk-W3PSIIMN.cjs');
63
63
  var chunkQUMUAJ2P_cjs = require('../chunk-QUMUAJ2P.cjs');
64
64
  var chunkVZOOGA47_cjs = require('../chunk-VZOOGA47.cjs');
65
- var chunk6AJJJ5HR_cjs = require('../chunk-6AJJJ5HR.cjs');
65
+ var chunk5R256EMF_cjs = require('../chunk-5R256EMF.cjs');
66
66
  var chunkEGSSLWNZ_cjs = require('../chunk-EGSSLWNZ.cjs');
67
67
  var chunkHDEOORSV_cjs = require('../chunk-HDEOORSV.cjs');
68
68
  var chunkP6HVJP6Z_cjs = require('../chunk-P6HVJP6Z.cjs');
@@ -2288,6 +2288,76 @@ function ConnectedAgentCreator({
2288
2288
  ) })
2289
2289
  ] });
2290
2290
  }
2291
+ var DEFAULT_LABELS = {
2292
+ addressCopied: "Agent address copied",
2293
+ addressCopyFailed: "Could not copy the address",
2294
+ deleted: (agent) => `Agent "${agent.given_name}" deleted.`,
2295
+ deleteFailed: (error) => `Delete failed: ${error instanceof Error ? error.message : error}`
2296
+ };
2297
+ function useConnectedAgentManagement({
2298
+ confirmDelete,
2299
+ onAssignTask,
2300
+ labels
2301
+ } = {}) {
2302
+ const { data: agents = [], isLoading } = react.useAgents();
2303
+ const deletion = react.useDeleteAgents();
2304
+ const { notify: notify18 } = chunkB3NYBMDR_cjs.useBlocksEnvironment();
2305
+ const l = { ...DEFAULT_LABELS, ...labels };
2306
+ const [editorOpen, setEditorOpen] = React9.useState(false);
2307
+ const [editing, setEditing] = React9.useState(null);
2308
+ const [assignFor, setAssignFor] = React9.useState(null);
2309
+ const onEditorOpenChange = (open) => {
2310
+ setEditorOpen(open);
2311
+ };
2312
+ const create4 = () => {
2313
+ setEditing(null);
2314
+ setEditorOpen(true);
2315
+ };
2316
+ const edit = (agent) => {
2317
+ setEditing(agent);
2318
+ setEditorOpen(true);
2319
+ };
2320
+ const assign = (agent) => {
2321
+ if (onAssignTask) onAssignTask(agent);
2322
+ else setAssignFor(agent);
2323
+ };
2324
+ const remove = async (agent) => {
2325
+ try {
2326
+ if (confirmDelete && !await confirmDelete(agent)) return false;
2327
+ await deletion.mutateAsync({ agentExtIds: [agent.external_id] });
2328
+ notify18(l.deleted(agent), "success");
2329
+ return true;
2330
+ } catch (error) {
2331
+ notify18(l.deleteFailed(error), "error");
2332
+ return false;
2333
+ }
2334
+ };
2335
+ const copyAddress = async (address) => {
2336
+ try {
2337
+ await navigator.clipboard.writeText(address);
2338
+ notify18(l.addressCopied, "success");
2339
+ } catch {
2340
+ if (l.addressCopyFailed !== null) notify18(l.addressCopyFailed, "error");
2341
+ }
2342
+ };
2343
+ return {
2344
+ agents,
2345
+ isLoading,
2346
+ create: create4,
2347
+ edit,
2348
+ assign,
2349
+ remove,
2350
+ copyAddress,
2351
+ editorProps: { open: editorOpen, onOpenChange: onEditorOpenChange, agent: editing },
2352
+ assignmentProps: assignFor ? {
2353
+ open: true,
2354
+ onOpenChange: (open) => {
2355
+ if (!open) setAssignFor(null);
2356
+ },
2357
+ initialAgentExtId: assignFor.external_id
2358
+ } : null
2359
+ };
2360
+ }
2291
2361
  var RUN_KIND = {
2292
2362
  email_documents: "Email",
2293
2363
  annotate_documents: "AI Review",
@@ -29004,6 +29074,870 @@ function ConnectedGridView(props) {
29004
29074
  );
29005
29075
  return /* @__PURE__ */ jsxRuntime.jsx(chunkLKK52DEY_cjs.GridView, { ...props, gridState, onGridStateChange });
29006
29076
  }
29077
+ function useEmailSyncTrigger() {
29078
+ const arbi = react.useArbi();
29079
+ const { notify: notify18 } = chunkB3NYBMDR_cjs.useBlocksEnvironment();
29080
+ const triggerSync = react.useTriggerMailboxSync();
29081
+ const runSync = React9.useCallback(
29082
+ async ({
29083
+ vendorKey,
29084
+ workspaceExtId,
29085
+ workspaceLabel = "the workspace"
29086
+ }) => {
29087
+ await arbi.connectors.bridgeTokens({ vendor: vendorKey });
29088
+ if (workspaceExtId) {
29089
+ await arbi.workspaces.open(workspaceExtId).catch(() => {
29090
+ });
29091
+ }
29092
+ triggerSync.mutate(
29093
+ { vendorKey, workspaceExtId },
29094
+ {
29095
+ onSuccess: (res) => {
29096
+ const n = res?.estimated_count;
29097
+ if (n === 0) {
29098
+ notify18("You\u2019re up to date \u2014 no new emails to sync.", "success");
29099
+ } else if (n != null && n > 0) {
29100
+ notify18(
29101
+ `Fetching ${n} new email${n === 1 ? "" : "s"} to ${workspaceLabel}.`,
29102
+ "success"
29103
+ );
29104
+ } else {
29105
+ notify18("Sync started \u2014 fetching new emails\u2026", "success");
29106
+ }
29107
+ },
29108
+ onError: (err) => {
29109
+ if (react.connectorErrorStatus(err) === 425) {
29110
+ notify18("Still preparing your session \u2014 please try Sync now again.", "error");
29111
+ } else if (react.connectorErrorStatus(err) === 409) {
29112
+ notify18("Reconnect needed \u2014 your account needs to be re-authorized.", "error");
29113
+ } else if (react.connectorErrorStatus(err) === 404) {
29114
+ notify18("Email sync is not enabled for this connector yet.", "error");
29115
+ } else {
29116
+ notify18("Could not start sync. Please try again.", "error");
29117
+ }
29118
+ }
29119
+ }
29120
+ );
29121
+ },
29122
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- triggerSync.mutate is a stable TanStack Query reference
29123
+ [arbi, notify18, triggerSync.mutate]
29124
+ );
29125
+ return { runSync, isPending: triggerSync.isPending };
29126
+ }
29127
+ function useImportHandoff(running, processed) {
29128
+ const [lastRunCount, setLastRunCount] = React9.useState(null);
29129
+ const seenWhileRunning = React9.useRef(null);
29130
+ React9.useEffect(() => {
29131
+ if (running) {
29132
+ setLastRunCount(null);
29133
+ if (typeof processed === "number") seenWhileRunning.current = processed;
29134
+ return;
29135
+ }
29136
+ if (seenWhileRunning.current !== null) {
29137
+ setLastRunCount(seenWhileRunning.current);
29138
+ seenWhileRunning.current = null;
29139
+ }
29140
+ }, [running, processed]);
29141
+ return {
29142
+ lastRunCount,
29143
+ dismiss: () => setLastRunCount(null)
29144
+ };
29145
+ }
29146
+ function ImportHandoff({
29147
+ count: count2,
29148
+ noun,
29149
+ onDismiss,
29150
+ onViewProgress,
29151
+ "data-testid": testId
29152
+ }) {
29153
+ if (count2 <= 0) return null;
29154
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-start justify-between gap-3", "data-testid": testId, children: [
29155
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-[34px] text-sm leading-snug text-muted-foreground", children: [
29156
+ "Imported ",
29157
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-foreground", children: count2.toLocaleString() }),
29158
+ " ",
29159
+ count2 === 1 ? noun : `${noun}s`,
29160
+ " \xB7 indexing in the background"
29161
+ ] }),
29162
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-1.5", children: [
29163
+ onViewProgress && /* @__PURE__ */ jsxRuntime.jsxs(
29164
+ ui.Button,
29165
+ {
29166
+ variant: "outline",
29167
+ size: "sm",
29168
+ className: "h-7 gap-1.5",
29169
+ onClick: onViewProgress,
29170
+ "data-testid": testId ? `${testId}-view` : void 0,
29171
+ children: [
29172
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ClockFading, { className: "h-3.5 w-3.5" }),
29173
+ "View progress"
29174
+ ]
29175
+ }
29176
+ ),
29177
+ /* @__PURE__ */ jsxRuntime.jsx(
29178
+ ui.Button,
29179
+ {
29180
+ variant: "ghost",
29181
+ size: "sm",
29182
+ className: "h-7 px-2 text-muted-foreground",
29183
+ onClick: onDismiss,
29184
+ "aria-label": "Dismiss import summary",
29185
+ "data-testid": testId ? `${testId}-dismiss` : void 0,
29186
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" })
29187
+ }
29188
+ )
29189
+ ] })
29190
+ ] });
29191
+ }
29192
+ var PROVIDER_FAMILIES = [
29193
+ { key: "microsoft", label: "Microsoft", vendors: ["microsoft"] },
29194
+ { key: "google", label: "Google", vendors: ["gmail"] }
29195
+ ];
29196
+ function VendorGlyph({ catalog }) {
29197
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkWALADS2S_cjs.VendorLogo, { vendorKey: catalog.vendor_key, className: "h-7 w-7" });
29198
+ }
29199
+ function mailboxProductName(catalog) {
29200
+ if (catalog.vendor_key === "microsoft") return "Outlook";
29201
+ if (catalog.vendor_key === "gmail") return "Gmail";
29202
+ return catalog.display_name;
29203
+ }
29204
+ function EmailProviderRow({
29205
+ catalog,
29206
+ userConnector,
29207
+ workspaceExtId,
29208
+ workspaceName,
29209
+ onViewProgress,
29210
+ onNeedsReconnectChange
29211
+ }) {
29212
+ const [settingsOpen, setSettingsOpen] = React9.useState(false);
29213
+ const { runSync, isPending: syncPending } = useEmailSyncTrigger();
29214
+ const cancelSync = react.useCancelMailboxSync();
29215
+ const arbi = react.useArbi();
29216
+ const isConnected = !!userConnector?.is_connected;
29217
+ const thisSync = userConnector?.syncs?.find((s) => s.workspace_ext_id === workspaceExtId);
29218
+ const syncingHere = isConnected && !!thisSync && thisSync.enabled;
29219
+ const [tokensBridged, setTokensBridged] = React9.useState(false);
29220
+ React9.useEffect(() => {
29221
+ if (!isConnected) {
29222
+ setTokensBridged(false);
29223
+ return;
29224
+ }
29225
+ let cancelled = false;
29226
+ void arbi.connectors.bridgeTokens({ vendor: catalog.vendor_key, autoSyncWorkspaceExtId: workspaceExtId }).finally(() => {
29227
+ if (!cancelled) setTokensBridged(true);
29228
+ });
29229
+ return () => {
29230
+ cancelled = true;
29231
+ };
29232
+ }, [isConnected, arbi, catalog.vendor_key, workspaceExtId]);
29233
+ const { data: mailboxFolders, error: foldersError } = react.useMailboxFolders(
29234
+ catalog.vendor_key,
29235
+ isConnected && tokensBridged
29236
+ );
29237
+ const needsReconnect = isConnected && !!foldersError;
29238
+ React9.useEffect(() => {
29239
+ onNeedsReconnectChange(catalog.vendor_key, needsReconnect);
29240
+ }, [needsReconnect, catalog.vendor_key, onNeedsReconnectChange]);
29241
+ const { data: progress, refetch: refetchProgress } = react.useMailboxSyncProgress(
29242
+ catalog.vendor_key,
29243
+ workspaceExtId,
29244
+ syncingHere
29245
+ );
29246
+ const running = !!progress?.running;
29247
+ const { lastRunCount, dismiss: dismissHandoff } = useImportHandoff(running, progress?.processed);
29248
+ react.useRefreshConnectorsOnRunEnd(running);
29249
+ const busy = syncPending;
29250
+ const kickProgressPolling = () => {
29251
+ [500, 1400, 2800].forEach((ms) => window.setTimeout(() => void refetchProgress(), ms));
29252
+ };
29253
+ const syncNow = () => {
29254
+ void runSync({ vendorKey: catalog.vendor_key, workspaceExtId, workspaceLabel: workspaceName });
29255
+ kickProgressPolling();
29256
+ };
29257
+ const stopSync = () => cancelSync.mutate(
29258
+ { vendorKey: catalog.vendor_key, workspaceExtId },
29259
+ { onSettled: () => void refetchProgress() }
29260
+ );
29261
+ const emailNoun = (n) => n === 1 ? "email" : "emails";
29262
+ const syncedCount = thisSync?.synced_count ?? 0;
29263
+ return /* @__PURE__ */ jsxRuntime.jsxs(
29264
+ chunkWALADS2S_cjs.ImportRow,
29265
+ {
29266
+ testId: `email-provider-row-${catalog.vendor_key}`,
29267
+ logo: /* @__PURE__ */ jsxRuntime.jsx(VendorGlyph, { catalog }),
29268
+ name: mailboxProductName(catalog),
29269
+ actions: (
29270
+ // Connecting AND reconnecting are owned by the family header, so a
29271
+ // not-connected or needs-reconnect row shows no button of its own.
29272
+ !isConnected || needsReconnect ? null : /* @__PURE__ */ jsxRuntime.jsx(
29273
+ chunkWALADS2S_cjs.ImportRunActions,
29274
+ {
29275
+ isRunning: running,
29276
+ isStopping: cancelSync.isPending,
29277
+ isBusy: busy,
29278
+ onImport: syncingHere ? syncNow : () => setSettingsOpen(true),
29279
+ onStop: stopSync,
29280
+ onSettings: () => setSettingsOpen(true),
29281
+ settingsLabel: `${mailboxProductName(catalog)} sync settings`,
29282
+ stopButton: { testId: `email-stop-${catalog.vendor_key}` }
29283
+ }
29284
+ )
29285
+ ),
29286
+ children: [
29287
+ isConnected && !needsReconnect && !running && /* @__PURE__ */ jsxRuntime.jsxs(
29288
+ chunkWALADS2S_cjs.ImportSummary,
29289
+ {
29290
+ aside: /* @__PURE__ */ jsxRuntime.jsx(chunkWALADS2S_cjs.ImportAside, { children: thisSync && thisSync.folders.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
29291
+ chunkWALADS2S_cjs.FolderSummary,
29292
+ {
29293
+ names: thisSync.folders.map(
29294
+ (id) => mailboxFolders?.find((f) => f.id === id)?.name
29295
+ ),
29296
+ testId: `email-folders-${catalog.vendor_key}`
29297
+ }
29298
+ ) }),
29299
+ children: [
29300
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
29301
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-foreground", children: syncedCount.toLocaleString() }),
29302
+ " ",
29303
+ emailNoun(syncedCount),
29304
+ " in this workspace"
29305
+ ] }),
29306
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-testid": `email-last-sync-${catalog.vendor_key}`, children: [
29307
+ thisSync?.last_sync_at ? `Last synced ${ui.formatRelativeTime(thisSync.last_sync_at, { style: "compact" })}` : "Not synced yet",
29308
+ thisSync?.backfill_since ? ` \xB7 Backfill: since ${new Date(thisSync.backfill_since).toLocaleDateString()}` : thisSync?.backfill_window != null && ` \xB7 Backfill: ${windowLabel(thisSync.backfill_window)}`
29309
+ ] })
29310
+ ]
29311
+ }
29312
+ ),
29313
+ running && /* @__PURE__ */ jsxRuntime.jsx(
29314
+ chunkWALADS2S_cjs.ImportProgress,
29315
+ {
29316
+ processed: progress?.processed ?? 0,
29317
+ total: progress?.total,
29318
+ noun: "emails",
29319
+ testId: `email-progress-${catalog.vendor_key}`
29320
+ }
29321
+ ),
29322
+ !running && lastRunCount !== null && /* @__PURE__ */ jsxRuntime.jsx(
29323
+ ImportHandoff,
29324
+ {
29325
+ count: lastRunCount,
29326
+ noun: "email",
29327
+ onDismiss: dismissHandoff,
29328
+ onViewProgress,
29329
+ "data-testid": `email-handoff-${catalog.vendor_key}`
29330
+ }
29331
+ ),
29332
+ /* @__PURE__ */ jsxRuntime.jsx(
29333
+ ConnectedMailboxSyncDialog,
29334
+ {
29335
+ catalog,
29336
+ userConnector,
29337
+ open: settingsOpen,
29338
+ onOpenChange: setSettingsOpen,
29339
+ lockedWorkspaceExtId: workspaceExtId
29340
+ }
29341
+ )
29342
+ ]
29343
+ }
29344
+ );
29345
+ }
29346
+ function EmailImportPanel({
29347
+ workspaceExtId,
29348
+ workspaceName,
29349
+ onViewProgress,
29350
+ microsoftExtra,
29351
+ googleExtra
29352
+ }) {
29353
+ const arbi = react.useArbi();
29354
+ const { confirm, notify: notify18 } = chunkB3NYBMDR_cjs.useBlocksEnvironment();
29355
+ const { data: catalog = [] } = react.useConnectorCatalog();
29356
+ const { data: myConnectors = [] } = react.useMyConnectors();
29357
+ const disconnect = react.useDisconnectConnector();
29358
+ const isVendorVisible = react.useConnectorVendorVisibility();
29359
+ const [reconnectByVendor, setReconnectByVendor] = React9.useState({});
29360
+ const handleNeedsReconnectChange = React9.useCallback((vendorKey, needs) => {
29361
+ setReconnectByVendor(
29362
+ (prev) => prev[vendorKey] === needs ? prev : { ...prev, [vendorKey]: needs }
29363
+ );
29364
+ }, []);
29365
+ const mailboxCatalog = catalog.filter(
29366
+ (c) => react.isMailboxSyncVendor(c.vendor_key) && isVendorVisible(c.vendor_key)
29367
+ );
29368
+ const connectedByVendor = Object.fromEntries(myConnectors.map((uc) => [uc.vendor_key, uc]));
29369
+ const byVendor = Object.fromEntries(mailboxCatalog.map((c) => [c.vendor_key, c]));
29370
+ const connectFamily = async (vendorKey) => {
29371
+ try {
29372
+ window.location.href = await arbi.connectors.authorize(
29373
+ vendorKey,
29374
+ react.connectorReturnTo("accounts")
29375
+ );
29376
+ } catch {
29377
+ notify18("Could not start the connection. Please try again.", "error");
29378
+ }
29379
+ };
29380
+ const reconnectFamily = async (vendorKey) => {
29381
+ try {
29382
+ await disconnect.mutateAsync({ vendorKey });
29383
+ } catch {
29384
+ }
29385
+ try {
29386
+ window.location.href = await arbi.connectors.authorize(
29387
+ vendorKey,
29388
+ react.connectorReturnTo("accounts")
29389
+ );
29390
+ } catch {
29391
+ notify18("Could not start reconnection. Please try again.", "error");
29392
+ }
29393
+ };
29394
+ const extraByFamily = {
29395
+ microsoft: isVendorVisible("microsoft") ? microsoftExtra : null,
29396
+ google: isVendorVisible("gmail") ? googleExtra : null
29397
+ };
29398
+ const disconnectFamily = React9.useCallback(
29399
+ async (family, connectVendor, identity) => {
29400
+ const who = identity ? `${identity} will be disconnected.` : "This account will be disconnected.";
29401
+ const ok = await confirm({
29402
+ message: `${who} Documents already imported stay in the workspace, but nothing further will sync until you connect again.`,
29403
+ title: `Disconnect ${family.label}?`
29404
+ });
29405
+ if (!ok) return;
29406
+ await disconnect.mutateAsync({ vendorKey: connectVendor });
29407
+ if (connectVendor === "microsoft") {
29408
+ for (const spVendor of react.SHAREPOINT_VENDORS) {
29409
+ if (connectedByVendor[spVendor]) {
29410
+ await disconnect.mutateAsync({ vendorKey: spVendor }).catch(() => {
29411
+ });
29412
+ }
29413
+ }
29414
+ }
29415
+ notify18(`Disconnected ${family.label}`, "success");
29416
+ },
29417
+ [confirm, disconnect, connectedByVendor, notify18]
29418
+ );
29419
+ const groups = PROVIDER_FAMILIES.map((family) => {
29420
+ const entries = family.vendors.map((v) => byVendor[v]).filter(Boolean);
29421
+ const extra = extraByFamily[family.key] ?? null;
29422
+ const connectVendor = family.vendors[0];
29423
+ const connectUc = connectedByVendor[connectVendor];
29424
+ const connected = !!connectUc?.is_connected;
29425
+ const identity = family.vendors.map((v) => connectedByVendor[v]).find((uc) => uc?.is_connected && uc?.vendor_user_identity)?.vendor_user_identity;
29426
+ const mailboxNeedsReconnect = family.vendors.some((v) => reconnectByVendor[v]);
29427
+ const needsReconnect = connected && (react.isDriveSyncVendor(connectVendor) && !!connectUc?.drive_needs_reconsent || mailboxNeedsReconnect);
29428
+ return { family, entries, extra, identity, connectVendor, connected, needsReconnect };
29429
+ }).filter((g) => g.entries.length > 0 || g.extra);
29430
+ if (groups.length === 0) return null;
29431
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkWALADS2S_cjs.ImportPanel, { "data-testid": "email-import-panel", children: groups.map(
29432
+ ({ family, entries, extra, identity, connectVendor, connected, needsReconnect }) => /* @__PURE__ */ jsxRuntime.jsx(
29433
+ chunkWALADS2S_cjs.ImportFamilySection,
29434
+ {
29435
+ label: family.label,
29436
+ identity,
29437
+ action: !connected ? "connect" : needsReconnect ? "reconnect" : "disconnect",
29438
+ isActionPending: disconnect.isPending,
29439
+ onAction: () => void (!connected ? connectFamily(connectVendor) : needsReconnect ? reconnectFamily(connectVendor) : disconnectFamily(family, connectVendor, identity)),
29440
+ testId: `import-family-${family.key}`,
29441
+ actionButton: !connected ? { testId: `import-family-connect-${family.key}` } : needsReconnect ? { testId: `import-family-reconnect-${family.key}` } : { testId: `import-family-disconnect-${family.key}` },
29442
+ children: /* @__PURE__ */ jsxRuntime.jsxs(chunkWALADS2S_cjs.ImportList, { children: [
29443
+ entries.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(
29444
+ EmailProviderRow,
29445
+ {
29446
+ catalog: entry,
29447
+ userConnector: connectedByVendor[entry.vendor_key],
29448
+ workspaceExtId,
29449
+ workspaceName,
29450
+ onViewProgress,
29451
+ onNeedsReconnectChange: handleNeedsReconnectChange
29452
+ },
29453
+ entry.vendor_key
29454
+ )),
29455
+ extra
29456
+ ] })
29457
+ },
29458
+ family.key
29459
+ )
29460
+ ) });
29461
+ }
29462
+ function useDriveSyncTrigger() {
29463
+ const arbi = react.useArbi();
29464
+ const { notify: notify18 } = chunkB3NYBMDR_cjs.useBlocksEnvironment();
29465
+ const triggerSync = react.useTriggerDriveSync();
29466
+ const runSync = React9.useCallback(
29467
+ async ({
29468
+ vendorKey,
29469
+ workspaceExtId,
29470
+ workspaceLabel = "the workspace"
29471
+ }) => {
29472
+ await arbi.connectors.bridgeTokens({ vendor: vendorKey });
29473
+ if (workspaceExtId) {
29474
+ await arbi.workspaces.open(workspaceExtId).catch(() => {
29475
+ });
29476
+ }
29477
+ triggerSync.mutate(
29478
+ { vendorKey },
29479
+ {
29480
+ onSuccess: (res) => {
29481
+ const n = res?.estimated_count;
29482
+ if (n === 0) {
29483
+ notify18("You\u2019re up to date \u2014 no new documents to sync.", "success");
29484
+ } else if (n != null && n > 0) {
29485
+ notify18(
29486
+ `Fetching ${n} new document${n === 1 ? "" : "s"} to ${workspaceLabel}.`,
29487
+ "success"
29488
+ );
29489
+ } else {
29490
+ notify18("Sync started \u2014 fetching new documents\u2026", "success");
29491
+ }
29492
+ },
29493
+ onError: (err) => {
29494
+ if (react.connectorErrorStatus(err) === 425) {
29495
+ notify18("Still preparing your session \u2014 please try Sync now again.", "error");
29496
+ } else if (react.connectorErrorStatus(err) === 409) {
29497
+ notify18("Reconnect needed \u2014 your account needs to be re-authorized.", "error");
29498
+ } else if (react.connectorErrorStatus(err) === 404) {
29499
+ notify18("Drive sync is not enabled for this connector yet.", "error");
29500
+ } else {
29501
+ notify18("Could not start sync. Please try again.", "error");
29502
+ }
29503
+ }
29504
+ }
29505
+ );
29506
+ },
29507
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- triggerSync.mutate is a stable TanStack Query reference
29508
+ [arbi, notify18, triggerSync.mutate]
29509
+ );
29510
+ return { runSync, isPending: triggerSync.isPending };
29511
+ }
29512
+ var DRIVE_PRODUCT = {
29513
+ microsoft: { name: "OneDrive", glyph: "onedrive" },
29514
+ gmail: { name: "Google Drive", glyph: "googledrive" },
29515
+ microsoft_sharepoint: { name: "SharePoint", glyph: "sharepoint" },
29516
+ box: { name: "Box", glyph: "box" },
29517
+ dropbox: { name: "Dropbox", glyph: "dropbox" },
29518
+ onenote: { name: "OneNote", glyph: "onenote" },
29519
+ clio: { name: "Clio", glyph: "clio" }
29520
+ };
29521
+ function driveProduct(vendorKey) {
29522
+ return DRIVE_PRODUCT[vendorKey] ?? { name: "Drive", glyph: "onedrive" };
29523
+ }
29524
+ function VendorGlyph2({ catalog }) {
29525
+ return /* @__PURE__ */ jsxRuntime.jsx(
29526
+ chunkWALADS2S_cjs.VendorLogo,
29527
+ {
29528
+ vendorKey: catalog.vendor_key,
29529
+ product: driveProduct(catalog.vendor_key).glyph,
29530
+ className: "h-7 w-7"
29531
+ }
29532
+ );
29533
+ }
29534
+ function OneDriveProviderRow({
29535
+ catalog,
29536
+ userConnector,
29537
+ workspaceExtId,
29538
+ workspaceName,
29539
+ onViewProgress
29540
+ }) {
29541
+ const [settingsOpen, setSettingsOpen] = React9.useState(false);
29542
+ const { runSync, isPending: syncPending } = useDriveSyncTrigger();
29543
+ const cancelSync = react.useCancelDriveSync();
29544
+ const arbi = react.useArbi();
29545
+ const { notify: notify18 } = chunkB3NYBMDR_cjs.useBlocksEnvironment();
29546
+ const isConnected = !!userConnector?.is_connected;
29547
+ const product = driveProduct(catalog.vendor_key);
29548
+ const status = userConnector?.drive_sync_status ?? null;
29549
+ const configuredHere = status != null && userConnector?.drive_sync_workspace_ext_id === workspaceExtId;
29550
+ const folderCount = userConnector?.drive_sync_folders?.length ?? 0;
29551
+ const needsReconsent = isConnected && !!userConnector?.drive_needs_reconsent;
29552
+ const [tokensBridged, setTokensBridged] = React9.useState(false);
29553
+ React9.useEffect(() => {
29554
+ if (!isConnected) {
29555
+ setTokensBridged(false);
29556
+ return;
29557
+ }
29558
+ let cancelled = false;
29559
+ void arbi.connectors.bridgeTokens({ vendor: catalog.vendor_key, autoSyncWorkspaceExtId: workspaceExtId }).finally(() => {
29560
+ if (!cancelled) setTokensBridged(true);
29561
+ });
29562
+ return () => {
29563
+ cancelled = true;
29564
+ };
29565
+ }, [isConnected, arbi, catalog.vendor_key, workspaceExtId]);
29566
+ const { error: foldersError } = react.useDriveFolders(
29567
+ catalog.vendor_key,
29568
+ isConnected && tokensBridged && !needsReconsent
29569
+ );
29570
+ const needsReconnect = needsReconsent || isConnected && react.connectorErrorStatus(foldersError) === 409;
29571
+ const { data: progress, refetch: refetchProgress } = react.useDriveSyncProgress(
29572
+ catalog.vendor_key,
29573
+ configuredHere && !needsReconnect
29574
+ );
29575
+ const running = !!progress?.running;
29576
+ const { lastRunCount, dismiss: dismissHandoff } = useImportHandoff(running, progress?.processed);
29577
+ react.useRefreshConnectorsOnRunEnd(running);
29578
+ const { data: estimate, refetch: refetchEstimate } = react.useDriveSyncEstimate(
29579
+ catalog.vendor_key,
29580
+ configuredHere && tokensBridged && !needsReconnect && !running
29581
+ );
29582
+ const lastSummaryRef = React9.useRef(null);
29583
+ const baselinedRef = React9.useRef(false);
29584
+ React9.useEffect(() => {
29585
+ if (progress === void 0) return;
29586
+ const s = progress.summary;
29587
+ const finishedAt = s?.finished_at ?? null;
29588
+ if (!baselinedRef.current) {
29589
+ baselinedRef.current = true;
29590
+ lastSummaryRef.current = finishedAt;
29591
+ return;
29592
+ }
29593
+ if (!s?.finished_at || lastSummaryRef.current === s.finished_at) return;
29594
+ lastSummaryRef.current = s.finished_at;
29595
+ const total = s.attempted || s.ingested;
29596
+ const importedMsg = `Imported ${s.ingested} of ${total} document${total === 1 ? "" : "s"} from ${product.name}.`;
29597
+ const skipped = s.skipped ?? [];
29598
+ if (skipped.length === 0) {
29599
+ notify18(importedMsg, "success");
29600
+ } else {
29601
+ notify18(`${importedMsg} ${skipped.length} couldn\u2019t be imported:`, "warning", {
29602
+ duration: 12e3,
29603
+ description: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "mt-1 max-h-56 space-y-0.5 overflow-y-auto pr-1 text-xs", children: skipped.map((f, i) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "break-all", children: [
29604
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: f.name }),
29605
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
29606
+ " \u2014 ",
29607
+ f.reason
29608
+ ] })
29609
+ ] }, i)) })
29610
+ });
29611
+ }
29612
+ void refetchEstimate();
29613
+ }, [progress, refetchEstimate, product.name, notify18]);
29614
+ const pendingCount = estimate?.estimated_count;
29615
+ const busy = syncPending;
29616
+ const ownsAuth = catalog.vendor_key === "microsoft_sharepoint";
29617
+ const [reauthPending, setReauthPending] = React9.useState(false);
29618
+ const reconnectSelf = async () => {
29619
+ setReauthPending(true);
29620
+ try {
29621
+ window.location.href = await arbi.connectors.authorize(
29622
+ catalog.vendor_key,
29623
+ react.connectorReturnTo("accounts")
29624
+ );
29625
+ } catch {
29626
+ setReauthPending(false);
29627
+ notify18("Could not start reconnection. Please try again.", "error");
29628
+ }
29629
+ };
29630
+ const kickProgressPolling = () => {
29631
+ [500, 1400, 2800].forEach((ms) => window.setTimeout(() => void refetchProgress(), ms));
29632
+ };
29633
+ const syncNow = () => {
29634
+ void runSync({
29635
+ vendorKey: catalog.vendor_key,
29636
+ workspaceExtId,
29637
+ workspaceLabel: workspaceName
29638
+ });
29639
+ kickProgressPolling();
29640
+ [1500, 4e3].forEach((ms) => window.setTimeout(() => void refetchEstimate(), ms));
29641
+ };
29642
+ const stopSync = () => cancelSync.mutate(
29643
+ { vendorKey: catalog.vendor_key },
29644
+ { onSettled: () => void refetchProgress() }
29645
+ );
29646
+ const driveNoun = (n) => n === 1 ? "document" : "documents";
29647
+ const showRunActions = isConnected && !needsReconnect;
29648
+ const reconnectAction = ownsAuth && needsReconnect ? /* @__PURE__ */ jsxRuntime.jsx(
29649
+ chunkWALADS2S_cjs.ImportActionButton,
29650
+ {
29651
+ onClick: () => void reconnectSelf(),
29652
+ disabled: reauthPending,
29653
+ "data-testid": `onedrive-reconnect-${catalog.vendor_key}`,
29654
+ children: reauthPending ? "Reconnecting\u2026" : "Reconnect"
29655
+ }
29656
+ ) : null;
29657
+ return /* @__PURE__ */ jsxRuntime.jsxs(
29658
+ chunkWALADS2S_cjs.ImportRow,
29659
+ {
29660
+ testId: `onedrive-provider-row-${catalog.vendor_key}`,
29661
+ logo: /* @__PURE__ */ jsxRuntime.jsx(VendorGlyph2, { catalog }),
29662
+ name: product.name,
29663
+ actions: (
29664
+ // OneDrive/Google Drive: connecting AND reconnecting are owned by the family header.
29665
+ // SharePoint (ownsAuth) is a separate grant, so its row renders its OWN Reconnect (D1).
29666
+ showRunActions ? (
29667
+ // Until folders are configured here (or when nothing new is pending), Import now
29668
+ // stays disabled; the gear opens the folder picker.
29669
+ /* @__PURE__ */ jsxRuntime.jsx(
29670
+ chunkWALADS2S_cjs.ImportRunActions,
29671
+ {
29672
+ isRunning: running,
29673
+ isStopping: cancelSync.isPending,
29674
+ isBusy: busy,
29675
+ importDisabled: !configuredHere || pendingCount === 0,
29676
+ importTitle: !configuredHere ? `Choose ${product.name} folders in settings first` : pendingCount === 0 ? "No new documents to import" : void 0,
29677
+ onImport: syncNow,
29678
+ onStop: stopSync,
29679
+ onSettings: () => setSettingsOpen(true),
29680
+ settingsLabel: `${product.name} import settings`,
29681
+ importButton: { testId: `onedrive-sync-${catalog.vendor_key}` },
29682
+ settingsButton: { testId: `onedrive-settings-${catalog.vendor_key}` },
29683
+ stopButton: { testId: `onedrive-stop-${catalog.vendor_key}` }
29684
+ }
29685
+ )
29686
+ ) : reconnectAction
29687
+ ),
29688
+ children: [
29689
+ ownsAuth && needsReconnect && /* @__PURE__ */ jsxRuntime.jsxs(chunkWALADS2S_cjs.ImportHint, { "data-testid": `onedrive-reconnect-hint-${catalog.vendor_key}`, children: [
29690
+ "Couldn\u2019t reach SharePoint. Click ",
29691
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Reconnect" }),
29692
+ " \u2014 if it keeps happening, log out and back in to refresh the connection."
29693
+ ] }),
29694
+ configuredHere && !needsReconnect && !running && /* @__PURE__ */ jsxRuntime.jsxs(
29695
+ chunkWALADS2S_cjs.ImportSummary,
29696
+ {
29697
+ className: "mt-2",
29698
+ aside: typeof pendingCount === "number" ? /* @__PURE__ */ jsxRuntime.jsx(chunkWALADS2S_cjs.ImportAside, { className: "max-w-none shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("span", { "data-testid": `drive-pending-${catalog.vendor_key}`, children: pendingCount > 0 ? `${pendingCount.toLocaleString()} new ${driveNoun(pendingCount)} to sync` : "No new documents to sync" }) }) : void 0,
29699
+ children: [
29700
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
29701
+ "Syncing ",
29702
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-foreground", children: folderCount }),
29703
+ " folder",
29704
+ folderCount === 1 ? "" : "s",
29705
+ " into this workspace"
29706
+ ] }),
29707
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": `drive-last-sync-${catalog.vendor_key}`, children: userConnector?.drive_last_sync_at ? `Last synced ${ui.formatRelativeTime(userConnector.drive_last_sync_at, { style: "compact" })}` : "Not synced yet" })
29708
+ ]
29709
+ }
29710
+ ),
29711
+ isConnected && !needsReconnect && !running && !configuredHere && /* @__PURE__ */ jsxRuntime.jsxs(
29712
+ "button",
29713
+ {
29714
+ type: "button",
29715
+ className: "ml-[34px] mt-2 text-left text-sm leading-snug text-muted-foreground hover:text-foreground pointer-coarse:min-h-11",
29716
+ onClick: () => setSettingsOpen(true),
29717
+ "data-testid": `onedrive-choose-folders-${catalog.vendor_key}`,
29718
+ children: [
29719
+ "Choose folders in ",
29720
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "underline", children: "settings" }),
29721
+ " to start syncing"
29722
+ ]
29723
+ }
29724
+ ),
29725
+ running && /* @__PURE__ */ jsxRuntime.jsx(
29726
+ chunkWALADS2S_cjs.ImportProgress,
29727
+ {
29728
+ processed: progress?.processed ?? 0,
29729
+ total: progress?.total,
29730
+ noun: "documents",
29731
+ testId: `onedrive-progress-${catalog.vendor_key}`
29732
+ }
29733
+ ),
29734
+ !running && lastRunCount !== null && /* @__PURE__ */ jsxRuntime.jsx(
29735
+ ImportHandoff,
29736
+ {
29737
+ count: lastRunCount,
29738
+ noun: "document",
29739
+ onDismiss: dismissHandoff,
29740
+ onViewProgress,
29741
+ "data-testid": `onedrive-handoff-${catalog.vendor_key}`
29742
+ }
29743
+ ),
29744
+ /* @__PURE__ */ jsxRuntime.jsx(
29745
+ ConnectedDriveSyncDialog,
29746
+ {
29747
+ catalog,
29748
+ userConnector,
29749
+ open: settingsOpen,
29750
+ onOpenChange: setSettingsOpen,
29751
+ lockedWorkspaceExtId: workspaceExtId,
29752
+ onEnabled: () => void refetchEstimate()
29753
+ }
29754
+ )
29755
+ ]
29756
+ }
29757
+ );
29758
+ }
29759
+ function SharePointEnableRow({
29760
+ catalog,
29761
+ sharePointAdminUrl
29762
+ }) {
29763
+ const arbi = react.useArbi();
29764
+ const { notify: notify18 } = chunkB3NYBMDR_cjs.useBlocksEnvironment();
29765
+ const [pending, setPending] = React9.useState(false);
29766
+ const product = driveProduct(catalog.vendor_key);
29767
+ const enable = async () => {
29768
+ setPending(true);
29769
+ try {
29770
+ window.location.href = await arbi.connectors.authorize(
29771
+ catalog.vendor_key,
29772
+ react.connectorReturnTo("accounts")
29773
+ );
29774
+ } catch {
29775
+ setPending(false);
29776
+ notify18("Could not start the connection. Please try again.", "error");
29777
+ }
29778
+ };
29779
+ const copyAdminLink = async () => {
29780
+ const link = sharePointAdminUrl;
29781
+ if (!link) return;
29782
+ try {
29783
+ await navigator.clipboard.writeText(link);
29784
+ notify18("Approval link copied \u2014 send it to your Microsoft admin.", "success");
29785
+ } catch {
29786
+ notify18(`Copy this link for your Microsoft admin: ${link}`, "info");
29787
+ }
29788
+ };
29789
+ return /* @__PURE__ */ jsxRuntime.jsx(
29790
+ chunkWALADS2S_cjs.ImportRow,
29791
+ {
29792
+ testId: `onedrive-provider-row-${catalog.vendor_key}`,
29793
+ logo: /* @__PURE__ */ jsxRuntime.jsx(chunkWALADS2S_cjs.VendorLogo, { vendorKey: catalog.vendor_key, product: product.glyph, className: "h-7 w-7" }),
29794
+ name: product.name,
29795
+ actions: /* @__PURE__ */ jsxRuntime.jsx(
29796
+ chunkWALADS2S_cjs.ImportActionButton,
29797
+ {
29798
+ onClick: () => void enable(),
29799
+ disabled: pending,
29800
+ "data-testid": `onedrive-enable-${catalog.vendor_key}`,
29801
+ children: pending ? "Enabling\u2026" : `Enable ${product.name}`
29802
+ }
29803
+ ),
29804
+ children: sharePointAdminUrl && /* @__PURE__ */ jsxRuntime.jsxs(chunkWALADS2S_cjs.ImportHint, { children: [
29805
+ "Does your organization require admin approval?",
29806
+ " ",
29807
+ /* @__PURE__ */ jsxRuntime.jsx(
29808
+ "button",
29809
+ {
29810
+ type: "button",
29811
+ className: "underline hover:text-foreground",
29812
+ onClick: () => void copyAdminLink(),
29813
+ "data-testid": "sharepoint-copy-admin-link",
29814
+ children: "Copy the approval link"
29815
+ }
29816
+ ),
29817
+ " ",
29818
+ "and send it to your Microsoft admin \u2014 they won't need an ARBI account."
29819
+ ] })
29820
+ }
29821
+ );
29822
+ }
29823
+ function DriveImportPanel({
29824
+ workspaceExtId,
29825
+ workspaceName,
29826
+ onViewProgress,
29827
+ only,
29828
+ sharePointAdminUrl
29829
+ }) {
29830
+ const { data: catalog = [] } = react.useConnectorCatalog();
29831
+ const { data: myConnectors = [] } = react.useMyConnectors();
29832
+ const driveCatalog = catalog.filter(
29833
+ (c) => react.isDriveSyncVendor(c.vendor_key) && (!only || c.vendor_key === only)
29834
+ );
29835
+ if (driveCatalog.length === 0) return null;
29836
+ const connectedByVendor = Object.fromEntries(myConnectors.map((uc) => [uc.vendor_key, uc]));
29837
+ const microsoftConnected = !!connectedByVendor["microsoft"]?.is_connected;
29838
+ const rows = driveCatalog.map((entry) => {
29839
+ const uc = connectedByVendor[entry.vendor_key];
29840
+ if (entry.vendor_key === "microsoft_sharepoint" && !uc) {
29841
+ if (microsoftConnected) {
29842
+ return /* @__PURE__ */ jsxRuntime.jsx(
29843
+ SharePointEnableRow,
29844
+ {
29845
+ catalog: entry,
29846
+ sharePointAdminUrl
29847
+ },
29848
+ entry.vendor_key
29849
+ );
29850
+ }
29851
+ const product = driveProduct(entry.vendor_key);
29852
+ return /* @__PURE__ */ jsxRuntime.jsx(
29853
+ chunkWALADS2S_cjs.ImportRow,
29854
+ {
29855
+ testId: `onedrive-provider-row-${entry.vendor_key}`,
29856
+ logo: /* @__PURE__ */ jsxRuntime.jsx(
29857
+ chunkWALADS2S_cjs.VendorLogo,
29858
+ {
29859
+ vendorKey: entry.vendor_key,
29860
+ product: product.glyph,
29861
+ className: "h-7 w-7"
29862
+ }
29863
+ ),
29864
+ name: product.name
29865
+ },
29866
+ entry.vendor_key
29867
+ );
29868
+ }
29869
+ return /* @__PURE__ */ jsxRuntime.jsx(
29870
+ OneDriveProviderRow,
29871
+ {
29872
+ catalog: entry,
29873
+ userConnector: uc,
29874
+ workspaceExtId,
29875
+ workspaceName,
29876
+ onViewProgress
29877
+ },
29878
+ entry.vendor_key
29879
+ );
29880
+ }).filter(Boolean);
29881
+ if (rows.length === 0) return null;
29882
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkWALADS2S_cjs.ImportList, { "data-testid": "onedrive-import-panel", children: rows });
29883
+ }
29884
+ function useHasAccountsImport() {
29885
+ const isVendorVisible = react.useConnectorVendorVisibility();
29886
+ return isVendorVisible("microsoft") || isVendorVisible("gmail");
29887
+ }
29888
+ function ConnectedAccountsImport({
29889
+ workspaceExtId,
29890
+ workspaceName,
29891
+ onViewProgress,
29892
+ sharePointAdminUrl
29893
+ }) {
29894
+ const isVendorVisible = react.useConnectorVendorVisibility();
29895
+ if (!isVendorVisible("microsoft") && !isVendorVisible("gmail")) return null;
29896
+ return /* @__PURE__ */ jsxRuntime.jsx(
29897
+ EmailImportPanel,
29898
+ {
29899
+ workspaceExtId,
29900
+ workspaceName,
29901
+ onViewProgress,
29902
+ microsoftExtra: (
29903
+ // Two drive products ride Microsoft: OneDrive (the `microsoft` grant) and SharePoint
29904
+ // (its own grant, behind its own visibility toggle).
29905
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "divide-y divide-border", "data-testid": "upload-source-onedrive", children: [
29906
+ /* @__PURE__ */ jsxRuntime.jsx(
29907
+ DriveImportPanel,
29908
+ {
29909
+ workspaceExtId,
29910
+ workspaceName,
29911
+ onViewProgress,
29912
+ sharePointAdminUrl,
29913
+ only: "microsoft"
29914
+ }
29915
+ ),
29916
+ isVendorVisible("microsoft_sharepoint") && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": "upload-source-sharepoint", children: /* @__PURE__ */ jsxRuntime.jsx(
29917
+ DriveImportPanel,
29918
+ {
29919
+ workspaceExtId,
29920
+ workspaceName,
29921
+ onViewProgress,
29922
+ sharePointAdminUrl,
29923
+ only: "microsoft_sharepoint"
29924
+ }
29925
+ ) })
29926
+ ] })
29927
+ ),
29928
+ googleExtra: /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": "upload-source-googledrive", children: /* @__PURE__ */ jsxRuntime.jsx(
29929
+ DriveImportPanel,
29930
+ {
29931
+ workspaceExtId,
29932
+ workspaceName,
29933
+ onViewProgress,
29934
+ sharePointAdminUrl,
29935
+ only: "gmail"
29936
+ }
29937
+ ) })
29938
+ }
29939
+ );
29940
+ }
29007
29941
  var UNTITLED = "Untitled";
29008
29942
  function useDatabaseCellSources(databases) {
29009
29943
  const workspaceId = react.useArbiSessionState((state) => state.workspaceId);
@@ -34086,7 +35020,7 @@ function useConnectedThreadActivity(conversationId) {
34086
35020
  step: typeof event.detail?.step === "string" ? event.detail.step : void 0,
34087
35021
  createdAt: event.created_at,
34088
35022
  card: callDetail ? /* @__PURE__ */ jsxRuntime.jsx(
34089
- chunk6AJJJ5HR_cjs.ThreadCallLogCard,
35023
+ chunk5R256EMF_cjs.ThreadCallLogCard,
34090
35024
  {
34091
35025
  detail: callDetail,
34092
35026
  name: personName,
@@ -34094,7 +35028,7 @@ function useConnectedThreadActivity(conversationId) {
34094
35028
  time: ui.formatRelativeTime(event.created_at, { style: "short" })
34095
35029
  }
34096
35030
  ) : recordingCall ? /* @__PURE__ */ jsxRuntime.jsx(
34097
- chunk6AJJJ5HR_cjs.RecordingCard,
35031
+ chunk5R256EMF_cjs.RecordingCard,
34098
35032
  {
34099
35033
  callExtId: recordingCall,
34100
35034
  recordingExtId: recordingId,
@@ -36929,7 +37863,7 @@ var MessageComponent = ({
36929
37863
  const statusLabel = isFailed ? "Response failed" : isStopped ? "Stopped" : finalElapsedSeconds >= 0.05 ? `Answered in ${finalElapsedSeconds.toFixed(1)}s` : "Complete";
36930
37864
  const timeLabel = ui.formatFriendlyDate(message.created_at || "");
36931
37865
  const messageId = message.external_id;
36932
- const transcriptRuns = chunk6AJJJ5HR_cjs.useTranscriptRuns();
37866
+ const transcriptRuns = chunk5R256EMF_cjs.useTranscriptRuns();
36933
37867
  const messageRole = isUser ? "user" : "assistant";
36934
37868
  const menuItems = [
36935
37869
  ...isUser ? [
@@ -37137,7 +38071,7 @@ var MessageComponent = ({
37137
38071
  const speakerName = speaker ? ui.getUserDisplayName(speaker) : null;
37138
38072
  const isMe = transcriptSegment.speaker_ext_id === currentUser?.external_id;
37139
38073
  return /* @__PURE__ */ jsxRuntime.jsx(
37140
- chunk6AJJJ5HR_cjs.TranscriptEntry,
38074
+ chunk5R256EMF_cjs.TranscriptEntry,
37141
38075
  {
37142
38076
  speakerId: transcriptSegment.speaker_ext_id,
37143
38077
  speakerName: isMe ? "Me" : speakerName || "Former member",
@@ -37698,6 +38632,763 @@ function ConnectedMessageList({ messages }) {
37698
38632
  /* @__PURE__ */ jsxRuntime.jsx(ConnectedThreadsPreview, { open: previewOpen, onOpenChange: setPreviewOpen })
37699
38633
  ] });
37700
38634
  }
38635
+ function ThreadSearch({ children, ResultsBoundary = chunkTM2D4XT4_cjs.ErrorBoundary }) {
38636
+ const [query, setQuery] = React9.useState("");
38637
+ const [submitted, setSubmitted] = React9.useState("");
38638
+ const selectedWorkspaceId = react.useArbiSessionState((s) => s.workspaceId);
38639
+ const { notify: notify18, openConversation } = chunkB3NYBMDR_cjs.useBlocksEnvironment();
38640
+ const search = react.useConversationSearch();
38641
+ const isSearching = search.isPending;
38642
+ const groups = React9.useMemo(
38643
+ () => search.isError ? [] : (search.data?.results ?? []).map((g) => ({
38644
+ id: g.conversation_ext_id,
38645
+ title: g.title,
38646
+ matches: g.messages.map((m) => ({
38647
+ id: m.message_ext_id,
38648
+ role: m.role,
38649
+ score: m.score,
38650
+ snippet: m.snippet
38651
+ }))
38652
+ })),
38653
+ [search.data, search.isError]
38654
+ );
38655
+ const handleSearch = React9.useCallback(() => {
38656
+ const q = query.trim();
38657
+ if (!q || !selectedWorkspaceId || isSearching) return;
38658
+ setSubmitted(q);
38659
+ search.mutate(
38660
+ { query: q, search_mode: "hybrid", limit: 20 },
38661
+ {
38662
+ onError: (err) => {
38663
+ console.error("Conversation search failed", err);
38664
+ notify18("Conversation search failed", "error");
38665
+ }
38666
+ }
38667
+ );
38668
+ }, [query, selectedWorkspaceId, isSearching, search, notify18]);
38669
+ const clearSearch = React9.useCallback(() => {
38670
+ setQuery("");
38671
+ setSubmitted("");
38672
+ }, []);
38673
+ const openHit = React9.useCallback(
38674
+ (conversationId, messageId) => {
38675
+ openConversation(conversationId, messageId ? { messageId } : void 0);
38676
+ },
38677
+ [openConversation]
38678
+ );
38679
+ return /* @__PURE__ */ jsxRuntime.jsx(
38680
+ chunkDWWRLKEZ_cjs.ConversationSearchView,
38681
+ {
38682
+ query,
38683
+ onQueryChange: setQuery,
38684
+ onSubmit: handleSearch,
38685
+ canSubmit: !!query.trim() && !!selectedWorkspaceId && !isSearching,
38686
+ isSearching,
38687
+ submittedQuery: submitted,
38688
+ groups,
38689
+ onOpenConversation: openHit,
38690
+ onClear: clearSearch,
38691
+ ResultsBoundary,
38692
+ children
38693
+ }
38694
+ );
38695
+ }
38696
+ var DEFAULT_THREAD_VISIBILITY = { me: null, workspace: null };
38697
+ var relativeTime2 = (iso) => ui.formatRelativeTime(iso, { style: "short" });
38698
+ var LIST_LABELS = {
38699
+ emptyTitle: "Nothing here yet",
38700
+ emptyMessage: "Use New: just type what you need, or fill in an owner and a due date. You always decide when a thread is done.",
38701
+ untitled: `Untitled ${ui.getEntityLabel("CONVERSATION").toLowerCase()}`,
38702
+ noMatches: `No ${ui.getEntityLabel("CONVERSATION", "PLURAL").toLowerCase()} match.`,
38703
+ selectAll: "Select all"
38704
+ };
38705
+ var RENAME_DIALOG = { testId: "rename-conversation-modal" };
38706
+ function useStableRecencyOrder(rows) {
38707
+ const orderRef = React9.useRef([]);
38708
+ return React9.useMemo(() => {
38709
+ const byRecency = [...rows].sort(
38710
+ (a, b) => new Date(b.updated_at || b.created_at || 0).getTime() - new Date(a.updated_at || a.created_at || 0).getTime()
38711
+ );
38712
+ const present = new Set(byRecency.map((r) => r.external_id));
38713
+ const known = new Set(orderRef.current);
38714
+ const added = byRecency.map((r) => r.external_id).filter((id) => !known.has(id));
38715
+ orderRef.current = [...added, ...orderRef.current.filter((id) => present.has(id))];
38716
+ const byId = new Map(byRecency.map((r) => [r.external_id, r]));
38717
+ return orderRef.current.flatMap((id) => byId.get(id) ?? []);
38718
+ }, [rows]);
38719
+ }
38720
+ function ConnectedThreadsPage({
38721
+ showHeader = true,
38722
+ search = false,
38723
+ ResultsBoundary,
38724
+ focusLauncher,
38725
+ layout = "list",
38726
+ workflowActions
38727
+ }) {
38728
+ const mode = layout === "inbox" ? "tasks" : "threads";
38729
+ const { confirm, notify: notify18, openConversation, openDocument } = chunkB3NYBMDR_cjs.useBlocksEnvironment();
38730
+ const { conversations: all, isLoading } = react.useConversationItems();
38731
+ const [doneFilter] = react.useTransientView("threads.done", "exclude");
38732
+ const [visibilityFilters] = react.useTransientView("threads.visibility", DEFAULT_THREAD_VISIBILITY);
38733
+ const [meetingFilter] = react.useTransientView("threads.meetings", null);
38734
+ const [topbarFilterQuery, setTopbarFilterQuery] = react.useTransientView("topbar.filter", "");
38735
+ const currentUserExtId = react.useArbiSession().user?.external_id;
38736
+ const listed = React9.useMemo(
38737
+ () => all.filter((c) => mode === "threads" || c.status != null),
38738
+ [all, mode]
38739
+ );
38740
+ const tasks = useStableRecencyOrder(listed);
38741
+ const updateConversation = react.useUpdateConversation();
38742
+ const deleteConversation = react.useDeleteConversation();
38743
+ const people = useTaskPeople();
38744
+ const renderPerson = useRenderTaskPerson();
38745
+ const canEditShared = react.useCanEditShared();
38746
+ const isWorkspaceOwner = react.useIsWorkspaceOwner();
38747
+ const { data: agents = [] } = react.useAgents();
38748
+ const { data: workflows = [] } = react.useWorkflows();
38749
+ const agentNames = React9.useMemo(
38750
+ () => Object.fromEntries(agents.map((a) => [a.external_id, a.given_name || a.email])),
38751
+ [agents]
38752
+ );
38753
+ const workflowNames = React9.useMemo(
38754
+ () => Object.fromEntries(workflows.map((w) => [w.external_id, w.name])),
38755
+ [workflows]
38756
+ );
38757
+ const runConversation = react.useRunConversation();
38758
+ const [busyId, setBusyId] = React9.useState(null);
38759
+ const [editorOpen, setEditorOpen] = React9.useState(false);
38760
+ const [editing, setEditing] = React9.useState(null);
38761
+ const [startOpen, setStartOpen] = React9.useState(false);
38762
+ const [parentForNew, setParentForNew] = React9.useState(void 0);
38763
+ const nameOf = (task) => task.title?.trim() || task.workflow_ext_id && workflowNames[task.workflow_ext_id] || "Untitled task";
38764
+ const openCreate = () => {
38765
+ setParentForNew(void 0);
38766
+ setStartOpen(true);
38767
+ };
38768
+ const openAddSubtask = (parent) => {
38769
+ setParentForNew(parent.external_id);
38770
+ setStartOpen(true);
38771
+ };
38772
+ const [renaming, setRenaming] = React9.useState(null);
38773
+ const [newTitle, setNewTitle] = React9.useState("");
38774
+ const [isExportOpen, setIsExportOpen] = React9.useState(false);
38775
+ const [exportRows, setExportRows] = React9.useState([]);
38776
+ const openEdit = (task) => {
38777
+ if (mode === "threads" || !task.status) {
38778
+ setRenaming(task);
38779
+ setNewTitle(task.title ?? "");
38780
+ return;
38781
+ }
38782
+ setEditing(task);
38783
+ setEditorOpen(true);
38784
+ };
38785
+ const act = async (task, action, success, failure) => {
38786
+ setBusyId(task.external_id);
38787
+ try {
38788
+ await action();
38789
+ if (success) notify18(success, "success");
38790
+ } catch (error) {
38791
+ notify18(
38792
+ error instanceof browser.ArbiApiError && error.detail ? `${failure}: ${error.detail}` : failure,
38793
+ "error"
38794
+ );
38795
+ } finally {
38796
+ setBusyId(null);
38797
+ }
38798
+ };
38799
+ const patch = (task, body) => updateConversation.mutateAsync({ conversationId: task.external_id, patch: body });
38800
+ const setStatus = (task, status, success) => act(task, () => patch(task, { status }), success, "Failed to update task");
38801
+ const handleToggleShared = (task, shouldShare) => act(
38802
+ task,
38803
+ () => patch(task, { shared: shouldShare }),
38804
+ shouldShare ? `Shared \u201C${nameOf(task)}\u201D with the workspace` : `Made \u201C${nameOf(task)}\u201D private`,
38805
+ "Failed to change who can see the task"
38806
+ );
38807
+ const handleMove = (task, parentId) => act(
38808
+ task,
38809
+ () => patch(task, { parent_conversation_ext_id: parentId }),
38810
+ parentId ? `Moved \u201C${nameOf(task)}\u201D` : `Moved \u201C${nameOf(task)}\u201D to the top level`,
38811
+ "Failed to move task"
38812
+ );
38813
+ const handleDelete = async (task) => {
38814
+ const subtasks = tasks.filter((t) => t.parent_conversation_ext_id === task.external_id).length;
38815
+ const confirmed = await confirm({
38816
+ message: `Delete \u201C${nameOf(task)}\u201D? This can't be undone from here.${subtasks ? ` Its ${subtasks === 1 ? "sub-task stays" : `${subtasks} sub-tasks stay`} and ${subtasks === 1 ? "moves" : "move"} to the top level.` : ""}`,
38817
+ title: "Delete task"
38818
+ });
38819
+ if (!confirmed) return;
38820
+ await act(
38821
+ task,
38822
+ () => deleteConversation.mutateAsync(task.external_id),
38823
+ `Deleted \u201C${nameOf(task)}\u201D`,
38824
+ "Failed to delete task"
38825
+ );
38826
+ };
38827
+ const forEach = async (rows, one, done) => {
38828
+ let failed = 0;
38829
+ for (const task of rows) {
38830
+ try {
38831
+ await one(task);
38832
+ } catch {
38833
+ failed += 1;
38834
+ }
38835
+ }
38836
+ notify18(
38837
+ failed ? `${failed} of ${rows.length} could not be changed: you may not be allowed to change them` : done,
38838
+ failed ? "error" : "success"
38839
+ );
38840
+ };
38841
+ const handleMarkDoneMany = (rows) => forEach(rows, (task) => patch(task, { status: "done" }), `Marked ${rows.length} done`);
38842
+ const handleDeleteMany = async (rows) => {
38843
+ const named = rows.slice(0, 3).map((task) => `"${nameOf(task)}"`).join(", ");
38844
+ const more = rows.length - 3;
38845
+ const confirmed = await confirm({
38846
+ message: `Delete ${more > 0 ? `${named} and ${more} more` : named}? This cannot be undone.`,
38847
+ title: `Delete ${rows.length} item${rows.length === 1 ? "" : "s"}`
38848
+ });
38849
+ if (!confirmed) return;
38850
+ await forEach(
38851
+ rows,
38852
+ (task) => deleteConversation.mutateAsync(task.external_id),
38853
+ `Deleted ${rows.length}`
38854
+ );
38855
+ };
38856
+ const handleSaveRename = React9.useCallback(() => {
38857
+ if (!renaming || !newTitle.trim()) return;
38858
+ updateConversation.mutate(
38859
+ { conversationId: renaming.external_id, patch: { title: newTitle.trim() } },
38860
+ {
38861
+ onSuccess: () => {
38862
+ notify18("Conversation renamed successfully", "success");
38863
+ setRenaming(null);
38864
+ setNewTitle("");
38865
+ },
38866
+ onError: (error) => {
38867
+ console.error("Failed to rename conversation:", error);
38868
+ notify18("Failed to rename conversation", "error");
38869
+ }
38870
+ }
38871
+ );
38872
+ }, [renaming, newTitle, updateConversation, notify18]);
38873
+ const handleBulkShare = async (rows) => {
38874
+ const unshared = rows.filter((c) => !c.is_shared);
38875
+ if (unshared.length === 0) {
38876
+ await confirm({
38877
+ message: "All selected conversations are already shared",
38878
+ title: "Info",
38879
+ kind: "alert"
38880
+ });
38881
+ return;
38882
+ }
38883
+ const noun = ui.getEntityLabel("CONVERSATION", unshared.length > 1 ? "PLURAL" : "SINGULAR");
38884
+ const confirmed = await confirm({
38885
+ message: `Are you sure you want to share ${unshared.length} ${noun.toLowerCase()} with everyone in the current ${ui.getEntityLabel("WORKSPACE").toLowerCase()}? You can make them private again later.`,
38886
+ title: `Share ${ui.getEntityLabel("CONVERSATION", "PLURAL")}`
38887
+ });
38888
+ if (!confirmed) return;
38889
+ try {
38890
+ await Promise.all(
38891
+ unshared.map(
38892
+ (c) => updateConversation.mutateAsync({ conversationId: c.external_id, patch: { shared: true } })
38893
+ )
38894
+ );
38895
+ notify18(`${unshared.length} ${noun.toLowerCase()} shared successfully`, "success");
38896
+ } catch (error) {
38897
+ console.error("Failed to share conversations:", error);
38898
+ notify18("Failed to share some conversations", "error");
38899
+ }
38900
+ };
38901
+ const { data: workspaceDocs } = react.useDocuments();
38902
+ const outputsByTask = React9.useMemo(() => {
38903
+ const out = {};
38904
+ for (const [conversationId, docs] of Object.entries(
38905
+ chunkDWWRLKEZ_cjs.groupOutputsByConversation(workspaceDocs ?? [])
38906
+ )) {
38907
+ out[conversationId] = docs.map((d) => ({
38908
+ id: d.external_id,
38909
+ name: ui.getDocumentTitle(d, d.external_id)
38910
+ }));
38911
+ }
38912
+ return out;
38913
+ }, [workspaceDocs]);
38914
+ const handleOpenOutput = (documentId) => openDocument(documentId);
38915
+ const handleGrantAccess = (task) => act(
38916
+ task,
38917
+ () => runConversation.mutateAsync(task.external_id),
38918
+ `Running \u201C${nameOf(task)}\u201D`,
38919
+ "Failed to run task"
38920
+ );
38921
+ const threadLabels = useThreadLabels(canEditShared);
38922
+ const selectionActions = (selected, isCompact) => {
38923
+ const mine = selected.every((c) => c.created_by_ext_id === currentUserExtId);
38924
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
38925
+ mode === "threads" && selected.every((row2) => row2.is_owner || row2.is_shared && canEditShared) && selected.some((row2) => row2.status !== "done") && !selected.some((row2) => row2.in_progress || row2.status === "generating") && /* @__PURE__ */ jsxRuntime.jsx(
38926
+ chunkV4ISCZJ7_cjs.SelectionBarAction,
38927
+ {
38928
+ icon: lucideReact.CheckCheck,
38929
+ label: "Mark Done",
38930
+ onClick: () => void handleMarkDoneMany(selected),
38931
+ isCompact,
38932
+ testId: "threads-bulk-done"
38933
+ }
38934
+ ),
38935
+ threadLabels.renderBulkLabels(selected, isCompact),
38936
+ mine && selected.some((c) => !c.is_shared) && /* @__PURE__ */ jsxRuntime.jsx(
38937
+ ui.VisibilityToggle,
38938
+ {
38939
+ items: selected,
38940
+ onToggle: () => void handleBulkShare(selected),
38941
+ disablePrivate: true,
38942
+ showLabel: false,
38943
+ tooltipInactive: "Share all with workspace members",
38944
+ tooltipMixed: "Share all with workspace members (some already shared)",
38945
+ "data-testid": "bulk-shared-toggle"
38946
+ }
38947
+ ),
38948
+ /* @__PURE__ */ jsxRuntime.jsx(
38949
+ chunkV4ISCZJ7_cjs.SelectionBarAction,
38950
+ {
38951
+ icon: lucideReact.FolderUp,
38952
+ label: "Export",
38953
+ onClick: () => {
38954
+ setExportRows(selected);
38955
+ setIsExportOpen(true);
38956
+ },
38957
+ isCompact,
38958
+ tooltip: `Export the selected ${ui.getEntityLabel("CONVERSATION", "PLURAL").toLowerCase()} to another ${ui.getEntityLabel("WORKSPACE").toLowerCase()}`,
38959
+ testId: "export-chats-button"
38960
+ }
38961
+ ),
38962
+ mode === "threads" && selected.every((row2) => row2.is_owner || isWorkspaceOwner) && /* @__PURE__ */ jsxRuntime.jsx(
38963
+ chunkV4ISCZJ7_cjs.SelectionBarAction,
38964
+ {
38965
+ icon: lucideReact.Trash2,
38966
+ label: "Delete",
38967
+ className: "text-red-text hover:bg-red-bg hover:text-red-text",
38968
+ onClick: () => void handleDeleteMany(selected),
38969
+ isCompact,
38970
+ testId: "threads-bulk-delete"
38971
+ }
38972
+ )
38973
+ ] });
38974
+ };
38975
+ const page = /* @__PURE__ */ jsxRuntime.jsxs(
38976
+ "div",
38977
+ {
38978
+ className: "flex h-full min-h-0 flex-col",
38979
+ "data-testid": mode === "tasks" ? "tasks-page" : "threads-page",
38980
+ children: [
38981
+ /* @__PURE__ */ jsxRuntime.jsx("main", { className: "flex min-h-0 flex-1 flex-col bg-background", children: mode === "threads" ? /* @__PURE__ */ jsxRuntime.jsx(
38982
+ chunkO3MRE2HL_cjs.ConversationListView,
38983
+ {
38984
+ showHeader,
38985
+ conversations: tasks,
38986
+ doneFilter,
38987
+ visibilityFilters,
38988
+ meetingFilter,
38989
+ renderThread: (row2) => /* @__PURE__ */ jsxRuntime.jsx(
38990
+ ConversationEntity,
38991
+ {
38992
+ conversation: row2,
38993
+ showRePrefix: false,
38994
+ labelMaxWidth: "max-w-full",
38995
+ className: "w-full max-w-full [&_.truncate]:line-clamp-2 [&_.truncate]:whitespace-normal [&_.truncate]:break-words [&_.truncate]:text-left",
38996
+ "data-testid": `thread-open-${row2.external_id}`
38997
+ }
38998
+ ),
38999
+ renderLabels: threadLabels.renderLabels,
39000
+ labelText: threadLabels.labelText,
39001
+ renderBy: (row2) => /* @__PURE__ */ jsxRuntime.jsx(
39002
+ chunkO3MRE2HL_cjs.ConversationTurnSpeaker,
39003
+ {
39004
+ variant: "icon",
39005
+ role: row2.last_message_role,
39006
+ actor: row2.last_message_actor,
39007
+ currentUserId: currentUserExtId,
39008
+ colorClass: row2.last_message_actor ? ui.getUserAvatarColor(row2.last_message_actor.external_id) : void 0
39009
+ }
39010
+ ),
39011
+ renderStatus: (row2) => /* @__PURE__ */ jsxRuntime.jsx(ConversationStatusCell, { conversation: row2 }),
39012
+ isLoading,
39013
+ filterText: topbarFilterQuery ?? "",
39014
+ formatDate: relativeTime2,
39015
+ onOpen: (c) => openConversation(c.external_id),
39016
+ onRename: openEdit,
39017
+ onDelete: handleDelete,
39018
+ canEditShared,
39019
+ isWorkspaceOwner,
39020
+ selectionActions,
39021
+ footer: /* @__PURE__ */ jsxRuntime.jsx(ConnectedThreadLauncher, { autoFocus: focusLauncher })
39022
+ }
39023
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
39024
+ chunkO3MRE2HL_cjs.TaskInbox,
39025
+ {
39026
+ tasks,
39027
+ isLoading,
39028
+ ...workflowActions,
39029
+ onCreate: openCreate,
39030
+ filterText: topbarFilterQuery ?? "",
39031
+ labels: LIST_LABELS,
39032
+ gridId: "conversation-list-grid-v4",
39033
+ onFilterTextChange: (text2) => setTopbarFilterQuery(text2),
39034
+ outputsByTask,
39035
+ onOpenActivity: (task) => openConversation(task.external_id),
39036
+ formatRelative: relativeTime2,
39037
+ onOpenOutput: handleOpenOutput,
39038
+ busyId,
39039
+ formatDate: ui.formatFriendlyDate,
39040
+ onOpenThread: (conversationId) => openConversation(conversationId),
39041
+ onMarkDone: (task) => setStatus(task, "done", `Marked \u201C${nameOf(task)}\u201D done`),
39042
+ onReopen: (task) => setStatus(task, "todo", `Reopened \u201C${nameOf(task)}\u201D`),
39043
+ people,
39044
+ agentNames,
39045
+ workflowNames,
39046
+ canEditShared,
39047
+ isWorkspaceOwner,
39048
+ renderPerson,
39049
+ onToggleShared: handleToggleShared,
39050
+ onEdit: openEdit,
39051
+ onDelete: handleDelete,
39052
+ onAddSubtask: openAddSubtask,
39053
+ onMove: handleMove,
39054
+ onMarkDoneMany: handleMarkDoneMany,
39055
+ onDeleteMany: handleDeleteMany,
39056
+ onGrantAccess: handleGrantAccess,
39057
+ selectionActions
39058
+ }
39059
+ ) }),
39060
+ /* @__PURE__ */ jsxRuntime.jsx(
39061
+ ConnectedTaskStartDialog,
39062
+ {
39063
+ open: startOpen,
39064
+ onOpenChange: setStartOpen,
39065
+ initialParentId: parentForNew
39066
+ }
39067
+ ),
39068
+ /* @__PURE__ */ jsxRuntime.jsx(ConnectedTaskComposer, { open: editorOpen, onOpenChange: setEditorOpen, task: editing }),
39069
+ /* @__PURE__ */ jsxRuntime.jsx(
39070
+ ConnectedExportDialog,
39071
+ {
39072
+ open: isExportOpen,
39073
+ onOpenChange: setIsExportOpen,
39074
+ items: exportRows.map((c) => ({ extId: c.external_id, label: nameOf(c) })),
39075
+ entityType: "CONVERSATION",
39076
+ testId: "export-chats-modal"
39077
+ }
39078
+ ),
39079
+ /* @__PURE__ */ jsxRuntime.jsx(
39080
+ chunkFEVJA4BP_cjs.RenameDialog,
39081
+ {
39082
+ open: !!renaming,
39083
+ onClose: () => {
39084
+ setRenaming(null);
39085
+ setNewTitle("");
39086
+ },
39087
+ title: `Rename ${ui.getEntityLabel("CONVERSATION")}`,
39088
+ labels: { description: "Rename the conversation title" },
39089
+ fieldLabel: `${ui.getEntityLabel("CONVERSATION")} Title`,
39090
+ placeholder: "Enter title",
39091
+ value: newTitle,
39092
+ onChange: setNewTitle,
39093
+ onSave: handleSaveRename,
39094
+ canSave: !!newTitle.trim(),
39095
+ dialogTestId: RENAME_DIALOG.testId
39096
+ }
39097
+ )
39098
+ ]
39099
+ }
39100
+ );
39101
+ return search ? /* @__PURE__ */ jsxRuntime.jsx(ThreadSearch, { ResultsBoundary, children: page }) : page;
39102
+ }
39103
+ function ConnectedFilterDropdown({
39104
+ stateKey,
39105
+ ...props
39106
+ }) {
39107
+ const [open, setOpen] = react.useTransientView(`filter.dropdown.${stateKey}`, false);
39108
+ return /* @__PURE__ */ jsxRuntime.jsx(
39109
+ chunkAQPZ4QMV_cjs.TriStateFilterMenu,
39110
+ {
39111
+ ...props,
39112
+ testId: `${stateKey}-filter-button`,
39113
+ open,
39114
+ onOpenChange: setOpen
39115
+ }
39116
+ );
39117
+ }
39118
+ function SearchSparkleIcon({ className }) {
39119
+ return /* @__PURE__ */ jsxRuntime.jsxs(
39120
+ "svg",
39121
+ {
39122
+ viewBox: "0 0 24 24",
39123
+ fill: "none",
39124
+ stroke: "currentColor",
39125
+ strokeWidth: "2",
39126
+ strokeLinecap: "round",
39127
+ strokeLinejoin: "round",
39128
+ "aria-hidden": "true",
39129
+ className,
39130
+ children: [
39131
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "10.5", cy: "10.5", r: "7.5" }),
39132
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m21 21-5.2-5.2" }),
39133
+ /* @__PURE__ */ jsxRuntime.jsx(
39134
+ "path",
39135
+ {
39136
+ d: "M10.5 6.8c.35 2.1 1.6 3.35 3.7 3.7-2.1.35-3.35 1.6-3.7 3.7-.35-2.1-1.6-3.35-3.7-3.7 2.1-.35 3.35-1.6 3.7-3.7Z",
39137
+ fill: "currentColor",
39138
+ strokeWidth: "1"
39139
+ }
39140
+ )
39141
+ ]
39142
+ }
39143
+ );
39144
+ }
39145
+ function SemanticSearchButton({ active, onClick }) {
39146
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Tooltip, { children: [
39147
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
39148
+ ui.Button,
39149
+ {
39150
+ type: "button",
39151
+ variant: "ghost",
39152
+ size: "icon",
39153
+ onClick,
39154
+ "aria-label": "Semantic search",
39155
+ "aria-pressed": active,
39156
+ "data-testid": "semantic-search-button",
39157
+ className: active ? "bg-muted text-primary" : "text-muted-foreground hover:text-foreground",
39158
+ children: /* @__PURE__ */ jsxRuntime.jsx(SearchSparkleIcon, { className: "size-5" })
39159
+ }
39160
+ ) }),
39161
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TooltipContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Semantic search" }) })
39162
+ ] });
39163
+ }
39164
+ var DEFAULT_THREAD_VISIBILITY2 = { me: null, workspace: null };
39165
+ function ConnectedConversationPage({
39166
+ renderComposerAccessory,
39167
+ ResultsBoundary,
39168
+ onGoToDocuments,
39169
+ modelSelector,
39170
+ composerAccessory,
39171
+ composerTools,
39172
+ ConversationThread: ConversationThread2
39173
+ }) {
39174
+ const session = react.useArbiSessionStore();
39175
+ const { openFiles } = chunkB3NYBMDR_cjs.useBlocksEnvironment();
39176
+ React9.useEffect(() => () => session.setActiveCitationKey(null), [session]);
39177
+ const { isInChat, setActiveTab } = useThreadTabs();
39178
+ const [doneFilter, setDoneFilter] = react.useTransientView(
39179
+ "threads.done",
39180
+ "exclude"
39181
+ );
39182
+ const [visibilityFilters, setVisibilityFilters] = react.useTransientView(
39183
+ "threads.visibility",
39184
+ DEFAULT_THREAD_VISIBILITY2
39185
+ );
39186
+ const [meetingFilter, setMeetingFilter] = react.useTransientView(
39187
+ "threads.meetings",
39188
+ null
39189
+ );
39190
+ const [threadFilter, setThreadFilter] = react.useTransientView("topbar.filter", "");
39191
+ const { data: userSettings } = react.useUserSettings();
39192
+ const isDeveloper = userSettings?.developer === true;
39193
+ const showPaMode = userSettings?.show_pa_mode ?? false;
39194
+ const searchEnabled = userSettings?.show_conversation_search === true;
39195
+ const [semanticSearchOpen, setSemanticSearchOpen] = React9.useState(false);
39196
+ const handleSelectSource = (source) => {
39197
+ if (source === "internet") {
39198
+ setUrlDialogOpen(true);
39199
+ return;
39200
+ }
39201
+ chunkB3NYBMDR_cjs.openDialog("upload", { tab: "upload", source });
39202
+ };
39203
+ const handleGoToDocuments = () => {
39204
+ chunkB3NYBMDR_cjs.closeDialog("conversationDocuments");
39205
+ if (onGoToDocuments) onGoToDocuments();
39206
+ else openFiles();
39207
+ };
39208
+ const handleStatusClick = () => {
39209
+ chunkB3NYBMDR_cjs.openDialog("conversationDocuments");
39210
+ };
39211
+ const currentConversationId = react.useArbiSessionState((state) => state.conversationId);
39212
+ const { conversations: taskItems } = react.useConversationItems();
39213
+ const conversations = taskItems;
39214
+ const workspaceId = react.useArbiSessionState((state) => state.workspaceId);
39215
+ const { data: workspaces = [] } = react.useWorkspaces();
39216
+ const workspace = workspaces.find((item) => item.external_id === workspaceId);
39217
+ const workspaceRole = react.useWorkspaceRole();
39218
+ const isGuest = workspaceRole === "guest";
39219
+ const canUpload = workspaceRole !== null && !isGuest;
39220
+ const [urlDialogOpen, setUrlDialogOpen] = React9.useState(false);
39221
+ const [focusLauncher, setFocusLauncher] = React9.useState(false);
39222
+ React9.useEffect(() => {
39223
+ if (isInChat) setFocusLauncher(false);
39224
+ }, [isInChat]);
39225
+ const uploadUrls = useAddFromUrls({
39226
+ onZipFiles: (files) => chunkB3NYBMDR_cjs.openDialog("upload", { tab: "upload", files, source: "computer" })
39227
+ });
39228
+ const uploadDisabledReason = isGuest ? "Guests cannot upload documents in this workspace" : "You cannot upload to this workspace";
39229
+ const { data: allWorkspaceDocuments = [] } = react.useDocuments();
39230
+ const { data: conversationDocuments } = react.useConversationDocuments();
39231
+ const pinnedDocumentId = react.useArbiSessionState((state) => state.pinnedDocumentId);
39232
+ const pinnedRef = artifacts.parseVersionRef(pinnedDocumentId);
39233
+ const pinnedDocument = conversationDocuments?.find((d) => d.external_id === pinnedRef.docId) ?? allWorkspaceDocuments?.find((d) => d.external_id === pinnedRef.docId);
39234
+ const pinnedTitle = pinnedDocument ? `${ui.getDocumentTitle(pinnedDocument)}${pinnedRef.version ? ` (version ${pinnedRef.version})` : ""}` : null;
39235
+ const startNewChat = (asPaChat) => {
39236
+ session.clearConversationError(currentConversationId || "new");
39237
+ session.startNewConversation();
39238
+ session.openThreadTab(null);
39239
+ session.setPaMode(true);
39240
+ };
39241
+ const threadFilterDropdown = /* @__PURE__ */ jsxRuntime.jsx(
39242
+ ConnectedFilterDropdown,
39243
+ {
39244
+ stateKey: "threads",
39245
+ filterStates: /* @__PURE__ */ new Map([
39246
+ ["done", doneFilter],
39247
+ ["me", visibilityFilters.me],
39248
+ ["workspace", visibilityFilters.workspace],
39249
+ ["meeting", meetingFilter]
39250
+ ]),
39251
+ onFiltersChange: (filters) => {
39252
+ setDoneFilter(filters.get("done") ?? null);
39253
+ setMeetingFilter(filters.get("meeting") ?? null);
39254
+ setVisibilityFilters({
39255
+ me: filters.get("me") ?? null,
39256
+ workspace: filters.get("workspace") ?? null
39257
+ });
39258
+ },
39259
+ options: [
39260
+ {
39261
+ id: "me",
39262
+ label: "Only Me",
39263
+ count: conversations.filter((thread) => !thread.is_shared).length
39264
+ },
39265
+ {
39266
+ id: "workspace",
39267
+ label: "Workspace",
39268
+ count: conversations.filter((thread) => thread.is_shared).length
39269
+ },
39270
+ {
39271
+ id: "meeting",
39272
+ label: "Meetings",
39273
+ count: conversations.filter((thread) => !!thread.meeting_call_ext_id).length
39274
+ },
39275
+ {
39276
+ id: "done",
39277
+ label: "Done",
39278
+ count: conversations.filter((thread) => thread.status === "done").length
39279
+ }
39280
+ ],
39281
+ hasExternalActiveState: Boolean(threadFilter.trim()),
39282
+ renderChevron: true,
39283
+ disableHoverOpen: true,
39284
+ align: "start"
39285
+ }
39286
+ );
39287
+ const threadFilterBox = /* @__PURE__ */ jsxRuntime.jsx(
39288
+ chunk2EI7NCUA_cjs.FilterInput,
39289
+ {
39290
+ filter: threadFilterDropdown,
39291
+ borderless: true,
39292
+ value: threadFilter,
39293
+ onChange: setThreadFilter,
39294
+ fields: ["text"],
39295
+ onFieldsChange: () => {
39296
+ },
39297
+ hideFieldPicker: true,
39298
+ ariaLabel: "Filter threads",
39299
+ labels: doneFilter === "exclude" ? { placeholder: "Done hidden" } : void 0,
39300
+ className: "w-44 max-w-[40vw]"
39301
+ }
39302
+ );
39303
+ const { data: workspaceTags = [] } = react.useTags();
39304
+ const historyCount = chunkO3MRE2HL_cjs.filterConversationRows(
39305
+ conversations,
39306
+ threadFilter,
39307
+ (row2) => workspaceTags.filter((tag) => row2.label_ext_ids?.includes(tag.external_id)).map((tag) => tag.name).join(" "),
39308
+ doneFilter,
39309
+ visibilityFilters,
39310
+ meetingFilter
39311
+ ).length;
39312
+ const historyFiltered = Boolean(threadFilter.trim()) || doneFilter !== null || meetingFilter !== null || Object.values(visibilityFilters).some(Boolean);
39313
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
39314
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkDWWRLKEZ_cjs.ConversationRoot, { children: [
39315
+ /* @__PURE__ */ jsxRuntime.jsxs(chunkDWWRLKEZ_cjs.ConversationHeader, { children: [
39316
+ /* @__PURE__ */ jsxRuntime.jsx(
39317
+ ConnectedThreadTabs,
39318
+ {
39319
+ historyCount,
39320
+ historyFiltered,
39321
+ historyActions: threadFilterBox,
39322
+ rightContent: (isCompact) => /* @__PURE__ */ jsxRuntime.jsxs(chunkDWWRLKEZ_cjs.ConversationHeaderActions, { children: [
39323
+ searchEnabled && /* @__PURE__ */ jsxRuntime.jsx(
39324
+ SemanticSearchButton,
39325
+ {
39326
+ active: semanticSearchOpen && !isInChat,
39327
+ onClick: () => {
39328
+ if (isInChat) {
39329
+ setActiveTab("history");
39330
+ setSemanticSearchOpen(true);
39331
+ } else {
39332
+ setSemanticSearchOpen((open) => !open);
39333
+ }
39334
+ }
39335
+ }
39336
+ ),
39337
+ isInChat && /* @__PURE__ */ jsxRuntime.jsx(chunk5R256EMF_cjs.ConnectedConversationCallActions, {}),
39338
+ isInChat && /* @__PURE__ */ jsxRuntime.jsx(
39339
+ chunkDWWRLKEZ_cjs.NewChatButton,
39340
+ {
39341
+ entityLabel: "Task",
39342
+ labels: { newEntity: () => "New Task" },
39343
+ isCompact,
39344
+ onClick: () => {
39345
+ setFocusLauncher(true);
39346
+ setActiveTab("history");
39347
+ }
39348
+ }
39349
+ ),
39350
+ showPaMode && /* @__PURE__ */ jsxRuntime.jsx(chunkDWWRLKEZ_cjs.NewPaChatButton, { isCompact, onClick: () => startNewChat() })
39351
+ ] })
39352
+ }
39353
+ ),
39354
+ isInChat && /* @__PURE__ */ jsxRuntime.jsx(ConnectedThreadTaskBar, { conversationId: currentConversationId })
39355
+ ] }),
39356
+ isInChat && /* @__PURE__ */ jsxRuntime.jsx(
39357
+ ConversationThread2,
39358
+ {
39359
+ modelSelector,
39360
+ composerAccessory: renderComposerAccessory ? renderComposerAccessory({
39361
+ documents: conversationDocuments || [],
39362
+ pinnedTitle,
39363
+ onStatusClick: handleStatusClick,
39364
+ onSelectSource: handleSelectSource,
39365
+ onAddFromSources: handleGoToDocuments,
39366
+ canUpload,
39367
+ uploadDisabledReason
39368
+ }) : composerAccessory,
39369
+ composerTools: composerTools !== void 0 ? composerTools : isDeveloper && /* @__PURE__ */ jsxRuntime.jsx(
39370
+ chunkDWWRLKEZ_cjs.ConversationSettingsButton,
39371
+ {
39372
+ label: `${ui.getEntityLabel("CONVERSATION")} Settings`,
39373
+ onClick: () => chunkB3NYBMDR_cjs.openDialog("conversationSettings")
39374
+ }
39375
+ )
39376
+ }
39377
+ ),
39378
+ !isInChat && /* @__PURE__ */ jsxRuntime.jsx(chunkDWWRLKEZ_cjs.ConversationHistoryPane, { children: searchEnabled && semanticSearchOpen ? /* @__PURE__ */ jsxRuntime.jsx(ConnectedThreadsPage, { showHeader: false, search: true, ResultsBoundary }) : /* @__PURE__ */ jsxRuntime.jsx(ConnectedThreadsPage, { showHeader: false, focusLauncher }) })
39379
+ ] }),
39380
+ /* @__PURE__ */ jsxRuntime.jsx(
39381
+ chunkWALADS2S_cjs.UrlInputDialog,
39382
+ {
39383
+ open: urlDialogOpen,
39384
+ onOpenChange: setUrlDialogOpen,
39385
+ onUrlsSubmit: uploadUrls,
39386
+ titleWorkspaceName: workspace?.name,
39387
+ titleIcon: workspace && /* @__PURE__ */ jsxRuntime.jsx(ConnectedWorkspaceEntity, { workspace, size: 24, variant: "icon" })
39388
+ }
39389
+ )
39390
+ ] });
39391
+ }
37701
39392
  function useStartRequestedDraft(enabled = true) {
37702
39393
  const session = react.useArbiSessionStore();
37703
39394
  chunkB3NYBMDR_cjs.useIntentRequest(
@@ -38288,7 +39979,7 @@ function useThreadScroll({
38288
39979
  scrollToBottom
38289
39980
  };
38290
39981
  }
38291
- function ConnectedConversation({
39982
+ function ConversationThread({
38292
39983
  modelSelector,
38293
39984
  composerAccessory,
38294
39985
  composerTools
@@ -38388,7 +40079,7 @@ function ConnectedConversation({
38388
40079
  const isGuest = react.useWorkspaceRole() === "guest";
38389
40080
  const meetingReadOnly = isGuest && !!currentTask?.meeting_call_ext_id;
38390
40081
  const meetingCallExtId = currentTask?.meeting_call_ext_id ?? null;
38391
- const threadMessages = chunk6AJJJ5HR_cjs.useMeetingThreadMessages(meetingCallExtId, messageHistory);
40082
+ const threadMessages = chunk5R256EMF_cjs.useMeetingThreadMessages(meetingCallExtId, messageHistory);
38392
40083
  const [firstTurnPrompt, setFirstTurnPrompt] = React9.useState(null);
38393
40084
  const currentUserExtId = react.useArbiSession().user?.external_id ?? "";
38394
40085
  const pendingFirstTurn = React9.useMemo(
@@ -38436,7 +40127,7 @@ function ConnectedConversation({
38436
40127
  return shownThreadMessages.slice(0, editIndex);
38437
40128
  }, [shownThreadMessages, editingMessageId]);
38438
40129
  const transcriptRunInfo = React9.useMemo(
38439
- () => chunk6AJJJ5HR_cjs.threadTranscriptRuns(meetingCallExtId ? visibleMessages : []),
40130
+ () => chunk5R256EMF_cjs.threadTranscriptRuns(meetingCallExtId ? visibleMessages : []),
38440
40131
  [meetingCallExtId, visibleMessages]
38441
40132
  );
38442
40133
  const threadLines = React9.useMemo(
@@ -38451,7 +40142,7 @@ function ConnectedConversation({
38451
40142
  }),
38452
40143
  [threadMessages]
38453
40144
  );
38454
- const provisionalSpeakers = chunk6AJJJ5HR_cjs.useProvisionalSpeakers(meetingCallExtId, threadLines);
40145
+ const provisionalSpeakers = chunk5R256EMF_cjs.useProvisionalSpeakers(meetingCallExtId, threadLines);
38455
40146
  const showProvisional = !!meetingCallExtId && meetingView !== "chat";
38456
40147
  const latestContextUsage = React9.useMemo(() => {
38457
40148
  const messages = messageHistory;
@@ -38590,7 +40281,7 @@ function ConnectedConversation({
38590
40281
  useStartRequestedDraft();
38591
40282
  const orphanedMessage = react.getOrphanedLastMessage(messageHistory, isGenerating, assistantMode);
38592
40283
  return /* @__PURE__ */ jsxRuntime.jsxs(chunkDWWRLKEZ_cjs.ConversationBody, { children: [
38593
- /* @__PURE__ */ jsxRuntime.jsx(chunkDWWRLKEZ_cjs.ConversationMain, { "data-testid": `conversation-${currentConversationId}`, children: threadsLoading ? /* @__PURE__ */ jsxRuntime.jsx(chunkDWWRLKEZ_cjs.ConversationLoading, {}) : messageHistory.length > 0 || isBranching ? /* @__PURE__ */ jsxRuntime.jsx(AskAgainContext.Provider, { value: handleAskAgain, children: /* @__PURE__ */ jsxRuntime.jsxs(chunk6AJJJ5HR_cjs.TranscriptRunsContext.Provider, { value: transcriptRunInfo, children: [
40284
+ /* @__PURE__ */ jsxRuntime.jsx(chunkDWWRLKEZ_cjs.ConversationMain, { "data-testid": `conversation-${currentConversationId}`, children: threadsLoading ? /* @__PURE__ */ jsxRuntime.jsx(chunkDWWRLKEZ_cjs.ConversationLoading, {}) : messageHistory.length > 0 || isBranching ? /* @__PURE__ */ jsxRuntime.jsx(AskAgainContext.Provider, { value: handleAskAgain, children: /* @__PURE__ */ jsxRuntime.jsxs(chunk5R256EMF_cjs.TranscriptRunsContext.Provider, { value: transcriptRunInfo, children: [
38594
40285
  meetingCallExtId && transcriptLineCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center py-2", children: /* @__PURE__ */ jsxRuntime.jsx(
38595
40286
  chunkNXHETIOB_cjs.ConversationFilter,
38596
40287
  {
@@ -38609,12 +40300,12 @@ function ConnectedConversation({
38609
40300
  }
38610
40301
  ) }),
38611
40302
  /* @__PURE__ */ jsxRuntime.jsx(ConnectedMessageArea, { ref: containerRef, messages: visibleMessages }),
38612
- showProvisional && /* @__PURE__ */ jsxRuntime.jsx(chunk6AJJJ5HR_cjs.ProvisionalSpeakers, { ids: provisionalSpeakers })
40303
+ showProvisional && /* @__PURE__ */ jsxRuntime.jsx(chunk5R256EMF_cjs.ProvisionalSpeakers, { ids: provisionalSpeakers })
38613
40304
  ] }) }) : meetingCallExtId ? (
38614
40305
  // A meeting thread with nothing yet: call-aware, not the upload prompt.
38615
40306
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
38616
- /* @__PURE__ */ jsxRuntime.jsx(chunk6AJJJ5HR_cjs.CallConversationEmpty, { callExtId: meetingCallExtId }),
38617
- /* @__PURE__ */ jsxRuntime.jsx(chunk6AJJJ5HR_cjs.ProvisionalSpeakers, { ids: provisionalSpeakers })
40307
+ /* @__PURE__ */ jsxRuntime.jsx(chunk5R256EMF_cjs.CallConversationEmpty, { callExtId: meetingCallExtId }),
40308
+ /* @__PURE__ */ jsxRuntime.jsx(chunk5R256EMF_cjs.ProvisionalSpeakers, { ids: provisionalSpeakers })
38618
40309
  ] })
38619
40310
  ) : currentTask && currentTask.status != null ? /* @__PURE__ */ jsxRuntime.jsx(chunkO3MRE2HL_cjs.TaskEmptyState, { task: currentTask }) : pendingFirstTurn && isGenerating ? /* @__PURE__ */ jsxRuntime.jsx(ConnectedMessageArea, { ref: containerRef, messages: pendingFirstTurn }) : /* @__PURE__ */ jsxRuntime.jsx(
38620
40311
  ConnectedConversationEmpty,
@@ -38744,6 +40435,33 @@ function ConnectedConversation({
38744
40435
  slashWorkflows.launcher
38745
40436
  ] });
38746
40437
  }
40438
+ function ConnectedConversation({
40439
+ layout = "thread",
40440
+ page,
40441
+ conversationId,
40442
+ ...props
40443
+ }) {
40444
+ const session = react.useArbiSessionStore();
40445
+ React9.useEffect(() => {
40446
+ if (conversationId === void 0) return;
40447
+ if (layout === "page") {
40448
+ const tabId = conversationId ?? "new";
40449
+ if (session.getState().activeThreadTabId !== tabId) session.openThreadTab(conversationId);
40450
+ } else if (session.getState().conversationId !== conversationId) {
40451
+ session.setConversationId(conversationId);
40452
+ }
40453
+ }, [conversationId, layout, session]);
40454
+ return layout === "page" ? /* @__PURE__ */ jsxRuntime.jsx(
40455
+ ConnectedConversationPage,
40456
+ {
40457
+ ...page,
40458
+ modelSelector: props.modelSelector,
40459
+ composerAccessory: props.composerAccessory,
40460
+ composerTools: props.composerTools,
40461
+ ConversationThread
40462
+ }
40463
+ ) : /* @__PURE__ */ jsxRuntime.jsx(ConversationThread, { ...props });
40464
+ }
38747
40465
  function ConnectedCompactConversation() {
38748
40466
  const containerRef = React9.useRef(null);
38749
40467
  const inputRef = React9.useRef(null);
@@ -41506,474 +43224,6 @@ function ConnectedAccountAccessBadge() {
41506
43224
  /* @__PURE__ */ jsxRuntime.jsx(ui.PopoverContent, { className: "max-w-xs text-sm", align: "end", children: explanation })
41507
43225
  ] });
41508
43226
  }
41509
- function ThreadSearch({ children, ResultsBoundary = chunkTM2D4XT4_cjs.ErrorBoundary }) {
41510
- const [query, setQuery] = React9.useState("");
41511
- const [submitted, setSubmitted] = React9.useState("");
41512
- const selectedWorkspaceId = react.useArbiSessionState((s) => s.workspaceId);
41513
- const { notify: notify18, openConversation } = chunkB3NYBMDR_cjs.useBlocksEnvironment();
41514
- const search = react.useConversationSearch();
41515
- const isSearching = search.isPending;
41516
- const groups = React9.useMemo(
41517
- () => search.isError ? [] : (search.data?.results ?? []).map((g) => ({
41518
- id: g.conversation_ext_id,
41519
- title: g.title,
41520
- matches: g.messages.map((m) => ({
41521
- id: m.message_ext_id,
41522
- role: m.role,
41523
- score: m.score,
41524
- snippet: m.snippet
41525
- }))
41526
- })),
41527
- [search.data, search.isError]
41528
- );
41529
- const handleSearch = React9.useCallback(() => {
41530
- const q = query.trim();
41531
- if (!q || !selectedWorkspaceId || isSearching) return;
41532
- setSubmitted(q);
41533
- search.mutate(
41534
- { query: q, search_mode: "hybrid", limit: 20 },
41535
- {
41536
- onError: (err) => {
41537
- console.error("Conversation search failed", err);
41538
- notify18("Conversation search failed", "error");
41539
- }
41540
- }
41541
- );
41542
- }, [query, selectedWorkspaceId, isSearching, search, notify18]);
41543
- const clearSearch = React9.useCallback(() => {
41544
- setQuery("");
41545
- setSubmitted("");
41546
- }, []);
41547
- const openHit = React9.useCallback(
41548
- (conversationId, messageId) => {
41549
- openConversation(conversationId, messageId ? { messageId } : void 0);
41550
- },
41551
- [openConversation]
41552
- );
41553
- return /* @__PURE__ */ jsxRuntime.jsx(
41554
- chunkDWWRLKEZ_cjs.ConversationSearchView,
41555
- {
41556
- query,
41557
- onQueryChange: setQuery,
41558
- onSubmit: handleSearch,
41559
- canSubmit: !!query.trim() && !!selectedWorkspaceId && !isSearching,
41560
- isSearching,
41561
- submittedQuery: submitted,
41562
- groups,
41563
- onOpenConversation: openHit,
41564
- onClear: clearSearch,
41565
- ResultsBoundary,
41566
- children
41567
- }
41568
- );
41569
- }
41570
- var DEFAULT_THREAD_VISIBILITY = { me: null, workspace: null };
41571
- var relativeTime2 = (iso) => ui.formatRelativeTime(iso, { style: "short" });
41572
- var LIST_LABELS = {
41573
- emptyTitle: "Nothing here yet",
41574
- emptyMessage: "Use New: just type what you need, or fill in an owner and a due date. You always decide when a thread is done.",
41575
- untitled: `Untitled ${ui.getEntityLabel("CONVERSATION").toLowerCase()}`,
41576
- noMatches: `No ${ui.getEntityLabel("CONVERSATION", "PLURAL").toLowerCase()} match.`,
41577
- selectAll: "Select all"
41578
- };
41579
- var RENAME_DIALOG = { testId: "rename-conversation-modal" };
41580
- function useStableRecencyOrder(rows) {
41581
- const orderRef = React9.useRef([]);
41582
- return React9.useMemo(() => {
41583
- const byRecency = [...rows].sort(
41584
- (a, b) => new Date(b.updated_at || b.created_at || 0).getTime() - new Date(a.updated_at || a.created_at || 0).getTime()
41585
- );
41586
- const present = new Set(byRecency.map((r) => r.external_id));
41587
- const known = new Set(orderRef.current);
41588
- const added = byRecency.map((r) => r.external_id).filter((id) => !known.has(id));
41589
- orderRef.current = [...added, ...orderRef.current.filter((id) => present.has(id))];
41590
- const byId = new Map(byRecency.map((r) => [r.external_id, r]));
41591
- return orderRef.current.flatMap((id) => byId.get(id) ?? []);
41592
- }, [rows]);
41593
- }
41594
- function ConnectedThreadsPage({
41595
- showHeader = true,
41596
- search = false,
41597
- ResultsBoundary,
41598
- focusLauncher,
41599
- layout = "list",
41600
- workflowActions
41601
- }) {
41602
- const mode = layout === "inbox" ? "tasks" : "threads";
41603
- const { confirm, notify: notify18, openConversation, openDocument } = chunkB3NYBMDR_cjs.useBlocksEnvironment();
41604
- const { conversations: all, isLoading } = react.useConversationItems();
41605
- const [doneFilter] = react.useTransientView("threads.done", "exclude");
41606
- const [visibilityFilters] = react.useTransientView("threads.visibility", DEFAULT_THREAD_VISIBILITY);
41607
- const [meetingFilter] = react.useTransientView("threads.meetings", null);
41608
- const [topbarFilterQuery, setTopbarFilterQuery] = react.useTransientView("topbar.filter", "");
41609
- const currentUserExtId = react.useArbiSession().user?.external_id;
41610
- const listed = React9.useMemo(
41611
- () => all.filter((c) => mode === "threads" || c.status != null),
41612
- [all, mode]
41613
- );
41614
- const tasks = useStableRecencyOrder(listed);
41615
- const updateConversation = react.useUpdateConversation();
41616
- const deleteConversation = react.useDeleteConversation();
41617
- const people = useTaskPeople();
41618
- const renderPerson = useRenderTaskPerson();
41619
- const canEditShared = react.useCanEditShared();
41620
- const isWorkspaceOwner = react.useIsWorkspaceOwner();
41621
- const { data: agents = [] } = react.useAgents();
41622
- const { data: workflows = [] } = react.useWorkflows();
41623
- const agentNames = React9.useMemo(
41624
- () => Object.fromEntries(agents.map((a) => [a.external_id, a.given_name || a.email])),
41625
- [agents]
41626
- );
41627
- const workflowNames = React9.useMemo(
41628
- () => Object.fromEntries(workflows.map((w) => [w.external_id, w.name])),
41629
- [workflows]
41630
- );
41631
- const runConversation = react.useRunConversation();
41632
- const [busyId, setBusyId] = React9.useState(null);
41633
- const [editorOpen, setEditorOpen] = React9.useState(false);
41634
- const [editing, setEditing] = React9.useState(null);
41635
- const [startOpen, setStartOpen] = React9.useState(false);
41636
- const [parentForNew, setParentForNew] = React9.useState(void 0);
41637
- const nameOf = (task) => task.title?.trim() || task.workflow_ext_id && workflowNames[task.workflow_ext_id] || "Untitled task";
41638
- const openCreate = () => {
41639
- setParentForNew(void 0);
41640
- setStartOpen(true);
41641
- };
41642
- const openAddSubtask = (parent) => {
41643
- setParentForNew(parent.external_id);
41644
- setStartOpen(true);
41645
- };
41646
- const [renaming, setRenaming] = React9.useState(null);
41647
- const [newTitle, setNewTitle] = React9.useState("");
41648
- const [isExportOpen, setIsExportOpen] = React9.useState(false);
41649
- const [exportRows, setExportRows] = React9.useState([]);
41650
- const openEdit = (task) => {
41651
- if (mode === "threads" || !task.status) {
41652
- setRenaming(task);
41653
- setNewTitle(task.title ?? "");
41654
- return;
41655
- }
41656
- setEditing(task);
41657
- setEditorOpen(true);
41658
- };
41659
- const act = async (task, action, success, failure) => {
41660
- setBusyId(task.external_id);
41661
- try {
41662
- await action();
41663
- if (success) notify18(success, "success");
41664
- } catch (error) {
41665
- notify18(
41666
- error instanceof browser.ArbiApiError && error.detail ? `${failure}: ${error.detail}` : failure,
41667
- "error"
41668
- );
41669
- } finally {
41670
- setBusyId(null);
41671
- }
41672
- };
41673
- const patch = (task, body) => updateConversation.mutateAsync({ conversationId: task.external_id, patch: body });
41674
- const setStatus = (task, status, success) => act(task, () => patch(task, { status }), success, "Failed to update task");
41675
- const handleToggleShared = (task, shouldShare) => act(
41676
- task,
41677
- () => patch(task, { shared: shouldShare }),
41678
- shouldShare ? `Shared \u201C${nameOf(task)}\u201D with the workspace` : `Made \u201C${nameOf(task)}\u201D private`,
41679
- "Failed to change who can see the task"
41680
- );
41681
- const handleMove = (task, parentId) => act(
41682
- task,
41683
- () => patch(task, { parent_conversation_ext_id: parentId }),
41684
- parentId ? `Moved \u201C${nameOf(task)}\u201D` : `Moved \u201C${nameOf(task)}\u201D to the top level`,
41685
- "Failed to move task"
41686
- );
41687
- const handleDelete = async (task) => {
41688
- const subtasks = tasks.filter((t) => t.parent_conversation_ext_id === task.external_id).length;
41689
- const confirmed = await confirm({
41690
- message: `Delete \u201C${nameOf(task)}\u201D? This can't be undone from here.${subtasks ? ` Its ${subtasks === 1 ? "sub-task stays" : `${subtasks} sub-tasks stay`} and ${subtasks === 1 ? "moves" : "move"} to the top level.` : ""}`,
41691
- title: "Delete task"
41692
- });
41693
- if (!confirmed) return;
41694
- await act(
41695
- task,
41696
- () => deleteConversation.mutateAsync(task.external_id),
41697
- `Deleted \u201C${nameOf(task)}\u201D`,
41698
- "Failed to delete task"
41699
- );
41700
- };
41701
- const forEach = async (rows, one, done) => {
41702
- let failed = 0;
41703
- for (const task of rows) {
41704
- try {
41705
- await one(task);
41706
- } catch {
41707
- failed += 1;
41708
- }
41709
- }
41710
- notify18(
41711
- failed ? `${failed} of ${rows.length} could not be changed: you may not be allowed to change them` : done,
41712
- failed ? "error" : "success"
41713
- );
41714
- };
41715
- const handleMarkDoneMany = (rows) => forEach(rows, (task) => patch(task, { status: "done" }), `Marked ${rows.length} done`);
41716
- const handleDeleteMany = async (rows) => {
41717
- const named = rows.slice(0, 3).map((task) => `"${nameOf(task)}"`).join(", ");
41718
- const more = rows.length - 3;
41719
- const confirmed = await confirm({
41720
- message: `Delete ${more > 0 ? `${named} and ${more} more` : named}? This cannot be undone.`,
41721
- title: `Delete ${rows.length} item${rows.length === 1 ? "" : "s"}`
41722
- });
41723
- if (!confirmed) return;
41724
- await forEach(
41725
- rows,
41726
- (task) => deleteConversation.mutateAsync(task.external_id),
41727
- `Deleted ${rows.length}`
41728
- );
41729
- };
41730
- const handleSaveRename = React9.useCallback(() => {
41731
- if (!renaming || !newTitle.trim()) return;
41732
- updateConversation.mutate(
41733
- { conversationId: renaming.external_id, patch: { title: newTitle.trim() } },
41734
- {
41735
- onSuccess: () => {
41736
- notify18("Conversation renamed successfully", "success");
41737
- setRenaming(null);
41738
- setNewTitle("");
41739
- },
41740
- onError: (error) => {
41741
- console.error("Failed to rename conversation:", error);
41742
- notify18("Failed to rename conversation", "error");
41743
- }
41744
- }
41745
- );
41746
- }, [renaming, newTitle, updateConversation, notify18]);
41747
- const handleBulkShare = async (rows) => {
41748
- const unshared = rows.filter((c) => !c.is_shared);
41749
- if (unshared.length === 0) {
41750
- await confirm({
41751
- message: "All selected conversations are already shared",
41752
- title: "Info",
41753
- kind: "alert"
41754
- });
41755
- return;
41756
- }
41757
- const noun = ui.getEntityLabel("CONVERSATION", unshared.length > 1 ? "PLURAL" : "SINGULAR");
41758
- const confirmed = await confirm({
41759
- message: `Are you sure you want to share ${unshared.length} ${noun.toLowerCase()} with everyone in the current ${ui.getEntityLabel("WORKSPACE").toLowerCase()}? You can make them private again later.`,
41760
- title: `Share ${ui.getEntityLabel("CONVERSATION", "PLURAL")}`
41761
- });
41762
- if (!confirmed) return;
41763
- try {
41764
- await Promise.all(
41765
- unshared.map(
41766
- (c) => updateConversation.mutateAsync({ conversationId: c.external_id, patch: { shared: true } })
41767
- )
41768
- );
41769
- notify18(`${unshared.length} ${noun.toLowerCase()} shared successfully`, "success");
41770
- } catch (error) {
41771
- console.error("Failed to share conversations:", error);
41772
- notify18("Failed to share some conversations", "error");
41773
- }
41774
- };
41775
- const { data: workspaceDocs } = react.useDocuments();
41776
- const outputsByTask = React9.useMemo(() => {
41777
- const out = {};
41778
- for (const [conversationId, docs] of Object.entries(
41779
- chunkDWWRLKEZ_cjs.groupOutputsByConversation(workspaceDocs ?? [])
41780
- )) {
41781
- out[conversationId] = docs.map((d) => ({
41782
- id: d.external_id,
41783
- name: ui.getDocumentTitle(d, d.external_id)
41784
- }));
41785
- }
41786
- return out;
41787
- }, [workspaceDocs]);
41788
- const handleOpenOutput = (documentId) => openDocument(documentId);
41789
- const handleGrantAccess = (task) => act(
41790
- task,
41791
- () => runConversation.mutateAsync(task.external_id),
41792
- `Running \u201C${nameOf(task)}\u201D`,
41793
- "Failed to run task"
41794
- );
41795
- const threadLabels = useThreadLabels(canEditShared);
41796
- const selectionActions = (selected, isCompact) => {
41797
- const mine = selected.every((c) => c.created_by_ext_id === currentUserExtId);
41798
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
41799
- mode === "threads" && selected.every((row2) => row2.is_owner || row2.is_shared && canEditShared) && selected.some((row2) => row2.status !== "done") && !selected.some((row2) => row2.in_progress || row2.status === "generating") && /* @__PURE__ */ jsxRuntime.jsx(
41800
- chunkV4ISCZJ7_cjs.SelectionBarAction,
41801
- {
41802
- icon: lucideReact.CheckCheck,
41803
- label: "Mark Done",
41804
- onClick: () => void handleMarkDoneMany(selected),
41805
- isCompact,
41806
- testId: "threads-bulk-done"
41807
- }
41808
- ),
41809
- threadLabels.renderBulkLabels(selected, isCompact),
41810
- mine && selected.some((c) => !c.is_shared) && /* @__PURE__ */ jsxRuntime.jsx(
41811
- ui.VisibilityToggle,
41812
- {
41813
- items: selected,
41814
- onToggle: () => void handleBulkShare(selected),
41815
- disablePrivate: true,
41816
- showLabel: false,
41817
- tooltipInactive: "Share all with workspace members",
41818
- tooltipMixed: "Share all with workspace members (some already shared)",
41819
- "data-testid": "bulk-shared-toggle"
41820
- }
41821
- ),
41822
- /* @__PURE__ */ jsxRuntime.jsx(
41823
- chunkV4ISCZJ7_cjs.SelectionBarAction,
41824
- {
41825
- icon: lucideReact.FolderUp,
41826
- label: "Export",
41827
- onClick: () => {
41828
- setExportRows(selected);
41829
- setIsExportOpen(true);
41830
- },
41831
- isCompact,
41832
- tooltip: `Export the selected ${ui.getEntityLabel("CONVERSATION", "PLURAL").toLowerCase()} to another ${ui.getEntityLabel("WORKSPACE").toLowerCase()}`,
41833
- testId: "export-chats-button"
41834
- }
41835
- ),
41836
- mode === "threads" && selected.every((row2) => row2.is_owner || isWorkspaceOwner) && /* @__PURE__ */ jsxRuntime.jsx(
41837
- chunkV4ISCZJ7_cjs.SelectionBarAction,
41838
- {
41839
- icon: lucideReact.Trash2,
41840
- label: "Delete",
41841
- className: "text-red-text hover:bg-red-bg hover:text-red-text",
41842
- onClick: () => void handleDeleteMany(selected),
41843
- isCompact,
41844
- testId: "threads-bulk-delete"
41845
- }
41846
- )
41847
- ] });
41848
- };
41849
- const page = /* @__PURE__ */ jsxRuntime.jsxs(
41850
- "div",
41851
- {
41852
- className: "flex h-full min-h-0 flex-col",
41853
- "data-testid": mode === "tasks" ? "tasks-page" : "threads-page",
41854
- children: [
41855
- /* @__PURE__ */ jsxRuntime.jsx("main", { className: "flex min-h-0 flex-1 flex-col bg-background", children: mode === "threads" ? /* @__PURE__ */ jsxRuntime.jsx(
41856
- chunkO3MRE2HL_cjs.ConversationListView,
41857
- {
41858
- showHeader,
41859
- conversations: tasks,
41860
- doneFilter,
41861
- visibilityFilters,
41862
- meetingFilter,
41863
- renderThread: (row2) => /* @__PURE__ */ jsxRuntime.jsx(
41864
- ConversationEntity,
41865
- {
41866
- conversation: row2,
41867
- showRePrefix: false,
41868
- labelMaxWidth: "max-w-full",
41869
- className: "w-full max-w-full [&_.truncate]:line-clamp-2 [&_.truncate]:whitespace-normal [&_.truncate]:break-words [&_.truncate]:text-left",
41870
- "data-testid": `thread-open-${row2.external_id}`
41871
- }
41872
- ),
41873
- renderLabels: threadLabels.renderLabels,
41874
- labelText: threadLabels.labelText,
41875
- renderBy: (row2) => /* @__PURE__ */ jsxRuntime.jsx(
41876
- chunkO3MRE2HL_cjs.ConversationTurnSpeaker,
41877
- {
41878
- variant: "icon",
41879
- role: row2.last_message_role,
41880
- actor: row2.last_message_actor,
41881
- currentUserId: currentUserExtId,
41882
- colorClass: row2.last_message_actor ? ui.getUserAvatarColor(row2.last_message_actor.external_id) : void 0
41883
- }
41884
- ),
41885
- renderStatus: (row2) => /* @__PURE__ */ jsxRuntime.jsx(ConversationStatusCell, { conversation: row2 }),
41886
- isLoading,
41887
- filterText: topbarFilterQuery ?? "",
41888
- formatDate: relativeTime2,
41889
- onOpen: (c) => openConversation(c.external_id),
41890
- onRename: openEdit,
41891
- onDelete: handleDelete,
41892
- canEditShared,
41893
- isWorkspaceOwner,
41894
- selectionActions,
41895
- footer: /* @__PURE__ */ jsxRuntime.jsx(ConnectedThreadLauncher, { autoFocus: focusLauncher })
41896
- }
41897
- ) : /* @__PURE__ */ jsxRuntime.jsx(
41898
- chunkO3MRE2HL_cjs.TaskInbox,
41899
- {
41900
- tasks,
41901
- isLoading,
41902
- ...workflowActions,
41903
- onCreate: openCreate,
41904
- filterText: topbarFilterQuery ?? "",
41905
- labels: LIST_LABELS,
41906
- gridId: "conversation-list-grid-v4",
41907
- onFilterTextChange: (text2) => setTopbarFilterQuery(text2),
41908
- outputsByTask,
41909
- onOpenActivity: (task) => openConversation(task.external_id),
41910
- formatRelative: relativeTime2,
41911
- onOpenOutput: handleOpenOutput,
41912
- busyId,
41913
- formatDate: ui.formatFriendlyDate,
41914
- onOpenThread: (conversationId) => openConversation(conversationId),
41915
- onMarkDone: (task) => setStatus(task, "done", `Marked \u201C${nameOf(task)}\u201D done`),
41916
- onReopen: (task) => setStatus(task, "todo", `Reopened \u201C${nameOf(task)}\u201D`),
41917
- people,
41918
- agentNames,
41919
- workflowNames,
41920
- canEditShared,
41921
- isWorkspaceOwner,
41922
- renderPerson,
41923
- onToggleShared: handleToggleShared,
41924
- onEdit: openEdit,
41925
- onDelete: handleDelete,
41926
- onAddSubtask: openAddSubtask,
41927
- onMove: handleMove,
41928
- onMarkDoneMany: handleMarkDoneMany,
41929
- onDeleteMany: handleDeleteMany,
41930
- onGrantAccess: handleGrantAccess,
41931
- selectionActions
41932
- }
41933
- ) }),
41934
- /* @__PURE__ */ jsxRuntime.jsx(
41935
- ConnectedTaskStartDialog,
41936
- {
41937
- open: startOpen,
41938
- onOpenChange: setStartOpen,
41939
- initialParentId: parentForNew
41940
- }
41941
- ),
41942
- /* @__PURE__ */ jsxRuntime.jsx(ConnectedTaskComposer, { open: editorOpen, onOpenChange: setEditorOpen, task: editing }),
41943
- /* @__PURE__ */ jsxRuntime.jsx(
41944
- ConnectedExportDialog,
41945
- {
41946
- open: isExportOpen,
41947
- onOpenChange: setIsExportOpen,
41948
- items: exportRows.map((c) => ({ extId: c.external_id, label: nameOf(c) })),
41949
- entityType: "CONVERSATION",
41950
- testId: "export-chats-modal"
41951
- }
41952
- ),
41953
- /* @__PURE__ */ jsxRuntime.jsx(
41954
- chunkFEVJA4BP_cjs.RenameDialog,
41955
- {
41956
- open: !!renaming,
41957
- onClose: () => {
41958
- setRenaming(null);
41959
- setNewTitle("");
41960
- },
41961
- title: `Rename ${ui.getEntityLabel("CONVERSATION")}`,
41962
- labels: { description: "Rename the conversation title" },
41963
- fieldLabel: `${ui.getEntityLabel("CONVERSATION")} Title`,
41964
- placeholder: "Enter title",
41965
- value: newTitle,
41966
- onChange: setNewTitle,
41967
- onSave: handleSaveRename,
41968
- canSave: !!newTitle.trim(),
41969
- dialogTestId: RENAME_DIALOG.testId
41970
- }
41971
- )
41972
- ]
41973
- }
41974
- );
41975
- return search ? /* @__PURE__ */ jsxRuntime.jsx(ThreadSearch, { ResultsBoundary, children: page }) : page;
41976
- }
41977
43227
  function useSessionPanelMode(panelId, defaultMode = "docked", isOpen = true) {
41978
43228
  const panelModes = react.useArbiSessionState((s) => s.shell.panels.modes);
41979
43229
  const setPanelModeStore = react.useArbiSessionStore().setPanelMode;
@@ -42375,7 +43625,7 @@ Object.defineProperty(exports, "useViewerStreamingDocument", {
42375
43625
  });
42376
43626
  Object.defineProperty(exports, "useMeetingThreadMessages", {
42377
43627
  enumerable: true,
42378
- get: function () { return chunk6AJJJ5HR_cjs.useMeetingThreadMessages; }
43628
+ get: function () { return chunk5R256EMF_cjs.useMeetingThreadMessages; }
42379
43629
  });
42380
43630
  Object.defineProperty(exports, "isListedDocument", {
42381
43631
  enumerable: true,
@@ -42446,6 +43696,7 @@ exports.ChatAttachmentList = ChatAttachmentList;
42446
43696
  exports.ConnectedAccountAccessBadge = ConnectedAccountAccessBadge;
42447
43697
  exports.ConnectedAccountCluster = ConnectedAccountCluster;
42448
43698
  exports.ConnectedAccountSettings = ConnectedAccountSettings;
43699
+ exports.ConnectedAccountsImport = ConnectedAccountsImport;
42449
43700
  exports.ConnectedAddContacts = ConnectedAddContacts;
42450
43701
  exports.ConnectedAgentChat = ConnectedAgentChat;
42451
43702
  exports.ConnectedAgentChatPanel = ConnectedAgentChatPanel;
@@ -42483,6 +43734,7 @@ exports.ConnectedFieldsManager = ConnectedFieldsManager;
42483
43734
  exports.ConnectedFilesBulkActions = ConnectedFilesBulkActions;
42484
43735
  exports.ConnectedFilesExplorer = ConnectedFilesExplorer;
42485
43736
  exports.ConnectedFilesPage = ConnectedFilesPage;
43737
+ exports.ConnectedFilterDropdown = ConnectedFilterDropdown;
42486
43738
  exports.ConnectedForgotPassword = ConnectedForgotPassword;
42487
43739
  exports.ConnectedGlobalDialogs = ConnectedGlobalDialogs;
42488
43740
  exports.ConnectedGrantWorkspaceAccessDialog = ConnectedGrantWorkspaceAccessDialog;
@@ -42727,6 +43979,7 @@ exports.useAuthPages = useAuthPages;
42727
43979
  exports.useAutoRefreshPendingProjects = useAutoRefreshPendingProjects;
42728
43980
  exports.useBatchCompleteToasts = useBatchCompleteToasts;
42729
43981
  exports.useChatMessageToasts = useChatMessageToasts;
43982
+ exports.useConnectedAgentManagement = useConnectedAgentManagement;
42730
43983
  exports.useConnectedCalendarCalls = useConnectedCalendarCalls;
42731
43984
  exports.useConnectedNotificationBell = useConnectedNotificationBell;
42732
43985
  exports.useConnectedShellWorkspaces = useConnectedShellWorkspaces;
@@ -42745,6 +43998,7 @@ exports.useFilesDialogs = useFilesDialogs;
42745
43998
  exports.useFilesGridStates = useFilesGridStates;
42746
43999
  exports.useFilesPrefs = useFilesPrefs;
42747
44000
  exports.useFilesStore = useFilesStore;
44001
+ exports.useHasAccountsImport = useHasAccountsImport;
42748
44002
  exports.useLaunchWorkflow = useLaunchWorkflow;
42749
44003
  exports.useMemberLookup = useMemberLookup;
42750
44004
  exports.useMessengerRows = useMessengerRows;