@burdenoff/microfe-workspaces 2026.520.1 → 2026.528.1

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 (234) hide show
  1. package/dist/WorkspacesRoot.js +4 -1
  2. package/dist/WorkspacesRoot.js.map +1 -1
  3. package/dist/WorkspacesRoutes.js +4 -4
  4. package/dist/WorkspacesRoutes.js.map +1 -1
  5. package/dist/components/CreateProjectDialog.js +1 -1
  6. package/dist/components/CreateProjectDialog.js.map +1 -1
  7. package/dist/components/CreateWorkspaceDialog.js +2 -2
  8. package/dist/components/CreateWorkspaceDialog.js.map +1 -1
  9. package/dist/components/InviteMemberDialog.js +2 -2
  10. package/dist/components/InviteMemberDialog.js.map +1 -1
  11. package/dist/components/MemberListItem.js +71 -86
  12. package/dist/components/MemberListItem.js.map +1 -1
  13. package/dist/components/ProjectCard.js +12 -10
  14. package/dist/components/ProjectCard.js.map +1 -1
  15. package/dist/components/WorkspaceCard.js.map +1 -1
  16. package/dist/components/WorkspacesErrorBoundary.js +12 -4
  17. package/dist/components/WorkspacesErrorBoundary.js.map +1 -1
  18. package/dist/components/tags/ProjectTagsWidget.js +248 -0
  19. package/dist/components/tags/ProjectTagsWidget.js.map +1 -0
  20. package/dist/hooks/useOrgsWithPermission.js +1 -1
  21. package/dist/hooks/useOrgsWithPermission.js.map +1 -1
  22. package/dist/hooks/useWorkspacesEventEmitter.js.map +1 -1
  23. package/dist/hooks/useWorkspacesPageView.js +6 -4
  24. package/dist/hooks/useWorkspacesPageView.js.map +1 -1
  25. package/dist/pages/CreateWorkspacePage.js +239 -224
  26. package/dist/pages/CreateWorkspacePage.js.map +1 -1
  27. package/dist/pages/InviteAcceptancePage.js +28 -28
  28. package/dist/pages/InviteAcceptancePage.js.map +1 -1
  29. package/dist/pages/MembersListPage.js +380 -352
  30. package/dist/pages/MembersListPage.js.map +1 -1
  31. package/dist/pages/ProjectDetailPage.js +96 -97
  32. package/dist/pages/ProjectDetailPage.js.map +1 -1
  33. package/dist/pages/ProjectsListPage.js +307 -304
  34. package/dist/pages/ProjectsListPage.js.map +1 -1
  35. package/dist/pages/WorkspaceSettingsPage.js +94 -91
  36. package/dist/pages/WorkspaceSettingsPage.js.map +1 -1
  37. package/dist/pages/WorkspacesListPage.js +1 -1
  38. package/dist/pages/WorkspacesListPage.js.map +1 -1
  39. package/dist/pages/dashboard/DashboardCustomizer.js +68 -68
  40. package/dist/pages/dashboard/DashboardCustomizer.js.map +1 -1
  41. package/dist/pages/dashboard/DashboardGrid.js +52 -41
  42. package/dist/pages/dashboard/DashboardGrid.js.map +1 -1
  43. package/dist/pages/dashboard/DashboardPage.js +74 -65
  44. package/dist/pages/dashboard/DashboardPage.js.map +1 -1
  45. package/dist/pages/dashboard/WidgetWrapper.js +3 -3
  46. package/dist/pages/dashboard/WidgetWrapper.js.map +1 -1
  47. package/dist/pages/dashboard/config.js +126 -30
  48. package/dist/pages/dashboard/config.js.map +1 -1
  49. package/dist/pages/dashboard/hooks/useDashboardData.js +39 -2
  50. package/dist/pages/dashboard/hooks/useDashboardData.js.map +1 -1
  51. package/dist/pages/dashboard/widgets/AgentsWidget.js +109 -0
  52. package/dist/pages/dashboard/widgets/AgentsWidget.js.map +1 -0
  53. package/dist/pages/dashboard/widgets/GroupsWidget.js +6 -5
  54. package/dist/pages/dashboard/widgets/GroupsWidget.js.map +1 -1
  55. package/dist/pages/dashboard/widgets/MembersWidget.js +6 -6
  56. package/dist/pages/dashboard/widgets/MembersWidget.js.map +1 -1
  57. package/dist/pages/dashboard/widgets/ProjectsWidget.js +8 -7
  58. package/dist/pages/dashboard/widgets/ProjectsWidget.js.map +1 -1
  59. package/dist/pages/dashboard/widgets/QuickActionsWidget.js +72 -18
  60. package/dist/pages/dashboard/widgets/QuickActionsWidget.js.map +1 -1
  61. package/dist/pages/dashboard/widgets/RecentActivityWidget.js +3 -3
  62. package/dist/pages/dashboard/widgets/RecentActivityWidget.js.map +1 -1
  63. package/dist/pages/dashboard/widgets/SessionsWidget.js +78 -0
  64. package/dist/pages/dashboard/widgets/SessionsWidget.js.map +1 -0
  65. package/dist/pages/dashboard/widgets/StorageWidget.js +35 -20
  66. package/dist/pages/dashboard/widgets/StorageWidget.js.map +1 -1
  67. package/dist/pages/dashboard/widgets/TagCloudWidget.js +2 -2
  68. package/dist/pages/dashboard/widgets/TagCloudWidget.js.map +1 -1
  69. package/dist/pages/dashboard/widgets/TipsWidget.js +81 -22
  70. package/dist/pages/dashboard/widgets/TipsWidget.js.map +1 -1
  71. package/dist/pages/dashboard/widgets/UpcomingEventsWidget.js +6 -5
  72. package/dist/pages/dashboard/widgets/UpcomingEventsWidget.js.map +1 -1
  73. package/dist/pages/dashboard/widgets/VibesWidget.js +64 -0
  74. package/dist/pages/dashboard/widgets/VibesWidget.js.map +1 -0
  75. package/dist/pages/dashboard/widgets/WelcomeWidget.js +5 -5
  76. package/dist/pages/dashboard/widgets/WelcomeWidget.js.map +1 -1
  77. package/dist/pages/dashboard/widgets/WorkflowStatsWidget.js +3 -3
  78. package/dist/pages/dashboard/widgets/WorkflowStatsWidget.js.map +1 -1
  79. package/dist/pages/dashboard/widgets/WorkspacesWidget.js +6 -5
  80. package/dist/pages/dashboard/widgets/WorkspacesWidget.js.map +1 -1
  81. package/dist/providers/WorkspacesProvider.js +1 -1
  82. package/dist/providers/WorkspacesProvider.js.map +1 -1
  83. package/dist/store/workspacesStore.js.map +1 -1
  84. package/dist/utils/formatters.js +21 -16
  85. package/dist/utils/formatters.js.map +1 -1
  86. package/dist/utils/telemetryError.js +1 -1
  87. package/dist/utils/telemetryError.js.map +1 -1
  88. package/package.json +7 -7
  89. package/dist/WorkspacesRoot.d.ts +0 -35
  90. package/dist/WorkspacesRoot.d.ts.map +0 -1
  91. package/dist/WorkspacesRoutes.d.ts +0 -10
  92. package/dist/WorkspacesRoutes.d.ts.map +0 -1
  93. package/dist/components/CreateProjectDialog.d.ts +0 -6
  94. package/dist/components/CreateProjectDialog.d.ts.map +0 -1
  95. package/dist/components/CreateWorkspaceDialog.d.ts +0 -2
  96. package/dist/components/CreateWorkspaceDialog.d.ts.map +0 -1
  97. package/dist/components/InviteMemberDialog.d.ts +0 -7
  98. package/dist/components/InviteMemberDialog.d.ts.map +0 -1
  99. package/dist/components/MemberListItem.d.ts +0 -11
  100. package/dist/components/MemberListItem.d.ts.map +0 -1
  101. package/dist/components/ProjectCard.d.ts +0 -13
  102. package/dist/components/ProjectCard.d.ts.map +0 -1
  103. package/dist/components/WorkspaceCard.d.ts +0 -8
  104. package/dist/components/WorkspaceCard.d.ts.map +0 -1
  105. package/dist/components/WorkspacesErrorBoundary.d.ts +0 -27
  106. package/dist/components/WorkspacesErrorBoundary.d.ts.map +0 -1
  107. package/dist/components/index.d.ts +0 -8
  108. package/dist/components/index.d.ts.map +0 -1
  109. package/dist/constants/permissions.d.ts +0 -33
  110. package/dist/constants/permissions.d.ts.map +0 -1
  111. package/dist/generated/global-operations.d.ts +0 -319
  112. package/dist/generated/global-operations.d.ts.map +0 -1
  113. package/dist/generated/global-types.d.ts +0 -23527
  114. package/dist/generated/global-types.d.ts.map +0 -1
  115. package/dist/generated/wspace-operations.d.ts +0 -2300
  116. package/dist/generated/wspace-operations.d.ts.map +0 -1
  117. package/dist/generated/wspace-types.d.ts +0 -57851
  118. package/dist/generated/wspace-types.d.ts.map +0 -1
  119. package/dist/hooks/index.d.ts +0 -8
  120. package/dist/hooks/index.d.ts.map +0 -1
  121. package/dist/hooks/useMemberMutations.d.ts +0 -61
  122. package/dist/hooks/useMemberMutations.d.ts.map +0 -1
  123. package/dist/hooks/useOrgsWithPermission.d.ts +0 -7
  124. package/dist/hooks/useOrgsWithPermission.d.ts.map +0 -1
  125. package/dist/hooks/useProjectMutations.d.ts +0 -26
  126. package/dist/hooks/useProjectMutations.d.ts.map +0 -1
  127. package/dist/hooks/useProjects.d.ts +0 -16
  128. package/dist/hooks/useProjects.d.ts.map +0 -1
  129. package/dist/hooks/useScopedNavigation.d.ts +0 -4
  130. package/dist/hooks/useScopedNavigation.d.ts.map +0 -1
  131. package/dist/hooks/useTenants.d.ts +0 -13
  132. package/dist/hooks/useTenants.d.ts.map +0 -1
  133. package/dist/hooks/useWorkspaceActivity.d.ts +0 -12
  134. package/dist/hooks/useWorkspaceActivity.d.ts.map +0 -1
  135. package/dist/hooks/useWorkspaceMembers.d.ts +0 -24
  136. package/dist/hooks/useWorkspaceMembers.d.ts.map +0 -1
  137. package/dist/hooks/useWorkspaceMutations.d.ts +0 -36
  138. package/dist/hooks/useWorkspaceMutations.d.ts.map +0 -1
  139. package/dist/hooks/useWorkspacePermissions.d.ts +0 -29
  140. package/dist/hooks/useWorkspacePermissions.d.ts.map +0 -1
  141. package/dist/hooks/useWorkspaceRoles.d.ts +0 -8
  142. package/dist/hooks/useWorkspaceRoles.d.ts.map +0 -1
  143. package/dist/hooks/useWorkspaces.d.ts +0 -21
  144. package/dist/hooks/useWorkspaces.d.ts.map +0 -1
  145. package/dist/hooks/useWorkspacesEventEmitter.d.ts +0 -18
  146. package/dist/hooks/useWorkspacesEventEmitter.d.ts.map +0 -1
  147. package/dist/hooks/useWorkspacesPageView.d.ts +0 -27
  148. package/dist/hooks/useWorkspacesPageView.d.ts.map +0 -1
  149. package/dist/index.d.ts +0 -33
  150. package/dist/index.d.ts.map +0 -1
  151. package/dist/pages/ActivityListPage.d.ts +0 -2
  152. package/dist/pages/ActivityListPage.d.ts.map +0 -1
  153. package/dist/pages/CreateWorkspacePage.d.ts +0 -2
  154. package/dist/pages/CreateWorkspacePage.d.ts.map +0 -1
  155. package/dist/pages/InviteAcceptancePage.d.ts +0 -6
  156. package/dist/pages/InviteAcceptancePage.d.ts.map +0 -1
  157. package/dist/pages/MembersListPage.d.ts +0 -2
  158. package/dist/pages/MembersListPage.d.ts.map +0 -1
  159. package/dist/pages/ProjectDetailPage.d.ts +0 -2
  160. package/dist/pages/ProjectDetailPage.d.ts.map +0 -1
  161. package/dist/pages/ProjectsListPage.d.ts +0 -2
  162. package/dist/pages/ProjectsListPage.d.ts.map +0 -1
  163. package/dist/pages/WorkspaceDetailPage.d.ts +0 -2
  164. package/dist/pages/WorkspaceDetailPage.d.ts.map +0 -1
  165. package/dist/pages/WorkspaceSettingsPage.d.ts +0 -2
  166. package/dist/pages/WorkspaceSettingsPage.d.ts.map +0 -1
  167. package/dist/pages/WorkspacesListPage.d.ts +0 -2
  168. package/dist/pages/WorkspacesListPage.d.ts.map +0 -1
  169. package/dist/pages/dashboard/DashboardCustomizer.d.ts +0 -12
  170. package/dist/pages/dashboard/DashboardCustomizer.d.ts.map +0 -1
  171. package/dist/pages/dashboard/DashboardGrid.d.ts +0 -8
  172. package/dist/pages/dashboard/DashboardGrid.d.ts.map +0 -1
  173. package/dist/pages/dashboard/DashboardPage.d.ts +0 -14
  174. package/dist/pages/dashboard/DashboardPage.d.ts.map +0 -1
  175. package/dist/pages/dashboard/WidgetWrapper.d.ts +0 -17
  176. package/dist/pages/dashboard/WidgetWrapper.d.ts.map +0 -1
  177. package/dist/pages/dashboard/config.d.ts +0 -9
  178. package/dist/pages/dashboard/config.d.ts.map +0 -1
  179. package/dist/pages/dashboard/hooks/useDashboardData.d.ts +0 -9
  180. package/dist/pages/dashboard/hooks/useDashboardData.d.ts.map +0 -1
  181. package/dist/pages/dashboard/hooks/useDashboardPreferences.d.ts +0 -4
  182. package/dist/pages/dashboard/hooks/useDashboardPreferences.d.ts.map +0 -1
  183. package/dist/pages/dashboard/types.d.ts +0 -145
  184. package/dist/pages/dashboard/types.d.ts.map +0 -1
  185. package/dist/pages/dashboard/widgets/GroupsWidget.d.ts +0 -4
  186. package/dist/pages/dashboard/widgets/GroupsWidget.d.ts.map +0 -1
  187. package/dist/pages/dashboard/widgets/MembersWidget.d.ts +0 -4
  188. package/dist/pages/dashboard/widgets/MembersWidget.d.ts.map +0 -1
  189. package/dist/pages/dashboard/widgets/ProjectsWidget.d.ts +0 -4
  190. package/dist/pages/dashboard/widgets/ProjectsWidget.d.ts.map +0 -1
  191. package/dist/pages/dashboard/widgets/QuickActionsWidget.d.ts +0 -4
  192. package/dist/pages/dashboard/widgets/QuickActionsWidget.d.ts.map +0 -1
  193. package/dist/pages/dashboard/widgets/RecentActivityWidget.d.ts +0 -4
  194. package/dist/pages/dashboard/widgets/RecentActivityWidget.d.ts.map +0 -1
  195. package/dist/pages/dashboard/widgets/StorageWidget.d.ts +0 -4
  196. package/dist/pages/dashboard/widgets/StorageWidget.d.ts.map +0 -1
  197. package/dist/pages/dashboard/widgets/SystemHealthWidget.d.ts +0 -4
  198. package/dist/pages/dashboard/widgets/SystemHealthWidget.d.ts.map +0 -1
  199. package/dist/pages/dashboard/widgets/SystemHealthWidget.js +0 -59
  200. package/dist/pages/dashboard/widgets/SystemHealthWidget.js.map +0 -1
  201. package/dist/pages/dashboard/widgets/TagCloudWidget.d.ts +0 -4
  202. package/dist/pages/dashboard/widgets/TagCloudWidget.d.ts.map +0 -1
  203. package/dist/pages/dashboard/widgets/TipsWidget.d.ts +0 -4
  204. package/dist/pages/dashboard/widgets/TipsWidget.d.ts.map +0 -1
  205. package/dist/pages/dashboard/widgets/UpcomingEventsWidget.d.ts +0 -4
  206. package/dist/pages/dashboard/widgets/UpcomingEventsWidget.d.ts.map +0 -1
  207. package/dist/pages/dashboard/widgets/WelcomeWidget.d.ts +0 -4
  208. package/dist/pages/dashboard/widgets/WelcomeWidget.d.ts.map +0 -1
  209. package/dist/pages/dashboard/widgets/WorkflowStatsWidget.d.ts +0 -4
  210. package/dist/pages/dashboard/widgets/WorkflowStatsWidget.d.ts.map +0 -1
  211. package/dist/pages/dashboard/widgets/WorkspacesWidget.d.ts +0 -4
  212. package/dist/pages/dashboard/widgets/WorkspacesWidget.d.ts.map +0 -1
  213. package/dist/providers/WorkspacesProvider.d.ts +0 -13
  214. package/dist/providers/WorkspacesProvider.d.ts.map +0 -1
  215. package/dist/store/workspacesStore.d.ts +0 -82
  216. package/dist/store/workspacesStore.d.ts.map +0 -1
  217. package/dist/types/index.d.ts +0 -280
  218. package/dist/types/index.d.ts.map +0 -1
  219. package/dist/utils/formatters.d.ts +0 -60
  220. package/dist/utils/formatters.d.ts.map +0 -1
  221. package/dist/utils/i18n.d.ts +0 -13
  222. package/dist/utils/i18n.d.ts.map +0 -1
  223. package/dist/utils/index.d.ts +0 -3
  224. package/dist/utils/index.d.ts.map +0 -1
  225. package/dist/utils/nativeBridge.d.ts +0 -3
  226. package/dist/utils/nativeBridge.d.ts.map +0 -1
  227. package/dist/utils/projectTags.d.ts +0 -6
  228. package/dist/utils/projectTags.d.ts.map +0 -1
  229. package/dist/utils/slug.d.ts +0 -13
  230. package/dist/utils/slug.d.ts.map +0 -1
  231. package/dist/utils/telemetryError.d.ts +0 -2
  232. package/dist/utils/telemetryError.d.ts.map +0 -1
  233. package/dist/utils/tokenHelpers.d.ts +0 -114
  234. package/dist/utils/tokenHelpers.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"useWorkspacesEventEmitter.js","names":[],"sources":["../../src/hooks/useWorkspacesEventEmitter.ts"],"sourcesContent":["/**\n * Workspaces-domain event emitter. Emits lifecycle events to the host shell's\n * event bus per `~/products/infra/infra-specs/microfrontends/47-FRONTEND-EVENT-BUS.md`.\n *\n * The MFE never sinks directly to Rybbit/audit — it goes through the bus.\n *\n * The fe-libs `EventBus.emit` is statically typed against `BurdenoffEventName`\n * which doesn't list our workspaces-domain names. The runtime bus is dynamic,\n * so the cast loses autocomplete but is sound.\n */\nimport { useCallback } from 'react';\n\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\n\nexport type WorkspacesDomainEvent =\n // Lifecycle (success)\n | 'workspace.created'\n | 'workspace.updated'\n | 'workspace.deleted'\n | 'workspace.archived'\n | 'workspace.reactivated'\n | 'project.created'\n | 'project.updated'\n | 'project.deleted'\n | 'project.archived'\n | 'project.unarchived'\n | 'workspace-member.added'\n | 'workspace-member.removed'\n | 'workspace-member.role-updated'\n | 'workspace-invitation.created'\n | 'workspace-invitation.updated'\n | 'workspace-invitation.accepted'\n | 'workspace-invitation.rejected'\n | 'workspace-invitation.cancelled'\n | 'workspace-invitation.resent'\n | 'workspace-invitation.deleted'\n | 'workspace-activity.appended'\n // Failure / observability — forwarded to OtelBrowserSink + audit sink\n | 'workspace.create_failed'\n | 'workspace.update_failed'\n | 'workspace.delete_failed'\n | 'workspace.archive_failed'\n | 'workspace.reactivate_failed'\n | 'project.create_failed'\n | 'project.update_failed'\n | 'project.delete_failed'\n | 'project.archive_failed'\n | 'project.unarchive_failed'\n | 'workspace-member.add_failed'\n | 'workspace-member.remove_failed'\n | 'workspace-member.role-update_failed'\n | 'workspace-invitation.create_failed'\n | 'workspace-invitation.update_failed'\n | 'workspace-invitation.accept_failed'\n | 'workspace-invitation.reject_failed'\n | 'workspace-invitation.cancel_failed'\n | 'workspace-invitation.resend_failed'\n | 'workspace-invitation.delete_failed'\n // Module-scoped (plural) — describes a navigation event into the module,\n // not an action on a single resource.\n | 'workspaces.page.viewed';\n\nexport interface WorkspacesEventPayload {\n workspaceId?: string;\n projectId?: string;\n memberId?: string;\n invitationId?: string;\n userId?: string;\n email?: string;\n source?: string;\n // Observability fields (no PII per SRE guide §7)\n page?: string;\n durationMs?: number;\n errorCode?: string;\n errorMessage?: string;\n}\n\nexport function useWorkspacesEventEmitter(): {\n emit: (event: WorkspacesDomainEvent, payload?: WorkspacesEventPayload) => void;\n} {\n const bus = useEventBus();\n // Memoize the emit callback so consumers (notably `useWorkspacesPageView`)\n // can put it in effect dep arrays without firing on every render.\n const emit = useCallback(\n (event: WorkspacesDomainEvent, payload: WorkspacesEventPayload = {}) => {\n try {\n type DynamicEmit = (e: string, p: unknown) => void;\n (bus as unknown as { emit: DynamicEmit }).emit(event, payload);\n } catch (err) {\n // Bus failures must not break workspace operations — but in dev we\n // surface the error so a wrong event shape doesn't disappear silently.\n if (import.meta.env?.DEV) {\n // eslint-disable-next-line no-console\n console.warn('[useWorkspacesEventEmitter] event bus emit failed', {\n event,\n payload,\n err,\n });\n }\n }\n },\n [bus]\n );\n return { emit };\n}\n"],"mappings":";;;AA6EA,SAAgB,IAEd;CACA,IAAM,IAAM,GAAa;AAuBzB,QAAO,EAAE,MApBI,GACV,GAA8B,IAAkC,EAAE,KAAK;AACtE,MAAI;AAED,KAAyC,KAAK,GAAO,EAAQ;UAClD;IAahB,CAAC,EAAI,CACN,EACc"}
