@arbidocs/blocks 0.4.144 → 0.4.146

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 (154) hide show
  1. package/dist/agents/index.cjs +264 -264
  2. package/dist/agents/index.js +7 -7
  3. package/dist/{chunk-ON3TKY5Y.js → chunk-5YHEHEJT.js} +242 -4
  4. package/dist/chunk-5YHEHEJT.js.map +1 -0
  5. package/dist/{chunk-7NGAWGA3.js → chunk-A6IU4GIW.js} +190 -7
  6. package/dist/chunk-A6IU4GIW.js.map +1 -0
  7. package/dist/{chunk-BUWBXJ2N.cjs → chunk-C3CGJK7A.cjs} +192 -6
  8. package/dist/chunk-C3CGJK7A.cjs.map +1 -0
  9. package/dist/{chunk-X3TGXEFS.js → chunk-C44TDH54.js} +6 -6
  10. package/dist/{chunk-X3TGXEFS.js.map → chunk-C44TDH54.js.map} +1 -1
  11. package/dist/{chunk-YFY3TQ6Q.cjs → chunk-COCGRJLA.cjs} +7 -7
  12. package/dist/{chunk-YFY3TQ6Q.cjs.map → chunk-COCGRJLA.cjs.map} +1 -1
  13. package/dist/{chunk-45LRMW54.js → chunk-DN2KI4BU.js} +8 -10
  14. package/dist/chunk-DN2KI4BU.js.map +1 -0
  15. package/dist/{chunk-R26BK7YL.cjs → chunk-DTROMMDX.cjs} +4 -4
  16. package/dist/{chunk-R26BK7YL.cjs.map → chunk-DTROMMDX.cjs.map} +1 -1
  17. package/dist/{chunk-65THHQVB.cjs → chunk-ECW2R2KF.cjs} +27 -27
  18. package/dist/{chunk-65THHQVB.cjs.map → chunk-ECW2R2KF.cjs.map} +1 -1
  19. package/dist/{chunk-RI6DZA5X.js → chunk-EF4ZLKRM.js} +3 -3
  20. package/dist/{chunk-RI6DZA5X.js.map → chunk-EF4ZLKRM.js.map} +1 -1
  21. package/dist/chunk-EV7W64B6.js +134 -0
  22. package/dist/chunk-EV7W64B6.js.map +1 -0
  23. package/dist/{chunk-WS5EX7DN.cjs → chunk-EYKISBDO.cjs} +5 -5
  24. package/dist/{chunk-WS5EX7DN.cjs.map → chunk-EYKISBDO.cjs.map} +1 -1
  25. package/dist/{chunk-JZNXRMLH.cjs → chunk-GAYMJWTC.cjs} +8 -10
  26. package/dist/chunk-GAYMJWTC.cjs.map +1 -0
  27. package/dist/{chunk-I7WG3JRD.js → chunk-H4D7WKDY.js} +3 -3
  28. package/dist/{chunk-I7WG3JRD.js.map → chunk-H4D7WKDY.js.map} +1 -1
  29. package/dist/{chunk-2FJMTZNJ.js → chunk-IJST4EBM.js} +8 -8
  30. package/dist/{chunk-2FJMTZNJ.js.map → chunk-IJST4EBM.js.map} +1 -1
  31. package/dist/{chunk-3RJN2VTL.js → chunk-IXWJGOM2.js} +3 -3
  32. package/dist/{chunk-3RJN2VTL.js.map → chunk-IXWJGOM2.js.map} +1 -1
  33. package/dist/{chunk-CYNF5PZI.js → chunk-J5CWKFSC.js} +3 -3
  34. package/dist/{chunk-CYNF5PZI.js.map → chunk-J5CWKFSC.js.map} +1 -1
  35. package/dist/{chunk-TP6PLDNM.cjs → chunk-KMZWKSKO.cjs} +8 -8
  36. package/dist/{chunk-TP6PLDNM.cjs.map → chunk-KMZWKSKO.cjs.map} +1 -1
  37. package/dist/{chunk-C4WSHRR6.cjs → chunk-KPZZ5FHE.cjs} +32 -12
  38. package/dist/chunk-KPZZ5FHE.cjs.map +1 -0
  39. package/dist/{chunk-O2ODDTMA.cjs → chunk-LPYEUD2D.cjs} +9 -9
  40. package/dist/{chunk-O2ODDTMA.cjs.map → chunk-LPYEUD2D.cjs.map} +1 -1
  41. package/dist/{chunk-RA3ZJ45L.cjs → chunk-MFMASSEO.cjs} +25 -44
  42. package/dist/chunk-MFMASSEO.cjs.map +1 -0
  43. package/dist/chunk-NHZK64TQ.js +75 -0
  44. package/dist/chunk-NHZK64TQ.js.map +1 -0
  45. package/dist/{chunk-BPBSSMRB.js → chunk-NRFAWUVD.js} +3 -3
  46. package/dist/{chunk-BPBSSMRB.js.map → chunk-NRFAWUVD.js.map} +1 -1
  47. package/dist/chunk-NWNVWO6L.cjs +80 -0
  48. package/dist/chunk-NWNVWO6L.cjs.map +1 -0
  49. package/dist/{chunk-XGZX22ET.cjs → chunk-O2GW5IY6.cjs} +38 -38
  50. package/dist/{chunk-XGZX22ET.cjs.map → chunk-O2GW5IY6.cjs.map} +1 -1
  51. package/dist/{chunk-33ZOUJXA.js → chunk-OBWYM25Y.js} +13 -32
  52. package/dist/chunk-OBWYM25Y.js.map +1 -0
  53. package/dist/{chunk-Y3KA6X7B.js → chunk-OVR3XMYL.js} +4 -4
  54. package/dist/{chunk-Y3KA6X7B.js.map → chunk-OVR3XMYL.js.map} +1 -1
  55. package/dist/{chunk-ABUO6PIQ.cjs → chunk-RB7GX2VT.cjs} +12 -12
  56. package/dist/{chunk-ABUO6PIQ.cjs.map → chunk-RB7GX2VT.cjs.map} +1 -1
  57. package/dist/chunk-RXK3XP62.cjs +144 -0
  58. package/dist/chunk-RXK3XP62.cjs.map +1 -0
  59. package/dist/{chunk-LYUO3E6V.js → chunk-SZOFGU7W.js} +3 -3
  60. package/dist/{chunk-LYUO3E6V.js.map → chunk-SZOFGU7W.js.map} +1 -1
  61. package/dist/{chunk-A6J2IBUG.js → chunk-T5B7FM7S.js} +4 -4
  62. package/dist/{chunk-A6J2IBUG.js.map → chunk-T5B7FM7S.js.map} +1 -1
  63. package/dist/{chunk-YNIBUKV5.js → chunk-TBEVGWY3.js} +32 -14
  64. package/dist/chunk-TBEVGWY3.js.map +1 -0
  65. package/dist/{chunk-MJCCBMM5.cjs → chunk-TC3RQNEX.cjs} +6 -80
  66. package/dist/chunk-TC3RQNEX.cjs.map +1 -0
  67. package/dist/{chunk-QIMVTGKS.cjs → chunk-U73KPFYH.cjs} +255 -2
  68. package/dist/chunk-U73KPFYH.cjs.map +1 -0
  69. package/dist/{chunk-HFGXA5CL.cjs → chunk-UTTTJSQU.cjs} +4 -4
  70. package/dist/{chunk-HFGXA5CL.cjs.map → chunk-UTTTJSQU.cjs.map} +1 -1
  71. package/dist/{chunk-DLBUFHLY.js → chunk-VTTZZ4FN.js} +4 -74
  72. package/dist/chunk-VTTZZ4FN.js.map +1 -0
  73. package/dist/{chunk-5FTIHRZH.cjs → chunk-XVUOMWMD.cjs} +4 -4
  74. package/dist/{chunk-5FTIHRZH.cjs.map → chunk-XVUOMWMD.cjs.map} +1 -1
  75. package/dist/{chunk-444XKG46.js → chunk-YKQ2DPIP.js} +3 -3
  76. package/dist/{chunk-444XKG46.js.map → chunk-YKQ2DPIP.js.map} +1 -1
  77. package/dist/{chunk-HEMU73OP.cjs → chunk-YSHIC4NJ.cjs} +4 -4
  78. package/dist/{chunk-HEMU73OP.cjs.map → chunk-YSHIC4NJ.cjs.map} +1 -1
  79. package/dist/citations/index.cjs +12 -12
  80. package/dist/citations/index.js +3 -3
  81. package/dist/connect/docx.cjs +11 -11
  82. package/dist/connect/docx.js +8 -8
  83. package/dist/connect/index.cjs +1079 -333
  84. package/dist/connect/index.cjs.map +1 -1
  85. package/dist/connect/index.d.ts +2 -0
  86. package/dist/connect/index.js +953 -222
  87. package/dist/connect/index.js.map +1 -1
  88. package/dist/connection/ConnectedNotificationRelevance.d.ts +4 -1
  89. package/dist/connection/ConnectedSettings.d.ts +3 -2
  90. package/dist/connection/ai.d.ts +27 -72
  91. package/dist/connection/settings-page/ConnectedAccountSettings.d.ts +35 -0
  92. package/dist/connection/settings-page/ConnectedMailSettings.d.ts +13 -0
  93. package/dist/connection/settings-page/ConnectedPremiumModels.d.ts +1 -0
  94. package/dist/connection/settings-page/ConnectedPrivacySettings.d.ts +12 -0
  95. package/dist/connection/settings-page/ConnectedSettingsPage.d.ts +29 -0
  96. package/dist/connection/settings-page/SessionStatusIcon.d.ts +7 -0
  97. package/dist/connection/settings-page/index.d.ts +6 -0
  98. package/dist/connection/workspace-settings/ConnectedWorkspaceSettings.d.ts +53 -0
  99. package/dist/connection/workspace-settings/index.d.ts +2 -0
  100. package/dist/connection/workspace-settings/useConnectedWorkspaceSettings.d.ts +85 -0
  101. package/dist/connection/workspaceData.d.ts +6 -6
  102. package/dist/facts/index.cjs +3 -3
  103. package/dist/facts/index.js +2 -2
  104. package/dist/files/index.cjs +3 -3
  105. package/dist/files/index.js +2 -2
  106. package/dist/home/index.cjs +20 -20
  107. package/dist/home/index.js +4 -4
  108. package/dist/index.cjs +468 -632
  109. package/dist/index.cjs.map +1 -1
  110. package/dist/index.d.ts +1 -0
  111. package/dist/index.js +23 -204
  112. package/dist/index.js.map +1 -1
  113. package/dist/provider/BlocksProvider.d.ts +5 -1
  114. package/dist/provider/settings-section.d.ts +9 -0
  115. package/dist/retrieval/index.cjs +4 -4
  116. package/dist/retrieval/index.js +2 -2
  117. package/dist/settings/AppearanceSettings.d.ts +18 -0
  118. package/dist/settings/ServerConnectionControls.d.ts +16 -0
  119. package/dist/settings/SettingsPage.d.ts +31 -0
  120. package/dist/settings/index.cjs +178 -241
  121. package/dist/settings/index.cjs.map +1 -1
  122. package/dist/settings/index.d.ts +3 -1
  123. package/dist/settings/index.js +86 -198
  124. package/dist/settings/index.js.map +1 -1
  125. package/dist/shell/index.cjs +44 -44
  126. package/dist/shell/index.js +3 -3
  127. package/dist/site/index.cjs +74 -73
  128. package/dist/site/index.js +3 -2
  129. package/dist/studio/index.cjs +78 -77
  130. package/dist/studio/index.cjs.map +1 -1
  131. package/dist/studio/index.js +10 -9
  132. package/dist/studio/index.js.map +1 -1
  133. package/dist/workflow-canvas/index.cjs +25 -25
  134. package/dist/workflow-canvas/index.js +8 -8
  135. package/dist/workspaces/CommonWorkspaceToggle.d.ts +15 -0
  136. package/dist/workspaces/index.cjs +41 -110
  137. package/dist/workspaces/index.cjs.map +1 -1
  138. package/dist/workspaces/index.d.ts +1 -0
  139. package/dist/workspaces/index.js +7 -104
  140. package/dist/workspaces/index.js.map +1 -1
  141. package/node_modules/@arbidocs/coedit/package.json +1 -1
  142. package/package.json +4 -4
  143. package/dist/chunk-33ZOUJXA.js.map +0 -1
  144. package/dist/chunk-45LRMW54.js.map +0 -1
  145. package/dist/chunk-7NGAWGA3.js.map +0 -1
  146. package/dist/chunk-BUWBXJ2N.cjs.map +0 -1
  147. package/dist/chunk-C4WSHRR6.cjs.map +0 -1
  148. package/dist/chunk-DLBUFHLY.js.map +0 -1
  149. package/dist/chunk-JZNXRMLH.cjs.map +0 -1
  150. package/dist/chunk-MJCCBMM5.cjs.map +0 -1
  151. package/dist/chunk-ON3TKY5Y.js.map +0 -1
  152. package/dist/chunk-QIMVTGKS.cjs.map +0 -1
  153. package/dist/chunk-RA3ZJ45L.cjs.map +0 -1
  154. package/dist/chunk-YNIBUKV5.js.map +0 -1
