@arbidocs/blocks 0.4.152 → 0.4.154

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 (221) hide show
  1. package/dist/{ConnectedNativeDocxComparison-OFPIXNJB.js → ConnectedNativeDocxComparison-OLWRQSRS.js} +11 -11
  2. package/dist/{ConnectedNativeDocxComparison-OFPIXNJB.js.map → ConnectedNativeDocxComparison-OLWRQSRS.js.map} +1 -1
  3. package/dist/{ConnectedNativeDocxComparison-Y5BNLNH6.cjs → ConnectedNativeDocxComparison-YORMOPPN.cjs} +12 -12
  4. package/dist/{ConnectedNativeDocxComparison-Y5BNLNH6.cjs.map → ConnectedNativeDocxComparison-YORMOPPN.cjs.map} +1 -1
  5. package/dist/{ConnectedNativeDocxEditor-LRYU5HPA.js → ConnectedNativeDocxEditor-34EBIIFS.js} +10 -10
  6. package/dist/{ConnectedNativeDocxEditor-LRYU5HPA.js.map → ConnectedNativeDocxEditor-34EBIIFS.js.map} +1 -1
  7. package/dist/{ConnectedNativeDocxEditor-HTEW5JAH.cjs → ConnectedNativeDocxEditor-EHTWGGX3.cjs} +12 -12
  8. package/dist/{ConnectedNativeDocxEditor-HTEW5JAH.cjs.map → ConnectedNativeDocxEditor-EHTWGGX3.cjs.map} +1 -1
  9. package/dist/{ConnectedStreamedWordArtifact-QW74LKHN.cjs → ConnectedStreamedWordArtifact-5DK6QGYN.cjs} +12 -12
  10. package/dist/ConnectedStreamedWordArtifact-5DK6QGYN.cjs.map +1 -0
  11. package/dist/{ConnectedStreamedWordArtifact-QAUVUCSX.js → ConnectedStreamedWordArtifact-GLIDLSAS.js} +11 -11
  12. package/dist/{ConnectedStreamedWordArtifact-QAUVUCSX.js.map → ConnectedStreamedWordArtifact-GLIDLSAS.js.map} +1 -1
  13. package/dist/WorkspaceTableView-5OWX53R5.js +376 -0
  14. package/dist/WorkspaceTableView-5OWX53R5.js.map +1 -0
  15. package/dist/WorkspaceTableView-ZFMAYHUD.cjs +378 -0
  16. package/dist/WorkspaceTableView-ZFMAYHUD.cjs.map +1 -0
  17. package/dist/agents/index.cjs +282 -282
  18. package/dist/agents/index.js +7 -7
  19. package/dist/{chunk-RQ2Y7USX.cjs → chunk-2VHYOTWW.cjs} +3 -3
  20. package/dist/chunk-2VHYOTWW.cjs.map +1 -0
  21. package/dist/{chunk-DTROMMDX.cjs → chunk-3VULDTNL.cjs} +4 -4
  22. package/dist/{chunk-DTROMMDX.cjs.map → chunk-3VULDTNL.cjs.map} +1 -1
  23. package/dist/{chunk-UTTTJSQU.cjs → chunk-4RPBUMHB.cjs} +4 -4
  24. package/dist/{chunk-UTTTJSQU.cjs.map → chunk-4RPBUMHB.cjs.map} +1 -1
  25. package/dist/chunk-53RCZPMR.cjs +496 -0
  26. package/dist/chunk-53RCZPMR.cjs.map +1 -0
  27. package/dist/chunk-5TDGVOR5.js +142 -0
  28. package/dist/chunk-5TDGVOR5.js.map +1 -0
  29. package/dist/{chunk-CU2O32Z4.cjs → chunk-6QAAIDQQ.cjs} +62 -99
  30. package/dist/chunk-6QAAIDQQ.cjs.map +1 -0
  31. package/dist/chunk-7HHYMDPE.js +431 -0
  32. package/dist/chunk-7HHYMDPE.js.map +1 -0
  33. package/dist/{chunk-SMN32BQ3.cjs → chunk-7NL6WJER.cjs} +3 -160
  34. package/dist/chunk-7NL6WJER.cjs.map +1 -0
  35. package/dist/{chunk-T74Q3MCZ.cjs → chunk-BDA3RHYD.cjs} +4 -4
  36. package/dist/{chunk-T74Q3MCZ.cjs.map → chunk-BDA3RHYD.cjs.map} +1 -1
  37. package/dist/{chunk-IXWJGOM2.js → chunk-BQ77KSXU.js} +3 -3
  38. package/dist/{chunk-IXWJGOM2.js.map → chunk-BQ77KSXU.js.map} +1 -1
  39. package/dist/chunk-BTF4AZMG.js +148 -0
  40. package/dist/chunk-BTF4AZMG.js.map +1 -0
  41. package/dist/{chunk-HALD6ZB5.cjs → chunk-C3SMTA3C.cjs} +4 -4
  42. package/dist/{chunk-HALD6ZB5.cjs.map → chunk-C3SMTA3C.cjs.map} +1 -1
  43. package/dist/{chunk-GAYMJWTC.cjs → chunk-CB4TIDEX.cjs} +6 -6
  44. package/dist/{chunk-GAYMJWTC.cjs.map → chunk-CB4TIDEX.cjs.map} +1 -1
  45. package/dist/{chunk-KPZZ5FHE.cjs → chunk-CNHUJRQ4.cjs} +10 -6
  46. package/dist/chunk-CNHUJRQ4.cjs.map +1 -0
  47. package/dist/{chunk-Q4BY2CQQ.cjs → chunk-CQCNU5KT.cjs} +28 -28
  48. package/dist/{chunk-Q4BY2CQQ.cjs.map → chunk-CQCNU5KT.cjs.map} +1 -1
  49. package/dist/{chunk-GRGS5M6O.cjs → chunk-CROGFB46.cjs} +160 -3
  50. package/dist/chunk-CROGFB46.cjs.map +1 -0
  51. package/dist/{chunk-QN47Q4N7.js → chunk-CU6LDQ57.js} +3 -3
  52. package/dist/{chunk-QN47Q4N7.js.map → chunk-CU6LDQ57.js.map} +1 -1
  53. package/dist/{chunk-EF4ZLKRM.js → chunk-DEPF5LQI.js} +3 -3
  54. package/dist/{chunk-EF4ZLKRM.js.map → chunk-DEPF5LQI.js.map} +1 -1
  55. package/dist/{chunk-JAANWQGB.js → chunk-ETZ5A3GU.js} +3 -3
  56. package/dist/{chunk-JAANWQGB.js.map → chunk-ETZ5A3GU.js.map} +1 -1
  57. package/dist/{chunk-TBEVGWY3.js → chunk-F57LNUSZ.js} +10 -6
  58. package/dist/chunk-F57LNUSZ.js.map +1 -0
  59. package/dist/{chunk-GFNELPDP.cjs → chunk-FM3IRQJW.cjs} +10 -5
  60. package/dist/chunk-FM3IRQJW.cjs.map +1 -0
  61. package/dist/chunk-FPHTSNOE.js +465 -0
  62. package/dist/chunk-FPHTSNOE.js.map +1 -0
  63. package/dist/{chunk-OVR3XMYL.js → chunk-FYZXDZM7.js} +3 -3
  64. package/dist/{chunk-OVR3XMYL.js.map → chunk-FYZXDZM7.js.map} +1 -1
  65. package/dist/{chunk-2FLWPM3B.cjs → chunk-GC2FSPSQ.cjs} +7 -7
  66. package/dist/{chunk-2FLWPM3B.cjs.map → chunk-GC2FSPSQ.cjs.map} +1 -1
  67. package/dist/{chunk-DB2OXRQC.js → chunk-GO3BN76C.js} +7 -7
  68. package/dist/{chunk-DB2OXRQC.js.map → chunk-GO3BN76C.js.map} +1 -1
  69. package/dist/{chunk-XZIYRKLW.cjs → chunk-H32DV7XS.cjs} +5 -139
  70. package/dist/chunk-H32DV7XS.cjs.map +1 -0
  71. package/dist/{chunk-4236BRZK.js → chunk-HP2C4MD3.js} +29 -3
  72. package/dist/chunk-HP2C4MD3.js.map +1 -0
  73. package/dist/{chunk-ZP6Q3KXU.cjs → chunk-HUATKA3M.cjs} +4 -4
  74. package/dist/{chunk-ZP6Q3KXU.cjs.map → chunk-HUATKA3M.cjs.map} +1 -1
  75. package/dist/chunk-ISHFVKVU.js +304 -0
  76. package/dist/chunk-ISHFVKVU.js.map +1 -0
  77. package/dist/chunk-JUUOJP7I.cjs +164 -0
  78. package/dist/chunk-JUUOJP7I.cjs.map +1 -0
  79. package/dist/{chunk-4KMLM3GY.cjs → chunk-KBO75NLM.cjs} +7 -7
  80. package/dist/{chunk-4KMLM3GY.cjs.map → chunk-KBO75NLM.cjs.map} +1 -1
  81. package/dist/{chunk-Z4NQ3TED.js → chunk-KCSIX7CY.js} +3 -3
  82. package/dist/{chunk-Z4NQ3TED.js.map → chunk-KCSIX7CY.js.map} +1 -1
  83. package/dist/{chunk-DN2KI4BU.js → chunk-KDLX5AA7.js} +3 -3
  84. package/dist/{chunk-DN2KI4BU.js.map → chunk-KDLX5AA7.js.map} +1 -1
  85. package/dist/{chunk-WFA2GVZJ.js → chunk-MF5KQ4PS.js} +3 -3
  86. package/dist/{chunk-WFA2GVZJ.js.map → chunk-MF5KQ4PS.js.map} +1 -1
  87. package/dist/{chunk-YXNNNP57.js → chunk-MNG7N6M2.js} +4 -4
  88. package/dist/{chunk-YXNNNP57.js.map → chunk-MNG7N6M2.js.map} +1 -1
  89. package/dist/chunk-MSFQDELO.cjs +482 -0
  90. package/dist/chunk-MSFQDELO.cjs.map +1 -0
  91. package/dist/{chunk-KSHKTOY2.js → chunk-NUSBINUM.js} +3 -3
  92. package/dist/chunk-NUSBINUM.js.map +1 -0
  93. package/dist/{chunk-EYKISBDO.cjs → chunk-OALEDG67.cjs} +5 -5
  94. package/dist/{chunk-EYKISBDO.cjs.map → chunk-OALEDG67.cjs.map} +1 -1
  95. package/dist/{chunk-COCGRJLA.cjs → chunk-OFV3PRF2.cjs} +7 -7
  96. package/dist/{chunk-COCGRJLA.cjs.map → chunk-OFV3PRF2.cjs.map} +1 -1
  97. package/dist/chunk-OOU4QLRK.cjs +319 -0
  98. package/dist/chunk-OOU4QLRK.cjs.map +1 -0
  99. package/dist/chunk-OU3RGQFX.cjs +136 -0
  100. package/dist/chunk-OU3RGQFX.cjs.map +1 -0
  101. package/dist/{chunk-3PCBYOIZ.js → chunk-P6RIBIVN.js} +38 -7
  102. package/dist/chunk-P6RIBIVN.js.map +1 -0
  103. package/dist/{chunk-LXTOOUEN.cjs → chunk-Q7CQYYZW.cjs} +5 -5
  104. package/dist/{chunk-LXTOOUEN.cjs.map → chunk-Q7CQYYZW.cjs.map} +1 -1
  105. package/dist/{chunk-CROTH2BS.js → chunk-QKR5LWDO.js} +9 -40
  106. package/dist/{chunk-CROTH2BS.js.map → chunk-QKR5LWDO.js.map} +1 -1
  107. package/dist/{chunk-HUJF2XM2.js → chunk-RE7NULEY.js} +3 -3
  108. package/dist/{chunk-HUJF2XM2.js.map → chunk-RE7NULEY.js.map} +1 -1
  109. package/dist/chunk-REH7PX3N.cjs +145 -0
  110. package/dist/chunk-REH7PX3N.cjs.map +1 -0
  111. package/dist/chunk-RQKWYKZY.js +127 -0
  112. package/dist/chunk-RQKWYKZY.js.map +1 -0
  113. package/dist/{chunk-U6JQ4KMX.cjs → chunk-SN2GZ4ZM.cjs} +29 -2
  114. package/dist/chunk-SN2GZ4ZM.cjs.map +1 -0
  115. package/dist/{chunk-R6VCPDPF.js → chunk-SZSJGZSO.js} +156 -6
  116. package/dist/chunk-SZSJGZSO.js.map +1 -0
  117. package/dist/{chunk-US3S4DCB.js → chunk-TF7HN5EU.js} +10 -5
  118. package/dist/chunk-TF7HN5EU.js.map +1 -0
  119. package/dist/{chunk-YKQ2DPIP.js → chunk-VF5EUAIV.js} +3 -3
  120. package/dist/{chunk-YKQ2DPIP.js.map → chunk-VF5EUAIV.js.map} +1 -1
  121. package/dist/{chunk-KMZWKSKO.cjs → chunk-VZPFYZZU.cjs} +4 -4
  122. package/dist/{chunk-KMZWKSKO.cjs.map → chunk-VZPFYZZU.cjs.map} +1 -1
  123. package/dist/{chunk-ZLEYLCE4.js → chunk-WK6FVIF7.js} +6 -156
  124. package/dist/chunk-WK6FVIF7.js.map +1 -0
  125. package/dist/{chunk-COA3S3CZ.js → chunk-XI37A7HH.js} +4 -4
  126. package/dist/{chunk-COA3S3CZ.js.map → chunk-XI37A7HH.js.map} +1 -1
  127. package/dist/{chunk-LGBAZD37.js → chunk-XRL4R2TT.js} +7 -139
  128. package/dist/chunk-XRL4R2TT.js.map +1 -0
  129. package/dist/{chunk-4JNKXOFZ.cjs → chunk-YBJ4QGNH.cjs} +11 -11
  130. package/dist/{chunk-4JNKXOFZ.cjs.map → chunk-YBJ4QGNH.cjs.map} +1 -1
  131. package/dist/{chunk-GFOEWPAP.cjs → chunk-YF3QUHKN.cjs} +49 -12
  132. package/dist/chunk-YF3QUHKN.cjs.map +1 -0
  133. package/dist/{chunk-H4D7WKDY.js → chunk-YNMO3DSR.js} +3 -3
  134. package/dist/{chunk-H4D7WKDY.js.map → chunk-YNMO3DSR.js.map} +1 -1
  135. package/dist/citations/index.cjs +10 -10
  136. package/dist/citations/index.js +2 -2
  137. package/dist/collaboration/index.cjs +77 -77
  138. package/dist/collaboration/index.js +2 -2
  139. package/dist/connect/docx.cjs +14 -14
  140. package/dist/connect/docx.js +10 -10
  141. package/dist/connect/index.cjs +1577 -962
  142. package/dist/connect/index.cjs.map +1 -1
  143. package/dist/connect/index.d.ts +3 -0
  144. package/dist/connect/index.js +1014 -450
  145. package/dist/connect/index.js.map +1 -1
  146. package/dist/connect/viewer.cjs +66 -66
  147. package/dist/connect/viewer.js +10 -10
  148. package/dist/connection/ConnectionProvider.d.ts +7 -0
  149. package/dist/connection/projects/ConnectedProjectsPanel.d.ts +34 -0
  150. package/dist/connection/projects/index.d.ts +1 -0
  151. package/dist/connection/workspace-dashboard/ConnectedWorkspaceDashboard.d.ts +37 -0
  152. package/dist/connection/workspace-dashboard/dashboard-rows.d.ts +42 -0
  153. package/dist/connection/workspace-dashboard/index.d.ts +1 -0
  154. package/dist/connection/workspace-list/ConnectedWorkspaceList.d.ts +37 -0
  155. package/dist/connection/workspace-list/WorkspaceCardsView.d.ts +15 -0
  156. package/dist/connection/workspace-list/WorkspaceFilterMenu.d.ts +4 -0
  157. package/dist/connection/workspace-list/WorkspaceTableView.d.ts +13 -0
  158. package/dist/connection/workspace-list/index.d.ts +5 -0
  159. package/dist/connection/workspace-list/projectBilling.d.ts +21 -0
  160. package/dist/connection/workspace-list/useConnectedWorkspaceList.d.ts +251 -0
  161. package/dist/connection/workspace-list/workspaceTable.d.ts +58 -0
  162. package/dist/connection/workspace-settings/ConnectedWorkspaceMembers.d.ts +26 -0
  163. package/dist/connection/workspace-settings/ConnectedWorkspaceSettings.d.ts +7 -9
  164. package/dist/connection/workspace-settings/index.d.ts +2 -1
  165. package/dist/connection/workspace-settings/useConnectedWorkspaceSettings.d.ts +0 -1
  166. package/dist/facts/index.cjs +3 -3
  167. package/dist/facts/index.js +2 -2
  168. package/dist/files/index.cjs +169 -169
  169. package/dist/files/index.js +3 -3
  170. package/dist/home/index.cjs +119 -459
  171. package/dist/home/index.cjs.map +1 -1
  172. package/dist/home/index.js +13 -419
  173. package/dist/home/index.js.map +1 -1
  174. package/dist/index.cjs +510 -510
  175. package/dist/index.js +18 -18
  176. package/dist/provider/BlocksProvider.d.ts +9 -1
  177. package/dist/retrieval/index.cjs +4 -4
  178. package/dist/retrieval/index.js +2 -2
  179. package/dist/settings/index.cjs +169 -165
  180. package/dist/settings/index.d.ts +1 -0
  181. package/dist/settings/index.js +2 -2
  182. package/dist/settings/tri-state-filters.d.ts +13 -0
  183. package/dist/shell/index.cjs +44 -44
  184. package/dist/shell/index.js +3 -3
  185. package/dist/site/index.cjs +5 -5
  186. package/dist/site/index.js +1 -1
  187. package/dist/studio/index.cjs +14 -14
  188. package/dist/studio/index.js +6 -6
  189. package/dist/workflow-canvas/index.cjs +27 -27
  190. package/dist/workflow-canvas/index.js +9 -9
  191. package/dist/workspaces/index.cjs +110 -369
  192. package/dist/workspaces/index.cjs.map +1 -1
  193. package/dist/workspaces/index.d.ts +2 -0
  194. package/dist/workspaces/index.js +12 -350
  195. package/dist/workspaces/index.js.map +1 -1
  196. package/dist/workspaces/workspace-groups.d.ts +90 -0
  197. package/dist/workspaces/workspace-roles.d.ts +11 -0
  198. package/node_modules/@arbidocs/coedit/package.json +1 -1
  199. package/package.json +5 -5
  200. package/dist/ConnectedStreamedWordArtifact-QW74LKHN.cjs.map +0 -1
  201. package/dist/chunk-3PCBYOIZ.js.map +0 -1
  202. package/dist/chunk-4236BRZK.js.map +0 -1
  203. package/dist/chunk-CU2O32Z4.cjs.map +0 -1
  204. package/dist/chunk-EV7W64B6.js +0 -134
  205. package/dist/chunk-EV7W64B6.js.map +0 -1
  206. package/dist/chunk-GFNELPDP.cjs.map +0 -1
  207. package/dist/chunk-GFOEWPAP.cjs.map +0 -1
  208. package/dist/chunk-GRGS5M6O.cjs.map +0 -1
  209. package/dist/chunk-KPZZ5FHE.cjs.map +0 -1
  210. package/dist/chunk-KSHKTOY2.js.map +0 -1
  211. package/dist/chunk-LGBAZD37.js.map +0 -1
  212. package/dist/chunk-R6VCPDPF.js.map +0 -1
  213. package/dist/chunk-RQ2Y7USX.cjs.map +0 -1
  214. package/dist/chunk-RXK3XP62.cjs +0 -144
  215. package/dist/chunk-RXK3XP62.cjs.map +0 -1
  216. package/dist/chunk-SMN32BQ3.cjs.map +0 -1
  217. package/dist/chunk-TBEVGWY3.js.map +0 -1
  218. package/dist/chunk-U6JQ4KMX.cjs.map +0 -1
  219. package/dist/chunk-US3S4DCB.js.map +0 -1
  220. package/dist/chunk-XZIYRKLW.cjs.map +0 -1
  221. package/dist/chunk-ZLEYLCE4.js.map +0 -1