1
+ {"version":3,"file":"useWorkspacesEventEmitter.js","names":[],"sources":["../../src/hooks/useWorkspacesEventEmitter.ts"],"sourcesContent":["/**\n * Workspaces-domain event emitter. Emits lifecycle events to the host shell's\n * event bus per `~/products/infra/infra-specs/microfrontends/47-FRONTEND-EVENT-BUS.md`.\n *\n * The MFE never sinks directly to Rybbit/audit — it goes through the bus.\n *\n * The fe-libs `EventBus.emit` is statically typed against `BurdenoffEventName`\n * which doesn't list our workspaces-domain names. The runtime bus is dynamic,\n * so the cast loses autocomplete but is sound.\n */\nimport { useCallback } from 'react';\n\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\n\nexport type WorkspacesDomainEvent =\n // Lifecycle (success)\n | 'workspace.created'\n | 'workspace.updated'\n | 'workspace.deleted'\n | 'workspace.archived'\n | 'workspace.reactivated'\n | 'project.created'\n | 'project.updated'\n | 'project.deleted'\n | 'project.archived'\n | 'project.unarchived'\n | 'workspace-member.added'\n | 'workspace-member.removed'\n | 'workspace-member.role-updated'\n | 'workspace-invitation.created'\n | 'workspace-invitation.updated'\n | 'workspace-invitation.accepted'\n | 'workspace-invitation.rejected'\n | 'workspace-invitation.cancelled'\n | 'workspace-invitation.resent'\n | 'workspace-invitation.deleted'\n | 'workspace-activity.appended'\n // Failure / observability — forwarded to OtelBrowserSink + audit sink\n | 'workspace.create_failed'\n | 'workspace.update_failed'\n | 'workspace.delete_failed'\n | 'workspace.archive_failed'\n | 'workspace.reactivate_failed'\n | 'project.create_failed'\n | 'project.update_failed'\n | 'project.delete_failed'\n | 'project.archive_failed'\n | 'project.unarchive_failed'\n | 'workspace-member.add_failed'\n | 'workspace-member.remove_failed'\n | 'workspace-member.role-update_failed'\n | 'workspace-invitation.create_failed'\n | 'workspace-invitation.update_failed'\n | 'workspace-invitation.accept_failed'\n | 'workspace-invitation.reject_failed'\n | 'workspace-invitation.cancel_failed'\n | 'workspace-invitation.resend_failed'\n | 'workspace-invitation.delete_failed'\n // Module-scoped (plural) — describes a navigation event into the module,\n // not an action on a single resource.\n | 'workspaces.page.viewed';\n\nexport interface WorkspacesEventPayload {\n workspaceId?: string;\n projectId?: string;\n memberId?: string;\n invitationId?: string;\n userId?: string;\n email?: string;\n source?: string;\n // Observability fields (no PII per SRE guide §7)\n page?: string;\n durationMs?: number;\n errorCode?: string;\n errorMessage?: string;\n}\n\nexport function useWorkspacesEventEmitter(): {\n emit: (event: WorkspacesDomainEvent, payload?: WorkspacesEventPayload) => void;\n} {\n const bus = useEventBus();\n // Memoize the emit callback so consumers (notably `useWorkspacesPageView`)\n // can put it in effect dep arrays without firing on every render.\n const emit = useCallback(\n (event: WorkspacesDomainEvent, payload: WorkspacesEventPayload = {}) => {\n try {\n type DynamicEmit = (e: string, p: unknown) => void;\n (bus as unknown as { emit: DynamicEmit }).emit(event, payload);\n } catch (err) {\n // Bus failures must not break workspace operations — but in dev we\n // surface the error so a wrong event shape doesn't disappear silently.\n if (import.meta.env?.DEV) {\n console.warn('[useWorkspacesEventEmitter] event bus emit failed', {\n event,\n payload,\n err,\n });\n }\n }\n },\n [bus]\n );\n return { emit };\n}\n"],"mappings":";;;AA6EA,SAAgB,IAEd;CACA,IAAM,IAAM,GAAa;AAsBzB,QAAO,EAAE,MAnBI,GACV,GAA8B,IAAkC,EAAE,KAAK;AACtE,MAAI;AAED,KAAyC,KAAK,GAAO,EAAQ;UAClD;IAYhB,CAAC,EAAI,CACN,EACc"}
@@ -3,14 +3,14 @@ import { useEffect as t, useRef as n } from "react";
3
3
  //#region src/hooks/useWorkspacesPageView.ts