@@ -1,9 +1,10 @@
1
1
  "use client";
2
- import { DraggableHeader, SettingsSection, ProfileCard, AvatarPicker, IdentityVerificationCard, IdentityVerificationDialog, RequireVerified, PasswordChangeDialog, SettingsCard, SettingsActionRow, EMAIL_NOTIFICATION_KEYS, EMAIL_NOTIFICATION_CATEGORIES, NotificationCategoryList, toNotificationCategories, toActiveSessionViews, SettingsRow, ActiveSessionsDialog, LogoutDialog, toLogoutSessionViews, SettingsDangerZone, DeleteAccountDialog, toDeleteBlockerViews } from '../chunk-ON3TKY5Y.js';
2
+ import { PageLoading, WorkspacePageFrame, WorkspaceIdentityPanel, WorkspaceProjectSlot, WorkspaceAudienceLine, CommonWorkspaceToggle, ExpandableSection, LeaveFooter } from '../chunk-EV7W64B6.js';
3
+ import { DraggableHeader, SettingsSection, ProfileCard, AvatarPicker, IdentityVerificationCard, IdentityVerificationDialog, RequireVerified, PasswordChangeDialog, SettingsCard, SettingsActionRow, EMAIL_NOTIFICATION_KEYS, EMAIL_NOTIFICATION_CATEGORIES, NotificationCategoryList, toNotificationCategories, toActiveSessionViews, SettingsRow, ActiveSessionsDialog, LogoutDialog, toLogoutSessionViews, SettingsDangerZone, DeleteAccountDialog, toDeleteBlockerViews, SettingsPanel, PremiumModelsFrame, SettingsPage, serverConnectionView, ServerConnectionButton, ModelProviderLabel } from '../chunk-5YHEHEJT.js';
3
4
  export { ConnectedAssistantDock, redlineStats, textToArtifact, toRedlineMarkdown, useConnectedAiTask, useConnectedChat, useSemanticSearch, useWorkspaceDocs } from '../chunk-CSI2B2H5.js';
4
- import { useConnectedWorkspaceRole, ConnectedNativeDocxEditor } from '../chunk-33ZOUJXA.js';
5
- export { ConnectedWorkflowDocumentsField, ConnectedWorkflowLauncher, ConnectedWorkflowsTable, DEFAULT_CONNECTED_WORKFLOWS_TABLE_LABELS, NativeDocxSupportProvider, toWorkflowFieldDocument, useConnectedAgentOptions, useConnectedWorkflowScopeSource, useConnectedWorkspaceRole, useNativeDocxSupport } from '../chunk-33ZOUJXA.js';
6
- export { ConnectedWorkspaceDataProvider, useConnectedConversations, useConnectedDocuments, useConnectedTags } from '../chunk-45LRMW54.js';
5
+ import { useConnectedWorkspaceRole, ConnectedNativeDocxEditor } from '../chunk-OBWYM25Y.js';
6
+ export { ConnectedWorkflowDocumentsField, ConnectedWorkflowLauncher, ConnectedWorkflowsTable, DEFAULT_CONNECTED_WORKFLOWS_TABLE_LABELS, NativeDocxSupportProvider, toWorkflowFieldDocument, useConnectedAgentOptions, useConnectedWorkflowScopeSource, useConnectedWorkspaceRole, useNativeDocxSupport } from '../chunk-OBWYM25Y.js';
7
+ export { ConnectedWorkspaceDataProvider, useConnectedConversations, useConnectedDocuments, useConnectedTags } from '../chunk-DN2KI4BU.js';
7
8
  import { ConnectionProvider, useConnection, useConnectedWorkspace } from '../chunk-US3S4DCB.js';
8
9
  export { ConnectionProvider, SESSION_EXPIRED_MESSAGE, isAuthenticated, useConnectedWorkspace, useConnection } from '../chunk-US3S4DCB.js';
9
10
  import { SignDocumentDialog } from '../chunk-2YOVK524.js';
@@ -11,21 +12,22 @@ import '../chunk-MTSKK3BN.js';
11
12
  import '../chunk-2FL7QJKJ.js';
12
13
  import '../chunk-HFZ45FD3.js';
13
14
  import { FilesFilterBar, FolderFilterButton, FolderPickerRow } from '../chunk-7RJTEWYM.js';
14
- import { WorkspaceActivityList, WorkspaceNotificationMenu, ThreadFollowMenuItem, ThreadFollowButton, TagTable, tagTableDocx } from '../chunk-7NGAWGA3.js';
15
- import { workspaceKindColor } from '../chunk-A3XPS2EU.js';
15
+ import { WorkspaceActivityList, WorkspaceNotificationMenu, ThreadFollowMenuItem, ThreadFollowButton, TagTable, LoadingIndicator, EntityIdentityBar, IDENTITY_NAME_MAX_LENGTH, tagTableDocx } from '../chunk-A6IU4GIW.js';
16
+ import { MemberAvatarStack } from '../chunk-XNOASBGW.js';
17
+ import { WorkspaceIdentity, workspaceKindColor } from '../chunk-A3XPS2EU.js';
16
18
  import { PlainMailBodyEditor, draftMailCompose, replyMailCompose, emptyMailCompose, MailGrid, MailMessageView, MailDocumentPicker, parseMailRecipients } from '../chunk-6HCJ3ZEU.js';
17
19
  import '../chunk-SV65E4QW.js';
18
20
  import { DOCX_MIME_TYPE } from '../chunk-QXMR5YHC.js';
19
21
  import '../chunk-AF6RDAJF.js';
20
- import { buildLibrarySkills, filterLibrarySkills, SKILL_SOURCE_LABELS, SKILL_TYPE_LABELS, SkillViewToggle, SkillFilterChips, SkillTile, SkillGenerateForm, SkillLibraryDetail, parseSkillFrontmatter, SKILL_MAIN_FILENAME, SkillEditForm, DEFAULT_AGENT_CAPABILITIES, stripPersonaPreamble, AgentCreator, DEFAULT_AGENT_TYPES, DEFAULT_AGENT_TEMPLATES, AgentAvatarField, isValidAgentName, AgentConnectInstructions, TaskRunsDialog, TaskActivityDialog, WorkflowStepBar, composePersona, importSkillFile, importSkillFromUrl, WorkflowRunner, skillSlug, serializeSkill, fromPlanSteps, toPlanSteps, useWorkflowView, workflowToSkillMarkdown } from '../chunk-X3TGXEFS.js';
22
+ import { buildLibrarySkills, filterLibrarySkills, SKILL_SOURCE_LABELS, SKILL_TYPE_LABELS, SkillViewToggle, SkillFilterChips, SkillTile, SkillGenerateForm, SkillLibraryDetail, parseSkillFrontmatter, SKILL_MAIN_FILENAME, SkillEditForm, DEFAULT_AGENT_CAPABILITIES, stripPersonaPreamble, AgentCreator, DEFAULT_AGENT_TYPES, DEFAULT_AGENT_TEMPLATES, AgentAvatarField, isValidAgentName, AgentConnectInstructions, TaskRunsDialog, TaskActivityDialog, WorkflowStepBar, composePersona, importSkillFile, importSkillFromUrl, WorkflowRunner, skillSlug, serializeSkill, fromPlanSteps, toPlanSteps, useWorkflowView, workflowToSkillMarkdown } from '../chunk-C44TDH54.js';
21
23
  import { MultiSelect } from '../chunk-CQCC7LE7.js';
22
- import { PersonPill } from '../chunk-A6J2IBUG.js';
23
- import '../chunk-3RJN2VTL.js';
24
- import { TriStateFilterMenu } from '../chunk-KSHKTOY2.js';
24
+ import { PersonPill } from '../chunk-T5B7FM7S.js';
25
+ import '../chunk-IXWJGOM2.js';
25
26
  import '../chunk-RLWIUUQ5.js';
27
+ import { TriStateFilterMenu } from '../chunk-KSHKTOY2.js';
26
28
  import '../chunk-P6GHJSLR.js';
27
29
  import '../chunk-EVUEIBNU.js';
28
- import '../chunk-444XKG46.js';
30
+ import '../chunk-YKQ2DPIP.js';
29
31
  import { SelectionBar, SelectionBarAction } from '../chunk-NUNKSZKU.js';
30
32
  import { FilterInput } from '../chunk-YU2KUMGE.js';
31
33
  import { GridView } from '../chunk-N5YEF3LC.js';
@@ -45,18 +47,18 @@ import '../chunk-AUS3KBHJ.js';
45
47
  import '../chunk-SLSBJRWW.js';
46
48
  import '../chunk-NPLYHR2E.js';
47
49
  import '../chunk-7F6CBP3Z.js';
48
- import { useCopyText } from '../chunk-CYNF5PZI.js';
49
- import { useBlocksEnvironment } from '../chunk-YNIBUKV5.js';
50
+ import { useCopyText } from '../chunk-J5CWKFSC.js';
51
+ import { useBlocksEnvironment, useRequestedSettingsSection } from '../chunk-TBEVGWY3.js';
50
52
  import { ModalScaffold } from '../chunk-TX2ZICS7.js';
51
53
  import { fmtDate, initials } from '../chunk-OXF2IFXG.js';
52
54
  import '../chunk-VUNV25KB.js';
53
55
  import { lazy, useState, useMemo, useEffect, useCallback, useRef, Suspense, useSyncExternalStore, useLayoutEffect } from 'react';
54
56
  import { QueryClient, QueryClientProvider, useQueryClient, useQuery } from '@tanstack/react-query';