@@ -1,46 +1,54 @@
1
1
  "use client";
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, ConnectionsLoading, ConnectionsError, ConnectionsEmpty, SettingsPage, SyncDialogBody, SyncField, SyncSelect, SyncSmallNote, SyncLoading, SyncReconnectNotice, SyncNote, SyncTreeFrame, SyncLinkRow, SyncLinkButton, SyncOptions, SyncOptionToggle, SyncDialogFooter, InvoicesDialog, PlanDialogFrame, ProjectList, RenameDialog, SharedProjectsSection, SharedProjectRow, MoreInfo, MoreInfoList, ProjectDetailHeader, PlanBadge, ProjectDetailSection, PlanStack, PlanNotice, PlanPickerCard, PlanPickerHeader, PricingToggle, PromoCodeInput, PlanActionButton, ProjectRow, QuotaMeter, FilterChip, applyInvertedIndexFilter, buildInvertedIndex, serverConnectionView, ServerConnectionButton, ModelProviderLabel, SyncFolderRow, SyncFolderStatus, PlanTierOption, PlanActionRow, SubscriptionStatusView, DailyCapField, UsagePanel, UsageSummary, UsageQuotaHint, UsageToggle, UsageSection, UsageLineChart, UsageLegend, UsageProportionBar, UsageActionButton, PlanInfoPopover, PlanCardGrid, ReferralRewardSummary, CheckoutDialogFrame, ConnectionCard, ReferralRewardNote } from '../chunk-4236BRZK.js';
4
- export { ConnectedAssistantDock, redlineStats, textToArtifact, toRedlineMarkdown, useConnectedAiTask, useConnectedChat, useSemanticSearch, useWorkspaceDocs } from '../chunk-Z4NQ3TED.js';
5
- import { useConnectedWorkspaceRole, ConnectedNativeDocxEditor } from '../chunk-DB2OXRQC.js';
6
- export { ConnectedWorkflowDocumentsField, ConnectedWorkflowLauncher, ConnectedWorkflowsTable, DEFAULT_CONNECTED_WORKFLOWS_TABLE_LABELS, NativeDocxSupportProvider, toWorkflowFieldDocument, useConnectedAgentOptions, useConnectedWorkflowScopeSource, useConnectedWorkspaceRole, useNativeDocxSupport } from '../chunk-DB2OXRQC.js';
2
+ import { useBillingSupport, formatMoney, isProProject, useSelfExtId, addonCharge, formatPeriodEnd, quoteParts, taxDetail, money2, ANNUAL_PREMIUM_AI_NOTE, totalWithTaxWord, planBadgeView, DEFAULT_SPEND_CAP_PENCE, findProPrices, packPrice, calcSavingsPercent, parseBudgetPounds, getQuotaItems, PRO_PACKS, planNameForPacks, proTierName, STORAGE_BLOCK_GB, ADDON_BLOCK_AI_GBP, formatResetDate, quoteError, POSTCODE_COUNTRIES, addonPrice, checkoutBlockPriceText, quoteTotalLine, apiErrorDetail, checkoutItemsLabel, projectGroupBilling, SUGGESTED_DAILY_CAP_PER_USER, FREE_STORAGE_MB, FREE_AI_GBP, PRO_AI_GBP, PRO_STORAGE_GB, plusVat, planPreviewLines, PAY_TODAY_UNPRICED, aiUsageResetTimestamp, TAX_LOCATION_INVALID, FREE_COLLABORATORS, MAX_CHECKOUT_BLOCKS, reduceBounds, splitBlocks, autoRoom, isAddonBudgetZero, nextRemovedBlockSize, stepLabel, addStepCaption, blocksLabel, MIN_AUTO_TOPUP_THRESHOLD_GBP, USAGE_CAP_LABEL, CAP_REACHED_MESSAGE, USAGE_CAP_HELP, PLAN_CHOICE_PACKS, nextPeriodBody, addonSettingsBody, budgetSavedMessage } from '../chunk-7HHYMDPE.js';
3
+ export { BillingSupportProvider, CAP_REACHED_MESSAGE, ZERO_BUDGET_MESSAGE, aiUsageResetTimestamp, formatMoney, formatResetDate, getQuotaItems, isAddonBudgetZero, isProProject, planBadgeView, planName, projectGroupBilling, useBillingSupport, useRewardBalance } from '../chunk-7HHYMDPE.js';
4
+ import { getRoleBadgeClass, formatRole, getRoleDescription, PageLoading, WorkspacePageFrame, WorkspaceIdentityPanel, WorkspaceProjectSlot, WorkspaceAudienceLine, CommonWorkspaceToggle, ExpandableSection, LeaveFooter, WorkspaceList, WorkspaceGroup, WorkspaceCard } from '../chunk-FPHTSNOE.js';
5
+ import { isAgentAccount, workspaceConversationCount, workspaceDocumentCount, isListedWorkspace, WORKSPACE_CATEGORY_FILTERS, projectFilterId, workspaceFilterAttributes, groupWorkspacesByProject, byRecentUpdate } from '../chunk-BTF4AZMG.js';
6
+ import { HomeLoadError, HomeFrame, HomeMain, HomeCenteredScroll, HomeCenteredColumn, DashboardRoot, DashboardBand, DashboardColumns, RecentList, DashboardAction, FactsStrip, FactMark, CreateTile } from '../chunk-ISHFVKVU.js';
7
+ import { ProjectBandTitle, PlainBandTitle } from '../chunk-RQKWYKZY.js';
8
+ import '../chunk-5TDGVOR5.js';
9
+ 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, ConnectionsLoading, ConnectionsError, ConnectionsEmpty, SettingsPage, SyncDialogBody, SyncField, SyncSelect, SyncSmallNote, SyncLoading, SyncReconnectNotice, SyncNote, SyncTreeFrame, SyncLinkRow, SyncLinkButton, SyncOptions, SyncOptionToggle, SyncDialogFooter, InvoicesDialog, PlanDialogFrame, ProjectList, RenameDialog, SharedProjectsSection, SharedProjectRow, MoreInfo, MoreInfoList, ProjectDetailHeader, PlanBadge, ProjectDetailSection, PlanStack, PlanNotice, PlanPickerCard, PlanPickerHeader, PricingToggle, PromoCodeInput, PlanActionButton, applyTriStateFilters, PanelFrame, PanelAddButton, PanelFrameBody, PanelScroll, PanelActionsRow, ProjectRow, QuotaMeter, FilterChip, applyInvertedIndexFilter, buildInvertedIndex, serverConnectionView, ServerConnectionButton, ModelProviderLabel, SyncFolderRow, SyncFolderStatus, PlanTierOption, PlanActionRow, SubscriptionStatusView, DailyCapField, UsagePanel, UsageSummary, UsageQuotaHint, UsageToggle, UsageSection, UsageLineChart, UsageLegend, UsageProportionBar, UsageActionButton, PlanInfoPopover, PlanCardGrid, ReferralRewardSummary, CheckoutDialogFrame, ConnectionCard, ReferralRewardNote } from '../chunk-HP2C4MD3.js';
10
+ export { ConnectedAssistantDock, redlineStats, textToArtifact, toRedlineMarkdown, useConnectedAiTask, useConnectedChat, useSemanticSearch, useWorkspaceDocs } from '../chunk-KCSIX7CY.js';
11
+ import { useConnectedWorkspaceRole, ConnectedNativeDocxEditor } from '../chunk-GO3BN76C.js';
12
+ export { ConnectedWorkflowDocumentsField, ConnectedWorkflowLauncher, ConnectedWorkflowsTable, DEFAULT_CONNECTED_WORKFLOWS_TABLE_LABELS, NativeDocxSupportProvider, toWorkflowFieldDocument, useConnectedAgentOptions, useConnectedWorkflowScopeSource, useConnectedWorkspaceRole, useNativeDocxSupport } from '../chunk-GO3BN76C.js';
7
13
  export { DocumentViewerSupportProvider, useDocumentViewerSupport } from '../chunk-EYJMMGXF.js';
8
14
  import { FilterButton, FilesViewCenter, FilesFilterBar, ROW_MIN, rowHeightForLines, linesForRowHeight, RowDensityControl, FolderFilterButton, FolderPickerRow, FieldLabelsSelect } from '../chunk-JGOST4IL.js';
9
15
  import '../chunk-RC6VTY2H.js';
10
- import { useConnectedTags, useConnectedDocuments, useConnectedConversations } from '../chunk-DN2KI4BU.js';
11
- export { ConnectedWorkspaceDataProvider, useConnectedConversations, useConnectedDocuments, useConnectedTags } from '../chunk-DN2KI4BU.js';
12
- import { ConnectionProvider, useConnection, useConnectedWorkspace } from '../chunk-US3S4DCB.js';
13
- export { ConnectionProvider, SESSION_EXPIRED_MESSAGE, isAuthenticated, useConnectedWorkspace, useConnection } from '../chunk-US3S4DCB.js';
16
+ import { useConnectedTags, useConnectedDocuments, useConnectedConversations } from '../chunk-KDLX5AA7.js';
17
+ export { ConnectedWorkspaceDataProvider, useConnectedConversations, useConnectedDocuments, useConnectedTags } from '../chunk-KDLX5AA7.js';
18
+ import { ConnectionProvider, useConnection, useConnectedWorkspace } from '../chunk-TF7HN5EU.js';
19
+ export { ConnectionProvider, SESSION_EXPIRED_MESSAGE, isAuthenticated, useConnectedWorkspace, useConnection } from '../chunk-TF7HN5EU.js';
14
20
  import { SignDocumentDialog } from '../chunk-2YOVK524.js';
15
21
  import '../chunk-MTSKK3BN.js';
16
22
  import '../chunk-265GOG4W.js';
17
23
  import { docIdsOf, toFactCitations, FactsToolbar, FactsFieldsButton, FactComposer, FactDateInput, FactSourcesRow, FactsLoading, FactsLoadError, FactsEmptyState, FactsCalendar, FactsGanttPane, FactsBulkBar, FactSourceGroup, EMPTY_FACT_DATE_FIELDS, withoutChunk, factDateSpanToFields, FactFieldRow, FactLabelsCell, enableFactTableColumnResize, citedVersionRef, withChunk, factDateFieldsToSpan, createFactColumns, FactRowActions, withoutDoc, withDoc, sourceDocCount, DEFAULT_FACT_COLUMN_LABELS } from '../chunk-WU34CHU5.js';
18
24
  import { ViewToggle } from '../chunk-JJA6GQKH.js';
19
25
  import { FactSourcesPanel, FactPassageItem } from '../chunk-HFZ45FD3.js';
20
- import { WorkspaceActivityList, WorkspaceNotificationMenu, ThreadFollowMenuItem, ThreadFollowButton, TagTable, TagPicker, tagsPageNouns, entitiesPhrase, ExtractEntitiesDialog, GridRowNavigator, LoadingIndicator, EntityIdentityBar, IDENTITY_NAME_MAX_LENGTH, tagTableDocx, documentCount, tagTableLabels, TagDetail, tagDetailLabels, tagNoteLabel, tagKindDescription, glossaryEntries, glossaryDocx, glossaryMarkdown, glossaryFileName } from '../chunk-YXNNNP57.js';
26
+ import { WorkspaceActivityList, WorkspaceNotificationMenu, ThreadFollowMenuItem, ThreadFollowButton, TagTable, TagPicker, tagsPageNouns, entitiesPhrase, ExtractEntitiesDialog, GridRowNavigator, LoadingIndicator, EntityIdentityBar, IDENTITY_NAME_MAX_LENGTH, tagTableDocx, documentCount, tagTableLabels, TagDetail, tagDetailLabels, tagNoteLabel, tagKindDescription, glossaryEntries, glossaryDocx, glossaryMarkdown, glossaryFileName } from '../chunk-MNG7N6M2.js';
21
27
  import { MemberAvatarStack } from '../chunk-XNOASBGW.js';
22
- import { renderSearchSnippet, SearchGroupHeader, isMeaningMatch, extractHighlightTerms, passesRelevanceCutoff, groupSearchResults, SearchPillToggle, SearchPagination, SearchPageFrame, SearchPageHeader, ApplyLabelDialog, SearchPageBody, SearchToolbarRow, SearchBar, SearchControlsBar, RelevanceThreshold, SearchTotalsHeadline, ApplyLabelButton, getSearchMatchHint, SearchResultsMain, SearchResultsInner, SearchErrorBanner, SearchResultList, SearchGroupCard, SearchNoResults, SearchEmptyState } from '../chunk-G4IYES7G.js';
23
28
  import { UsageMeter } from '../chunk-66TA5IBN.js';
29
+ import '../chunk-UJE32SST.js';
24
30
  import '../chunk-NHZK64TQ.js';
25
- import { PlainMailBodyEditor, buildMailFolderTree, MailFolderTree, draftMailCompose, replyMailCompose, emptyMailCompose, MailGrid, MailMessageView, MailDocumentPicker, parseMailRecipients } from '../chunk-R6VCPDPF.js';
31
+ import { renderSearchSnippet, SearchGroupHeader, isMeaningMatch, extractHighlightTerms, passesRelevanceCutoff, groupSearchResults, SearchPillToggle, SearchPagination, SearchPageFrame, SearchPageHeader, ApplyLabelDialog, SearchPageBody, SearchToolbarRow, SearchBar, SearchControlsBar, RelevanceThreshold, SearchTotalsHeadline, ApplyLabelButton, getSearchMatchHint, SearchResultsMain, SearchResultsInner, SearchErrorBanner, SearchResultList, SearchGroupCard, SearchNoResults, SearchEmptyState } from '../chunk-G4IYES7G.js';
32
+ import { PlainMailBodyEditor, MemberNameCell, MemberMutedText, MemberRoleCell, MemberListLoading, MemberBulkActions, buildMailFolderTree, MailFolderTree, draftMailCompose, replyMailCompose, emptyMailCompose, MailGrid, MailMessageView, MailDocumentPicker, parseMailRecipients } from '../chunk-SZSJGZSO.js';
33
+ import '../chunk-NBV56SGU.js';
26
34
  import '../chunk-SDOEHEJP.js';
27
35
  import { WorkspaceIdentity, workspaceKindColor } from '../chunk-A3XPS2EU.js';
28
- import '../chunk-SV65E4QW.js';
36
+ import { buildDeepLinkPath } from '../chunk-SV65E4QW.js';
29
37
  import '../chunk-ZCOVDK2E.js';