4
4
  var r = (e) => typeof e == "string" && e.length > 0;
5
5
  function i(i, a) {
6
- let { emit: o } = e(), s = a?.workspaceId, c = a?.projectId, l = a?.requireParams ?? !1, u = n(null);
6
+ let { emit: o } = e(), s = a?.workspaceId, c = a?.projectId, l = a?.requireParams ?? !1, u = a ? "workspaceId" in a : !1, d = a ? "projectId" in a : !1, f = n(null);
7
7
  t(() => {
8
8
  if (l) {
9
9
  let e = [];
10
- if (a && "workspaceId" in a && e.push(s), a && "projectId" in a && e.push(c), e.some((e) => !r(e))) return;
10
+ if (u && e.push(s), d && e.push(c), e.some((e) => !r(e))) return;
11
11
  }
12
12
  let e = `${i}::${s ?? ""}::${c ?? ""}`;
13
- u.current !== e && (u.current = e, o("workspaces.page.viewed", {
13
+ f.current !== e && (f.current = e, o("workspaces.page.viewed", {
14
14
  page: i,
15
15
  workspaceId: s ?? void 0,
16
16
  projectId: c ?? void 0
@@ -20,7 +20,9 @@ function i(i, a) {
20
20
  i,
21
21
  s,
22
22
  c,
23
- l
23
+ l,
24
+ u,
25
+ d
24
26
  ]);
25
27
  }
26
28
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"useWorkspacesPageView.js","names":[],"sources":["../../src/hooks/useWorkspacesPageView.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\n\nimport { useWorkspacesEventEmitter } from './useWorkspacesEventEmitter';\n\ninterface PageViewExtra {\n /**\n * Workspace context for the page. `undefined` / `null` / `''` are all\n * treated as \"unresolved\" when `requireParams` is true so that\n * `useParams()`'s `string | undefined` initial render doesn't fire\n * a phantom event with missing context.\n */\n workspaceId?: string | null;\n projectId?: string | null;\n /**\n * Set to `true` on routes that include `:workspaceId` / `:projectId`\n * in the path. The hook then skips the emit until **every value\n * supplied in `extra`** resolves to a non-empty string. Anything you\n * don't pass to `extra` is treated as \"not applicable to this page\"\n * — the hook ignores it.\n */\n requireParams?: boolean;\n}\n\nconst isResolved = (v: string | null | undefined): v is string =>\n typeof v === 'string' && v.length > 0;\n\n/**\n * Emit a `workspaces.page.viewed` event when a top-level workspaces page mounts\n * (and again when its `page` / `workspaceId` / `projectId` context changes).\n * The event is forwarded by the shell's bus to OtelBrowserSink / RybbitSink /\n * BackendAuditSink — the MFE never sinks directly.\n */\nexport function useWorkspacesPageView(page: string, extra?: PageViewExtra): void {\n const { emit } = useWorkspacesEventEmitter();\n const workspaceId = extra?.workspaceId;\n const projectId = extra?.projectId;\n const requireParams = extra?.requireParams ?? false;\n\n // Track the last (page, workspaceId, projectId) tuple we emitted for, so\n // when params resolve asynchronously and the same effect re-runs we don't\n // double-fire — and so a quick router transition that lands on the same\n // page only counts once.\n const lastKey = useRef<string | null>(null);\n\n useEffect(() => {\n // Skip while params are still resolving on routes that need them.\n // We check every key the caller actually supplied — if `extra.projectId`\n // wasn't passed it stays `undefined` and is ignored; if it WAS passed\n // (even as `undefined` from `useParams`) we wait for it to resolve.\n if (requireParams) {\n const passed: Array<string | null | undefined> = [];\n if (extra && 'workspaceId' in extra) passed.push(workspaceId);\n if (extra && 'projectId' in extra) passed.push(projectId);\n if (passed.some((v) => !isResolved(v))) {\n if (import.meta.env?.DEV) {\n // eslint-disable-next-line no-console\n console.debug('[useWorkspacesPageView] skipping — required params not yet resolved', {\n page,\n workspaceId,\n projectId,\n });\n }\n return;\n }\n }\n\n const key = `${page}::${workspaceId ?? ''}::${projectId ?? ''}`;\n if (lastKey.current === key) return;\n lastKey.current = key;\n\n emit('workspaces.page.viewed', {\n page,\n workspaceId: workspaceId ?? undefined,\n projectId: projectId ?? undefined,\n });\n // `extra` is read up-front and stable for the lifetime of this\n // page mount — the workspaceId/projectId values inside it ARE in\n // the dep array, which is what matters for effect re-runs.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [emit, page, workspaceId, projectId, requireParams]);\n}\n"],"mappings":";;;AAuBA,IAAM,KAAc,MAClB,OAAO,KAAM,YAAY,EAAE,SAAS;AAQtC,SAAgB,EAAsB,GAAc,GAA6B;CAC/E,IAAM,EAAE,YAAS,GAA2B,EACtC,IAAc,GAAO,aACrB,IAAY,GAAO,WACnB,IAAgB,GAAO,iBAAiB,IAMxC,IAAU,EAAsB,KAAK;AAE3C,SAAgB;AAKd,MAAI,GAAe;GACjB,IAAM,IAA2C,EAAE;AAGnD,OAFI,KAAS,iBAAiB,KAAO,EAAO,KAAK,EAAY,EACzD,KAAS,eAAe,KAAO,EAAO,KAAK,EAAU,EACrD,EAAO,MAAM,MAAM,CAAC,EAAW,EAAE,CAAC,CASpC;;EAIJ,IAAM,IAAM,GAAG,EAAK,IAAI,KAAe,GAAG,IAAI,KAAa;AACvD,IAAQ,YAAY,MACxB,EAAQ,UAAU,GAElB,EAAK,0BAA0B;GAC7B;GACA,aAAa,KAAe,KAAA;GAC5B,WAAW,KAAa,KAAA;GACzB,CAAC;IAKD;EAAC;EAAM;EAAM;EAAa;EAAW;EAAc,CAAC"}
1
+ {"version":3,"file":"useWorkspacesPageView.js","names":[],"sources":["../../src/hooks/useWorkspacesPageView.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\n\nimport { useWorkspacesEventEmitter } from './useWorkspacesEventEmitter';\n\ninterface PageViewExtra {\n /**\n * Workspace context for the page. `undefined` / `null` / `''` are all\n * treated as \"unresolved\" when `requireParams` is true so that\n * `useParams()`'s `string | undefined` initial render doesn't fire\n * a phantom event with missing context.\n */\n workspaceId?: string | null;\n projectId?: string | null;\n /**\n * Set to `true` on routes that include `:workspaceId` / `:projectId`\n * in the path. The hook then skips the emit until **every value\n * supplied in `extra`** resolves to a non-empty string. Anything you\n * don't pass to `extra` is treated as \"not applicable to this page\"\n * — the hook ignores it.\n */\n requireParams?: boolean;\n}\n\nconst isResolved = (v: string | null | undefined): v is string =>\n typeof v === 'string' && v.length > 0;\n\n/**\n * Emit a `workspaces.page.viewed` event when a top-level workspaces page mounts\n * (and again when its `page` / `workspaceId` / `projectId` context changes).\n * The event is forwarded by the shell's bus to OtelBrowserSink / RybbitSink /\n * BackendAuditSink — the MFE never sinks directly.\n */\nexport function useWorkspacesPageView(page: string, extra?: PageViewExtra): void {\n const { emit } = useWorkspacesEventEmitter();\n const workspaceId = extra?.workspaceId;\n const projectId = extra?.projectId;\n const requireParams = extra?.requireParams ?? false;\n const hasWorkspaceIdKey = extra ? 'workspaceId' in extra : false;\n const hasProjectIdKey = extra ? 'projectId' in extra : false;\n\n // Track the last (page, workspaceId, projectId) tuple we emitted for, so\n // when params resolve asynchronously and the same effect re-runs we don't\n // double-fire — and so a quick router transition that lands on the same\n // page only counts once.\n const lastKey = useRef<string | null>(null);\n\n useEffect(() => {\n // Skip while params are still resolving on routes that need them.\n // We check every key the caller actually supplied — if `extra.projectId`\n // wasn't passed it stays `undefined` and is ignored; if it WAS passed\n // (even as `undefined` from `useParams`) we wait for it to resolve.\n if (requireParams) {\n const passed: Array<string | null | undefined> = [];\n if (hasWorkspaceIdKey) passed.push(workspaceId);\n if (hasProjectIdKey) passed.push(projectId);\n if (passed.some((v) => !isResolved(v))) {\n if (import.meta.env?.DEV) {\n console.debug('[useWorkspacesPageView] skipping — required params not yet resolved', {\n page,\n workspaceId,\n projectId,\n });\n }\n return;\n }\n }\n\n const key = `${page}::${workspaceId ?? ''}::${projectId ?? ''}`;\n if (lastKey.current === key) return;\n lastKey.current = key;\n\n emit('workspaces.page.viewed', {\n page,\n workspaceId: workspaceId ?? undefined,\n projectId: projectId ?? undefined,\n });\n }, [emit, page, workspaceId, projectId, requireParams, hasWorkspaceIdKey, hasProjectIdKey]);\n}\n"],"mappings":";;;AAuBA,IAAM,KAAc,MAClB,OAAO,KAAM,YAAY,EAAE,SAAS;AAQtC,SAAgB,EAAsB,GAAc,GAA6B;CAC/E,IAAM,EAAE,YAAS,GAA2B,EACtC,IAAc,GAAO,aACrB,IAAY,GAAO,WACnB,IAAgB,GAAO,iBAAiB,IACxC,IAAoB,IAAQ,iBAAiB,IAAQ,IACrD,IAAkB,IAAQ,eAAe,IAAQ,IAMjD,IAAU,EAAsB,KAAK;AAE3C,SAAgB;AAKd,MAAI,GAAe;GACjB,IAAM,IAA2C,EAAE;AAGnD,OAFI,KAAmB,EAAO,KAAK,EAAY,EAC3C,KAAiB,EAAO,KAAK,EAAU,EACvC,EAAO,MAAM,MAAM,CAAC,EAAW,EAAE,CAAC,CAQpC;;EAIJ,IAAM,IAAM,GAAG,EAAK,IAAI,KAAe,GAAG,IAAI,KAAa;AACvD,IAAQ,YAAY,MACxB,EAAQ,UAAU,GAElB,EAAK,0BAA0B;GAC7B;GACA,aAAa,KAAe,KAAA;GAC5B,WAAW,KAAa,KAAA;GACzB,CAAC;IACD;EAAC;EAAM;EAAM;EAAa;EAAW;EAAe;EAAmB;EAAgB,CAAC"}
@@ -1,29 +1,30 @@
1
1
  import { useWorkspacesContext as e } from "../providers/WorkspacesProvider.js";
2
2
  import { tWithFallback as t } from "../utils/i18n.js";
3
- import { useWorkspacesPageView as n } from "../hooks/useWorkspacesPageView.js";
4
- import { useCreateWorkspace as r } from "../hooks/useWorkspaceMutations.js";
5
- import { useMyOrganizations as i, useMyTenants as a } from "../hooks/useTenants.js";
6
- import { generateSlug as o } from "../utils/slug.js";
7
- import { useOrgsWithPermission as s } from "../hooks/useOrgsWithPermission.js";
8
- import { useEffect as c, useMemo as l } from "react";
9
- import { AlertCircle as u, ArrowLeft as d } from "lucide-react";
10
- import { jsx as f, jsxs as p } from "react/jsx-runtime";
11
- import { Button as m, Card as h, CardContent as g, CardDescription as _, CardHeader as v, CardTitle as y, Skeleton as b } from "@burdenoff/fe-libs/ui";
12
- import { Link as x, useNavigate as S } from "react-router-dom";
13
- import { AccessDenied as C } from "@burdenoff/fe-libs/shared/components";
3
+ import { useWorkspacesPageView as ee } from "../hooks/useWorkspacesPageView.js";
4
+ import { useCreateWorkspace as n } from "../hooks/useWorkspaceMutations.js";
5
+ import { useMyOrganizations as r, useMyTenants as i } from "../hooks/useTenants.js";
6
+ import { generateSlug as a } from "../utils/slug.js";
7
+ import { useOrgsWithPermission as o } from "../hooks/useOrgsWithPermission.js";
8
+ import { useEffect as s, useMemo as c } from "react";
9
+ import { AlertCircle as l, ArrowLeft as u } from "lucide-react";
10
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
11
+ import { Button as p, Card as te, CardContent as m, CardDescription as h, CardHeader as g, CardTitle as _, Skeleton as v } from "@burdenoff/fe-libs/ui";
12
+ import { Link as y, useNavigate as b } from "react-router-dom";
13
+ import { useUpgradePrompt as x } from "@burdenoff/fe-libs/shared/hooks";
14
+ import { AccessDenied as S, UpgradeInlineBanner as C } from "@burdenoff/fe-libs/shared/components";
14
15
  import { useI18n as w } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
15
16
  import { useForm as T, z as E } from "@burdenoff/fe-libs/form";
16
17
  //#region src/pages/CreateWorkspacePage.tsx
17
18
  function D() {
18
- n("workspaces.create");
19
- let { t: D } = w(), O = l(() => E.object({
19
+ ee("workspaces.create");
20
+ let { t: D } = w(), { isFree: O, approachingLimits: k, plan: ne } = x({ resource: "workspaces" }), A = k[0], j = !!A && typeof A.limit == "number" && A.current >= A.limit, re = O && !!A, M = c(() => E.object({
20
21
  name: E.string().min(2, t(D, "createWorkspace.validation.nameMin", "Name must be at least 2 characters")).max(100),
21
22
  slug: E.string().min(2, t(D, "createWorkspace.validation.slugMin", "Slug must be at least 2 characters")).max(50).regex(/^[a-z0-9-]+$/, t(D, "createWorkspace.validation.slugFormat", "Slug can only contain lowercase letters, numbers, and hyphens")),
22
23
  tenantId: E.string().min(1, t(D, "createWorkspace.validation.tenantRequired", "Please select a tenant")),
23
24
  organizationId: E.string().min(1, t(D, "createWorkspace.validation.organizationRequired", "Please select an organization")),
24
25
  type: E.enum(["TEAM", "PERSONAL"]).optional()
25
- }), [D]), k = S(), { basePath: A = "/" } = e(), { mutate: j, isPending: M } = r(), { data: N, isLoading: P, error: F } = a(), { data: I, isLoading: L, error: R } = i(), z = N?.items ?? [], B = I?.items ?? [], V = l(() => z.find((e) => e.type === "SHARED" || e.slug === "burdenoff-shared")?.id ?? z[0]?.id ?? "", [z]), H = T({
26
- schema: O,
26
+ }), [D]), N = b(), { basePath: P = "/" } = e(), { mutate: F, isPending: I } = n(), { data: L, isLoading: R, error: z } = i(), { data: B, isLoading: V, error: H } = r(), U = c(() => L?.items ?? [], [L]), W = c(() => B?.items ?? [], [B]), G = c(() => U.find((e) => e.type === "SHARED" || e.slug === "burdenoff-shared")?.id ?? U[0]?.id ?? "", [U]), K = T({
27
+ schema: M,
27
28
  defaultValues: {
28
29
  name: "",
29
30
  slug: "",
@@ -31,240 +32,254 @@ function D() {
31
32
  organizationId: "",
32
33
  type: "TEAM"
33
34
  }
34
- }), U = H.watch("tenantId"), W = H.watch("name"), { allowedIds: G, loading: K, isError: q } = s(l(() => B.map((e) => e.id), [B]), "workspace", "create"), J = l(() => U ? B.filter((e) => e.tenantId === U) : [], [U, B]), Y = l(() => q ? J : J.filter((e) => G.has(e.id)), [
35
- J,
36
- G,
37
- q
35
+ }), q = K.watch("tenantId"), J = K.watch("name"), { allowedIds: Y, loading: X, isError: Z } = o(c(() => W.map((e) => e.id), [W]), "workspace", "create"), Q = c(() => q ? W.filter((e) => e.tenantId === q) : [], [q, W]), $ = c(() => Z ? Q : Q.filter((e) => Y.has(e.id)), [
36
+ Q,
37
+ Y,
38
+ Z
38
39
  ]);
39
- c(() => {
40
- H.setValue("slug", W ? o(W) : "");
41
- }, [W, H]), c(() => {
42
- H.setValue("organizationId", "");
43
- }, [U, H]), c(() => {
44
- !H.getValues("tenantId") && V && H.setValue("tenantId", V, {
40
+ s(() => {
41
+ K.setValue("slug", J ? a(J) : "");
42
+ }, [J, K]), s(() => {
43
+ K.setValue("organizationId", "");
44
+ }, [q, K]), s(() => {
45
+ !K.getValues("tenantId") && G && K.setValue("tenantId", G, {
45
46
  shouldDirty: !1,
46
47
  shouldTouch: !1
47
48
  });
48
- }, [V, H]), c(() => {
49
- let e = H.getValues("organizationId");
50
- !Y.some((t) => t.id === e) && Y[0]?.id && H.setValue("organizationId", Y[0].id, {
49
+ }, [G, K]), s(() => {
50
+ let e = K.getValues("organizationId");
51
+ !$.some((t) => t.id === e) && $[0]?.id && K.setValue("organizationId", $[0].id, {
51
52
  shouldDirty: !1,
52
53
  shouldTouch: !1
53
54
  });
54
- }, [Y, H]);
55
- let X = (e) => {
56
- j({
55
+ }, [$, K]);
56
+ let ie = (e) => {
57
+ F({
57
58
  name: e.name,
58
59
  slug: e.slug,
59
60
  tenantId: e.tenantId,
60
61
  organizationId: e.organizationId,
61
62
  type: e.type
62
63
  }, { onSuccess: (e) => {
63
- k(`${A}/${e.id}`);
64
+ N(`${P}/${e.id}`);
64
65
  } });
65
- }, Z = G.size > 0, Q = P || L || K, $ = !F && !R && B.length > 0;
66
- return !Q && !q && $ && !Z ? /* @__PURE__ */ p("div", {
66
+ }, ae = Y.size > 0, oe = R || V || X, se = !z && !H && W.length > 0;
67
+ return !oe && !Z && se && !ae ? /* @__PURE__ */ f("div", {
67
68
  className: "p-6",
68
- children: [/* @__PURE__ */ p(x, {
69
- to: `${A}/list`,
69
+ children: [/* @__PURE__ */ f(y, {
70
+ to: `${P}/list`,
70
71
  className: "inline-flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors mb-6",
71
- children: [/* @__PURE__ */ f(d, { size: 20 }), t(D, "createWorkspace.backToWorkspaces", "Back to Workspaces")]
72
- }), /* @__PURE__ */ f(C, {
72
+ children: [/* @__PURE__ */ d(u, { size: 20 }), t(D, "createWorkspace.backToWorkspaces", "Back to Workspaces")]
73
+ }), /* @__PURE__ */ d(S, {
73
74
  variant: "card",
74
75
  title: t(D, "createWorkspace.permissionRequiredTitle", "Permission Required"),
75
76
  description: t(D, "createWorkspace.permissionRequiredDescription", "You don't have permission to create workspaces in any of your organizations."),
76
77
  details: t(D, "createWorkspace.permissionRequiredDetails", "Required: workspace:create"),
77
78
  primaryAction: {
78
79
  label: t(D, "createWorkspace.goBack", "Go Back"),
79
- onClick: () => k(`${A}/list`)
80
+ onClick: () => N(`${P}/list`)
80
81
  }
81
82
  })]
82
- }) : /* @__PURE__ */ p("div", {
83
+ }) : /* @__PURE__ */ f("div", {
83
84
  className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
84
- children: [/* @__PURE__ */ p(x, {
85
- to: `${A}/list`,
86
- className: "inline-flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors",
87
- children: [/* @__PURE__ */ f(d, { size: 20 }), t(D, "createWorkspace.backToWorkspaces", "Back to Workspaces")]
88
- }), /* @__PURE__ */ p(h, {
89
- className: "max-w-2xl mx-auto",
90
- children: [/* @__PURE__ */ p(v, { children: [/* @__PURE__ */ f(y, { children: t(D, "createWorkspace.title", "Create New Workspace") }), /* @__PURE__ */ f(_, { children: t(D, "createWorkspace.subtitle", "Set up a new workspace for your team or personal use") })] }), /* @__PURE__ */ p(g, { children: [q && /* @__PURE__ */ p("div", {
91
- role: "alert",
92
- className: "mb-4 flex items-start gap-2 rounded-md border border-warning/30 bg-warning/10 p-3 text-sm text-foreground",
93
- children: [/* @__PURE__ */ f(u, {
94
- size: 16,
95
- className: "mt-0.5 shrink-0 text-warning"
96
- }), /* @__PURE__ */ f("span", { children: t(D, "createWorkspace.permissionCheckUnavailable", "We couldn't verify your workspace-create permissions just now, so the organization list isn't filtered. If you submit and don't have access, the request will be rejected and you can retry.") })]
97
- }), /* @__PURE__ */ p("form", {
98
- onSubmit: H.handleSubmit(X),
99
- className: "space-y-6",
100
- children: [
101
- /* @__PURE__ */ p("div", {
102
- className: "space-y-2",
103
- children: [
104
- /* @__PURE__ */ f("label", {
105
- htmlFor: "workspace-name",
106
- className: "text-sm font-medium text-foreground",
107
- children: t(D, "createWorkspace.nameLabel", "Workspace Name *")
108
- }),
109
- /* @__PURE__ */ f("input", {
110
- id: "workspace-name",
111
- placeholder: t(D, "createWorkspace.namePlaceholder", "My Workspace"),
112
- className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground",
113
- ...H.register("name")
114
- }),
115
- /* @__PURE__ */ f("p", {
116
- className: "text-xs text-muted-foreground",
117
- children: t(D, "createWorkspace.nameHint", "A descriptive name for your workspace")
118
- }),
119
- H.formState.errors.name?.message && /* @__PURE__ */ f("p", {
120
- className: "text-sm text-destructive",
121
- children: H.formState.errors.name.message
122
- })
123
- ]
124
- }),
125
- /* @__PURE__ */ p("div", {
126
- className: "space-y-2",
127
- children: [
128
- /* @__PURE__ */ f("label", {
129
- htmlFor: "workspace-slug",
130
- className: "text-sm font-medium text-foreground",
131
- children: t(D, "createWorkspace.slugLabel", "Slug *")
132
- }),
133
- /* @__PURE__ */ f("input", {
134
- id: "workspace-slug",
135
- placeholder: t(D, "createWorkspace.slugPlaceholder", "my-workspace"),
136
- className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground",
137
- ...H.register("slug")
138
- }),
139
- /* @__PURE__ */ f("p", {
140
- className: "text-xs text-muted-foreground",
141
- children: t(D, "createWorkspace.slugHint", "URL-friendly identifier (auto-generated, but you can edit it)")
142
- }),
143
- H.formState.errors.slug?.message && /* @__PURE__ */ f("p", {
144
- className: "text-sm text-destructive",
145
- children: H.formState.errors.slug.message
146
- })
147
- ]
148
- }),
149
- /* @__PURE__ */ p("div", {
150
- className: "space-y-2",
151
- children: [
152
- /* @__PURE__ */ f("label", {
153
- htmlFor: "workspace-tenant",
154
- className: "text-sm font-medium text-foreground",
155
- children: t(D, "createWorkspace.tenantLabel", "Tenant *")
156
- }),
157
- P ? /* @__PURE__ */ f(b, { className: "h-10 w-full" }) : F ? /* @__PURE__ */ p("div", {
158
- className: "flex items-center gap-2 text-sm text-destructive",
159
- children: [/* @__PURE__ */ f(u, { size: 16 }), t(D, "createWorkspace.failedToLoadTenants", "Failed to load tenants")]
160
- }) : z.length === 0 ? /* @__PURE__ */ f("div", {
161
- className: "text-sm text-muted-foreground",
162
- children: t(D, "createWorkspace.noTenantsAvailable", "No tenants available. Contact your administrator.")
163
- }) : /* @__PURE__ */ p("select", {
164
- id: "workspace-tenant",
165
- className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground",
166
- ...H.register("tenantId"),
167
- children: [/* @__PURE__ */ f("option", {
168
- value: "",
169
- children: t(D, "createWorkspace.selectTenantPlaceholder", "Select a tenant")
170
- }), z.map((e) => /* @__PURE__ */ f("option", {
171
- value: e.id,
172
- children: e.name
173
- }, e.id))]
174
- }),
175
- /* @__PURE__ */ f("p", {
176
- className: "text-xs text-muted-foreground",
177
- children: t(D, "createWorkspace.tenantHint", "Select which tenant this workspace belongs to")
178
- }),
179
- H.formState.errors.tenantId?.message && /* @__PURE__ */ f("p", {
180
- className: "text-sm text-destructive",
181
- children: H.formState.errors.tenantId.message
182
- })
183
- ]
184
- }),
185
- /* @__PURE__ */ p("div", {
186
- className: "space-y-2",
187
- children: [
188
- /* @__PURE__ */ f("label", {
189
- htmlFor: "workspace-organization",
190
- className: "text-sm font-medium text-foreground",
191
- children: t(D, "createWorkspace.organizationLabel", "Organization *")
192
- }),
193
- L || K ? /* @__PURE__ */ f(b, { className: "h-10 w-full" }) : R ? /* @__PURE__ */ p("div", {
194
- className: "flex items-center gap-2 text-sm text-destructive",
195
- children: [/* @__PURE__ */ f(u, { size: 16 }), t(D, "createWorkspace.failedToLoadOrganizations", "Failed to load organizations")]
196
- }) : U ? Y.length === 0 ? /* @__PURE__ */ f("div", {
197
- className: "text-sm text-muted-foreground",
198
- children: t(D, "createWorkspace.noOrganizationsFound", "No organizations found for this tenant")
199
- }) : /* @__PURE__ */ p("select", {
200
- id: "workspace-organization",
201
- className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground",
202
- disabled: !U,
203
- ...H.register("organizationId"),
204
- children: [/* @__PURE__ */ f("option", {
205
- value: "",
206
- children: t(D, "createWorkspace.selectOrganizationPlaceholder", "Select an organization")
207
- }), Y.map((e) => /* @__PURE__ */ f("option", {
208
- value: e.id,
209
- children: e.name
210
- }, e.id))]
211
- }) : /* @__PURE__ */ f("div", {
212
- className: "text-sm text-muted-foreground",
213
- children: t(D, "createWorkspace.selectTenantFirst", "Please select a tenant first")
214
- }),
215
- /* @__PURE__ */ f("p", {
216
- className: "text-xs text-muted-foreground",
217
- children: t(D, "createWorkspace.organizationHint", "Select which organization owns this workspace")
218
- }),
219
- H.formState.errors.organizationId?.message && /* @__PURE__ */ f("p", {
220
- className: "text-sm text-destructive",
221
- children: H.formState.errors.organizationId.message
222
- })
223
- ]
224
- }),
225
- /* @__PURE__ */ p("div", {
226
- className: "space-y-2",
227
- children: [
228
- /* @__PURE__ */ f("label", {
229
- htmlFor: "workspace-type",
230
- className: "text-sm font-medium text-foreground",
231
- children: t(D, "createWorkspace.typeLabel", "Workspace Type")
232
- }),
233
- /* @__PURE__ */ p("select", {
234
- id: "workspace-type",
235
- className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground",
236
- ...H.register("type"),
237
- children: [/* @__PURE__ */ f("option", {
238
- value: "TEAM",
239
- children: t(D, "createWorkspace.typeTeam", "Team Workspace")
240
- }), /* @__PURE__ */ f("option", {
241
- value: "PERSONAL",
242
- children: t(D, "createWorkspace.typePersonal", "Personal Workspace")
243
- })]
244
- }),
245
- /* @__PURE__ */ f("p", {
246
- className: "text-xs text-muted-foreground",
247
- children: t(D, "createWorkspace.typeHint", "Choose between a collaborative workspace or a personal one")
248
- })
249
- ]
250
- }),
251
- /* @__PURE__ */ p("div", {
252
- className: "flex justify-end gap-3 pt-4",
253
- children: [/* @__PURE__ */ f(m, {
254
- type: "button",
255
- variant: "outline",
256
- onClick: () => k(`${A}/list`),
257
- disabled: M,
258
- children: t(D, "createWorkspace.cancel", "Cancel")
259
- }), /* @__PURE__ */ f(m, {
260
- type: "submit",
261
- disabled: M || P || L || K,
262
- children: M ? t(D, "createWorkspace.creating", "Creating...") : t(D, "createWorkspace.submit", "Create Workspace")
263
- })]
264
- })
265
- ]
266
- })] })]
267
- })]
85
+ children: [
86
+ /* @__PURE__ */ f(y, {
87
+ to: `${P}/list`,
88
+ className: "inline-flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors",
89
+ children: [/* @__PURE__ */ d(u, { size: 20 }), t(D, "createWorkspace.backToWorkspaces", "Back to Workspaces")]
90
+ }),
91
+ re && /* @__PURE__ */ d("div", {
92
+ className: "max-w-2xl mx-auto w-full",
93
+ children: /* @__PURE__ */ d(C, {
94
+ resource: "workspaces",
95
+ current: A.current,
96
+ limit: A.limit ?? void 0,
97
+ severity: j ? "critical" : void 0,
98
+ message: j ? t(D, "createWorkspace.upgradeCapMessage", `You've used all workspaces in the ${ne?.planName ?? "free"} plan.`) : t(D, "createWorkspace.upgradeApproachingMessage", "Upgrade to create more workspaces.")
99
+ })
100
+ }),
101
+ /* @__PURE__ */ f(te, {
102
+ className: "max-w-2xl mx-auto",
103
+ children: [/* @__PURE__ */ f(g, { children: [/* @__PURE__ */ d(_, { children: t(D, "createWorkspace.title", "Create New Workspace") }), /* @__PURE__ */ d(h, { children: t(D, "createWorkspace.subtitle", "Set up a new workspace for your team or personal use") })] }), /* @__PURE__ */ f(m, { children: [Z && /* @__PURE__ */ f("div", {
104
+ role: "alert",
105
+ className: "mb-4 flex items-start gap-2 rounded-md border border-warning/30 bg-warning/10 p-3 text-sm text-foreground",
106
+ children: [/* @__PURE__ */ d(l, {
107
+ size: 16,
108
+ className: "mt-0.5 shrink-0 text-warning"
109
+ }), /* @__PURE__ */ d("span", { children: t(D, "createWorkspace.permissionCheckUnavailable", "We couldn't verify your workspace-create permissions just now, so the organization list isn't filtered. If you submit and don't have access, the request will be rejected and you can retry.") })]
110
+ }), /* @__PURE__ */ f("form", {
111
+ onSubmit: K.handleSubmit(ie),
112
+ className: "space-y-6",
113
+ children: [
114
+ /* @__PURE__ */ f("div", {
115
+ className: "space-y-2",
116
+ children: [
117
+ /* @__PURE__ */ d("label", {
118
+ htmlFor: "workspace-name",
119
+ className: "text-sm font-medium text-foreground",
120
+ children: t(D, "createWorkspace.nameLabel", "Workspace Name *")
121
+ }),
122
+ /* @__PURE__ */ d("input", {
123
+ id: "workspace-name",
124
+ placeholder: t(D, "createWorkspace.namePlaceholder", "My Workspace"),
125
+ className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground",
126
+ ...K.register("name")
127
+ }),
128
+ /* @__PURE__ */ d("p", {
129
+ className: "text-xs text-muted-foreground",
130
+ children: t(D, "createWorkspace.nameHint", "A descriptive name for your workspace")
131
+ }),
132
+ K.formState.errors.name?.message && /* @__PURE__ */ d("p", {
133
+ className: "text-sm text-destructive",
134
+ children: K.formState.errors.name.message
135
+ })
136
+ ]
137
+ }),
138
+ /* @__PURE__ */ f("div", {
139
+ className: "space-y-2",
140
+ children: [
141
+ /* @__PURE__ */ d("label", {
142
+ htmlFor: "workspace-slug",
143
+ className: "text-sm font-medium text-foreground",
144
+ children: t(D, "createWorkspace.slugLabel", "Slug *")
145
+ }),
146
+ /* @__PURE__ */ d("input", {
147
+ id: "workspace-slug",
148
+ placeholder: t(D, "createWorkspace.slugPlaceholder", "my-workspace"),
149
+ className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground",
150
+ ...K.register("slug")
151
+ }),
152
+ /* @__PURE__ */ d("p", {
153
+ className: "text-xs text-muted-foreground",
154
+ children: t(D, "createWorkspace.slugHint", "URL-friendly identifier (auto-generated, but you can edit it)")
155
+ }),
156
+ K.formState.errors.slug?.message && /* @__PURE__ */ d("p", {
157
+ className: "text-sm text-destructive",
158
+ children: K.formState.errors.slug.message
159
+ })
160
+ ]
161
+ }),
162
+ /* @__PURE__ */ f("div", {
163
+ className: "space-y-2",
164
+ children: [
165
+ /* @__PURE__ */ d("label", {
166
+ htmlFor: "workspace-tenant",
167
+ className: "text-sm font-medium text-foreground",
168
+ children: t(D, "createWorkspace.tenantLabel", "Tenant *")
169
+ }),
170
+ R ? /* @__PURE__ */ d(v, { className: "h-10 w-full" }) : z ? /* @__PURE__ */ f("div", {
171
+ className: "flex items-center gap-2 text-sm text-destructive",
172
+ children: [/* @__PURE__ */ d(l, { size: 16 }), t(D, "createWorkspace.failedToLoadTenants", "Failed to load tenants")]
173
+ }) : U.length === 0 ? /* @__PURE__ */ d("div", {
174
+ className: "text-sm text-muted-foreground",
175
+ children: t(D, "createWorkspace.noTenantsAvailable", "No tenants available. Contact your administrator.")
176
+ }) : /* @__PURE__ */ f("select", {
177
+ id: "workspace-tenant",
178
+ className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground",
179
+ ...K.register("tenantId"),
180
+ children: [/* @__PURE__ */ d("option", {
181
+ value: "",
182
+ children: t(D, "createWorkspace.selectTenantPlaceholder", "Select a tenant")
183
+ }), U.map((e) => /* @__PURE__ */ d("option", {
184
+ value: e.id,
185
+ children: e.name
186
+ }, e.id))]
187
+ }),
188
+ /* @__PURE__ */ d("p", {
189
+ className: "text-xs text-muted-foreground",
190
+ children: t(D, "createWorkspace.tenantHint", "Select which tenant this workspace belongs to")
191
+ }),
192
+ K.formState.errors.tenantId?.message && /* @__PURE__ */ d("p", {
193
+ className: "text-sm text-destructive",
194
+ children: K.formState.errors.tenantId.message
195
+ })
196
+ ]
197
+ }),
198
+ /* @__PURE__ */ f("div", {
199
+ className: "space-y-2",
200
+ children: [
201
+ /* @__PURE__ */ d("label", {
202
+ htmlFor: "workspace-organization",
203
+ className: "text-sm font-medium text-foreground",
204
+ children: t(D, "createWorkspace.organizationLabel", "Organization *")
205
+ }),
206
+ V || X ? /* @__PURE__ */ d(v, { className: "h-10 w-full" }) : H ? /* @__PURE__ */ f("div", {
207
+ className: "flex items-center gap-2 text-sm text-destructive",
208
+ children: [/* @__PURE__ */ d(l, { size: 16 }), t(D, "createWorkspace.failedToLoadOrganizations", "Failed to load organizations")]
209
+ }) : q ? $.length === 0 ? /* @__PURE__ */ d("div", {
210
+ className: "text-sm text-muted-foreground",
211
+ children: t(D, "createWorkspace.noOrganizationsFound", "No organizations found for this tenant")
212
+ }) : /* @__PURE__ */ f("select", {
213
+ id: "workspace-organization",
214
+ className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground",
215
+ disabled: !q,
216
+ ...K.register("organizationId"),
217
+ children: [/* @__PURE__ */ d("option", {
218
+ value: "",
219
+ children: t(D, "createWorkspace.selectOrganizationPlaceholder", "Select an organization")
220
+ }), $.map((e) => /* @__PURE__ */ d("option", {
221
+ value: e.id,
222
+ children: e.name
223
+ }, e.id))]
224
+ }) : /* @__PURE__ */ d("div", {
225
+ className: "text-sm text-muted-foreground",
226
+ children: t(D, "createWorkspace.selectTenantFirst", "Please select a tenant first")
227
+ }),
228
+ /* @__PURE__ */ d("p", {
229
+ className: "text-xs text-muted-foreground",
230
+ children: t(D, "createWorkspace.organizationHint", "Select which organization owns this workspace")
231
+ }),
232
+ K.formState.errors.organizationId?.message && /* @__PURE__ */ d("p", {
233
+ className: "text-sm text-destructive",
234
+ children: K.formState.errors.organizationId.message
235
+ })
236
+ ]
237
+ }),
238
+ /* @__PURE__ */ f("div", {
239
+ className: "space-y-2",
240
+ children: [
241
+ /* @__PURE__ */ d("label", {
242
+ htmlFor: "workspace-type",
243
+ className: "text-sm font-medium text-foreground",
244
+ children: t(D, "createWorkspace.typeLabel", "Workspace Type")
245
+ }),
246
+ /* @__PURE__ */ f("select", {
247
+ id: "workspace-type",
248
+ className: "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground",
249
+ ...K.register("type"),
250
+ children: [/* @__PURE__ */ d("option", {
251
+ value: "TEAM",
252
+ children: t(D, "createWorkspace.typeTeam", "Team Workspace")
253
+ }), /* @__PURE__ */ d("option", {
254
+ value: "PERSONAL",
255
+ children: t(D, "createWorkspace.typePersonal", "Personal Workspace")
256
+ })]
257
+ }),
258
+ /* @__PURE__ */ d("p", {
259
+ className: "text-xs text-muted-foreground",
260
+ children: t(D, "createWorkspace.typeHint", "Choose between a collaborative workspace or a personal one")
261
+ })
262
+ ]
263
+ }),
264
+ /* @__PURE__ */ f("div", {
265
+ className: "flex justify-end gap-3 pt-4",
266
+ children: [/* @__PURE__ */ d(p, {
267
+ type: "button",
268
+ variant: "outline",
269
+ onClick: () => N(`${P}/list`),
270
+ disabled: I,
271
+ children: t(D, "createWorkspace.cancel", "Cancel")
272
+ }), /* @__PURE__ */ d(p, {
273
+ type: "submit",
274
+ disabled: I || R || V || X || j,
275
+ title: j ? t(D, "createWorkspace.disabledAtCap", "Workspace limit reached — upgrade your plan to create more.") : void 0,
276
+ children: I ? t(D, "createWorkspace.creating", "Creating...") : t(D, "createWorkspace.submit", "Create Workspace")
277
+ })]
278
+ })
279
+ ]
280
+ })] })]
281
+ })
282
+ ]
268
283
  });
269
284
  }
270
285
  //#endregion