55
- import { ArbiProvider, useConversations, useRunConversation, useWorkspaceActivity, useWorkspaceUsers, isWorkspaceNotificationType, useArbi, useNotifications, useDeleteNotifications, useMarkNotificationsRead, useWorkspaces, useWorkspaceNotificationLevel, useFollowThread, useUploadSkillFiles, useSkills, useSetSkillVisibility, useDeleteSkill, useSkillSource, useAgentModels, useMcpTools, useAgentConfig, useAgentWorkspaces, useCreateAgent, useSaveAgentConfig, useGrantAgentAccess, useRevokeAgentAccess, useGenerateAgentAvatar, useWorkflowRuns, useConversationActivity, useAgents, ArtifactCanvas, useArbiChat, useDocuments, useTagKindSchema, useTags, useSetTagValues, useUpdateTagKindSchema, useInvalidateTagData, useShellWorkspaces, useProfile, useUpdateProfile, useRequestEmailChange, useConfirmEmailChange, useNameEditor, useAvatarCrop, useEmailChange, ImageCropModal, useIdentityVerification, usePasswordChange, usePasswordChangeForm, useNotificationPreferences, useSessions, useCurrentSessionId, useTerminateSession, useSignOut, useDeleteAccount, useDeleteAccountFlow, useArbiWebSocket, useWorkNotifications, mailDraftIdFromContent, useMailClient, defaultMailAlias, useClaimNativeAlias, useMailOnline, useConnectMailAccount, useDisconnectMailAccount, useMailPolicy, useMailAccounts, useMailUnlock, useMailFolders, useMailMessages, useMailDraftCompose, useMailMessage, useMailCache, MailOfflineUnavailableError, accountPath, useCalendarEvents, useCalendars, useFetchCalendarEvent, useCalendarSettings, useCalendarOverlays, useCalendarOutbox, useCalendarAccounts, useSyncAccountsOnOpen, useResumeCalendarAccountConnect, useCreateEvent, useUpdateEvent, useDeleteEvent, useMoveEvent, useRespondToEvent, useCreateCalendar, useUpdateCalendar, useDeleteCalendar, useImportCalendar, useSaveCalendarSettings, useRefreshCalendar, useCalendarEvent, useMailAttachmentText, useCalendarEventByUid, getPublicBookingPage, bookPublicSlot, PublicBookingError, useAgentSession, useStartAgentSession, useCloseAgentSession, isQueuedCalendarWrite, isAliasTakenError, nextAliasSuggestion, aliasTakenMessage, mailJson, ArbiWebSocketProvider, isDeploymentUserNotification, getWorkspaceActionText, getWorkspaceSentPhrase, describeServerNotification, BOX_SEAT_REFUSED, BOX_SEAT_REFUSED_TITLE, documentActivityPhrase, isSignatureNotificationType, inputRequestTitle, WORK_NOTIFICATION_LABELS, useArbiSessionState, documentDisplayName, getWorkspaceKind, formatRelativeTime, useCreateWork, useActOnStep, useConversationThreads, fileAttachment, useMailProjects, useSaveMailDraft, useSendMail, useMailDraftReplaced, useCalendarInvitations, useDecideCounter, useSearchContacts, usePublishCalendar, useCalendarShares, useShareCalendar, useUnshareCalendar, useSubscribeCalendar, useHolidayCountries, useAddHolidayCalendar, cancelPublicBooking, AiAnswer, signatureNotificationPhrase, signatureRequestMeta, getNotificationTypeMeta, useMailDraftEditor, useFreeBusy, useRooms, useFindTime, useCalendarSupport, useStartCalendarAccountOAuth, useConnectOAuthAccount, useAppPasswords, splitAppPasswords, useBookingPages, useDeleteBookingPage, useSyncCalendarAccount, useUpdateCalendarAccount, useDisconnectCalendarAccount, ACCOUNT_VENDOR, useCalDavProfiles, useConnectCalDavAccount, useCreateAppPassword, useCreateFeed, useSaveBookingPage, useCreateRoom, useRevokeAppPassword } from '@arbidocs/react';
57
+ import { ArbiProvider, useConversations, useRunConversation, useWorkspaceActivity, useWorkspaceUsers, isWorkspaceNotificationType, useArbi, useNotifications, useDeleteNotifications, useMarkNotificationsRead, useWorkspaces, useWorkspaceNotificationLevel, useFollowThread, useUploadSkillFiles, useSkills, useSetSkillVisibility, useDeleteSkill, useSkillSource, useAgentModels, useMcpTools, useAgentConfig, useAgentWorkspaces, useCreateAgent, useSaveAgentConfig, useGrantAgentAccess, useRevokeAgentAccess, useGenerateAgentAvatar, useWorkflowRuns, useConversationActivity, useAgents, ArtifactCanvas, useArbiChat, useDocuments, useTagKindSchema, useTags, useSetTagValues, useUpdateTagKindSchema, useInvalidateTagData, useShellWorkspaces, ArbiBotHeadIcon, useProfile, useUpdateProfile, useRequestEmailChange, useConfirmEmailChange, useNameEditor, useAvatarCrop, useEmailChange, ImageCropModal, useIdentityVerification, usePasswordChange, usePasswordChangeForm, useNotificationPreferences, useSessions, useCurrentSessionId, useTerminateSession, useSignOut, useDeleteAccount, useDeleteAccountFlow, useMailClient, defaultMailAlias, useClaimNativeAlias, useMailOnline, useConnectMailAccount, useDisconnectMailAccount, useMailPolicy, useMailAccounts, useUserSettings, useUpdateUserSettings, useAvailableModels, useUpdateWorkspace, useAddWorkspaceMembers, useRemoveWorkspaceMembers, toShellWorkspace, useArbiWebSocket, useWorkNotifications, mailDraftIdFromContent, useMailUnlock, useMailFolders, useMailMessages, useMailDraftCompose, useMailMessage, useMailCache, MailOfflineUnavailableError, accountPath, useCalendarEvents, useCalendars, useFetchCalendarEvent, useCalendarSettings, useCalendarOverlays, useCalendarOutbox, useCalendarAccounts, useSyncAccountsOnOpen, useResumeCalendarAccountConnect, useCreateEvent, useUpdateEvent, useDeleteEvent, useMoveEvent, useRespondToEvent, useCreateCalendar, useUpdateCalendar, useDeleteCalendar, useImportCalendar, useSaveCalendarSettings, useRefreshCalendar, useCalendarEvent, useMailAttachmentText, useCalendarEventByUid, getPublicBookingPage, bookPublicSlot, PublicBookingError, useAgentSession, useStartAgentSession, useCloseAgentSession, isQueuedCalendarWrite, isAliasTakenError, nextAliasSuggestion, aliasTakenMessage, mailJson, ArbiWebSocketProvider, isDeploymentUserNotification, getWorkspaceActionText, getWorkspaceSentPhrase, describeServerNotification, BOX_SEAT_REFUSED, BOX_SEAT_REFUSED_TITLE, documentActivityPhrase, isSignatureNotificationType, inputRequestTitle, WORK_NOTIFICATION_LABELS, useArbiSessionState, documentDisplayName, getWorkspaceKind, formatRelativeTime, useCreateWork, useActOnStep, useConversationThreads, ProviderIcon, formatGbpPerMillionTokens, fileAttachment, useMailProjects, useSaveMailDraft, useSendMail, useMailDraftReplaced, useCalendarInvitations, useDecideCounter, useSearchContacts, usePublishCalendar, useCalendarShares, useShareCalendar, useUnshareCalendar, useSubscribeCalendar, useHolidayCountries, useAddHolidayCalendar, cancelPublicBooking, AiAnswer, signatureNotificationPhrase, signatureRequestMeta, getNotificationTypeMeta, useMailDraftEditor, useFreeBusy, useRooms, useFindTime, useCalendarSupport, useStartCalendarAccountOAuth, useConnectOAuthAccount, useAppPasswords, splitAppPasswords, useBookingPages, useDeleteBookingPage, useSyncCalendarAccount, useUpdateCalendarAccount, useDisconnectCalendarAccount, ACCOUNT_VENDOR, useCalDavProfiles, useConnectCalDavAccount, useCreateAppPassword, useCreateFeed, useSaveBookingPage, useCreateRoom, useRevokeAppPassword } from '@arbidocs/react';
56
58
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
57
- import { Button, Label, Input, cn, Textarea, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DocumentEntity, EntityPill, ShieldIcon, EntityIcon, Tooltip, TooltipTrigger, TooltipContent, Popover, PopoverTrigger, PopoverContent, Tabs, TabsList, TabsTrigger, TabsContent, DialogFooter, UserEntity, Switch } from '@arbidocs/react/ui';
59
+ import { Button, Label, Input, cn, Textarea, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Switch, getEntityLabel, DocumentEntity, EntityPill, ShieldIcon, EntityIcon, Tooltip, TooltipTrigger, TooltipContent, Popover, PopoverTrigger, PopoverContent, Tabs, TabsList, TabsTrigger, TabsContent, DialogFooter, UserEntity } from '@arbidocs/react/ui';
58
60
  import { useNotify } from '@arbidocs/react/shell';
59
- import { Bell, Activity, Info, UserCheck, Trash2, Loader2, Upload, Link2, Search, Plus, ArrowLeft, ExternalLink, UserCircle, KeyRound, Radio, Mail, Settings, Video, Printer, CalendarDays, Clock, MapPin, Globe, X, Paperclip, Send, Inbox, CalendarX, CalendarCheck, MessageSquare, CalendarSearch, Pencil, DoorOpen, RefreshCw, CheckCircle2, AlertTriangle, Check, Copy } from 'lucide-react';
61
+ import { Bell, Activity, Info, UserCheck, Trash2, Loader2, Upload, Link2, Search, Plus, ArrowLeft, ExternalLink, Monitor, UserCircle, KeyRound, Radio, LogOut, Wifi, RotateCcw, User, Mail, HatGlasses, MessageSquare, FolderInput, Settings, Video, Printer, CalendarDays, Clock, MapPin, Globe, X, Paperclip, Send, Inbox, CalendarX, CalendarCheck, CalendarSearch, Pencil, DoorOpen, RefreshCw, CheckCircle2, AlertTriangle, Check, Copy } from 'lucide-react';
60
62
  import { useIsOnline, downloadBlob, useOptionalDocumentTools, fetchDocumentPdf, DocumentToolsProvider } from '@arbidocs/react/document-tools';
61
63
  import { useStreamedArtifact } from '@arbidocs/react/artifacts';
62
64
  import { bytesToBase64 } from '@arbidocs/client';