30
38
  import { isDefinitionsLabel, DOCX_MIME_TYPE, toDefinitionSource, definitionLabels } from '../chunk-DIB4JYUY.js';
31
- import { SearchHit } from '../chunk-EF4ZLKRM.js';
39
+ import { SearchHit } from '../chunk-DEPF5LQI.js';
32
40
  import { TimelineZoomControl } from '../chunk-4EZVCGRL.js';
33
41
  import { decodeWhitespaceEntities } from '../chunk-AF6RDAJF.js';
34
- 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-3PCBYOIZ.js';
42
+ 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, STATUS_LABELS, asTaskStatus, workflowToSkillMarkdown } from '../chunk-P6RIBIVN.js';
35
43
  import { MultiSelect } from '../chunk-CQCC7LE7.js';
36
- import { PersonPill } from '../chunk-COA3S3CZ.js';
37
- import '../chunk-IXWJGOM2.js';
38
- import { TriStateFilterMenu, DocumentPicker } from '../chunk-KSHKTOY2.js';
44
+ import { PersonPill } from '../chunk-XI37A7HH.js';
45
+ import { SectionLabel } from '../chunk-BQ77KSXU.js';
46
+ import { TriStateFilterMenu, DocumentPicker } from '../chunk-NUSBINUM.js';
39
47
  import '../chunk-P6GHJSLR.js';
40
48
  import '../chunk-M4S75AEJ.js';
41
49
  import '../chunk-5LXQPP2K.js';
42
50
  import '../chunk-RLWIUUQ5.js';
43
- import '../chunk-YKQ2DPIP.js';
51
+ import '../chunk-VF5EUAIV.js';
44
52
  import { SelectionBar, SelectionBarAction } from '../chunk-NUNKSZKU.js';
45
53
  import { FilterInput } from '../chunk-YU2KUMGE.js';
46
54
  import { GridView } from '../chunk-N5YEF3LC.js';
@@ -57,21 +65,21 @@ import { splitDocRef, stepLevels, stepDocuments, stepKindOf, initialRunInputs, w
57
65
  import '../chunk-TZGBRLPK.js';
58
66
  import '../chunk-AUS3KBHJ.js';
59
67
  import '../chunk-AA3PT6KR.js';
60
- import '../chunk-SLSBJRWW.js';
68
+ import { useIsPhone } from '../chunk-SLSBJRWW.js';
61
69
  import '../chunk-NPLYHR2E.js';
62
70
  import '../chunk-7F6CBP3Z.js';
63
- import { PassagePill, useCopyText } from '../chunk-JAANWQGB.js';
64
- import { useBlocksEnvironment, useRequestedSettingsSection } from '../chunk-TBEVGWY3.js';
71
+ import { PassagePill, useCopyText } from '../chunk-ETZ5A3GU.js';
72
+ import { useBlocksEnvironment, useRequestedSettingsSection, BlocksProvider } from '../chunk-F57LNUSZ.js';
65
73
  import { ModalScaffold, ModalSection } from '../chunk-TX2ZICS7.js';
66
74
  import { fmtDate, initials } from '../chunk-OXF2IFXG.js';
67
75
  import '../chunk-VUNV25KB.js';
68
- import { lazy, memo, useState, useEffect, createContext, useCallback, useMemo, useRef, Suspense, useContext, useSyncExternalStore, useLayoutEffect, useId } from 'react';
76
+ import { lazy, memo, useState, useEffect, useCallback, useMemo, useRef, Suspense, useSyncExternalStore, useLayoutEffect, useId } from 'react';
69
77
  import { QueryClient, QueryClientProvider, useQueryClient, useQuery } from '@tanstack/react-query';
70
- import { HtmlIcon, useArbiSessionState, 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, useCreateTag, useSetTagValues, useUpdateTagKindSchema, useFacts, useDeleteTag, useExtractEntities, 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, useConnectorVendorVisibility, useConnectorCatalog, useMyConnectors, useDisconnectConnector, useSlackConnection, useDisconnectSlack, isMailboxSyncVendor, isSharePointVendor, useUpdateWorkspace, useAddWorkspaceMembers, useRemoveWorkspaceMembers, toShellWorkspace, useEnableMailboxSync, useMailboxFolders, useEnableDriveSync, useDriveFolderChildren, connectorErrorStatus, formatGbp, useProjectInvoices, useProjects, useUpdateProjectFields, useUserUsageToday, useChargeWatch, useAddonQuote, STILL_WORKING, useProjectBillingPortal, useIsSlow, useProducts, useCreateProject, useDeleteProject, useRefreshProject, MAX_RETRIEVE_DOC_IDS, useSemanticSearch, useAssignDocTags, useArbiWebSocket, useWorkNotifications, describeServerNotification, 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, connectorReturnTo, ArbiWebSocketProvider, isDeploymentUserNotification, getWorkspaceActionText, getWorkspaceSentPhrase, BOX_SEAT_REFUSED, BOX_SEAT_REFUSED_TITLE, documentActivityPhrase, isSignatureNotificationType, inputRequestTitle, WORK_NOTIFICATION_LABELS, documentDisplayName, getWorkspaceKind, formatRelativeTime, useCreateWork, useActOnStep, useConversationThreads, useUpdateTag, usePassageQuotes, useUpdateFact, useDeleteFact, useCreateFact, ProviderIcon, formatGbpPerMillionTokens, useDriveFolderDocCount, useChangeProjectPlan, useCancelProjectSubscription, usePreviewProjectPlanChange, useAddProjectAddonBlock, useProjectUsage, usePlanQuote, useCreateProjectCheckout, useInvalidateProjects, 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, useBookingPages, useDeleteBookingPage, SHAREPOINT_VENDORS, useUpdateProjectNextPeriodAddons, useUpdateProjectAddonSettings, useSyncCalendarAccount, useUpdateCalendarAccount, useDisconnectCalendarAccount, ACCOUNT_VENDOR, useCalDavProfiles, useConnectCalDavAccount, useSaveBookingPage, useCreateRoom } from '@arbidocs/react';
78
+ import { HtmlIcon, useArbiSessionState, 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, useCreateTag, useSetTagValues, useUpdateTagKindSchema, useFacts, useDeleteTag, useExtractEntities, 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, useConnectorVendorVisibility, useConnectorCatalog, useMyConnectors, useDisconnectConnector, useSlackConnection, useDisconnectSlack, isMailboxSyncVendor, isSharePointVendor, useUpdateWorkspace, useAddWorkspaceMembers, useRemoveWorkspaceMembers, useSetWorkspaceMemberRoles, toShellWorkspace, useEnableMailboxSync, useMailboxFolders, useEnableDriveSync, useDriveFolderChildren, connectorErrorStatus, useProjectInvoices, useProjects, useUpdateProjectFields, useUserUsageToday, formatGbp, useChargeWatch, useAddonQuote, STILL_WORKING, useProjectBillingPortal, useIsSlow, useProducts, useCreateProject, useDeleteProject, useRefreshProject, useCanCreateProjects, useDeleteWorkspaces, PROJECT_CREATION_DENIED_REASON, MAX_RETRIEVE_DOC_IDS, useSemanticSearch, useAssignDocTags, useArbiWebSocket, useWorkNotifications, describeServerNotification, 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, connectorReturnTo, ArbiWebSocketProvider, isDeploymentUserNotification, getWorkspaceActionText, getWorkspaceSentPhrase, BOX_SEAT_REFUSED, BOX_SEAT_REFUSED_TITLE, documentActivityPhrase, isSignatureNotificationType, inputRequestTitle, WORK_NOTIFICATION_LABELS, documentDisplayName, getWorkspaceKind, formatRelativeTime, useCreateWork, useActOnStep, useConversationThreads, useUpdateTag, usePassageQuotes, useUpdateFact, useDeleteFact, useCreateFact, ProviderIcon, formatGbpPerMillionTokens, useDriveFolderDocCount, useChangeProjectPlan, useCancelProjectSubscription, usePreviewProjectPlanChange, useAddProjectAddonBlock, useProjectUsage, usePlanQuote, useCreateProjectCheckout, useInvalidateProjects, 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, useBookingPages, useDeleteBookingPage, SHAREPOINT_VENDORS, useUpdateProjectNextPeriodAddons, useUpdateProjectAddonSettings, useSyncCalendarAccount, useUpdateCalendarAccount, useDisconnectCalendarAccount, ACCOUNT_VENDOR, useCalDavProfiles, useConnectCalDavAccount, useSaveBookingPage, useCreateRoom } from '@arbidocs/react';
71
79
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
72
- import { Badge, Button, Label, Input, cn, Textarea, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, tagKindNouns, tagKindTitle, isImageDocument, getDocumentTitle, getEntityColor, IconToggle, VisibilityToggle, Switch, getEntityLabel, ProjectEntity, DialogFooter, EntityIcon, DocumentEntity, EntityPill, ShieldIcon, getTagTypeLabel, Popover, PopoverTrigger, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, Tooltip, TooltipTrigger, TooltipContent, PopoverContent, Tabs, TabsList, TabsTrigger, TabsContent, UserEntity, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, formatFriendlyDate, VerifiedToggle, Progress } from '@arbidocs/react/ui';
80
+ import { Badge, Button, Label, Input, cn, Textarea, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, tagKindNouns, tagKindTitle, isImageDocument, getDocumentTitle, getEntityColor, IconToggle, VisibilityToggle, Switch, getEntityLabel, formatFriendlyDate, ProjectEntity, DialogFooter, EntityIcon, getDocIcon, Tooltip, TooltipTrigger, TooltipContent, DocumentEntity, EntityPill, ShieldIcon, getTagTypeLabel, Popover, PopoverTrigger, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, UserEntity, PopoverContent, Tabs, TabsList, TabsTrigger, TabsContent, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, VerifiedToggle, Progress } from '@arbidocs/react/ui';
73
81
  import { useNotify, notify, sharedSearchSession, takePendingSearch } from '@arbidocs/react/shell';
74
- import { Bell, Activity, Info, UserCheck, Trash2, Loader2, Upload, Link2, Search, Plus, ArrowLeft, ExternalLink, Tags, CheckCircle2, Milestone, Monitor, UserCircle, KeyRound, Radio, LogOut, Wifi, RotateCcw, Mail, User, HatGlasses, MessageSquare, PlugZap, FolderInput, PoundSterling, HardDrive, Users, FileText, Tag, Settings, Video, Printer, CalendarDays, Clock, MapPin, Globe, Sparkles, ArrowUpCircle, Building2, Contact, Scale, NotebookPen, Check, X, Pencil, BookA, ChevronDown, Paperclip, Quote, Download, Send, Inbox, CalendarX, CalendarCheck, Minimize2, Maximize2, Minus, CalendarSearch, DoorOpen, RefreshCw, AlertTriangle } from 'lucide-react';
82
+ import { Bell, Activity, Info, UserCheck, Trash2, Loader2, Upload, Link2, Search, Plus, ArrowLeft, ExternalLink, Tags, CheckCircle2, Milestone, Monitor, UserCircle, KeyRound, Radio, LogOut, Wifi, RotateCcw, Mail, User, HatGlasses, MessageSquare, PlugZap, FolderInput, SquareStack, Table, FileText, MessagesSquare, Tag, Settings, Video, Printer, CalendarDays, Clock, MapPin, Globe, Sparkles, ArrowUpCircle, Building2, Contact, Scale, NotebookPen, Check, X, Pencil, BookA, ChevronDown, Users, Paperclip, Quote, Download, Send, Inbox, CalendarX, CalendarCheck, Minimize2, Maximize2, Minus, CalendarSearch, DoorOpen, RefreshCw, AlertTriangle } from 'lucide-react';
75
83
  import { downloadBlob, useIsOnline, useOptionalDocumentTools, fetchDocumentPdf, DocumentToolsProvider } from '@arbidocs/react/document-tools';
76
84
  import { useStreamedArtifact } from '@arbidocs/react/artifacts';
77
85
  import { FLAT_TAG_KINDS, TAG_KINDS, refusalReason, getChildTags, tagUseCount, flattenTagTree, isFlatKind, isEntityTag, tagsForScope, filterDocumentTags, isLabelTag, getTagDescendantIds, getEligibleParentTags, canTagHaveParent } from '@arbidocs/sdk/browser';
@@ -672,13 +680,13 @@ function NotificationCenter({
672
680
  var PAGE_SIZE = 100;
673
681
  function localTime(timestamp) {
674
682
  const date = new Date(timestamp);
675
- const time = date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
683
+ const time2 = date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
676
684
  const today = /* @__PURE__ */ new Date();
677
685
  const yesterday = new Date(today);
678
686
  yesterday.setDate(today.getDate() - 1);
679
- if (date.toDateString() === today.toDateString()) return `Today, ${time}`;
680
- if (date.toDateString() === yesterday.toDateString()) return `Yesterday, ${time}`;
681
- return `${date.toLocaleDateString([], { month: "short", day: "numeric" })}, ${time}`;
687
+ if (date.toDateString() === today.toDateString()) return `Today, ${time2}`;
688
+ if (date.toDateString() === yesterday.toDateString()) return `Yesterday, ${time2}`;
689
+ return `${date.toLocaleDateString([], { month: "short", day: "numeric" })}, ${time2}`;
682
690
  }
683
691
  function DefaultUser({ user }) {
684
692
  const arbi = useArbi();
@@ -6660,27 +6668,11 @@ function useConnectedWorkspaceSettings(workspaceId, { onLeft } = {}) {
6660
6668
  }
6661
6669
  return "cancelled";
6662
6670
  }
6663
- const quota2 = status === 402 || lower.includes("limit reached") || lower.includes("quota") || lower.includes("upgrade");
6664
- if (!quota2) notify14(detail, "error");
6671
+ const quota = status === 402 || lower.includes("limit reached") || lower.includes("quota") || lower.includes("upgrade");
6672
+ if (!quota) notify14(detail, "error");
6665
6673
  return "error";
6666
6674
  }
6667
6675
  };
6668
- const removeMember = async (userExtId, email, name) => {
6669
- if (!workspace || !isOwner) return;
6670
- const ok = await confirm({
6671
- message: `Remove ${name} (${email}) from the "${workspace.name}" ${getEntityLabel("WORKSPACE")}?
6672
-
6673
- 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()}.`,
6674
- title: `Remove ${getEntityLabel("WORKSPACEUSER")}`
6675
- });
6676
- if (!ok) return;
6677
- try {
6678
- await remove.mutateAsync([userExtId]);
6679
- notify14(`Successfully removed ${name} from workspace`, "success");
6680
- } catch {
6681
- notify14(`Failed to remove ${name} from workspace`, "error");
6682
- }
6683
- };
6684
6676
  const leave = async () => {
6685
6677
  if (!workspace || !userId || isOwner) return;
6686
6678
  const name = workspace.name;
@@ -6708,19 +6700,246 @@ You will lose access to all content in this ${workspaceWord()}.`,
6708
6700
  updateIdentity,
6709
6701
  setPublic,
6710
6702
  share,
6711
- removeMember,
6712
6703
  leave,
6713
6704
  isSharing: add.isPending,
6714
6705
  isRemoving: remove.isPending
6715
6706
  };
6716
6707
  }
6708
+ var memberName = (user) => user.family_name ? `${user.given_name} ${user.family_name}` : user.given_name;
6709
+ var ALL_ROLES = ["owner", "collaborator", "guest"].map((value) => ({ value, label: formatRole(value), badgeClass: getRoleBadgeClass(value) }));
6710
+ var BULK_ROLES = ALL_ROLES.filter((r) => r.value !== "owner");
6711
+ var ROLE_ORDER = { owner: 0, collaborator: 1, guest: 2 };
6712
+ function roleLock(targetId, selfId, isOwner) {
6713
+ if (!isOwner) return "Only owners can change roles";
6714
+ if (targetId === selfId) return "Your role can only be changed by another owner";
6715
+ return null;
6716
+ }
6717
+ var defaultRenderMember = (member) => {
6718
+ const name = memberName(member.user);
6719
+ return /* @__PURE__ */ jsx(
6720
+ UserEntity,
6721
+ {
6722
+ size: "xs",
6723
+ variant: "pill",
6724
+ showTooltip: false,
6725
+ interactive: false,
6726
+ displayName: name,
6727
+ initials: initials(name || member.user.email),
6728
+ picture: member.user.picture
6729
+ }
6730
+ );
6731
+ };
6732
+ function ConnectedWorkspaceMembers({
6733
+ workspace,
6734
+ members,
6735
+ selfId,
6736
+ isOwner: isOwnerRaw,
6737
+ isLoading = false,
6738
+ readOnly = false,
6739
+ renderMember = defaultRenderMember,
6740
+ gridState,
6741
+ onGridStateChange
6742
+ }) {
6743
+ const { confirm, notify: notify14 } = useBlocksEnvironment();
6744
+ const isOwner = isOwnerRaw && !readOnly;
6745
+ const [selected, setSelected] = useState([]);
6746
+ const updateRoles = useSetWorkspaceMemberRoles();
6747
+ const remove = useRemoveWorkspaceMembers();
6748
+ const memberWord = (count) => getEntityLabel("WORKSPACEUSER", count === 1 ? "SINGULAR" : "PLURAL");
6749
+ const workspaceWord2 = getEntityLabel("WORKSPACE").toLowerCase();
6750
+ const inWorkspace = `"${workspace.name}"`;
6751
+ const setRoles = async (rows2, role) => {
6752
+ const single = rows2.length === 1 ? memberName(rows2[0].user) : null;
6753
+ try {
6754
+ await updateRoles.mutateAsync({ userIds: rows2.map((r) => r.user.external_id), role });
6755
+ notify14(
6756
+ single ? `${single}'s role updated to ${formatRole(role)} in "${workspace.name}"` : `Updated ${rows2.length} users to ${formatRole(role)} in "${workspace.name}"`,
6757
+ "success"
6758
+ );
6759
+ return true;
6760
+ } catch {
6761
+ notify14(
6762
+ single ? `Failed to update ${single}'s role` : `Failed to update roles in "${workspace.name}"`,
6763
+ "error"
6764
+ );
6765
+ return false;
6766
+ }
6767
+ };
6768
+ const rows = useMemo(
6769
+ () => [...members].sort((a, b) => {
6770
+ if (a.user.external_id === selfId) return -1;
6771
+ if (b.user.external_id === selfId) return 1;
6772
+ return (ROLE_ORDER[a.role] ?? 3) - (ROLE_ORDER[b.role] ?? 3);
6773
+ }),
6774
+ [members, selfId]
6775
+ );
6776
+ const columnDefs = useMemo(
6777
+ () => [
6778
+ {
6779
+ colId: "name",
6780
+ headerName: "Name",
6781
+ flex: 1,
6782
+ minWidth: 150,
6783
+ sortable: true,
6784
+ valueGetter: (p) => p.data ? memberName(p.data.user) : "",
6785
+ cellRenderer: (p) => p.data ? /* @__PURE__ */ jsx(MemberNameCell, { children: renderMember(p.data) }) : null
6786
+ },
6787
+ {
6788
+ colId: "email",
6789
+ headerName: "Email",
6790
+ flex: 1,
6791
+ minWidth: 180,
6792
+ sortable: true,
6793
+ valueGetter: (p) => p.data?.user.email ?? "",
6794
+ // Plain text, not a mailto: the row's click selects it.
6795
+ cellRenderer: (p) => p.data?.user.email ? /* @__PURE__ */ jsx(MemberMutedText, { className: "truncate", title: p.data.user.email, children: p.data.user.email }) : null
6796
+ },
6797
+ {
6798
+ colId: "role",
6799
+ headerName: "Role",
6800
+ width: 145,
6801
+ minWidth: 130,
6802
+ sortable: true,
6803
+ valueGetter: (p) => p.data?.role ?? "",
6804
+ cellRenderer: (p) => {
6805
+ const row = p.data;
6806
+ if (!row) return null;
6807
+ const lock = roleLock(row.user.external_id, selfId, isOwner);
6808
+ return /* @__PURE__ */ jsx(
6809
+ MemberRoleCell,
6810
+ {
6811
+ role: row.role,
6812
+ roles: ALL_ROLES,
6813
+ tooltip: lock ?? getRoleDescription(row.role),
6814
+ canChange: !lock,
6815
+ isPending: updateRoles.isPending,
6816
+ onChange: (value) => void setRoles([row], value),
6817
+ temporaryHint: row.is_temporary ? "Temporary, session-scoped grant \u2014 expires with the session." : void 0
6818
+ }
6819
+ );
6820
+ }
6821
+ },
6822
+ {
6823
+ colId: "joined_at",
6824
+ headerName: "Joined",
6825
+ width: 145,
6826
+ minWidth: 125,
6827
+ sortable: true,
6828
+ valueGetter: (p) => p.data ? new Date(p.data.joined_at).getTime() : "",
6829
+ cellRenderer: (p) => p.data ? /* @__PURE__ */ jsx(MemberMutedText, { className: "cursor-default", children: formatFriendlyDate(p.data.joined_at) }) : null
6830
+ },
6831
+ {
6832
+ colId: "conversation_count",
6833
+ headerName: getEntityLabel("CONVERSATION", "PLURAL"),
6834
+ width: 95,
6835
+ minWidth: 85,
6836
+ sortable: true,
6837
+ type: "numericColumn",
6838
+ valueGetter: (p) => p.data?.conversation_count ?? 0,
6839
+ cellRenderer: (p) => p.data ? /* @__PURE__ */ jsx(MemberMutedText, { children: p.data.conversation_count }) : null
6840
+ },
6841
+ {
6842
+ colId: "document_count",
6843
+ headerName: "Docs",
6844
+ width: 90,
6845
+ minWidth: 80,
6846
+ sortable: true,
6847
+ type: "numericColumn",
6848
+ valueGetter: (p) => p.data?.document_count ?? 0,
6849
+ cellRenderer: (p) => p.data ? /* @__PURE__ */ jsx(MemberMutedText, { children: p.data.document_count }) : null
6850
+ },
6851
+ {
6852
+ colId: "files_mb",
6853
+ headerName: "Storage",
6854
+ width: 110,
6855
+ minWidth: 95,
6856
+ sortable: true,
6857
+ type: "numericColumn",
6858
+ valueGetter: (p) => p.data?.files_mb ?? 0,
6859
+ cellRenderer: (p) => {
6860
+ if (!p.data) return null;
6861
+ const mb = p.data.files_mb ?? 0;
6862
+ return /* @__PURE__ */ jsxs(MemberMutedText, { children: [
6863
+ mb >= 100 ? Math.round(mb).toLocaleString("en-US") : mb.toFixed(1),
6864
+ " MB"
6865
+ ] });
6866
+ }
6867
+ }
6868
+ ],
6869
+ // eslint-disable-next-line react-hooks/exhaustive-deps
6870
+ [selfId, isOwner, updateRoles.isPending, renderMember, workspace.name]
6871
+ );
6872
+ const removeSelected = async () => {
6873
+ const count = selected.length;
6874
+ if (count === 0) return;
6875
+ const names = count === 1 ? `"${memberName(selected[0].user)}"` : `${count} ${memberWord(count).toLowerCase()}`;
6876
+ const members2 = getEntityLabel("WORKSPACEUSER", "PLURAL").toLowerCase();
6877
+ const confirmed = await confirm({
6878
+ title: `Remove ${count} ${memberWord(count)}`,
6879
+ message: `Remove ${names} from ${inWorkspace}?
6880
+
6881
+ Note that ${members2} may have saved private content in the ${workspaceWord2} that you cannot see. Once removed they immediately lose access to any content in the ${workspaceWord2}.`
6882
+ });
6883
+ if (!confirmed) return;
6884
+ try {
6885
+ await remove.mutateAsync(selected.map((m) => m.user.external_id));
6886
+ setSelected([]);
6887
+ notify14(`Removed ${names} from ${inWorkspace}`, "success");
6888
+ } catch {
6889
+ notify14(`Failed to remove some users from ${inWorkspace}`, "error");
6890
+ }
6891
+ };
6892
+ const changeSelectedRoles = async (role) => {
6893
+ const changeable = selected.filter((m) => !roleLock(m.user.external_id, selfId, isOwner));
6894
+ if (changeable.length === 0) return;
6895
+ if (await setRoles(changeable, role)) setSelected([]);
6896
+ };
6897
+ const canRemoveSelected = selected.every(
6898
+ (m) => m.role !== "owner" && m.user.external_id !== selfId
6899
+ );
6900
+ const canChangeRoleSelected = selected.some((m) => !roleLock(m.user.external_id, selfId, isOwner));
6901
+ const ownerOnly = `Only available to ${workspaceWord2} owner`;
6902
+ if (isLoading) return /* @__PURE__ */ jsx(MemberListLoading, {});
6903
+ return /* @__PURE__ */ jsxs("div", { "data-testid": "workspace-users", className: "relative flex flex-col", children: [
6904
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto", children: /* @__PURE__ */ jsx(
6905
+ GridView,
6906
+ {
6907
+ items: rows,
6908
+ columnDefs,
6909
+ getItemId: (m) => m.user.external_id,
6910
+ selection: { mode: "multiple", selected, onSelectionChange: setSelected },
6911
+ persistState: !!onGridStateChange,
6912
+ gridId: `workspace-users-${workspace.external_id}-v6`,
6913
+ gridState,
6914
+ onGridStateChange,
6915
+ height: "300px",
6916
+ className: "w-full grid-sort-left"
6917
+ }
6918
+ ) }),
6919
+ !readOnly && /* @__PURE__ */ jsx(SelectionBar, { count: selected.length, onClear: () => setSelected([]), children: /* @__PURE__ */ jsx(
6920
+ MemberBulkActions,
6921
+ {
6922
+ roles: BULK_ROLES,
6923
+ onChangeRole: (value) => void changeSelectedRoles(value),
6924
+ isRoleDisabled: !isOwner || !canChangeRoleSelected || updateRoles.isPending,
6925
+ roleTooltip: !isOwner ? ownerOnly : selected.length === 0 ? "Select users to change their role" : !canChangeRoleSelected ? "You cannot change your own role" : "Change role for selected users",
6926
+ isOwner,
6927
+ onRemove: () => void removeSelected(),
6928
+ isRemoveDisabled: !isOwner || !canRemoveSelected || remove.isPending,
6929
+ removeTooltip: !isOwner ? ownerOnly : "Remove selected from workspace"
6930
+ }
6931
+ ) })
6932
+ ] });
6933
+ }
6717
6934
  var isAgentMember = (member) => member.user.external_id.startsWith("agt-");
6718
- var memberName = (member) => member.user.family_name ? `${member.user.given_name} ${member.user.family_name}` : member.user.given_name;
6935
+ var memberName2 = (member) => member.user.family_name ? `${member.user.given_name} ${member.user.family_name}` : member.user.given_name;
6719
6936
  function ConnectedWorkspaceSettings({
6720
6937
  workspaceId,
6721
6938
  project,
6722
6939
  projectLine,
6723
- membersTable,
6940
+ renderMember,
6941
+ membersGridState,
6942
+ onMembersGridStateChange,
6724
6943
  shareDialog,
6725
6944
  children,
6726
6945
  onExport,
@@ -6730,6 +6949,7 @@ function ConnectedWorkspaceSettings({
6730
6949
  }) {
6731
6950
  const settings = useConnectedWorkspaceSettings(workspaceId, { onLeft });
6732
6951
  const { workspace, members, isOwner, isMember } = settings;
6952
+ const { userId } = useConnectedWorkspace();
6733
6953
  const { data: userSettings } = useUserSettings();
6734
6954
  const isDeveloper = userSettings?.developer === true;
6735
6955
  const showAgents = userSettings?.show_agent_sessions ?? false;
@@ -6817,7 +7037,7 @@ function ConnectedWorkspaceSettings({
6817
7037
  MemberAvatarStack,
6818
7038
  {
6819
7039
  members: visibleMembers.map((m) => ({
6820
- name: memberName(m),
7040
+ name: memberName2(m),
6821
7041
  picture: m.user.picture
6822
7042
  })),
6823
7043
  total: visibleMembers.length,
@@ -6838,17 +7058,23 @@ function ConnectedWorkspaceSettings({
6838
7058
  ]
6839
7059
  }
6840
7060
  ),
6841
- isMember && membersTable && /* @__PURE__ */ jsx(
7061
+ isMember && /* @__PURE__ */ jsx(
6842
7062
  ExpandableSection,
6843
7063
  {
6844
7064
  expanded: membersExpanded,
6845
7065
  testId: "workspace-settings-members-section",
6846
- children: membersTable({
6847
- workspace,
6848
- members: visibleMembers,
6849
- onRemove: settings.removeMember,
6850
- isRemoving: settings.isRemoving
6851
- })
7066
+ children: /* @__PURE__ */ jsx(
7067
+ ConnectedWorkspaceMembers,
7068
+ {
7069
+ workspace,
7070
+ members: visibleMembers,
7071
+ selfId: userId,
7072
+ isOwner,
7073
+ renderMember,
7074
+ gridState: membersGridState,
7075
+ onGridStateChange: onMembersGridStateChange
7076
+ }
7077
+ )
6852
7078
  }
6853
7079
  )
6854
7080
  ] }),
@@ -7516,20 +7742,6 @@ function ConnectedDriveSyncDialog({
7516
7742
  }
7517
7743
  );
7518
7744
  }
7519
- var BillingSupportContext = createContext({ stripeEnabled: false });
7520
- function BillingSupportProvider({
7521
- value,
7522
- children
7523
- }) {
7524
- return /* @__PURE__ */ jsx(BillingSupportContext.Provider, { value, children });
7525
- }
7526
- function useBillingSupport() {
7527
- return useContext(BillingSupportContext);
7528
- }
7529
- function useSelfExtId() {
7530
- const arbi = useArbi();
7531
- return arbi.isLoggedIn ? arbi.user.identity()?.externalId ?? void 0 : void 0;
7532
- }
7533
7745
  var focus = null;
7534
7746
  var listeners = /* @__PURE__ */ new Set();
7535
7747
  function requestProjectBillingFocus(next) {
@@ -7549,363 +7761,8 @@ function BillingProjectEntity({
7549
7761
  ...props
7550
7762
  }) {
7551
7763
  const { stripeEnabled } = useBillingSupport();
7552
- const isPaid = stripeEnabled && (subscription === "active" || subscription === "past_due" || subscription === "dev");
7553
- return /* @__PURE__ */ jsx(ProjectEntity, { ...props, subscription, isPaid });
7554
- }
7555
-
7556
- // src/connection/billing/plan-constants.ts
7557
- var PRO_AI_GBP = 10;
7558
- var PRO_STORAGE_GB = 5;
7559
- var ADDON_BLOCK_AI_GBP = 25;
7560
- var STORAGE_BLOCK_GB = 25;
7561
- var DEFAULT_SPEND_CAP_PENCE = 1e4;
7562
- var MIN_AUTO_TOPUP_THRESHOLD_GBP = 1;
7563
- var FREE_AI_GBP = 1;
7564
- var FREE_STORAGE_MB = 50;
7565
- var UNLIMITED_COLLABORATORS = 999;
7566
- var SUGGESTED_DAILY_CAP_PER_USER = 10;
7567
-
7568
- // src/connection/billing/quota-items.ts
7569
- var fmt = (v) => Math.round(v).toLocaleString("en-US");
7570
- function formatResetDate(unixTimestamp) {
7571
- if (!unixTimestamp) return null;
7572
- const date = new Date(unixTimestamp * 1e3);
7573
- return date.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
7574
- }
7575
- function aiUsageResetTimestamp(project) {
7576
- const periodEnd = project.plan_interval === "year" ? null : project.current_period_end;
7577
- const ts = project.addons?.ai_usage_reset_at ?? periodEnd ?? project.quotas?.budget_reset_at ?? null;
7578
- return ts && ts * 1e3 > Date.now() ? ts : null;
7579
- }
7580
- var quota = (q) => ({
7581
- used: q?.used ?? 0,
7582
- limit: q?.limit ?? 0
7583
- });
7584
- function storageText(gbValue, limitGb, unit = true) {
7585
- if (limitGb >= 1) {
7586
- const n = Math.round(gbValue * 10) / 10;
7587
- return `${n.toLocaleString("en-US")}${unit ? " GB" : ""}`;
7588
- }
7589
- return `${fmt(gbValue * 1e3)}${unit ? " MB" : ""}`;
7590
- }
7591
- var pctOf = (used, limit) => limit > 0 ? used / limit * 100 : 0;
7592
- function getQuotaItems(quotas) {
7593
- const aiUsage = quota(quotas?.ai_usage);
7594
- const storage = quota(quotas?.storage_gb);
7595
- const collaborators = quota(quotas?.collaborators);
7596
- const unlimitedCollaborators = collaborators.limit >= UNLIMITED_COLLABORATORS;
7597
- return [
7598
- {
7599
- key: "ai-usage",
7600
- icon: PoundSterling,
7601
- label: "AI usage",
7602
- used: formatGbp(aiUsage.used),
7603
- usedOfLimit: `${formatGbp(aiUsage.used)} / ${formatGbp(aiUsage.limit)}`,
7604
- pct: pctOf(aiUsage.used, aiUsage.limit)
7605
- },
7606
- {
7607
- key: "storage",
7608
- icon: HardDrive,
7609
- label: "Storage",
7610
- used: storageText(storage.used, storage.limit),
7611
- usedOfLimit: `${storageText(storage.used, storage.limit, false)} / ${storageText(
7612
- storage.limit,
7613
- storage.limit
7614
- )}`,
7615
- pct: pctOf(storage.used, storage.limit)
7616
- },
7617
- {
7618
- key: "collaborators",
7619
- icon: Users,
7620
- label: "Collaborators",
7621
- used: fmt(collaborators.used),
7622
- usedOfLimit: unlimitedCollaborators ? `${fmt(collaborators.used)} / Unlimited` : `${fmt(collaborators.used)} / ${fmt(collaborators.limit)}`,
7623
- // Zero seats (Free) IS the cap: 0 / 0 shows a full destructive bar,
7624
- // because you can't add anyone — the truth the upgrade door answers.
7625
- // (Only when the quota is actually present; a missing field on a
7626
- // partial payload stays an empty bar, not a false alarm.)
7627
- pct: unlimitedCollaborators ? 0 : quotas?.collaborators && collaborators.limit === 0 ? 100 : pctOf(collaborators.used, collaborators.limit)
7628
- }
7629
- ];
7630
- }
7631
- function useRewardBalance() {
7632
- const { data } = useUserSettings();
7633
- const ed = data?.extra_discount;
7634
- if (!ed || !ed.amount || ed.amount <= 0) return null;
7635
- return { amount: ed.amount, currency: ed.currency || "gbp" };
7636
- }
7637
- function formatMoney(cents, currency = "gbp") {
7638
- const value = cents / 100;
7639
- const isWhole = Number.isInteger(value);
7640
- const c = currency.toLowerCase();
7641
- const symbol = c === "usd" ? "$" : c === "gbp" ? "\xA3" : c === "eur" ? "\u20AC" : currency.toUpperCase() + " ";
7642
- return `${symbol}${value.toLocaleString("en-US", {
7643
- minimumFractionDigits: isWhole ? 0 : 2,
7644
- maximumFractionDigits: isWhole ? 0 : 2
7645
- })}`;
7646
- }
7647
- var gbp = (pence) => formatMoney(pence, "gbp");
7648
- function formatPeriodEnd(unix) {
7649
- if (!unix) return null;
7650
- return new Date(unix * 1e3).toLocaleDateString("en-GB", {
7651
- day: "numeric",
7652
- month: "short",
7653
- year: "numeric"
7654
- });
7655
- }
7656
- function addonPricePence(kind, addons) {
7657
- return kind === "ai_usage" ? addons.ai_block_price_pence : addons.storage_block_price_pence;
7658
- }
7659
- function addonPriceExVatPence(kind, addons) {
7660
- return kind === "ai_usage" ? addons.ai_block_price_ex_vat_pence : addons.storage_block_price_ex_vat_pence;
7661
- }
7662
- function addonSettingsBody(addons, change = {}) {
7663
- return {
7664
- spend_cap_pence: addons.spend_cap_pence ?? null,
7665
- auto_topup_threshold_gbp: addons.auto_topup_threshold_gbp,
7666
- ...change
7667
- };
7668
- }
7669
- function splitBlocks(kind, count, addons) {
7670
- const granted = (kind === "ai_usage" ? addons.legacy_ai_blocks : addons.legacy_storage_blocks) ?? 0;
7671
- const legacy = Math.max(0, Math.min(granted, count));
7672
- return { legacy, current: count - legacy };
7673
- }
7674
- function blockSize(kind, addons, legacy) {
7675
- if (kind === "ai_usage") {
7676
- return formatGbp(legacy ? addons.legacy_block_ai_gbp ?? 10 : addons.block_ai_gbp);
7677
- }
7678
- return `${legacy ? addons.legacy_block_storage_gb ?? 10 : addons.block_storage_gb} GB`;
7679
- }
7680
- function blocksLabel(kind, count, addons) {
7681
- const { legacy, current } = splitBlocks(kind, count, addons);
7682
- const parts = [
7683
- ...legacy > 0 ? [`${legacy} \xD7 ${blockSize(kind, addons, true)}`] : [],
7684
- ...current > 0 || legacy === 0 ? [`${current} \xD7 ${blockSize(kind, addons, false)}`] : []
7685
- ];
7686
- return `${parts.join(" + ")}${kind === "ai_usage" ? " of AI usage" : ""}`;
7687
- }
7688
- function reduceBounds(kind, addons) {
7689
- const current = kind === "ai_usage" ? addons.ai_blocks : addons.storage_blocks;
7690
- const pending = kind === "ai_usage" ? addons.ai_blocks_next : addons.storage_blocks_next;
7691
- const min = kind === "ai_usage" ? 0 : Math.min(addons.storage_blocks_min, current);
7692
- return { min, current, next: pending ?? current };
7693
- }
7694
- function blockMonthlyExVatPence(kind, addons) {
7695
- return kind === "ai_usage" ? addons.ai_block_monthly_ex_vat_pence : addons.storage_block_monthly_ex_vat_pence;
7696
- }
7697
- function blockPeriodExVatPence(kind, addons) {
7698
- return kind === "ai_usage" ? addons.ai_block_period_ex_vat_pence : addons.storage_block_period_ex_vat_pence;
7699
- }
7700
- function blockRenewalShort(kind, addons, isAnnual) {
7701
- return `${gbp(blockPeriodExVatPence(kind, addons))}/${isAnnual ? "year" : "month"} + VAT`;
7702
- }
7703
- var ANNUAL_PREMIUM_AI_NOTE = "No markup on Premium AI on annual plans";
7704
- function addonCharge(kind, addons, isAnnual, periodEnd) {
7705
- return {
7706
- now: gbp(addonPricePence(kind, addons)),
7707
- nowExVat: gbp(addonPriceExVatPence(kind, addons)),
7708
- nowVat: gbp(addonPricePence(kind, addons) - addonPriceExVatPence(kind, addons)),
7709
- until: isAnnual ? formatPeriodEnd(periodEnd) : null,
7710
- then: blockRenewalShort(kind, addons, isAnnual)
7711
- };
7712
- }
7713
- var CAP_REACHED_MESSAGE = "Usage cap reached: no more automatic top-ups this month.";
7714
- var ZERO_BUDGET_MESSAGE = "Automatic top-ups are off (\xA30 usage cap).";
7715
- var USAGE_CAP_LABEL = "Usage cap";
7716
- var USAGE_CAP_HELP = "The most automatic top-ups (AI usage added when it runs low, storage added when an upload needs it) may cost in a month. Adding or removing by hand is never limited by it; the plan and renewals are not counted. \xA30 = no automatic top-ups: AI usage and uploads stop at your allowance unless you add more. No limit = no cap.";
7717
- function isAddonBudgetZero(addons) {
7718
- return addons.spend_cap_pence === 0;
7719
- }
7720
- function autoRoom(kind, addons) {
7721
- const left = addons.cap_left_pence;
7722
- if (left == null) return addons.spend_cap_pence === 0 ? 0 : null;
7723
- const price = addonPriceExVatPence(kind, addons);
7724
- if (price <= 0) return 0;
7725
- const blocks = Math.floor(left / price);
7726
- return blocks * (kind === "ai_usage" ? addons.block_ai_gbp : addons.block_storage_gb);
7727
- }
7728
- function nextRemovedBlockSize(kind, addons) {
7729
- const { next } = reduceBounds(kind, addons);
7730
- const { current } = splitBlocks(kind, next, addons);
7731
- if (kind === "ai_usage") {
7732
- return current > 0 ? addons.block_ai_gbp : addons.legacy_block_ai_gbp ?? 10;
7733
- }
7734
- return current > 0 ? addons.block_storage_gb : addons.legacy_block_storage_gb ?? 10;
7735
- }
7736
- function parseBudgetPounds(value) {
7737
- if (value.trim() === "") return null;
7738
- const n = Number(value);
7739
- if (!Number.isFinite(n) || n < 0) return void 0;
7740
- return Math.round(n * 100);
7741
- }
7742
- function budgetSavedMessage(capPence) {
7743
- if (capPence == null) return "Usage cap: no limit";
7744
- if (capPence === 0) return "Usage cap: \xA30 (no automatic top-ups)";
7745
- return `Usage cap: ${gbp(capPence)} a month`;
7746
- }
7747
- var gbText = (n) => `${Math.round(n * 10) / 10} GB`;
7748
- function stepLabel(kind, size) {
7749
- return kind === "ai_usage" ? `${formatGbp(size)} of AI usage` : gbText(size);
7750
- }
7751
- function nextPeriodBody(kind, keep) {
7752
- return kind === "ai_usage" ? { ai_blocks: keep, storage_blocks: null } : { ai_blocks: null, storage_blocks: keep };
7753
- }
7754
- function addStepCaption(kind, addons) {
7755
- const now = gbp(addonPriceExVatPence(kind, addons));
7756
- const today = kind === "storage" ? `prorated today ${now}` : `today ${now}`;
7757
- return `${gbp(blockMonthlyExVatPence(kind, addons))}/month \xB7 ${today}`;
7758
- }
7759
-
7760
- // src/connection/billing/api-error.ts
7761
- function apiErrorDetail(error) {
7762
- const body = error?.apiError ?? error;
7763
- return body?.detail;
7764
- }
7765
-
7766
- // src/connection/billing/tax-quote.ts
7767
- var POSTCODE_COUNTRIES = ["US", "CA"];
7768
- var TAX_LOCATION_INVALID = "TAX_LOCATION_INVALID";
7769
- function money2(pence, currency = "gbp") {
7770
- const symbol = { gbp: "\xA3", usd: "$", eur: "\u20AC" }[currency.toLowerCase()] ?? `${currency} `;
7771
- return `${symbol}${(pence / 100).toLocaleString("en-GB", {
7772
- minimumFractionDigits: 2,
7773
- maximumFractionDigits: 2
7774
- })}`;
7775
- }
7776
- function taxKind(label) {
7777
- return /^vat\b/i.test(label ?? "") ? "VAT" : "tax";
7778
- }
7779
- function taxDetail({ subtotal, tax, label, reverseCharge }) {
7780
- if (reverseCharge) return "\xB7 no VAT (reverse charge)";
7781
- if (tax <= 0) return "\xB7 no tax";
7782
- return `incl. ${taxKind(label)} (${money2(subtotal)} + ${money2(tax)} ${label ?? "tax"})`;
7783
- }
7784
- function taxSummary(parts) {
7785
- return `${money2(parts.total)} ${taxDetail(parts)}`;
7786
- }
7787
- function totalWithTaxWord({ total, tax, label }) {
7788
- return tax > 0 ? `${money2(total)} incl. ${taxKind(label)}` : money2(total);
7789
- }
7790
- function quoteParts(quote) {
7791
- return {
7792
- subtotal: quote.subtotal_pence,
7793
- tax: quote.tax_pence,
7794
- total: quote.total_pence,
7795
- label: quote.tax_label,
7796
- reverseCharge: quote.reverse_charge
7797
- };
7798
- }
7799
- function quoteTotalLine(quote) {
7800
- return `Total today ${taxSummary(quoteParts(quote))}`;
7801
- }
7802
- function quoteError(error) {
7803
- const detail = apiErrorDetail(error);
7804
- if (detail && typeof detail === "object") {
7805
- const { code, message } = detail;
7806
- return {
7807
- code: typeof code === "string" ? code : void 0,
7808
- message: typeof message === "string" ? message : void 0
7809
- };
7810
- }
7811
- return { message: typeof detail === "string" ? detail : void 0 };
7812
- }
7813
-
7814
- // src/connection/billing/plan-pricing.ts
7815
- var gbp2 = (pence) => formatMoney(pence, "gbp");
7816
- function plusVat(exVatPence, currency = "gbp") {
7817
- return `${formatMoney(exVatPence, currency)} + VAT`;
7818
- }
7819
- var PRO_PACKS = 1;
7820
- var PLAN_CHOICE_PACKS = {
7821
- pro: PRO_PACKS
7822
- };
7823
- function planNameForPacks(packs) {
7824
- const n = packs ?? 0;
7825
- if (n <= 0) return "Free";
7826
- if (n === PRO_PACKS) return "Pro";
7827
- return `Pro \xD7${n}`;
7828
- }
7829
- function planPreviewLines(preview) {
7830
- if (preview.unchanged) return [{ id: "no-change", text: "No change" }];
7831
- const date = formatPeriodEnd(preview.next_renewal_at);
7832
- const cadence = preview.interval === "year" ? "year" : "month";
7833
- const lines = [
7834
- preview.awaiting_confirmation ? { id: "awaiting-bank", text: "Waiting for your bank" } : {
7835
- id: "pay-today",
7836
- text: preview.effective_now ? `Pay today ${taxSummary({
7837
- subtotal: preview.due_now_ex_vat_pence,
7838
- tax: preview.due_now_tax_pence,
7839
- total: preview.due_now_pence,
7840
- label: preview.tax_label
7841
- })}` : `Pay today ${gbp2(0)}`
7842
- },
7843
- {
7844
- id: "from",
7845
- text: `${date ? `From ${date}` : "From renewal"}: ${taxSummary({
7846
- subtotal: preview.next_renewal_ex_vat_pence,
7847
- tax: preview.next_renewal_tax_pence,
7848
- total: preview.next_renewal_pence,
7849
- label: preview.tax_label
7850
- })} a ${cadence}`
7851
- }
7852
- ];
7853
- if (!preview.effective_now) {
7854
- lines.push({ id: "current-until", text: `Current plan until ${date ?? "renewal"}` });
7855
- }
7856
- return lines;
7857
- }
7858
- var PAY_TODAY_UNPRICED = "Pay today: the difference for the rest of this period";
7859
- function addonPrice(price, kind = "ai_usage") {
7860
- return price?.addon_prices?.find((p) => p.kind === kind);
7861
- }
7862
- function checkoutItemsLabel(aiBlocks, storageBlocks) {
7863
- return [
7864
- "Pro",
7865
- aiBlocks > 0 && `${aiBlocks} \xD7 ${formatGbp(ADDON_BLOCK_AI_GBP)} of AI usage`,
7866
- storageBlocks > 0 && `${storageBlocks} \xD7 ${STORAGE_BLOCK_GB} GB`
7867
- ].filter(Boolean).join(" + ");
7868
- }
7869
- function packPrice(price, packs = PRO_PACKS) {
7870
- return price?.pack_prices?.find((p) => p.packs === packs);
7871
- }
7872
- function findProPrices(products) {
7873
- const prices = products?.[0]?.prices ?? [];
7874
- const pick = (interval) => prices.find((p) => p.interval === interval && p.default_price) ?? prices.find((p) => p.interval === interval);
7875
- return { monthly: pick("month"), annual: pick("year") };
7876
- }
7877
- function calcSavingsPercent(monthlyPrice, annualPrice) {
7878
- const monthly = packPrice(monthlyPrice)?.amount ?? monthlyPrice?.amount;
7879
- const annual = packPrice(annualPrice)?.amount ?? annualPrice?.amount;
7880
- if (monthly == null || annual == null || monthly === 0) return null;
7881
- const savings = Math.round((monthly * 12 - annual) / (monthly * 12) * 100);
7882
- return savings > 0 ? savings : null;
7883
- }
7884
- var MAX_CHECKOUT_BLOCKS = 100;
7885
- function checkoutBlockPriceText(price, kind) {
7886
- const block = addonPrice(price, kind);
7887
- if (!block) return null;
7888
- const currency = price?.currency ?? "gbp";
7889
- return price?.interval === "year" ? `${formatMoney(block.amount_ex_vat, currency)}/year + VAT each` : `${formatMoney(block.amount_ex_vat, currency)}/month + VAT each`;
7890
- }
7891
-
7892
- // src/connection/billing/plan-badge.ts
7893
- function isProProject(project) {
7894
- return project.plan_interval != null;
7895
- }
7896
- function proTierName(project) {
7897
- return project.addons?.plan_name || planNameForPacks(Math.max(project.packs ?? 1, 1));
7898
- }
7899
- function planName(project) {
7900
- if (project.subscription === "dev") return "Dev";
7901
- if (!isProProject(project)) return "Free";
7902
- return `${proTierName(project)} ${project.plan_interval === "year" ? "annual" : "monthly"}`;
7903
- }
7904
- function planBadgeView(project) {
7905
- const { subscription } = project;
7906
- const label = subscription === "canceled" ? "Cancelling" : subscription === "dev" ? "Dev" : isProProject(project) ? proTierName(project) : "Free";
7907
- const tone = subscription === "dev" ? "dev" : subscription === "canceled" || subscription === "past_due" ? "pending" : isProProject(project) ? "paid" : "free";
7908
- return { label, tone };
7764
+ const isPaid2 = stripeEnabled && (subscription === "active" || subscription === "past_due" || subscription === "dev");
7765
+ return /* @__PURE__ */ jsx(ProjectEntity, { ...props, subscription, isPaid: isPaid2 });
7909
7766
  }
7910
7767
  function formatInvoiceDate(iso) {
7911
7768
  const d = /* @__PURE__ */ new Date(`${iso}T00:00:00`);
@@ -7925,7 +7782,7 @@ function InvoicesModal({
7925
7782
  const { data, isLoading } = useProjectInvoices(open ? projectExtId : void 0);
7926
7783
  const invoices = data?.invoices;
7927
7784
  const invoiceViews = (invoices ?? []).map((inv, i) => {
7928
- const isPaid = inv.status === "paid";
7785
+ const isPaid2 = inv.status === "paid";
7929
7786
  return {
7930
7787
  key: inv.number ?? String(i),
7931
7788
  date: formatInvoiceDate(inv.date),
@@ -7933,9 +7790,9 @@ function InvoicesModal({
7933
7790
  amount: formatMoney(inv.amount, inv.currency),
7934
7791
  amountNote: inv.amount_ex_vat != null && inv.amount_ex_vat !== inv.amount ? `${formatMoney(inv.amount_ex_vat, inv.currency)} ex VAT` : void 0,
7935
7792
  status: inv.status,
7936
- isPaid,
7793
+ isPaid: isPaid2,
7937
7794
  href: inv.hosted_invoice_url ?? inv.url ?? inv.pdf_url ?? void 0,
7938
- linkLabel: isPaid ? "Receipt" : "Invoice"
7795
+ linkLabel: isPaid2 ? "Receipt" : "Invoice"
7939
7796
  };
7940
7797
  });
7941
7798
  return /* @__PURE__ */ jsx(
@@ -8134,7 +7991,7 @@ function buildPlanCards(selected, isAnnual, prices, isOnFree) {
8134
7991
  features: [
8135
7992
  `${formatGbp(FREE_AI_GBP)} of AI usage / month`,
8136
7993
  `${FREE_STORAGE_MB.toLocaleString("en-US")} MB storage`,
8137
- "Just you"
7994
+ FREE_COLLABORATORS === 0 ? "Just you" : `${FREE_COLLABORATORS} collaborators`
8138
7995
  ]
8139
7996
  };
8140
7997
  return [free, proCard(selected, isAnnual, prices)];
@@ -9349,7 +9206,7 @@ function ReduceAddonDialog({
9349
9206
  }
9350
9207
  ) });
9351
9208
  }
9352
- var gbp3 = (pence) => formatMoney(pence, "gbp");
9209
+ var gbp = (pence) => formatMoney(pence, "gbp");
9353
9210
  var gb2 = (n) => `${Math.round(n * 10) / 10} GB`;
9354
9211
  var pct = (used, limit) => limit > 0 ? Math.min(100, used / limit * 100) : 0;
9355
9212
  function formatShortDate(unix) {
@@ -9475,7 +9332,7 @@ function ResourceMeter({
9475
9332
  const from = periodEnd ?? "your next renewal";
9476
9333
  const fromShort = formatShortDate(addons.period_end ?? project.current_period_end) ?? "renewal";
9477
9334
  const { min, current, next } = reduceBounds(kind, addons);
9478
- const fmt2 = (n) => isAi ? formatGbp(n) : gb2(n);
9335
+ const fmt = (n) => isAi ? formatGbp(n) : gb2(n);
9479
9336
  const used = isAi ? addons.ai_used_gbp : addons.storage_used_gb;
9480
9337
  const allowance = isAi ? addons.ai_allowance_gbp : addons.storage_allowance_gb;
9481
9338
  const allowanceNext = isAi ? addons.ai_allowance_next_gbp : addons.storage_allowance_next_gb;
@@ -9503,12 +9360,12 @@ function ResourceMeter({
9503
9360
  {
9504
9361
  label: isAi ? "AI usage" : "Storage",
9505
9362
  hint: resets ? `resets ${resets}` : void 0,
9506
- value: `${fmt2(used)} of ${fmt2(allowance)}`,
9363
+ value: `${fmt(used)} of ${fmt(allowance)}`,
9507
9364
  allowance: { used, plan, topUps, autoRoom: capZero ? 0 : room },
9508
9365
  legend: {
9509
- plan: `Plan ${fmt2(plan)}`,
9510
- topUps: topUps > 0 ? `Top-ups ${fmt2(topUps)}${hasLegacy ? ` (${blocksLabel(kind, blocks, addons)})` : ""}` : void 0,
9511
- autoRoom: room != null && room > 0 && !capZero ? `Automatic up to ${fmt2(room)}` : void 0
9366
+ plan: `Plan ${fmt(plan)}`,
9367
+ topUps: topUps > 0 ? `Top-ups ${fmt(topUps)}${hasLegacy ? ` (${blocksLabel(kind, blocks, addons)})` : ""}` : void 0,
9368
+ autoRoom: room != null && room > 0 && !capZero ? `Automatic up to ${fmt(room)}` : void 0
9512
9369
  },
9513
9370
  testId: `usage-meter-${slug}`,
9514
9371
  details: autoLine || allowanceNext !== allowance || children ? /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -9596,7 +9453,7 @@ function UsageCapEditor({ project, addons }) {
9596
9453
  }
9597
9454
  );
9598
9455
  };
9599
- const readout = savedCap == null ? `${gbp3(spent)} this month \xB7 no limit` : savedCap === 0 ? "\xA30 \xB7 no automatic top-ups" : `${gbp3(spent)} of ${gbp3(savedCap)} used`;
9456
+ const readout = savedCap == null ? `${gbp(spent)} this month \xB7 no limit` : savedCap === 0 ? "\xA30 \xB7 no automatic top-ups" : `${gbp(spent)} of ${gbp(savedCap)} used`;
9600
9457
  const inputId = `spend-cap-${project.external_id}`;
9601
9458
  return /* @__PURE__ */ jsxs("div", { className: "space-y-3", ref: sectionRef, "data-testid": "project-spend-cap", children: [
9602
9459
  /* @__PURE__ */ jsx(
@@ -9612,7 +9469,7 @@ function UsageCapEditor({ project, addons }) {
9612
9469
  addons.cap_reached && savedCap != null && savedCap > 0 && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", "data-testid": "addon-cap-reached", children: CAP_REACHED_MESSAGE }),
9613
9470
  addons.manual_spent_pence > 0 && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", "data-testid": "addon-manual-spend", children: [
9614
9471
  "Added by hand this month: ",
9615
- gbp3(addons.manual_spent_pence),
9472
+ gbp(addons.manual_spent_pence),
9616
9473
  " \xB7 not capped"
9617
9474
  ] }),
9618
9475
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-4 gap-y-3", children: [
@@ -9788,7 +9645,7 @@ function formatShortDate2(unix) {
9788
9645
  if (!unix) return null;
9789
9646
  return new Date(unix * 1e3).toLocaleDateString("en-GB", { day: "numeric", month: "short" });
9790
9647
  }
9791
- var gbp4 = (pence) => formatMoney(pence, "gbp");
9648
+ var gbp2 = (pence) => formatMoney(pence, "gbp");
9792
9649
  var gbNum = (n) => `${Math.round(n * 10) / 10}`;
9793
9650
  var pct2 = (used, limit) => limit > 0 ? Math.min(100, used / limit * 100) : 0;
9794
9651
  function Meter({
@@ -9819,7 +9676,7 @@ function usePlanPrice(project) {
9819
9676
  }
9820
9677
  function paidLine(payment, addons) {
9821
9678
  const what = payment.kind === "storage" ? `${addons.block_storage_gb} GB added` : payment.kind === "ai_usage" ? `${formatGbp(addons.block_ai_gbp)} of AI usage added` : null;
9822
- const paid = payment.amount_pence != null ? `Paid ${gbp4(payment.amount_pence)}` : "Paid";
9679
+ const paid = payment.amount_pence != null ? `Paid ${gbp2(payment.amount_pence)}` : "Paid";
9823
9680
  return what ? `${paid} \xB7 ${what}` : paid;
9824
9681
  }
9825
9682
  function ProjectPlanCard({
@@ -9890,11 +9747,11 @@ function ProjectPlanCard({
9890
9747
  ] }),
9891
9748
  price && /* @__PURE__ */ jsxs("div", { className: "ml-auto text-right", "data-testid": "project-plan-price", children: [
9892
9749
  /* @__PURE__ */ jsxs("div", { className: "text-lg font-semibold tabular-nums text-foreground", children: [
9893
- price.ex != null ? plusVat(price.ex) : gbp4(price.incl),
9750
+ price.ex != null ? plusVat(price.ex) : gbp2(price.incl),
9894
9751
  /* @__PURE__ */ jsx("span", { className: "text-sm font-normal text-muted-foreground", children: price.isAnnual ? "/year" : "/month" })
9895
9752
  ] }),
9896
9753
  price.ex != null && /* @__PURE__ */ jsxs("div", { className: "text-xs text-muted-foreground", children: [
9897
- gbp4(price.incl),
9754
+ gbp2(price.incl),
9898
9755
  " incl. VAT"
9899
9756
  ] })
9900
9757
  ] })
@@ -9976,7 +9833,7 @@ function ProjectPlanCard({
9976
9833
  addons?.billing_error && /* @__PURE__ */ jsx(PlanNotice, { tone: "error", testId: "plan-billing-error", children: addons.billing_error }),
9977
9834
  confirmUrl ? /* @__PURE__ */ jsxs(PlanNotice, { testId: "plan-payment-state", children: [
9978
9835
  "Waiting for your bank",
9979
- pendingPayment?.amount_pence ? ` \xB7 ${gbp4(pendingPayment.amount_pence)}` : "",
9836
+ pendingPayment?.amount_pence ? ` \xB7 ${gbp2(pendingPayment.amount_pence)}` : "",
9980
9837
  " \xB7",
9981
9838
  " ",
9982
9839
  /* @__PURE__ */ jsxs(
@@ -10646,6 +10503,713 @@ function useAutoRefreshPendingProjects() {
10646
10503
  }
10647
10504
  }, [projects, refreshProject, currentUserExtId]);
10648
10505
  }
10506
+ function toWorkspaceSummary(workspace, selfId) {
10507
+ const people = (workspace.users ?? []).filter((m) => !isAgentAccount(m.user));
10508
+ const ordered = [
10509
+ ...people.filter((m) => m.role === "owner"),
10510
+ ...people.filter((m) => m.role !== "owner")
10511
+ ];
10512
+ const members = ordered.map((m) => ({
10513
+ name: m.user.family_name ? `${m.user.given_name} ${m.user.family_name}` : m.user.given_name,
10514
+ picture: m.user.picture
10515
+ }));
10516
+ const isMember = people.some((m) => m.user.external_id === selfId);
10517
+ return {
10518
+ id: workspace.external_id,
10519
+ name: workspace.name,
10520
+ description: workspace.description,
10521
+ docCount: workspaceDocumentCount(workspace),
10522
+ chatCount: workspaceConversationCount(workspace),
10523
+ memberCount: members.length,
10524
+ members,
10525
+ // A public workspace's members are hidden from someone who has not joined it.
10526
+ membersHidden: workspace.is_public && !isMember,
10527
+ updatedAt: workspace.updated_at
10528
+ };
10529
+ }
10530
+ function WorkspaceCardsView({
10531
+ list,
10532
+ currentWorkspaceId,
10533
+ onOpenWorkspace,
10534
+ onOpenProject,
10535
+ onCreateWorkspace,
10536
+ createDisabledReason
10537
+ }) {
10538
+ const { stripeEnabled } = useBillingSupport();
10539
+ const workspaceLabel = getEntityLabel("WORKSPACE");
10540
+ const projectLabel = getEntityLabel("PROJECT").toLowerCase();
10541
+ const { groups, projects, selfId } = list;
10542
+ if (groups.length === 0) {
10543
+ return /* @__PURE__ */ jsx(WorkspaceList, { testId: "workspace-cards-list", className: "gap-0", children: /* @__PURE__ */ jsx(
10544
+ CreateTile,
10545
+ {
10546
+ label: `New ${workspaceLabel.toLowerCase()}`,
10547
+ ariaLabel: `Create ${workspaceLabel}`,
10548
+ onSelect: () => onCreateWorkspace(),
10549
+ disabledReason: createDisabledReason,
10550
+ help: `A ${workspaceLabel.toLowerCase()} holds the documents and conversations for one matter or case.`,
10551
+ testId: "create-workspace-card"
10552
+ }
10553
+ ) });
10554
+ }
10555
+ return /* @__PURE__ */ jsx(WorkspaceList, { testId: "workspace-cards-list", children: groups.map((group) => {
10556
+ const project = projects.find((p) => p.external_id === group.projectExtId);
10557
+ const { breakdown, readout } = projectGroupBilling(project, {
10558
+ isOwned: group.isOwned,
10559
+ stripeEnabled
10560
+ });
10561
+ const count = group.workspaces.length;
10562
+ return /* @__PURE__ */ jsxs(
10563
+ WorkspaceGroup,
10564
+ {
10565
+ title: group.projectExtId ? /* @__PURE__ */ jsx(
10566
+ ProjectBandTitle,
10567
+ {
10568
+ name: group.title,
10569
+ count,
10570
+ nameTestId: `project-name-${group.projectExtId}`,
10571
+ breakdown,
10572
+ readout
10573
+ }
10574
+ ) : /* @__PURE__ */ jsx(
10575
+ PlainBandTitle,
10576
+ {
10577
+ title: group.title,
10578
+ count,
10579
+ hint: group.isCommon ? "Shared with everyone" : void 0
10580
+ }
10581
+ ),
10582
+ onOpen: group.projectExtId ? () => onOpenProject(group.projectExtId) : void 0,
10583
+ openLabel: "Plans & Usage",
10584
+ collapsedHint: group.isCommon ? `Show ${count} shared ${getEntityLabel("WORKSPACE", "PLURAL").toLowerCase()}` : void 0,
10585
+ isExpanded: !list.isCollapsed(group.key),
10586
+ onToggle: () => list.toggleGroup(group.key),
10587
+ children: [
10588
+ group.isOwned && group.projectExtId && /* @__PURE__ */ jsx(
10589
+ CreateTile,
10590
+ {
10591
+ label: `New ${workspaceLabel.toLowerCase()}`,
10592
+ ariaLabel: `Create ${workspaceLabel}`,
10593
+ onSelect: () => onCreateWorkspace(group.projectExtId),
10594
+ disabledReason: createDisabledReason,
10595
+ help: count === 0 ? `Already have one? Open it and change its ${projectLabel} to move it here.` : void 0,
10596
+ testId: "add-workspace-button"
10597
+ }
10598
+ ),
10599
+ [...group.workspaces].sort(byRecentUpdate).map((workspace) => /* @__PURE__ */ jsx(
10600
+ WorkspaceCard,
10601
+ {
10602
+ workspace: toWorkspaceSummary(workspace, selfId),
10603
+ current: currentWorkspaceId === workspace.external_id,
10604
+ onSelect: () => onOpenWorkspace(workspace),
10605
+ href: buildDeepLinkPath({ workspaceId: workspace.external_id }),
10606
+ mark: /* @__PURE__ */ jsx(
10607
+ ShieldIcon,
10608
+ {
10609
+ char: workspace.name.charAt(0),
10610
+ workspaceColor: workspaceKindColor(getWorkspaceKind(workspace)),
10611
+ size: 28,
10612
+ isSelected: true
10613
+ }
10614
+ ),
10615
+ testId: `workspace-card-${workspace.external_id}`,
10616
+ openCueTestId: `workspace-open-${workspace.external_id}`
10617
+ },
10618
+ workspace.external_id
10619
+ ))
10620
+ ]
10621
+ },
10622
+ group.key
10623
+ );
10624
+ }) });
10625
+ }
10626
+ function WorkspaceFilterMenu({ list }) {
10627
+ const [open, setOpen] = useState(false);
10628
+ const { workspaces, projects, selfId, pinned, filters, setFilters } = list;
10629
+ const { options: options2, groups } = useMemo(() => {
10630
+ const attributes = workspaces.map((w) => workspaceFilterAttributes(w, { selfId, pinned }));
10631
+ const countOf = (id) => attributes.filter((a) => a[id]).length;
10632
+ const projectIds = projects.map((p) => projectFilterId(p.external_id));
10633
+ const options3 = [
10634
+ ...projects.map((p) => ({
10635
+ id: projectFilterId(p.external_id),
10636
+ label: p.name,
10637
+ count: countOf(projectFilterId(p.external_id))
10638
+ })),
10639
+ ...WORKSPACE_CATEGORY_FILTERS.map(({ id, label }) => ({ id, label, count: countOf(id) }))
10640
+ ];
10641
+ const groups2 = [
10642
+ { label: "Projects", options: projectIds },
10643
+ { label: "Workspaces", options: WORKSPACE_CATEGORY_FILTERS.map((f) => f.id) }
10644
+ ];
10645
+ return { options: options3, groups: groups2 };
10646
+ }, [workspaces, projects, selfId, pinned]);
10647
+ return /* @__PURE__ */ jsx(
10648
+ TriStateFilterMenu,
10649
+ {
10650
+ testId: "workspace-filter-button",
10651
+ open,
10652
+ onOpenChange: setOpen,
10653
+ title: "Filter workspaces",
10654
+ triggerLabel: "Filter",
10655
+ renderChevron: true,
10656
+ filterStates: filters,
10657
+ onFiltersChange: setFilters,
10658
+ options: options2,
10659
+ groups
10660
+ }
10661
+ );
10662
+ }
10663
+ var DEFAULT_WORKSPACE_LIST_LABELS = {
10664
+ recentlyDeletedHint: (count) => `You can restore ${count === 1 ? "it" : "them"} from Recently deleted (Settings > Storage) for at least 30 days.`
10665
+ };
10666
+ function useConnectedWorkspaceList({
10667
+ filters: controlledFilters,
10668
+ onFiltersChange,
10669
+ labels
10670
+ } = {}) {
10671
+ const recentlyDeletedHint = labels?.recentlyDeletedHint ?? DEFAULT_WORKSPACE_LIST_LABELS.recentlyDeletedHint;
10672
+ const { confirm, notify: notify14 } = useBlocksEnvironment();
10673
+ const { userId: selfId } = useConnectedWorkspace();
10674
+ const workspacesQuery = useWorkspaces();
10675
+ const { data: projects } = useProjects();
10676
+ const { data: settings } = useUserSettings();
10677
+ const canCreateProjects = useCanCreateProjects();
10678
+ const deleteWorkspaces = useDeleteWorkspaces();
10679
+ const workspaces = useMemo(
10680
+ () => (workspacesQuery.data ?? []).filter(isListedWorkspace),
10681
+ [workspacesQuery.data]
10682
+ );
10683
+ const pinned = useMemo(
10684
+ () => new Set(settings?.pinned_workspaces ?? []),
10685
+ [settings?.pinned_workspaces]
10686
+ );
10687
+ const [localFilters, setLocalFilters] = useState({});
10688
+ const filters = controlledFilters ?? localFilters;
10689
+ const filterMap = useMemo(() => {
10690
+ const known = new Set(WORKSPACE_CATEGORY_FILTERS.map((f) => f.id));
10691
+ for (const p of projects ?? []) known.add(projectFilterId(p.external_id));
10692
+ for (const w of workspaces) if (w.project_ext_id) known.add(projectFilterId(w.project_ext_id));
10693
+ return new Map(Object.entries(filters).filter(([id, state]) => state !== null && known.has(id)));
10694
+ }, [filters, projects, workspaces]);
10695
+ const setFilters = useCallback(
10696
+ (next) => {
10697
+ const record = Object.fromEntries(next);
10698
+ if (onFiltersChange) onFiltersChange(record);
10699
+ if (controlledFilters === void 0) setLocalFilters(record);
10700
+ },
10701
+ [controlledFilters, onFiltersChange]
10702
+ );
10703
+ const attributesOf = useCallback(
10704
+ (workspace) => workspaceFilterAttributes(workspace, { selfId, pinned }),
10705
+ [selfId, pinned]
10706
+ );
10707
+ const filtered = useMemo(
10708
+ () => applyTriStateFilters(workspaces, filterMap, attributesOf),
10709
+ [workspaces, filterMap, attributesOf]
10710
+ );
10711
+ const groups = useMemo(
10712
+ () => groupWorkspacesByProject(filtered, {
10713
+ selfId,
10714
+ pinned,
10715
+ projects: projects ?? [],
10716
+ workspacesLabel: getEntityLabel("WORKSPACE", "PLURAL")
10717
+ }),
10718
+ [filtered, selfId, pinned, projects]
10719
+ );
10720
+ const [toggled, setToggled] = useState({});
10721
+ const isCollapsed = useCallback(
10722
+ (key) => toggled[key] ?? groups.some((g) => g.key === key && g.isCommon),
10723
+ [toggled, groups]
10724
+ );
10725
+ const toggleGroup = useCallback(
10726
+ (key) => setToggled((prev) => ({ ...prev, [key]: !isCollapsed(key) })),
10727
+ [isCollapsed]
10728
+ );
10729
+ const [selected, setSelected] = useState([]);
10730
+ const canDeleteSelected = selected.every((w) => !!selfId && w.created_by_ext_id === selfId);
10731
+ const deleteSelected = useCallback(async () => {
10732
+ const count = selected.length;
10733
+ if (count === 0) return;
10734
+ const noun = getEntityLabel("WORKSPACE", count === 1 ? "SINGULAR" : "PLURAL");
10735
+ const confirmed = await confirm({
10736
+ title: `Delete ${count} ${noun}`,
10737
+ message: `Delete ${count} ${noun.toLowerCase()}? ${recentlyDeletedHint(count)}`
10738
+ });
10739
+ if (!confirmed) return;
10740
+ try {
10741
+ await deleteWorkspaces.mutateAsync(selected.map((w) => w.external_id));
10742
+ setSelected([]);
10743
+ notify14(`Deleted ${count} ${noun.toLowerCase()}`, "success");
10744
+ } catch {
10745
+ notify14("Failed to delete some workspaces", "error");
10746
+ }
10747
+ }, [selected, confirm, notify14, deleteWorkspaces, recentlyDeletedHint]);
10748
+ return {
10749
+ selfId,
10750
+ /** Every listed workspace (unfiltered): the filter menu's counts. */
10751
+ workspaces,
10752
+ projects: projects ?? [],
10753
+ pinned,
10754
+ /** The filtered workspaces grouped by project, in list order. */
10755
+ groups,
10756
+ /** How many workspaces the filters let through. */
10757
+ shownCount: filtered.length,
10758
+ isLoading: workspacesQuery.isLoading,
10759
+ error: workspacesQuery.error,
10760
+ canCreateProjects,
10761
+ filters: filterMap,
10762
+ setFilters,
10763
+ isCollapsed,
10764
+ toggleGroup,
10765
+ selected,
10766
+ setSelected,
10767
+ canDeleteSelected,
10768
+ deleteSelected,
10769
+ isDeleting: deleteWorkspaces.isPending
10770
+ };
10771
+ }
10772
+ var WorkspaceTableView = lazy(
10773
+ () => import('../WorkspaceTableView-5OWX53R5.js').then((m) => ({ default: m.WorkspaceTableView }))
10774
+ );
10775
+ var WORKSPACES_TAB_ID = "workspaces";
10776
+ var defaultRenderMember2 = (user, size) => {
10777
+ const name = user.family_name ? `${user.given_name} ${user.family_name}` : user.given_name;
10778
+ return /* @__PURE__ */ jsx(
10779
+ UserEntity,
10780
+ {
10781
+ size,
10782
+ variant: "icon",
10783
+ showTooltip: false,
10784
+ interactive: false,
10785
+ displayName: name,
10786
+ initials: initials(name || user.email),
10787
+ picture: user.picture
10788
+ }
10789
+ );
10790
+ };
10791
+ function ConnectedWorkspaceList({
10792
+ onCreateWorkspace,
10793
+ view: controlledView,
10794
+ onViewChange,
10795
+ filters,
10796
+ onFiltersChange,
10797
+ gridState,
10798
+ onGridStateChange,
10799
+ renderMember = defaultRenderMember2,
10800
+ extraTabs = [],
10801
+ activeTab = WORKSPACES_TAB_ID,
10802
+ onTabChange,
10803
+ children,
10804
+ labels
10805
+ }) {
10806
+ const list = useConnectedWorkspaceList({ filters, onFiltersChange, labels });
10807
+ const { openProject } = useBlocksEnvironment();
10808
+ const { workspaceId: currentWorkspaceId, openWorkspace } = useConnectedWorkspace();
10809
+ const [localView, setLocalView] = useState("cards");
10810
+ const view = controlledView ?? localView;
10811
+ const isPhone = useIsPhone();
10812
+ const shownView = view === "table" && !isPhone ? "table" : "cards";
10813
+ const showList = activeTab === WORKSPACES_TAB_ID || !extraTabs.some((t) => t.id === activeTab);
10814
+ const setView = (next) => {
10815
+ onViewChange?.(next);
10816
+ if (controlledView === void 0) setLocalView(next);
10817
+ };
10818
+ const open = (workspace) => void openWorkspace(workspace.external_id, { name: workspace.name });
10819
+ const createDisabledReason = list.canCreateProjects === false ? PROJECT_CREATION_DENIED_REASON : void 0;
10820
+ if (list.isLoading) return /* @__PURE__ */ jsx(LoadingIndicator, { message: "Loading workspaces..." });
10821
+ if (list.error) {
10822
+ return /* @__PURE__ */ jsx(
10823
+ HomeLoadError,
10824
+ {
10825
+ title: "Unable to load workspaces",
10826
+ body: "Failed to connect to the server. Please check your connection and try again."
10827
+ }
10828
+ );
10829
+ }
10830
+ const newButton = createDisabledReason ? (
10831
+ // A disabled button emits no pointer events: the span carries the tooltip.
10832
+ /* @__PURE__ */ jsxs(Tooltip, { delayDuration: 50, children: [
10833
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("span", { tabIndex: 0, "data-testid": "home-new-workspace-disabled", children: /* @__PURE__ */ jsxs(Button, { disabled: true, "data-testid": "home-new-workspace", children: [
10834
+ /* @__PURE__ */ jsx(Plus, { className: "mr-0.5 size-4" }),
10835
+ "New"
10836
+ ] }) }) }),
10837
+ /* @__PURE__ */ jsx(TooltipContent, { children: createDisabledReason })
10838
+ ] })
10839
+ ) : /* @__PURE__ */ jsxs(Button, { onClick: () => onCreateWorkspace(), "data-testid": "home-new-workspace", children: [
10840
+ /* @__PURE__ */ jsx(Plus, { className: "mr-0.5 size-4" }),
10841
+ "New"
10842
+ ] });
10843
+ return /* @__PURE__ */ jsxs(HomeFrame, { children: [
10844
+ /* @__PURE__ */ jsx(
10845
+ TabHeader,
10846
+ {
10847
+ testId: "home-header",
10848
+ tabs: [
10849
+ {
10850
+ id: WORKSPACES_TAB_ID,
10851
+ label: getEntityLabel("WORKSPACE", "PLURAL"),
10852
+ count: list.shownCount,
10853
+ icon: /* @__PURE__ */ jsx(SquareStack, { className: "size-4" })
10854
+ },
10855
+ ...extraTabs
10856
+ ],
10857
+ activeTabId: showList ? WORKSPACES_TAB_ID : activeTab,
10858
+ onTabChange: (id) => onTabChange?.(id),
10859
+ centerContent: showList && !isPhone ? /* @__PURE__ */ jsx(
10860
+ ViewToggle,
10861
+ {
10862
+ options: [
10863
+ { value: "cards", icon: /* @__PURE__ */ jsx(SquareStack, { className: "size-4" }), label: "Cards" },
10864
+ { value: "grid", icon: /* @__PURE__ */ jsx(Table, { className: "size-4" }), label: "Table" }
10865
+ ],
10866
+ value: shownView === "table" ? "grid" : "cards",
10867
+ onChange: (value) => setView(value === "grid" ? "table" : "cards"),
10868
+ testIdPrefix: "workspaces",
10869
+ size: "sm",
10870
+ showLabels: true,
10871
+ hideTooltips: true
10872
+ }
10873
+ ) : void 0,
10874
+ rightContent: showList ? newButton : void 0
10875
+ }
10876
+ ),
10877
+ showList && // Above whichever view shows: both draw the same filtered groups.
10878
+ /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-6xl px-4 pb-3 sm:px-8", children: /* @__PURE__ */ jsx(WorkspaceFilterMenu, { list }) }),
10879
+ /* @__PURE__ */ jsx(HomeMain, { children: !showList ? children : shownView === "cards" ? (
10880
+ // Full-width scroller (its scrollbar rides the window edge) around a centred column.
10881
+ /* @__PURE__ */ jsx(HomeCenteredScroll, { children: /* @__PURE__ */ jsx(
10882
+ WorkspaceCardsView,
10883
+ {
10884
+ list,
10885
+ currentWorkspaceId,
10886
+ onOpenWorkspace: open,
10887
+ onOpenProject: openProject,
10888
+ onCreateWorkspace,
10889
+ createDisabledReason
10890
+ }
10891
+ ) })
10892
+ ) : /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(LoadingIndicator, { message: "Loading grid..." }), children: /* @__PURE__ */ jsx(HomeCenteredColumn, { children: /* @__PURE__ */ jsx(
10893
+ WorkspaceTableView,
10894
+ {
10895
+ list,
10896
+ onOpenWorkspace: open,
10897
+ onOpenProject: openProject,
10898
+ renderMember,
10899
+ gridState,
10900
+ onGridStateChange
10901
+ }
10902
+ ) }) }) })
10903
+ ] });
10904
+ }
10905
+ var PROJECTS_BASE_TAB_ID = "projects";
10906
+ var isPaid = (p) => p.subscription === "active" || p.subscription === "past_due";
10907
+ function useLocalProjectTabs() {
10908
+ const [openProjectIds, setOpen] = useState([]);
10909
+ const [activeProjectId, setActive] = useState(null);
10910
+ return {
10911
+ openProjectIds,
10912
+ activeProjectId,
10913
+ onSelect: (id) => {
10914
+ if (id) setOpen((open) => open.includes(id) ? open : [...open, id]);
10915
+ setActive(id);
10916
+ },
10917
+ onClose: (id) => {
10918
+ setOpen((open) => open.filter((openId) => openId !== id));
10919
+ setActive((active) => active === id ? null : active);
10920
+ }
10921
+ };
10922
+ }
10923
+ function ConnectedProjectsPanel({
10924
+ tabs: hostTabs,
10925
+ projectStorage,
10926
+ footer,
10927
+ headerRight,
10928
+ className
10929
+ }) {
10930
+ const localTabs = useLocalProjectTabs();
10931
+ const tabs = hostTabs ?? localTabs;
10932
+ const { data: projects } = useProjects();
10933
+ const canCreateProjects = useCanCreateProjects();
10934
+ const { userId } = useConnectedWorkspace();
10935
+ const { stripeEnabled } = useBillingSupport();
10936
+ const billingPortal = useOpenBillingPortal();
10937
+ const [newProjectOpen, setNewProjectOpen] = useState(false);
10938
+ useAutoRefreshPendingProjects();
10939
+ const ownedCount = (projects ?? []).filter((p) => p.created_by === userId).length;
10940
+ const activeProjectId = tabs.activeProjectId && tabs.openProjectIds.includes(tabs.activeProjectId) ? tabs.activeProjectId : null;
10941
+ const headerTabs = useMemo(
10942
+ () => [
10943
+ {
10944
+ id: PROJECTS_BASE_TAB_ID,
10945
+ // Named by its job; "project" is for the per-project tabs, where owning several matters.
10946
+ label: "Plan & Usage",
10947
+ icon: /* @__PURE__ */ jsx(EntityIcon, { entityType: "PROJECT" }),
10948
+ // Most users own one project: a count only once there are several.
10949
+ count: ownedCount > 1 ? ownedCount : void 0
10950
+ },
10951
+ ...tabs.openProjectIds.map((id) => ({
10952
+ id,
10953
+ label: projects?.find((p) => p.external_id === id)?.name ?? "Project",
10954
+ icon: /* @__PURE__ */ jsx(EntityIcon, { entityType: "PROJECT" }),
10955
+ onClose: () => tabs.onClose(id),
10956
+ closeTooltip: "Close project"
10957
+ }))
10958
+ ],
10959
+ [ownedCount, tabs, projects]
10960
+ );
10961
+ const paidProject = projects?.find(isPaid);
10962
+ const panel = /* @__PURE__ */ jsxs(PanelFrame, { className, testId: "projects-panel", children: [
10963
+ /* @__PURE__ */ jsx(DraggableHeader, { children: /* @__PURE__ */ jsx(
10964
+ TabHeader,
10965
+ {
10966
+ tabs: headerTabs,
10967
+ activeTabId: activeProjectId ?? PROJECTS_BASE_TAB_ID,
10968
+ onTabChange: (id) => tabs.onSelect(id === PROJECTS_BASE_TAB_ID ? null : id),
10969
+ afterTabs: (isCompact) => /* @__PURE__ */ jsx(
10970
+ PanelAddButton,
10971
+ {
10972
+ label: "New project",
10973
+ onClick: () => setNewProjectOpen(true),
10974
+ icon: /* @__PURE__ */ jsx(Plus, { className: "size-4" }),
10975
+ isCompact,
10976
+ testId: "new-project-button",
10977
+ disabledReason: canCreateProjects === false ? PROJECT_CREATION_DENIED_REASON : void 0
10978
+ }
10979
+ ),
10980
+ rightContent: headerRight,
10981
+ variant: "underline",
10982
+ compactBreakpoint: 360
10983
+ }
10984
+ ) }),
10985
+ /* @__PURE__ */ jsx(PanelFrameBody, { children: activeProjectId ? /* @__PURE__ */ jsx(PanelScroll, { children: /* @__PURE__ */ jsx(
10986
+ ProjectDetail,
10987
+ {
10988
+ projectExtId: activeProjectId,
10989
+ storage: projectStorage?.(activeProjectId)
10990
+ }
10991
+ ) }) : /* @__PURE__ */ jsxs(PanelScroll, { variant: "padded", children: [
10992
+ /* @__PURE__ */ jsx(ProjectsTable, {}),
10993
+ stripeEnabled && paidProject && /* @__PURE__ */ jsx(PanelActionsRow, { children: /* @__PURE__ */ jsxs(
10994
+ Button,
10995
+ {
10996
+ onClick: () => billingPortal.open(paidProject.external_id),
10997
+ size: "sm",
10998
+ variant: "outline",
10999
+ disabled: billingPortal.isPending,
11000
+ className: "flex items-center gap-1",
11001
+ children: [
11002
+ billingPortal.isPending ? "Opening\u2026" : "Billing portal",
11003
+ !billingPortal.isPending && /* @__PURE__ */ jsx(ExternalLink, { className: "h-3.5 w-3.5" })
11004
+ ]
11005
+ }
11006
+ ) }),
11007
+ /* @__PURE__ */ jsx(SharedProjects, {}),
11008
+ footer
11009
+ ] }) }),
11010
+ /* @__PURE__ */ jsx(
11011
+ NewProjectFlow,
11012
+ {
11013
+ open: newProjectOpen,
11014
+ onOpenChange: setNewProjectOpen,
11015
+ defaultName: `Project ${(projects?.length ?? 0) + 1}`
11016
+ }
11017
+ )
11018
+ ] });
11019
+ return hostTabs ? panel : /* @__PURE__ */ jsx(BlocksProvider, { openProject: localTabs.onSelect, children: panel });
11020
+ }
11021
+
11022
+ // src/connection/workspace-dashboard/dashboard-rows.ts
11023
+ var RECENT_ROWS = 5;
11024
+ var FACT_ROWS = 3;
11025
+ function shortDate(iso) {
11026
+ return new Date(iso).toLocaleDateString(void 0, { day: "numeric", month: "short" });
11027
+ }
11028
+ function timeAndDate(iso) {
11029
+ if (!iso) return "";
11030
+ const d = new Date(iso);
11031
+ if (Number.isNaN(d.getTime())) return "";
11032
+ const time2 = d.toLocaleTimeString(void 0, {
11033
+ hour: "2-digit",
11034
+ minute: "2-digit",
11035
+ hour12: false
11036
+ });
11037
+ return `${time2} \xB7 ${shortDate(iso)}`;
11038
+ }
11039
+ function humanizeStatus(status) {
11040
+ const words = status.replace(/[-_]/g, " ");
11041
+ return words.charAt(0).toUpperCase() + words.slice(1);
11042
+ }
11043
+ var time = (iso) => +new Date(iso ?? 0);
11044
+ function recentConversations(conversations) {
11045
+ return [...conversations].sort((a, b) => time(b.updated_at) - time(a.updated_at)).slice(0, RECENT_ROWS).map((c) => ({
11046
+ id: c.external_id,
11047
+ title: c.title?.trim() || "Untitled thread",
11048
+ subtitle: c.status ? [STATUS_LABELS[asTaskStatus(c.status)], c.due_at ? `due ${shortDate(c.due_at)}` : null].filter(Boolean).join(" \xB7 ") : `${c.message_count} ${c.message_count === 1 ? "message" : "messages"}`,
11049
+ time: timeAndDate(c.updated_at)
11050
+ }));
11051
+ }
11052
+ function recentDocuments(documents) {
11053
+ return [...documents].sort((a, b) => time(b.updated_at ?? b.created_at) - time(a.updated_at ?? a.created_at)).slice(0, RECENT_ROWS).map((d) => ({
11054
+ id: d.external_id,
11055
+ fileName: d.file_name,
11056
+ title: d.file_name || "Untitled document",
11057
+ subtitle: d.status && d.status !== "ready" && d.status !== "completed" ? humanizeStatus(d.status) : d.n_pages ? `${d.n_pages} ${d.n_pages === 1 ? "page" : "pages"}` : d.file_type ?? "Document",
11058
+ time: timeAndDate(d.updated_at ?? d.created_at)
11059
+ }));
11060
+ }
11061
+ function splitFacts(facts, now = /* @__PURE__ */ new Date()) {
11062
+ const startOfToday = new Date(now);
11063
+ startOfToday.setHours(0, 0, 0, 0);
11064
+ const dated = facts.filter((f) => f.date_start && new Date(f.date_start) >= startOfToday).sort((a, b) => time(a.date_start) - time(b.date_start)).slice(0, FACT_ROWS);
11065
+ const datedIds = new Set(dated.map((f) => f.external_id));
11066
+ const rest = facts.filter((f) => !datedIds.has(f.external_id)).sort((a, b) => time(b.created_at) - time(a.created_at)).slice(0, FACT_ROWS);
11067
+ const row = (f, stamp) => ({
11068
+ id: f.external_id,
11069
+ title: f.text,
11070
+ time: stamp
11071
+ });
11072
+ return {
11073
+ upcoming: dated.map((f) => row(f, f.date_start ? shortDate(f.date_start) : "")),
11074
+ recent: rest.map((f) => row(f, timeAndDate(f.created_at)))
11075
+ };
11076
+ }
11077
+ function ConnectedWorkspaceDashboard({
11078
+ actions,
11079
+ start,
11080
+ addFilesAction,
11081
+ aside,
11082
+ testId = "workspace-dashboard"
11083
+ }) {
11084
+ const { openDocument, openConversation } = useBlocksEnvironment();
11085
+ const { workspaceId } = useConnectedWorkspace();
11086
+ const { data: documents } = useConnectedDocuments();
11087
+ const { data: conversations } = useConnectedConversations();
11088
+ const { data: facts = [] } = useFacts(workspaceId);
11089
+ const conversationIcon = /* @__PURE__ */ jsx(EntityIcon, { entityType: "CONVERSATION", className: "mt-0.5 size-5 shrink-0" });
11090
+ const chatRows = useMemo(
11091
+ () => recentConversations(conversations).map((row) => ({
11092
+ ...row,
11093
+ leading: conversationIcon,
11094
+ href: workspaceId ? buildDeepLinkPath({ workspaceId, conversationId: row.id }) : void 0,
11095
+ onSelect: () => openConversation(row.id)
11096
+ })),
11097
+ // eslint-disable-next-line react-hooks/exhaustive-deps
11098
+ [conversations, workspaceId, openConversation]
11099
+ );
11100
+ const docRows = useMemo(
11101
+ () => recentDocuments(documents).map(({ fileName, ...row }) => ({
11102
+ ...row,
11103
+ // The file-type mark, bare: it carries its own identity.
11104
+ leading: /* @__PURE__ */ jsx("span", { className: "mt-0.5 shrink-0", children: getDocIcon(fileName, 20) }),
11105
+ href: workspaceId ? buildDeepLinkPath({ workspaceId, documentId: row.id }) : void 0,
11106
+ onSelect: () => openDocument(row.id)
11107
+ })),
11108
+ [documents, workspaceId, openDocument]
11109
+ );
11110
+ const { upcoming, recent } = useMemo(() => {
11111
+ const { upcoming: upcoming2, recent: recent2 } = splitFacts(facts);
11112
+ const toRow = (row) => ({
11113
+ ...row,
11114
+ leading: /* @__PURE__ */ jsx(FactMark, {}),
11115
+ // The item, not the list: the Facts page scrolls to this fact.
11116
+ onSelect: () => actions.openFact(row.id)
11117
+ });
11118
+ return { upcoming: upcoming2.map(toRow), recent: recent2.map(toRow) };
11119
+ }, [facts, actions]);
11120
+ return /* @__PURE__ */ jsxs(DashboardRoot, { testId, children: [
11121
+ start && /* @__PURE__ */ jsx(DashboardBand, { kind: "start", children: start }),
11122
+ /* @__PURE__ */ jsxs(DashboardBand, { kind: "recent", children: [
11123
+ /* @__PURE__ */ jsx(SectionLabel, { testId: `${testId}-recent-caption`, children: "Recent" }),
11124
+ /* @__PURE__ */ jsxs(DashboardColumns, { children: [
11125
+ /* @__PURE__ */ jsx(
11126
+ RecentList,
11127
+ {
11128
+ testId: `${testId}-docs`,
11129
+ icon: FileText,
11130
+ title: getEntityLabel("DOCUMENT", "PLURAL"),
11131
+ count: documents.length,
11132
+ onOpen: () => actions.openSection("documents"),
11133
+ action: addFilesAction,
11134
+ rows: docRows,
11135
+ caption: "Added",
11136
+ empty: {
11137
+ icon: Upload,
11138
+ label: "Add files or emails",
11139
+ description: "From your computer, a web link, or a connected mailbox.",
11140
+ onSelect: actions.addFiles
11141
+ }
11142
+ }
11143
+ ),
11144
+ /* @__PURE__ */ jsx(
11145
+ RecentList,
11146
+ {
11147
+ testId: `${testId}-chats`,
11148
+ icon: MessagesSquare,
11149
+ title: getEntityLabel("CONVERSATION", "PLURAL"),
11150
+ count: conversations.length,
11151
+ onOpen: () => actions.openSection("threads"),
11152
+ action: (
11153
+ // Quiet like every section action: the Start band is the page's first job.
11154
+ /* @__PURE__ */ jsx(
11155
+ DashboardAction,
11156
+ {
11157
+ emphasis: "quiet",
11158
+ icon: /* @__PURE__ */ jsx(Plus, { className: "size-4" }),
11159
+ label: "New",
11160
+ onClick: actions.newThread,
11161
+ testId: `${testId}-chats-new`
11162
+ }
11163
+ )
11164
+ ),
11165
+ rows: chatRows,
11166
+ caption: "Messaged",
11167
+ empty: {
11168
+ icon: Plus,
11169
+ label: "Ask ARBI anything",
11170
+ description: "Questions are answered from this workspace's files.",
11171
+ onSelect: actions.ask
11172
+ }
11173
+ }
11174
+ )
11175
+ ] })
11176
+ ] }),
11177
+ /* @__PURE__ */ jsxs(DashboardColumns, { children: [
11178
+ /* @__PURE__ */ jsx(
11179
+ FactsStrip,
11180
+ {
11181
+ testId: `${testId}-facts`,
11182
+ icon: Milestone,
11183
+ title: getEntityLabel("FACT", "PLURAL"),
11184
+ count: facts.length,
11185
+ onOpen: () => actions.openSection("facts"),
11186
+ action: /* @__PURE__ */ jsx(
11187
+ DashboardAction,
11188
+ {
11189
+ emphasis: "quiet",
11190
+ icon: /* @__PURE__ */ jsx(Plus, { className: "size-4" }),
11191
+ label: "New fact",
11192
+ onClick: actions.newFact,
11193
+ testId: `${testId}-facts-action`
11194
+ }
11195
+ ),
11196
+ groups: [
11197
+ { caption: "Upcoming", rows: upcoming, rowTestId: `${testId}-facts-upcoming-row` },
11198
+ { caption: "Created", rows: recent, rowTestId: `${testId}-facts-row` }
11199
+ ],
11200
+ empty: {
11201
+ icon: Milestone,
11202
+ label: `Add your first ${getEntityLabel("FACT").toLowerCase()}`,
11203
+ description: "A date, a decision, a preference \u2014 anything worth remembering.",
11204
+ onSelect: actions.newFact,
11205
+ testId: `${testId}-facts-empty-action`
11206
+ }
11207
+ }
11208
+ ),
11209
+ aside
11210
+ ] })
11211
+ ] });
11212
+ }
10649
11213
  var DEFAULT_SEARCH_ROW_LABELS = {
10650
11214
  meaningMatch: "Matched by meaning",
10651
11215
  meaningMatchTitle: "None of your search words appear in this passage. It matched by meaning.",
@@ -15014,7 +15578,7 @@ function subscribePhone(cb) {
15014
15578
  return () => mq?.removeEventListener?.("change", cb);
15015
15579
  }
15016
15580
  var isPhoneNow = () => typeof window !== "undefined" && !!window.matchMedia?.(PHONE_QUERY)?.matches;
15017
- function useIsPhone() {
15581
+ function useIsPhone2() {
15018
15582
  return useSyncExternalStore(subscribePhone, isPhoneNow, () => false);
15019
15583
  }
15020
15584
  var errorText3 = (err) => describeCalendarError(err);
@@ -15036,7 +15600,7 @@ function ConnectedCalendar({
15036
15600
  const arbi = useArbi();
15037
15601
  const fetchEvent = useFetchCalendarEvent();
15038
15602
  const notifyError = (prefix, err) => notify14(`${prefix}: ${errorText3(err)}`, "error");
15039
- const isPhone = useIsPhone();
15603
+ const isPhone = useIsPhone2();
15040
15604
  const { data: settingsData } = useCalendarSettings();
15041
15605
  const settings = settingsData ?? FALLBACK_SETTINGS;
15042
15606
  const zone = safeZone(settings.time_zone, detectTimeZone());
@@ -16318,6 +16882,6 @@ function ConnectedAgentChatPanel({
16318
16882
  ] });
16319
16883
  }
16320
16884
 
16321
- export { AddAddonDialog, ArbiAppProvider, BACKFILL_OPTIONS, BillingProjectEntity, BillingSupportProvider, CAP_REACHED_MESSAGE, ChangePlanDialog, ConnectedAccountSettings, ConnectedAgentChatPanel, ConnectedAgentCreator, ConnectedAppsSettings, ConnectedCalendar, ConnectedDangerZone, ConnectedDriveSyncDialog, ConnectedFactsPage, ConnectedIdentityVerification, ConnectedLogoutDialog, ConnectedMailAccounts, ConnectedMailComposer, ConnectedMailInviteCard, ConnectedMailMessage, ConnectedMailSettings, ConnectedMailSetup, ConnectedMailbox, ConnectedMailboxSyncDialog, ConnectedNotificationCenter, ConnectedNotificationPreferences, ConnectedPasswordChangeDialog, ConnectedPremiumModels, ConnectedPrivacySettings, ConnectedProfileCard, ConnectedPublicBooking, ConnectedRequireVerified, ConnectedSearchPage, ConnectedSecuritySection, ConnectedSessionsRow, ConnectedSettingsPage, ConnectedSkillUpload, ConnectedSkillsLibrary, ConnectedTagTable, ConnectedTagsPage, ConnectedTaskAccessRequest, ConnectedTaskActivityDialog, ConnectedThreadFollow, ConnectedUpcomingEvents, ConnectedWorkflowHistory, ConnectedWorkflowRunner, ConnectedWorkspaceActivity, ConnectedWorkspaceNotificationMenu, ConnectedWorkspaceSettings, DEFAULT_CONNECTED_SEARCH_PAGE_LABELS, DEFAULT_CONNECTED_SKILL_UPLOAD_LABELS, DEFAULT_CONNECTED_WORKFLOW_RUNNER_LABELS, DEFAULT_SEARCH_ROW_LABELS, DEFAULT_SETTINGS_SECTIONS, DEFAULT_TIMELINE_LABEL_WIDTH, FACTS_GRID_ID, InvoicesModal, NewProjectFlow, NotificationCenter, NotificationEvent, ProjectDetail, ProjectsTable, REFERRAL_OFFER, SETTINGS_SECTION_IDS, SessionStatusIcon, SharedProjects, StreamedArtifact, WorkflowRunThread, ZERO_BUDGET_MESSAGE, accountSettingsSection, aiUsageResetTimestamp, bookingCancelLink, buildNotificationCenterItems, chatSettingsSection, connectedAppsSettingsSection, countNotificationTypes, defaultUnmetPasswordRequirement, filterNotificationCenterItems, formatLastSync, formatMoney, formatResetDate, getQuotaItems, isAddonBudgetZero, isProProject, mailSettingsSection, openMeetingLink, planBadgeView, planName, privacySettingsSection, renderSessionStatusIcon, requestCalendarComposer, requestCalendarEvent, requestProjectBillingFocus, resolveMailbox, useAutoRefreshPendingProjects, useBillingSupport, useCalendarViewStore, useConnectedDocxNotifications, useConnectedShellWorkspaces, useConnectedWorkNotifications, useConnectedWorkspaceSettings, useOpenBillingPortal, useProjectBillingFocus, useReferralReward, useRewardBalance, windowLabel, workflowRunView };
16885
+ export { AddAddonDialog, ArbiAppProvider, BACKFILL_OPTIONS, BillingProjectEntity, ChangePlanDialog, ConnectedAccountSettings, ConnectedAgentChatPanel, ConnectedAgentCreator, ConnectedAppsSettings, ConnectedCalendar, ConnectedDangerZone, ConnectedDriveSyncDialog, ConnectedFactsPage, ConnectedIdentityVerification, ConnectedLogoutDialog, ConnectedMailAccounts, ConnectedMailComposer, ConnectedMailInviteCard, ConnectedMailMessage, ConnectedMailSettings, ConnectedMailSetup, ConnectedMailbox, ConnectedMailboxSyncDialog, ConnectedNotificationCenter, ConnectedNotificationPreferences, ConnectedPasswordChangeDialog, ConnectedPremiumModels, ConnectedPrivacySettings, ConnectedProfileCard, ConnectedProjectsPanel, ConnectedPublicBooking, ConnectedRequireVerified, ConnectedSearchPage, ConnectedSecuritySection, ConnectedSessionsRow, ConnectedSettingsPage, ConnectedSkillUpload, ConnectedSkillsLibrary, ConnectedTagTable, ConnectedTagsPage, ConnectedTaskAccessRequest, ConnectedTaskActivityDialog, ConnectedThreadFollow, ConnectedUpcomingEvents, ConnectedWorkflowHistory, ConnectedWorkflowRunner, ConnectedWorkspaceActivity, ConnectedWorkspaceDashboard, ConnectedWorkspaceList, ConnectedWorkspaceMembers, ConnectedWorkspaceNotificationMenu, ConnectedWorkspaceSettings, DEFAULT_CONNECTED_SEARCH_PAGE_LABELS, DEFAULT_CONNECTED_SKILL_UPLOAD_LABELS, DEFAULT_CONNECTED_WORKFLOW_RUNNER_LABELS, DEFAULT_SEARCH_ROW_LABELS, DEFAULT_SETTINGS_SECTIONS, DEFAULT_TIMELINE_LABEL_WIDTH, DEFAULT_WORKSPACE_LIST_LABELS, FACTS_GRID_ID, InvoicesModal, NewProjectFlow, NotificationCenter, NotificationEvent, PROJECTS_BASE_TAB_ID, ProjectDetail, ProjectsTable, REFERRAL_OFFER, SETTINGS_SECTION_IDS, SessionStatusIcon, SharedProjects, StreamedArtifact, WORKSPACES_TAB_ID, WorkflowRunThread, accountSettingsSection, bookingCancelLink, buildNotificationCenterItems, chatSettingsSection, connectedAppsSettingsSection, countNotificationTypes, defaultUnmetPasswordRequirement, filterNotificationCenterItems, formatLastSync, mailSettingsSection, openMeetingLink, privacySettingsSection, renderSessionStatusIcon, requestCalendarComposer, requestCalendarEvent, requestProjectBillingFocus, resolveMailbox, toWorkspaceSummary, useAutoRefreshPendingProjects, useCalendarViewStore, useConnectedDocxNotifications, useConnectedShellWorkspaces, useConnectedWorkNotifications, useConnectedWorkspaceList, useConnectedWorkspaceSettings, useOpenBillingPortal, useProjectBillingFocus, useReferralReward, windowLabel, workflowRunView };
16322
16886
  //# sourceMappingURL=index.js.map
16323
16887
  //# sourceMappingURL=index.js.map