@@ -806,11 +808,16 @@ function ConnectedWorkspaceNotificationMenu({
806
808
  workspaceId: workspaceProp,
807
809
  ...menuProps
808
810
  }) {
809
- const { workspaceId: selected, status } = useConnection();
811
+ const { notify } = useBlocksEnvironment();
812
+ const { workspaceId: selected, live } = useConnectedWorkspace();
810
813
  const workspaceId = workspaceProp ?? selected;
811
- const { level, setLevel, isLoading, isSaving } = useWorkspaceNotificationLevel(workspaceId, {
812
- enabled: status === "authenticated"
813
- });
814
+ const { level, setLevel, isLoading, isSaving, error } = useWorkspaceNotificationLevel(
815
+ workspaceId,
816
+ { enabled: live }
817
+ );
818
+ useEffect(() => {
819
+ if (error) notify("Could not save the workspace notification setting", "error");
820
+ }, [error, notify]);
814
821
  if (!workspaceId) return null;
815
822
  return /* @__PURE__ */ jsx(
816
823
  WorkspaceNotificationMenu,
@@ -827,9 +834,9 @@ function ConnectedThreadFollow({
827
834
  as = "button",
828
835
  ...props
829
836
  }) {
830
- const { status } = useConnection();
837
+ const { live } = useConnectedWorkspace();
831
838
  const { following, setFollowing, isLoading, isSaving } = useFollowThread(conversationId, {
832
- enabled: status === "authenticated"
839
+ enabled: live
833
840
  });
834
841
  if (!conversationId) return null;
835
842
  const Control = as === "menu-item" ? ThreadFollowMenuItem : ThreadFollowButton;
@@ -2743,6 +2750,11 @@ function useConnectedShellWorkspaces(options = {}) {
2743
2750
  select: (workspace) => setWorkspace(workspace.id)
2744
2751
  });
2745
2752
  }
2753
+ function SessionStatusIcon({ status, className }) {
2754
+ if (status === "agent") return /* @__PURE__ */ jsx(ArbiBotHeadIcon, { className: className ?? "w-4 h-4" });
2755
+ return /* @__PURE__ */ jsx(Monitor, { className: className ?? "w-4 h-4 text-muted-foreground" });
2756
+ }
2757
+ var renderSessionStatusIcon = (status) => /* @__PURE__ */ jsx(SessionStatusIcon, { status });
2746
2758
  function errorText2(error, fallback) {
2747
2759
  const body = error?.apiError;
2748
2760
  return typeof body?.detail === "string" ? body.detail : fallback;
@@ -2980,7 +2992,9 @@ function ConnectedNotificationPreferences({
2980
2992
  }
2981
2993
  ) }) });
2982
2994
  }
2983
- function ConnectedSessionsRow({ renderSessionIcon }) {
2995
+ function ConnectedSessionsRow({
2996
+ renderSessionIcon = renderSessionStatusIcon
2997
+ }) {
2984
2998
  const { notify, confirm } = useBlocksEnvironment();
2985
2999
  const [open, setOpen] = useState(false);
2986
3000
  const sessions = useSessions({ enabled: open });
@@ -3046,7 +3060,7 @@ function ConnectedLogoutDialog({
3046
3060
  onClose,
3047
3061
  canLogoutAll = true,
3048
3062
  confirmSignOut,
3049
- renderSessionIcon
3063
+ renderSessionIcon = renderSessionStatusIcon
3050
3064
  }) {
3051
3065
  const sessions = useSessions({ enabled: open });
3052
3066
  const signOut = useSignOut();
@@ -3124,211 +3138,80 @@ function ConnectedDangerZone({ renderSubscriptionLink }) {
3124
3138
  )
3125
3139
  ] });
3126
3140
  }
3127
- function useConnectedDocxNotifications(onOpen) {
3128
- const arbi = useArbi();
3129
- const { status, user, apiUrl } = useConnection();
3130
- const { notify } = useBlocksEnvironment();
3131
- const queries = useQueryClient();
3132
- const source = `docx-mentions:${apiUrl}:${user?.externalId || ""}`;
3133
- const queryKey = ["docx-mentions", apiUrl, user?.externalId];
3134
- const { data = [] } = useQuery({
3135
- queryKey,
3136
- queryFn: () => arbi.notifications.list({ type: "docx_mention" }),
3137
- enabled: status === "authenticated",
3138
- refetchInterval: 3e4
3139
- });
3140
- useArbiWebSocket((message) => {
3141
- if (message.type === "docx_mention") void queries.invalidateQueries({ queryKey });
3142
- });
3143
- useEffect(() => {
3144
- const items = [];
3145
- if (status === "authenticated")
3146
- for (const note of data) {
3147
- if (note.recipient.external_id !== user?.externalId || !note.workspace_ext_id) continue;
3148
- try {
3149
- const target = JSON.parse(note.content || "{}");
3150
- if (!target.document_id?.startsWith("doc-") || !target.comment_id) continue;
3151
- const documentId = target.document_id, commentId = target.comment_id, workspaceId = note.workspace_ext_id;
3152
- items.push({
3153
- id: `docx:${note.external_id}`,
3154
- title: "Mentioned you in a document comment",
3155
- description: [note.sender.given_name, note.sender.family_name].filter(Boolean).join(" "),
3156
- variant: "info",
3157
- ts: Date.parse(note.created_at),
3158
- read: note.read,
3159
- source,
3160
- onSelect: () => {
3161
- void Promise.resolve(onOpen({ documentId, commentId, workspaceId })).catch(
3162
- (error) => notify(
3163
- error instanceof Error ? error.message : "Could not open the document.",
3164
- "error"
3165
- )
3166
- );
3167
- }
3168
- });
3169
- } catch {
3170
- }
3171
- }
3172
- useNotify.getState().syncSource(source, items);
3173
- return () => useNotify.getState().syncSource(source, []);
3174
- }, [data, status, user?.externalId, source, onOpen, notify]);
3175
- const markRead = async (ids) => {
3176
- try {
3177
- await arbi.notifications.markRead(ids);
3178
- await queries.invalidateQueries({ queryKey });
3179
- } catch {
3180
- notify("Could not mark document mentions read.", "error");
3181
- }
3182
- };
3183
- return {
3184
- onMarkRead: (id) => {
3185
- if (id.startsWith("docx:")) void markRead([id.slice(5)]);
3186
- },
3187
- onMarkAllRead: () => {
3188
- void markRead(
3189
- data.filter((note) => !note.read && note.recipient.external_id === user?.externalId).map((note) => note.external_id)
3190
- );
3191
- }
3192
- };
3193
- }
3194
- function useConnectedWorkNotifications(onOpen) {
3195
- const { status, user, apiUrl } = useConnection();
3196
- const { notify } = useBlocksEnvironment();
3197
- const source = `work-notifications:${apiUrl}:${user?.externalId || ""}`;
3198
- const { data = [], markRead: persistRead } = useWorkNotifications({
3199
- apiUrl,
3200
- userId: user?.externalId,
3201
- enabled: status === "authenticated"
3202
- });
3203
- useEffect(() => {
3204
- const items = [];
3205
- if (status === "authenticated")
3206
- for (const note of data) {
3207
- if (note.recipient.external_id !== user?.externalId) continue;
3208
- const mapped = mapWorkNotification(note);
3209
- if (!mapped) continue;
3210
- items.push({
3211
- id: `work:${note.external_id}`,
3212
- title: mapped.title,
3213
- variant: note.type === "workflow_failed" ? "error" : note.type === "conversation_done" ? "success" : "info",
3214
- ts: Date.parse(note.created_at),
3215
- read: note.read,
3216
- source,
3217
- onSelect: () => {
3218
- void Promise.resolve().then(() => onOpen(mapped.target)).catch(
3219
- (error) => notify(
3220
- error instanceof Error ? error.message : "Could not open this notification.",
3221
- "error"
3222
- )
3223
- );
3224
- }
3225
- });
3226
- }
3227
- useNotify.getState().syncSource(source, items);
3228
- return () => useNotify.getState().syncSource(source, []);
3229
- }, [data, status, user?.externalId, source, onOpen, notify]);
3230
- const markRead = async (ids) => {
3231
- if (!ids.length) return;
3141
+ function ServerConnectionRow({ onRefresh, ...status }) {
3142
+ const { runtimeConfig } = useBlocksEnvironment();
3143
+ const [isRefreshing, setIsRefreshing] = useState(false);
3144
+ const view = serverConnectionView(status, runtimeConfig.deploymentDomain || "server");
3145
+ const refresh = async () => {
3146
+ setIsRefreshing(true);
3232
3147
  try {
3233
- await persistRead(ids);
3234
- } catch {
3235
- notify("Could not mark work notifications read.", "error");
3148
+ await onRefresh();
3149
+ } finally {
3150
+ setIsRefreshing(false);
3236
3151
  }
3237
3152
  };
3238
- return {
3239
- onMarkRead: (id) => {
3240
- if (data.some(
3241
- (note) => `work:${note.external_id}` === id && note.recipient.external_id === user?.externalId && mapWorkNotification(note)
3242
- ))
3243
- void markRead([id.slice(5)]);
3244
- },
3245
- onMarkAllRead: () => {
3246
- void markRead(
3247
- data.filter(
3248
- (note) => !note.read && note.recipient.external_id === user?.externalId && mapWorkNotification(note)
3249
- ).map((note) => note.external_id)
3250
- );
3153
+ return /* @__PURE__ */ jsx(SettingsRow, { label: "Server connection", description: view.description, children: /* @__PURE__ */ jsx(
3154
+ ServerConnectionButton,
3155
+ {
3156
+ state: view.state,
3157
+ label: view.label,
3158
+ isRefreshing,
3159
+ onRefresh: () => void refresh()
3251
3160
  }
3252
- };
3161
+ ) });
3253
3162
  }
3254
- function mapWorkNotification(note) {
3255
- const sender = [note.sender.given_name, note.sender.family_name].filter(Boolean).join(" ") || note.sender.email;
3256
- if (note.type === "workflow_failed") {
3257
- try {
3258
- const payload = JSON.parse(note.content || "{}");
3259
- if (!payload.workflow_ext_id?.match(/^wfl-[a-zA-Z0-9]+$/)) return null;
3260
- if (note.workspace_ext_id?.match(/^wrk-[a-zA-Z0-9]+$/) && note.conversation_ext_id?.match(/^con-[a-zA-Z0-9]+$/)) {
3261
- return {
3262
- title: "A workflow failed to run",
3263
- target: {
3264
- kind: "conversation",
3265
- workspaceId: note.workspace_ext_id,
3266
- conversationId: note.conversation_ext_id
3267
- }
3268
- };
3163
+ function ConnectedAccountSettings({
3164
+ avatarClassName,
3165
+ onManageBilling,
3166
+ formatIdentityPrice,
3167
+ afterProfile,
3168
+ getUnmetPasswordRequirement,
3169
+ securityRows,
3170
+ connection,
3171
+ onLogout,
3172
+ renderSessionIcon,
3173
+ renderSubscriptionLink
3174
+ }) {
3175
+ const [logoutOpen, setLogoutOpen] = useState(false);
3176
+ return /* @__PURE__ */ jsxs(SettingsPanel, { className: "max-w-2xl", children: [
3177
+ /* @__PURE__ */ jsx(ConnectedProfileCard, { avatarClassName, children: /* @__PURE__ */ jsx(
3178
+ ConnectedIdentityVerification,
3179
+ {
3180
+ onManageBilling,
3181
+ formatPrice: formatIdentityPrice
3269
3182
  }
3270
- return {
3271
- title: "A workflow failed to run",
3272
- target: {
3273
- kind: "workflow",
3274
- workflowId: payload.workflow_ext_id,
3275
- workspaceId: note.workspace_ext_id || void 0
3183
+ ) }),
3184
+ afterProfile,
3185
+ /* @__PURE__ */ jsx(ConnectedSecuritySection, { getUnmetRequirement: getUnmetPasswordRequirement, children: securityRows }),
3186
+ /* @__PURE__ */ jsx(SettingsSection, { icon: /* @__PURE__ */ jsx(Wifi, {}), title: "Session", children: /* @__PURE__ */ jsxs(SettingsCard, { children: [
3187
+ connection && /* @__PURE__ */ jsx(ServerConnectionRow, { ...connection }),
3188
+ /* @__PURE__ */ jsx(ConnectedSessionsRow, { renderSessionIcon }),
3189
+ /* @__PURE__ */ jsx(SettingsRow, { label: "Logout", description: "Sign out of your account on this device.", children: /* @__PURE__ */ jsxs(
3190
+ Button,
3191
+ {
3192
+ type: "button",
3193
+ variant: "secondary",
3194
+ size: "sm",
3195
+ onClick: onLogout ?? (() => setLogoutOpen(true)),
3196
+ className: "flex items-center gap-2",
3197
+ "data-testid": "logout-button",
3198
+ children: [
3199
+ /* @__PURE__ */ jsx(LogOut, { className: "w-4 h-4" }),
3200
+ "Logout"
3201
+ ]
3276
3202
  }
3277
- };
3278
- } catch {
3279
- return null;
3280
- }
3281
- }
3282
- if (note.type === "mail_draft_ready") {
3283
- const draftId = mailDraftIdFromContent(note.content);
3284
- if (!draftId) return null;
3285
- return {
3286
- title: `${sender} left a draft email for you to review`,
3287
- target: { kind: "mail_draft", draftId, mailbox: "native" }
3288
- };
3289
- }
3290
- const titles = {
3291
- mention: `${sender} mentioned you in a conversation`,
3292
- workspace_access_request: `${sender} needs workspace access to run a thread`,
3293
- conversation_ready: note.sender.external_id === note.recipient.external_id ? "Your thread is ready" : `${sender}\u2019s thread is ready`,
3294
- conversation_done: `${sender} marked a thread done`
3295
- };
3296
- const title = titles[note.type];
3297
- if (!title || !note.workspace_ext_id || !note.conversation_ext_id?.match(/^con-[a-zA-Z0-9]+$/))
3298
- return null;
3299
- return {
3300
- title,
3301
- target: {
3302
- kind: "conversation",
3303
- workspaceId: note.workspace_ext_id,
3304
- conversationId: note.conversation_ext_id,
3305
- ...note.message_ext_id ? { messageId: note.message_ext_id } : {}
3306
- }
3307
- };
3308
- }
3309
- function attachmentPath(accountId, messageId, attachmentId) {
3310
- return `${accountPath(accountId)}/messages/${encodeURIComponent(messageId)}/attachments/${encodeURIComponent(attachmentId)}`;
3311
- }
3312
- function saveFile(blob, name) {
3313
- const url = URL.createObjectURL(blob);
3314
- const link = document.createElement("a");
3315
- link.href = url;
3316
- link.download = name;
3317
- link.click();
3318
- setTimeout(() => URL.revokeObjectURL(url), 1e3);
3319
- }
3320
- function hydrateMailAttachments(client, account, messageId, attachments, { isOnline, offline }) {
3321
- return Promise.all(
3322
- attachments.map(async (a) => {
3323
- if (a.content_base64 != null) return a;
3324
- if (!isOnline) {
3325
- const file = await offline?.loadAttachment(account.id, messageId, a);
3326
- return file ? { ...a, content_base64: bytesToBase64(new Uint8Array(await file.arrayBuffer())) } : { ...a, content_base64: null };
3203
+ ) })
3204
+ ] }) }),
3205
+ /* @__PURE__ */ jsx(ConnectedDangerZone, { renderSubscriptionLink }),
3206
+ !onLogout && /* @__PURE__ */ jsx(
3207
+ ConnectedLogoutDialog,
3208
+ {
3209
+ open: logoutOpen,
3210
+ onClose: () => setLogoutOpen(false),
3211
+ renderSessionIcon
3327
3212
  }
3328
- const response = await client.fetch(attachmentPath(account.id, messageId, a.id));
3329
- return fileAttachment(new File([await response.blob()], a.name, { type: a.content_type }));
3330
- })
3331
- );
3213
+ )
3214
+ ] });
3332
3215
  }
3333
3216
  function ConnectedMailAccounts({
3334
3217
  policy,
@@ -3553,6 +3436,854 @@ function ConnectedMailAccounts({
3553
3436
  }
3554
3437
  );
3555
3438
  }
3439
+ var noop = () => {
3440
+ };
3441
+ function ConnectedMailSettings({ oauthReturnPath, settings }) {
3442
+ const { data: policy } = useMailPolicy();
3443
+ const accounts = useMailAccounts({ enabled: !!policy?.enabled });
3444
+ const { data: profile } = useProfile();
3445
+ if (accounts.isError) {
3446
+ return /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: accounts.error.message });
3447
+ }
3448
+ if (!policy || !accounts.isSuccess) return /* @__PURE__ */ jsx("p", { children: "Loading mail accounts\u2026" });
3449
+ return /* @__PURE__ */ jsx(
3450
+ ConnectedMailAccounts,
3451
+ {
3452
+ embedded: true,
3453
+ policy,
3454
+ accounts: accounts.data,
3455
+ user: profile && { given_name: profile.givenName, family_name: profile.familyName },
3456
+ oauthReturnPath,
3457
+ settings,
3458
+ onClose: noop
3459
+ },
3460
+ profile ? "named" : "unnamed"
3461
+ );
3462
+ }
3463
+ function ConnectedPrivacySettings({
3464
+ rows,
3465
+ showTipsReset = false
3466
+ }) {
3467
+ const { data: settings } = useUserSettings();
3468
+ const update = useUpdateUserSettings();
3469
+ const hideOnlineStatus = settings?.hide_online_status ?? false;
3470
+ const dismissedTips = settings?.dismissed_tips ?? [];
3471
+ return /* @__PURE__ */ jsxs(SettingsPanel, { className: "max-w-2xl", children: [
3472
+ /* @__PURE__ */ jsx(SettingsSection, { title: "Privacy and tips", children: /* @__PURE__ */ jsxs(SettingsCard, { children: [
3473
+ /* @__PURE__ */ jsx(
3474
+ SettingsRow,
3475
+ {
3476
+ label: "Show Online Status",
3477
+ labelFor: "showOnlineStatus",
3478
+ description: "When on, other users can see when you're online",
3479
+ children: /* @__PURE__ */ jsx(
3480
+ Switch,
3481
+ {
3482
+ id: "showOnlineStatus",
3483
+ checked: !hideOnlineStatus,
3484
+ onCheckedChange: (value) => update.mutate({ hide_online_status: !value }),
3485
+ "data-testid": "toggle-show-online-status"
3486
+ }
3487
+ )
3488
+ }
3489
+ ),
3490
+ rows,
3491
+ showTipsReset && /* @__PURE__ */ jsx(
3492
+ SettingsRow,
3493
+ {
3494
+ label: "Hidden tips",
3495
+ description: "Restore any Smart Tips you\u2019ve hidden with \u201Cdon\u2019t show again\u201D.",
3496
+ children: /* @__PURE__ */ jsxs(
3497
+ Button,
3498
+ {
3499
+ type: "button",
3500
+ variant: "outline",
3501
+ size: "sm",
3502
+ onClick: () => update.mutate({ dismissed_tips: [] }),
3503
+ disabled: dismissedTips.length === 0,
3504
+ className: "gap-1.5",
3505
+ "data-testid": "reset-tips-button",
3506
+ children: [
3507
+ /* @__PURE__ */ jsx(RotateCcw, { className: "h-4 w-4" }),
3508
+ "Reset tips"
3509
+ ]
3510
+ }
3511
+ )
3512
+ }
3513
+ )
3514
+ ] }) }),
3515
+ /* @__PURE__ */ jsx(ConnectedNotificationPreferences, {})
3516
+ ] });
3517
+ }
3518
+ var PROVIDER_NAMES = {
3519
+ openai: "OpenAI",
3520
+ fireworks_ai: "Fireworks AI",
3521
+ "vertex_ai-language-models": "Google",
3522
+ vertex_ai: "Google",
3523
+ gemini: "Google",
3524
+ anthropic: "Anthropic"
3525
+ };
3526
+ var isStandard = (model) => !!model?.tags?.includes("Standard");
3527
+ function PremiumCostHeader() {
3528
+ return /* @__PURE__ */ jsx("span", { className: "flex items-center gap-0.5", children: "\xA3/MT in-out" });
3529
+ }
3530
+ function cheapest(models) {
3531
+ return [...models].sort((a, b) => {
3532
+ const ao = a.output_cost_per_token;
3533
+ const bo = b.output_cost_per_token;
3534
+ if (ao == null && bo == null) return 0;
3535
+ if (ao == null) return 1;
3536
+ if (bo == null) return -1;
3537
+ return ao - bo;
3538
+ })[0];
3539
+ }
3540
+ var COLUMNS = [
3541
+ {
3542
+ colId: "model_name",
3543
+ headerName: "Model",
3544
+ field: "model_name",
3545
+ flex: 2,
3546
+ minWidth: 130,
3547
+ tooltipField: "model_name"
3548
+ },
3549
+ {
3550
+ colId: "provider",
3551
+ headerName: "Provider",
3552
+ field: "provider",
3553
+ flex: 1,
3554
+ minWidth: 120,
3555
+ cellRenderer: (params) => isStandard(params.data) ? /* @__PURE__ */ jsx(
3556
+ ModelProviderLabel,
3557
+ {
3558
+ logo: /* @__PURE__ */ jsx("img", { src: "/favicon.svg", alt: "ARBI", className: "size-3.5 flex-shrink-0 rounded-sm" }),
3559
+ children: "ARBI CITY"
3560
+ }
3561
+ ) : /* @__PURE__ */ jsx(
3562
+ ModelProviderLabel,
3563
+ {
3564
+ logo: /* @__PURE__ */ jsx(ProviderIcon, { modelName: params.data?.model_name, provider: params.value, size: 14 }),
3565
+ children: PROVIDER_NAMES[params.value ?? ""] || params.value || "\u2014"
3566
+ }
3567
+ )
3568
+ },
3569
+ {
3570
+ // Input and output cost in one column so the table fits the panel; sorted by output cost.
3571
+ colId: "cost",
3572
+ headerName: "Cost / MTok",
3573
+ headerComponentParams: { innerHeaderComponent: PremiumCostHeader },
3574
+ headerTooltip: "\xA3 per million tokens \u2014 input then output",
3575
+ field: "output_cost_per_token",
3576
+ flex: 1,
3577
+ minWidth: 120,
3578
+ type: "rightAligned",
3579
+ cellRenderer: (params) => /* @__PURE__ */ jsxs("span", { className: "tabular-nums", children: [
3580
+ formatGbpPerMillionTokens(params.data?.input_cost_per_token) ?? "\xA30",
3581
+ "-",
3582
+ formatGbpPerMillionTokens(params.data?.output_cost_per_token) ?? "\xA30"
3583
+ ] })
3584
+ }
3585
+ ];
3586
+ function ConnectedPremiumModels() {
3587
+ const { notify } = useBlocksEnvironment();
3588
+ const { data: settings } = useUserSettings();
3589
+ const update = useUpdateUserSettings();
3590
+ const { data: available } = useAvailableModels();
3591
+ const isDeveloper = settings?.developer === true;
3592
+ const premiumModel = settings?.premium_model;
3593
+ const premiumModels = useMemo(
3594
+ () => (available?.models ?? []).filter(
3595
+ (m) => m.tags?.includes("Premium") && (isDeveloper || !m.model_name.includes("@"))
3596
+ ),
3597
+ [available, isDeveloper]
3598
+ );
3599
+ const rows = useMemo(() => {
3600
+ const standards = (available?.models ?? []).filter(isStandard);
3601
+ if (standards.length === 0) return premiumModels;
3602
+ const reference = {
3603
+ ...standards[0],
3604
+ model_name: `Standard (${standards.map((m) => m.model_name).join(", ")})`
3605
+ };
3606
+ return [reference, ...premiumModels];
3607
+ }, [available, premiumModels]);
3608
+ const current = premiumModel ?? available?.premium_default ?? "";
3609
+ const save = useCallback(
3610
+ (model) => update.mutate(
3611
+ { premium_model: model },
3612
+ {
3613
+ onError: (err) => notify(`Failed to update Premium setting: ${String(err)}`, "error")
3614
+ }
3615
+ ),
3616
+ [update, notify]
3617
+ );
3618
+ const currentRef = useRef(current);
3619
+ currentRef.current = current;
3620
+ const [selected, setSelected] = useState([]);
3621
+ useEffect(() => {
3622
+ const match = premiumModels.filter((m) => m.model_name === current);
3623
+ setSelected(
3624
+ (prev) => prev.length === match.length && prev[0]?.model_name === match[0]?.model_name ? prev : match
3625
+ );
3626
+ }, [current, premiumModels]);
3627
+ const onSelectionChange = useCallback(
3628
+ (items) => {
3629
+ const picked = items.filter((m) => !isStandard(m));
3630
+ const next = picked[0]?.model_name;
3631
+ if (!next || next === currentRef.current) return;
3632
+ setSelected(picked);
3633
+ save(next);
3634
+ },
3635
+ [save]
3636
+ );
3637
+ if (premiumModels.length === 0) return null;
3638
+ return /* @__PURE__ */ jsx(SettingsPanel, { className: "max-w-2xl space-y-4", children: /* @__PURE__ */ jsx(SettingsSection, { title: "Premium models", children: /* @__PURE__ */ jsx(SettingsCard, { className: "space-y-0", children: /* @__PURE__ */ jsx(
3639
+ PremiumModelsFrame,
3640
+ {
3641
+ enabled: premiumModel !== "",
3642
+ onEnabledChange: (enabled) => {
3643
+ const target = enabled ? cheapest(premiumModels)?.model_name : "";
3644
+ if (target !== void 0) save(target);
3645
+ },
3646
+ children: /* @__PURE__ */ jsx(
3647
+ GridView,
3648
+ {
3649
+ items: rows,
3650
+ columnDefs: COLUMNS,
3651
+ getItemId: (m) => m.model_name,
3652
+ selection: { mode: "single", selected, onSelectionChange },
3653
+ gridOptions: {
3654
+ rowClassRules: { "opacity-60 italic": (p) => isStandard(p.data) }
3655
+ },
3656
+ height: Math.min(rows.length * 40 + 48, 320),
3657
+ testId: "premium-model-grid"
3658
+ }
3659
+ )
3660
+ }
3661
+ ) }) }) });
3662
+ }
3663
+ var SETTINGS_SECTION_IDS = {
3664
+ account: "account",
3665
+ mail: "mail",
3666
+ privacy: "privacy",
3667
+ chat: "chat"
3668
+ };
3669
+ function accountSettingsSection(props) {
3670
+ return {
3671
+ id: SETTINGS_SECTION_IDS.account,
3672
+ label: "Account",
3673
+ icon: /* @__PURE__ */ jsx(User, { className: "w-6 h-6" }),
3674
+ render: () => /* @__PURE__ */ jsx(ConnectedAccountSettings, { ...props })
3675
+ };
3676
+ }
3677
+ function mailSettingsSection(props) {
3678
+ return {
3679
+ id: SETTINGS_SECTION_IDS.mail,
3680
+ label: "Mail",
3681
+ icon: /* @__PURE__ */ jsx(Mail, { className: "w-6 h-6" }),
3682
+ render: () => /* @__PURE__ */ jsx(ConnectedMailSettings, { ...props })
3683
+ };
3684
+ }
3685
+ function privacySettingsSection(props) {
3686
+ return {
3687
+ id: SETTINGS_SECTION_IDS.privacy,
3688
+ label: "Privacy",
3689
+ icon: /* @__PURE__ */ jsx(HatGlasses, { className: "w-6 h-6" }),
3690
+ render: () => /* @__PURE__ */ jsx(ConnectedPrivacySettings, { ...props })
3691
+ };
3692
+ }
3693
+ function chatSettingsSection() {
3694
+ return {
3695
+ id: SETTINGS_SECTION_IDS.chat,
3696
+ label: "Chat",
3697
+ icon: /* @__PURE__ */ jsx(MessageSquare, { className: "w-6 h-6" }),
3698
+ render: () => /* @__PURE__ */ jsx(ConnectedPremiumModels, {})
3699
+ };
3700
+ }
3701
+ var DEFAULT_SETTINGS_SECTIONS = [
3702
+ accountSettingsSection(),
3703
+ privacySettingsSection(),
3704
+ chatSettingsSection()
3705
+ ];
3706
+ function ConnectedSettingsPage({
3707
+ sections = DEFAULT_SETTINGS_SECTIONS,
3708
+ section,
3709
+ onSectionChange,
3710
+ ...page
3711
+ }) {
3712
+ const requested = useRequestedSettingsSection();
3713
+ const [local, setLocal] = useState(requested?.section);
3714
+ useEffect(() => {
3715
+ if (requested) setLocal(requested.section);
3716
+ }, [requested]);
3717
+ const controlled = section !== void 0;
3718
+ return /* @__PURE__ */ jsx(
3719
+ SettingsPage,
3720
+ {
3721
+ ...page,
3722
+ sections,
3723
+ activeSectionId: controlled ? section : local,
3724
+ onSectionChange: (id) => {
3725
+ if (!controlled) setLocal(id);
3726
+ onSectionChange?.(id);
3727
+ }
3728
+ }
3729
+ );
3730
+ }
3731
+ function errorDetail(err) {
3732
+ const e = err;
3733
+ const detail = e?.detail ?? e?.apiError?.detail ?? e?.response?.data?.detail ?? e?.error?.detail;
3734
+ if (typeof detail === "string" && detail) return detail;
3735
+ const message = detail?.message;
3736
+ return typeof message === "string" && message ? message : void 0;
3737
+ }
3738
+ function errorStatus(err) {
3739
+ const e = err;
3740
+ return e?.status ?? e?.response?.status;
3741
+ }
3742
+ var workspaceWord = () => getEntityLabel("WORKSPACE").toLowerCase();
3743
+ var inviteMessage = (emails) => `${emails.length === 1 ? `${emails[0]} isn't on the platform yet.` : `These users aren't on the platform yet:
3744
+ ${emails.join("\n")}`}
3745
+
3746
+ Invite them by email? Once they sign up, they'll usually get access to this ${workspaceWord()} automatically \u2014 if not, they can request it themselves.`;
3747
+ function useConnectedWorkspaceSettings(workspaceId, { onLeft } = {}) {
3748
+ const { notify, confirm } = useBlocksEnvironment();
3749
+ const { workspaceId: openWorkspaceId, userId } = useConnectedWorkspace();
3750
+ const { data: workspaces } = useWorkspaces();
3751
+ const workspace = workspaces?.find((w) => w.external_id === workspaceId);
3752
+ const update = useUpdateWorkspace();
3753
+ const add = useAddWorkspaceMembers();
3754
+ const remove = useRemoveWorkspaceMembers();
3755
+ const members = workspace?.users ?? [];
3756
+ const role = members.find((m) => m.user.external_id === userId)?.role ?? null;
3757
+ const isOwner = role === "owner";
3758
+ const isMember = role !== null;
3759
+ const stillOpen = () => {
3760
+ if (!workspace) return false;
3761
+ if (openWorkspaceId === workspace.external_id) return true;
3762
+ notify(
3763
+ `Not saved: you switched to another ${workspaceWord()} first. Open "${workspace.name}" and try again.`,
3764
+ "warning"
3765
+ );
3766
+ return false;
3767
+ };
3768
+ const updateIdentity = async (data) => {
3769
+ if (!workspace || !stillOpen()) return;
3770
+ const changed = [
3771
+ ...data.name !== workspace.name ? ["name"] : [],
3772
+ ...data.description !== (workspace.description || "") ? ["description"] : []
3773
+ ];
3774
+ try {
3775
+ await update.mutateAsync({ name: data.name, description: data.description });
3776
+ if (changed.length > 0) {
3777
+ notify(`${getEntityLabel("WORKSPACE")} ${changed.join(", ")} updated`, "success");
3778
+ }
3779
+ } catch (err) {
3780
+ notify(err instanceof Error ? err.message : "Failed to update workspace", "error");
3781
+ throw err;
3782
+ }
3783
+ };
3784
+ const setPublic = async (isPublic) => {
3785
+ if (!workspace || !stillOpen()) return;
3786
+ await update.mutateAsync({ is_public: isPublic });
3787
+ notify(`Workspace is now ${isPublic ? "common" : "members-only"}`, "success");
3788
+ };
3789
+ const invite = async (emails, memberRole) => {
3790
+ try {
3791
+ await add.mutateAsync({ emails, role: memberRole, confirmInvite: true });
3792
+ notify(
3793
+ emails.length === 1 ? `Invitation sent to ${emails[0]}` : `Invitations sent to ${emails.length} users`,
3794
+ "success"
3795
+ );
3796
+ } catch (err) {
3797
+ const detail = errorDetail(err);
3798
+ notify(
3799
+ detail ? `Couldn't send the invitation: ${detail}` : "Failed to send the invitation.",
3800
+ "error"
3801
+ );
3802
+ }
3803
+ };
3804
+ const share = async (emails, memberRole = "collaborator") => {
3805
+ if (!workspace) return "error";
3806
+ const current = new Set(members.map((m) => m.user.email.toLowerCase()));
3807
+ try {
3808
+ const added = new Set(
3809
+ (await add.mutateAsync({ emails, role: memberRole }) ?? []).map(
3810
+ (m) => m.user.email.toLowerCase()
3811
+ )
3812
+ );
3813
+ const failed = emails.filter((email) => !added.has(email.toLowerCase()));
3814
+ if (failed.length === 0) return "added";
3815
+ const already = failed.filter((email) => current.has(email.toLowerCase()));
3816
+ const unknown = failed.filter((email) => !current.has(email.toLowerCase()));
3817
+ if (added.size > 0) {
3818
+ notify(`Added ${added.size} ${added.size === 1 ? "member" : "members"}`, "success");
3819
+ }
3820
+ if (already.length > 0) {
3821
+ notify(
3822
+ already.length === 1 ? `${already[0]} is already a member` : `${already.length} users are already members`,
3823
+ "info"
3824
+ );
3825
+ }
3826
+ if (unknown.length > 0 && await confirm({
3827
+ message: inviteMessage(unknown),
3828
+ title: "Invite by email?",
3829
+ kind: "yesno"
3830
+ })) {
3831
+ await invite(unknown, memberRole);
3832
+ return added.size > 0 ? "partial" : "invited";
3833
+ }
3834
+ return added.size > 0 ? "partial" : "already_member";
3835
+ } catch (err) {
3836
+ const status = errorStatus(err);
3837
+ const detail = errorDetail(err) || "Failed to add member to workspace";
3838
+ const lower = detail.toLowerCase();
3839
+ if (lower.includes("already has access")) return "already_member";
3840
+ const notRegistered = status === 404 || lower.includes("not found") || lower.includes("no user") || lower.includes("does not exist") || lower.includes("user not registered");
3841
+ if (notRegistered) {
3842
+ if (await confirm({
3843
+ message: inviteMessage(emails),
3844
+ title: "Invite by email?",
3845
+ kind: "yesno"
3846
+ })) {
3847
+ await invite(emails, memberRole);
3848
+ return "invited";
3849
+ }
3850
+ return "cancelled";
3851
+ }
3852
+ const quota = status === 402 || lower.includes("limit reached") || lower.includes("quota") || lower.includes("upgrade");
3853
+ if (!quota) notify(detail, "error");
3854
+ return "error";
3855
+ }
3856
+ };
3857
+ const removeMember = async (userExtId, email, name) => {
3858
+ if (!workspace || !isOwner) return;
3859
+ const ok = await confirm({
3860
+ message: `Remove ${name} (${email}) from the "${workspace.name}" ${getEntityLabel("WORKSPACE")}?
3861
+
3862
+ Note that ${getEntityLabel("WORKSPACEUSER", "PLURAL").toLowerCase()} may have saved private content in the workspace that you cannot see. If you remove them from the ${workspaceWord()} they will immediately lose access to any content in the ${workspaceWord()}.`,
3863
+ title: `Remove ${getEntityLabel("WORKSPACEUSER")}`
3864
+ });
3865
+ if (!ok) return;
3866
+ try {
3867
+ await remove.mutateAsync([userExtId]);
3868
+ notify(`Successfully removed ${name} from workspace`, "success");
3869
+ } catch {
3870
+ notify(`Failed to remove ${name} from workspace`, "error");
3871
+ }
3872
+ };
3873
+ const leave = async () => {
3874
+ if (!workspace || !userId || isOwner) return;
3875
+ const name = workspace.name;
3876
+ const ok = await confirm({
3877
+ message: `Are you sure you want to leave the "${name}" ${getEntityLabel("WORKSPACE")}?
3878
+
3879
+ You will lose access to all content in this ${workspaceWord()}.`,
3880
+ title: "Leave Workspace"
3881
+ });
3882
+ if (!ok) return;
3883
+ try {
3884
+ await remove.mutateAsync([userId]);
3885
+ onLeft?.();
3886
+ notify(`Successfully left ${name}`, "success");
3887
+ } catch {
3888
+ notify("Failed to leave workspace", "error");
3889
+ }
3890
+ };
3891
+ return {
3892
+ workspace,
3893
+ members,
3894
+ role,
3895
+ isOwner,
3896
+ isMember,
3897
+ updateIdentity,
3898
+ setPublic,
3899
+ share,
3900
+ removeMember,
3901
+ leave,
3902
+ isSharing: add.isPending,
3903
+ isRemoving: remove.isPending
3904
+ };
3905
+ }
3906
+ var isAgentMember = (member) => member.user.external_id.startsWith("agt-");
3907
+ var memberName = (member) => member.user.family_name ? `${member.user.given_name} ${member.user.family_name}` : member.user.given_name;
3908
+ function ConnectedWorkspaceSettings({
3909
+ workspaceId,
3910
+ project,
3911
+ projectLine,
3912
+ membersTable,
3913
+ shareDialog,
3914
+ children,
3915
+ onExport,
3916
+ onOpenActivity,
3917
+ onLeft,
3918
+ testId = "workspace-settings-page"
3919
+ }) {
3920
+ const settings = useConnectedWorkspaceSettings(workspaceId, { onLeft });
3921
+ const { workspace, members, isOwner, isMember } = settings;
3922
+ const { data: userSettings } = useUserSettings();
3923
+ const isDeveloper = userSettings?.developer === true;
3924
+ const showAgents = userSettings?.show_agent_sessions ?? false;
3925
+ const visibleMembers = useMemo(
3926
+ () => showAgents ? members : members.filter((m) => !isAgentMember(m)),
3927
+ [members, showAgents]
3928
+ );
3929
+ const [membersExpanded, setMembersExpanded] = useState(false);
3930
+ const [shareOpen, setShareOpen] = useState(false);
3931
+ if (!workspace) {
3932
+ return /* @__PURE__ */ jsx(PageLoading, { children: /* @__PURE__ */ jsx(LoadingIndicator, { message: "Loading workspace..." }) });
3933
+ }
3934
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3935
+ /* @__PURE__ */ jsxs(WorkspacePageFrame, { testId, children: [
3936
+ /* @__PURE__ */ jsxs(WorkspaceIdentityPanel, { children: [
3937
+ /* @__PURE__ */ jsx(
3938
+ EntityIdentityBar,
3939
+ {
3940
+ testId: "workspace-identity-bar",
3941
+ canEdit: isOwner,
3942
+ actions: isMember ? /* @__PURE__ */ jsx(
3943
+ ConnectedWorkspaceNotificationMenu,
3944
+ {
3945
+ workspaceId: workspace.external_id,
3946
+ onOpenActivity,
3947
+ testId: "workspace-home-notification-menu"
3948
+ }
3949
+ ) : void 0,
3950
+ fields: [
3951
+ {
3952
+ label: "Name",
3953
+ value: workspace.name,
3954
+ placeholder: "Untitled",
3955
+ maxLength: IDENTITY_NAME_MAX_LENGTH,
3956
+ valueClassName: "truncate text-base font-semibold",
3957
+ testId: "workspace-home-title",
3958
+ hideLabel: true,
3959
+ leading: /* @__PURE__ */ jsx(
3960
+ WorkspaceIdentity,
3961
+ {
3962
+ workspace: {
3963
+ ...toShellWorkspace(workspace),
3964
+ projectLine: projectLine?.(workspace)
3965
+ },
3966
+ expanded: false
3967
+ }
3968
+ ),
3969
+ trailing: project && /* @__PURE__ */ jsx(
3970
+ WorkspaceProjectSlot,
3971
+ {
3972
+ testId: "workspace-home-project",
3973
+ caption: `${getEntityLabel("PROJECT")}:`,
3974
+ children: project({ workspace, isOwner })
3975
+ }
3976
+ ),
3977
+ // Both fields go up together: the endpoint takes the pair.
3978
+ onSave: (name) => settings.updateIdentity({ name, description: workspace.description ?? "" })
3979
+ },
3980
+ {
3981
+ label: "Description",
3982
+ value: workspace.description ?? "",
3983
+ placeholder: "No description",
3984
+ multiline: true,
3985
+ valueClassName: "line-clamp-2 text-sm text-muted-foreground",
3986
+ testId: "workspace-home-description",
3987
+ hideLabel: true,
3988
+ trailing: /* @__PURE__ */ jsx(
3989
+ WorkspaceAudienceLine,
3990
+ {
3991
+ visibility: {
3992
+ testId: "workspace-home-visibility",
3993
+ caption: "Visibility:",
3994
+ toggle: isOwner && isDeveloper ? /* @__PURE__ */ jsx(
3995
+ CommonWorkspaceToggle,
3996
+ {
3997
+ isCommon: workspace.is_public ?? false,
3998
+ onToggle: (value) => void settings.setPublic(value),
3999
+ "data-testid": "workspace-visibility-toggle"
4000
+ }
4001
+ ) : void 0,
4002
+ stateText: workspace.is_public ? "Common \u2014 everyone on this deployment" : "Members only",
4003
+ stateHelp: workspace.is_public ? "Everyone on this deployment can see its files, not only its members." : "Only members of this workspace can see its files."
4004
+ },
4005
+ members: /* @__PURE__ */ jsx(
4006
+ MemberAvatarStack,
4007
+ {
4008
+ members: visibleMembers.map((m) => ({
4009
+ name: memberName(m),
4010
+ picture: m.user.picture
4011
+ })),
4012
+ total: visibleMembers.length,
4013
+ expanded: membersExpanded,
4014
+ onClick: () => setMembersExpanded((open) => !open),
4015
+ testId: "workspace-home-members-toggle"
4016
+ }
4017
+ ),
4018
+ share: isOwner && shareDialog ? {
4019
+ label: "Share",
4020
+ onClick: () => setShareOpen(true),
4021
+ testId: "workspace-quick-add-member"
4022
+ } : void 0
4023
+ }
4024
+ ),
4025
+ onSave: (description) => settings.updateIdentity({ name: workspace.name, description })
4026
+ }
4027
+ ]
4028
+ }
4029
+ ),
4030
+ isMember && membersTable && /* @__PURE__ */ jsx(
4031
+ ExpandableSection,
4032
+ {
4033
+ expanded: membersExpanded,
4034
+ testId: "workspace-settings-members-section",
4035
+ children: membersTable({
4036
+ workspace,
4037
+ members: visibleMembers,
4038
+ onRemove: settings.removeMember,
4039
+ isRemoving: settings.isRemoving
4040
+ })
4041
+ }
4042
+ )
4043
+ ] }),
4044
+ children,
4045
+ isMember && onExport && /* @__PURE__ */ jsx("div", { className: "flex justify-end px-4 pb-4", children: /* @__PURE__ */ jsxs(
4046
+ Button,
4047
+ {
4048
+ variant: "outline",
4049
+ size: "sm",
4050
+ onClick: onExport,
4051
+ "data-testid": "workspace-transfer-button",
4052
+ children: [
4053
+ /* @__PURE__ */ jsx(FolderInput, { className: "size-4" }),
4054
+ "Export, copy or move\u2026"
4055
+ ]
4056
+ }
4057
+ ) }),
4058
+ !isOwner && /* @__PURE__ */ jsx(
4059
+ LeaveFooter,
4060
+ {
4061
+ testId: "workspace-settings-footer",
4062
+ leave: {
4063
+ testId: "workspace-leave-button",
4064
+ label: settings.isRemoving ? "Leaving\u2026" : `Leave ${getEntityLabel("WORKSPACE").toLowerCase()}`,
4065
+ disabled: settings.isRemoving,
4066
+ onClick: () => void settings.leave()
4067
+ }
4068
+ }
4069
+ )
4070
+ ] }),
4071
+ isOwner && shareDialog?.({
4072
+ open: shareOpen,
4073
+ onOpenChange: setShareOpen,
4074
+ workspace,
4075
+ members: visibleMembers,
4076
+ onShare: settings.share,
4077
+ isSharing: settings.isSharing
4078
+ })
4079
+ ] });
4080
+ }
4081
+ function useConnectedDocxNotifications(onOpen) {
4082
+ const arbi = useArbi();
4083
+ const { status, user, apiUrl } = useConnection();
4084
+ const { notify } = useBlocksEnvironment();
4085
+ const queries = useQueryClient();
4086
+ const source = `docx-mentions:${apiUrl}:${user?.externalId || ""}`;
4087
+ const queryKey = ["docx-mentions", apiUrl, user?.externalId];
4088
+ const { data = [] } = useQuery({
4089
+ queryKey,
4090
+ queryFn: () => arbi.notifications.list({ type: "docx_mention" }),
4091
+ enabled: status === "authenticated",
4092
+ refetchInterval: 3e4
4093
+ });
4094
+ useArbiWebSocket((message) => {
4095
+ if (message.type === "docx_mention") void queries.invalidateQueries({ queryKey });
4096
+ });
4097
+ useEffect(() => {
4098
+ const items = [];
4099
+ if (status === "authenticated")
4100
+ for (const note of data) {
4101
+ if (note.recipient.external_id !== user?.externalId || !note.workspace_ext_id) continue;
4102
+ try {
4103
+ const target = JSON.parse(note.content || "{}");
4104
+ if (!target.document_id?.startsWith("doc-") || !target.comment_id) continue;
4105
+ const documentId = target.document_id, commentId = target.comment_id, workspaceId = note.workspace_ext_id;
4106
+ items.push({
4107
+ id: `docx:${note.external_id}`,
4108
+ title: "Mentioned you in a document comment",
4109
+ description: [note.sender.given_name, note.sender.family_name].filter(Boolean).join(" "),
4110
+ variant: "info",
4111
+ ts: Date.parse(note.created_at),
4112
+ read: note.read,
4113
+ source,
4114
+ onSelect: () => {
4115
+ void Promise.resolve(onOpen({ documentId, commentId, workspaceId })).catch(
4116
+ (error) => notify(
4117
+ error instanceof Error ? error.message : "Could not open the document.",
4118
+ "error"
4119
+ )
4120
+ );
4121
+ }
4122
+ });
4123
+ } catch {
4124
+ }
4125
+ }
4126
+ useNotify.getState().syncSource(source, items);
4127
+ return () => useNotify.getState().syncSource(source, []);
4128
+ }, [data, status, user?.externalId, source, onOpen, notify]);
4129
+ const markRead = async (ids) => {
4130
+ try {
4131
+ await arbi.notifications.markRead(ids);
4132
+ await queries.invalidateQueries({ queryKey });
4133
+ } catch {
4134
+ notify("Could not mark document mentions read.", "error");
4135
+ }
4136
+ };
4137
+ return {
4138
+ onMarkRead: (id) => {
4139
+ if (id.startsWith("docx:")) void markRead([id.slice(5)]);
4140
+ },
4141
+ onMarkAllRead: () => {
4142
+ void markRead(
4143
+ data.filter((note) => !note.read && note.recipient.external_id === user?.externalId).map((note) => note.external_id)
4144
+ );
4145
+ }
4146
+ };
4147
+ }
4148
+ function useConnectedWorkNotifications(onOpen) {
4149
+ const { status, user, apiUrl } = useConnection();
4150
+ const { notify } = useBlocksEnvironment();
4151
+ const source = `work-notifications:${apiUrl}:${user?.externalId || ""}`;
4152
+ const { data = [], markRead: persistRead } = useWorkNotifications({
4153
+ apiUrl,
4154
+ userId: user?.externalId,
4155
+ enabled: status === "authenticated"
4156
+ });
4157
+ useEffect(() => {
4158
+ const items = [];
4159
+ if (status === "authenticated")
4160
+ for (const note of data) {
4161
+ if (note.recipient.external_id !== user?.externalId) continue;
4162
+ const mapped = mapWorkNotification(note);
4163
+ if (!mapped) continue;
4164
+ items.push({
4165
+ id: `work:${note.external_id}`,
4166
+ title: mapped.title,
4167
+ variant: note.type === "workflow_failed" ? "error" : note.type === "conversation_done" ? "success" : "info",
4168
+ ts: Date.parse(note.created_at),
4169
+ read: note.read,
4170
+ source,
4171
+ onSelect: () => {
4172
+ void Promise.resolve().then(() => onOpen(mapped.target)).catch(
4173
+ (error) => notify(
4174
+ error instanceof Error ? error.message : "Could not open this notification.",
4175
+ "error"
4176
+ )
4177
+ );
4178
+ }
4179
+ });
4180
+ }
4181
+ useNotify.getState().syncSource(source, items);
4182
+ return () => useNotify.getState().syncSource(source, []);
4183
+ }, [data, status, user?.externalId, source, onOpen, notify]);
4184
+ const markRead = async (ids) => {
4185
+ if (!ids.length) return;
4186
+ try {
4187
+ await persistRead(ids);
4188
+ } catch {
4189
+ notify("Could not mark work notifications read.", "error");
4190
+ }
4191
+ };
4192
+ return {
4193
+ onMarkRead: (id) => {
4194
+ if (data.some(
4195
+ (note) => `work:${note.external_id}` === id && note.recipient.external_id === user?.externalId && mapWorkNotification(note)
4196
+ ))
4197
+ void markRead([id.slice(5)]);
4198
+ },
4199
+ onMarkAllRead: () => {
4200
+ void markRead(
4201
+ data.filter(
4202
+ (note) => !note.read && note.recipient.external_id === user?.externalId && mapWorkNotification(note)
4203
+ ).map((note) => note.external_id)
4204
+ );
4205
+ }
4206
+ };
4207
+ }
4208
+ function mapWorkNotification(note) {
4209
+ const sender = [note.sender.given_name, note.sender.family_name].filter(Boolean).join(" ") || note.sender.email;
4210
+ if (note.type === "workflow_failed") {
4211
+ try {
4212
+ const payload = JSON.parse(note.content || "{}");
4213
+ if (!payload.workflow_ext_id?.match(/^wfl-[a-zA-Z0-9]+$/)) return null;
4214
+ if (note.workspace_ext_id?.match(/^wrk-[a-zA-Z0-9]+$/) && note.conversation_ext_id?.match(/^con-[a-zA-Z0-9]+$/)) {
4215
+ return {
4216
+ title: "A workflow failed to run",
4217
+ target: {
4218
+ kind: "conversation",
4219
+ workspaceId: note.workspace_ext_id,
4220
+ conversationId: note.conversation_ext_id
4221
+ }
4222
+ };
4223
+ }
4224
+ return {
4225
+ title: "A workflow failed to run",
4226
+ target: {
4227
+ kind: "workflow",
4228
+ workflowId: payload.workflow_ext_id,
4229
+ workspaceId: note.workspace_ext_id || void 0
4230
+ }
4231
+ };
4232
+ } catch {
4233
+ return null;
4234
+ }
4235
+ }
4236
+ if (note.type === "mail_draft_ready") {
4237
+ const draftId = mailDraftIdFromContent(note.content);
4238
+ if (!draftId) return null;
4239
+ return {
4240
+ title: `${sender} left a draft email for you to review`,
4241
+ target: { kind: "mail_draft", draftId, mailbox: "native" }
4242
+ };
4243
+ }
4244
+ const titles = {
4245
+ mention: `${sender} mentioned you in a conversation`,
4246
+ workspace_access_request: `${sender} needs workspace access to run a thread`,
4247
+ conversation_ready: note.sender.external_id === note.recipient.external_id ? "Your thread is ready" : `${sender}\u2019s thread is ready`,
4248
+ conversation_done: `${sender} marked a thread done`
4249
+ };
4250
+ const title = titles[note.type];
4251
+ if (!title || !note.workspace_ext_id || !note.conversation_ext_id?.match(/^con-[a-zA-Z0-9]+$/))
4252
+ return null;
4253
+ return {
4254
+ title,
4255
+ target: {
4256
+ kind: "conversation",
4257
+ workspaceId: note.workspace_ext_id,
4258
+ conversationId: note.conversation_ext_id,
4259
+ ...note.message_ext_id ? { messageId: note.message_ext_id } : {}
4260
+ }
4261
+ };
4262
+ }
4263
+ function attachmentPath(accountId, messageId, attachmentId) {
4264
+ return `${accountPath(accountId)}/messages/${encodeURIComponent(messageId)}/attachments/${encodeURIComponent(attachmentId)}`;
4265
+ }
4266
+ function saveFile(blob, name) {
4267
+ const url = URL.createObjectURL(blob);
4268
+ const link = document.createElement("a");
4269
+ link.href = url;
4270
+ link.download = name;
4271
+ link.click();
4272
+ setTimeout(() => URL.revokeObjectURL(url), 1e3);
4273
+ }
4274
+ function hydrateMailAttachments(client, account, messageId, attachments, { isOnline, offline }) {
4275
+ return Promise.all(
4276
+ attachments.map(async (a) => {
4277
+ if (a.content_base64 != null) return a;
4278
+ if (!isOnline) {
4279
+ const file = await offline?.loadAttachment(account.id, messageId, a);
4280
+ return file ? { ...a, content_base64: bytesToBase64(new Uint8Array(await file.arrayBuffer())) } : { ...a, content_base64: null };
4281
+ }
4282
+ const response = await client.fetch(attachmentPath(account.id, messageId, a.id));
4283
+ return fileAttachment(new File([await response.blob()], a.name, { type: a.content_type }));
4284
+ })
4285
+ );
4286
+ }
3556
4287
  var sessionRooms = /* @__PURE__ */ new Map();
3557
4288
  function useWordBody({
3558
4289
  word,
@@ -8893,6 +9624,6 @@ function ConnectedAgentChatPanel({
8893
9624
  ] });
8894
9625
  }
8895
9626
 
8896
- export { ArbiAppProvider, ConnectedAgentChatPanel, ConnectedAgentCreator, ConnectedCalendar, ConnectedDangerZone, ConnectedIdentityVerification, ConnectedLogoutDialog, ConnectedMailAccounts, ConnectedMailComposer, ConnectedMailInviteCard, ConnectedMailMessage, ConnectedMailSetup, ConnectedMailbox, ConnectedNotificationCenter, ConnectedNotificationPreferences, ConnectedPasswordChangeDialog, ConnectedProfileCard, ConnectedPublicBooking, ConnectedRequireVerified, ConnectedSecuritySection, ConnectedSessionsRow, ConnectedSkillUpload, ConnectedSkillsLibrary, ConnectedTagTable, ConnectedTaskAccessRequest, ConnectedTaskActivityDialog, ConnectedThreadFollow, ConnectedUpcomingEvents, ConnectedWorkflowHistory, ConnectedWorkflowRunner, ConnectedWorkspaceActivity, ConnectedWorkspaceNotificationMenu, DEFAULT_CONNECTED_SKILL_UPLOAD_LABELS, DEFAULT_CONNECTED_WORKFLOW_RUNNER_LABELS, NotificationCenter, NotificationEvent, StreamedArtifact, WorkflowRunThread, bookingCancelLink, buildNotificationCenterItems, countNotificationTypes, defaultUnmetPasswordRequirement, filterNotificationCenterItems, openMeetingLink, requestCalendarComposer, requestCalendarEvent, resolveMailbox, useCalendarViewStore, useConnectedDocxNotifications, useConnectedShellWorkspaces, useConnectedWorkNotifications, workflowRunView };
9627
+ export { ArbiAppProvider, ConnectedAccountSettings, ConnectedAgentChatPanel, ConnectedAgentCreator, ConnectedCalendar, ConnectedDangerZone, ConnectedIdentityVerification, ConnectedLogoutDialog, ConnectedMailAccounts, ConnectedMailComposer, ConnectedMailInviteCard, ConnectedMailMessage, ConnectedMailSettings, ConnectedMailSetup, ConnectedMailbox, ConnectedNotificationCenter, ConnectedNotificationPreferences, ConnectedPasswordChangeDialog, ConnectedPremiumModels, ConnectedPrivacySettings, ConnectedProfileCard, ConnectedPublicBooking, ConnectedRequireVerified, ConnectedSecuritySection, ConnectedSessionsRow, ConnectedSettingsPage, ConnectedSkillUpload, ConnectedSkillsLibrary, ConnectedTagTable, ConnectedTaskAccessRequest, ConnectedTaskActivityDialog, ConnectedThreadFollow, ConnectedUpcomingEvents, ConnectedWorkflowHistory, ConnectedWorkflowRunner, ConnectedWorkspaceActivity, ConnectedWorkspaceNotificationMenu, ConnectedWorkspaceSettings, DEFAULT_CONNECTED_SKILL_UPLOAD_LABELS, DEFAULT_CONNECTED_WORKFLOW_RUNNER_LABELS, DEFAULT_SETTINGS_SECTIONS, NotificationCenter, NotificationEvent, SETTINGS_SECTION_IDS, SessionStatusIcon, StreamedArtifact, WorkflowRunThread, accountSettingsSection, bookingCancelLink, buildNotificationCenterItems, chatSettingsSection, countNotificationTypes, defaultUnmetPasswordRequirement, filterNotificationCenterItems, mailSettingsSection, openMeetingLink, privacySettingsSection, renderSessionStatusIcon, requestCalendarComposer, requestCalendarEvent, resolveMailbox, useCalendarViewStore, useConnectedDocxNotifications, useConnectedShellWorkspaces, useConnectedWorkNotifications, useConnectedWorkspaceSettings, workflowRunView };
8897
9628
  //# sourceMappingURL=index.js.map
8898
9629
  //# sourceMappingURL=index.js.map