@burdenoff/microfe-organization 2026.525.3 → 2026.527.2

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 (60) hide show
  1. package/dist/organization-management/AdminOrganizationRoutes.js +1 -1
  2. package/dist/organization-management/AdminOrganizationRoutes.js.map +1 -1
  3. package/dist/organization-management/UserOrganizationRoutes.js +1 -1
  4. package/dist/organization-management/UserOrganizationRoutes.js.map +1 -1
  5. package/dist/organization-management/modules/members/components/InviteMemberForm.js +2 -0
  6. package/dist/organization-management/modules/members/components/InviteMemberForm.js.map +1 -1
  7. package/dist/organization-management/modules/members/components/MyInviteCard.js +2 -0
  8. package/dist/organization-management/modules/members/components/MyInviteCard.js.map +1 -1
  9. package/dist/organization-management/modules/members/components/PendingInvitesList.js +2 -0
  10. package/dist/organization-management/modules/members/components/PendingInvitesList.js.map +1 -1
  11. package/dist/organization-management/modules/members/pages/InviteMemberPage.js +1 -0
  12. package/dist/organization-management/modules/members/pages/InviteMemberPage.js.map +1 -1
  13. package/dist/organization-management/modules/members/pages/MemberDetailPage.js +2 -1
  14. package/dist/organization-management/modules/members/pages/MemberDetailPage.js.map +1 -1
  15. package/dist/organization-management/modules/members/pages/MembersListPage.js +10 -2
  16. package/dist/organization-management/modules/members/pages/MembersListPage.js.map +1 -1
  17. package/dist/organization-management/modules/organizations/components/OrganizationForm.js +6 -0
  18. package/dist/organization-management/modules/organizations/components/OrganizationForm.js.map +1 -1
  19. package/dist/organization-management/modules/organizations/hooks/useOrgsWithPermission.js.map +1 -1
  20. package/dist/organization-management/modules/organizations/pages/OrganizationCreatePage.js +1 -0
  21. package/dist/organization-management/modules/organizations/pages/OrganizationCreatePage.js.map +1 -1
  22. package/dist/organization-management/modules/organizations/pages/OrganizationDetailPage.js +6 -1
  23. package/dist/organization-management/modules/organizations/pages/OrganizationDetailPage.js.map +1 -1
  24. package/dist/organization-management/modules/organizations/pages/OrganizationEditPage.js +1 -0
  25. package/dist/organization-management/modules/organizations/pages/OrganizationEditPage.js.map +1 -1
  26. package/dist/organization-management/modules/organizations/pages/OrganizationsListPage.js +15 -4
  27. package/dist/organization-management/modules/organizations/pages/OrganizationsListPage.js.map +1 -1
  28. package/dist/organization-management/modules/workspaces/components/AddWorkspaceMemberDialog.js.map +1 -1
  29. package/dist/organization-management/modules/workspaces/components/WorkspaceCard.js +5 -5
  30. package/dist/organization-management/modules/workspaces/components/WorkspaceCard.js.map +1 -1
  31. package/dist/organization-management/modules/workspaces/components/WorkspaceForm.js +6 -2
  32. package/dist/organization-management/modules/workspaces/components/WorkspaceForm.js.map +1 -1
  33. package/dist/organization-management/modules/workspaces/hooks/useWorkspaceMembers.js.map +1 -1
  34. package/dist/organization-management/modules/workspaces/hooks/useWorkspaces.js.map +1 -1
  35. package/dist/organization-management/modules/workspaces/pages/WorkspaceCreatePage.js +1 -0
  36. package/dist/organization-management/modules/workspaces/pages/WorkspaceCreatePage.js.map +1 -1
  37. package/dist/organization-management/modules/workspaces/pages/WorkspaceDetailPage.js +8 -1
  38. package/dist/organization-management/modules/workspaces/pages/WorkspaceDetailPage.js.map +1 -1
  39. package/dist/organization-management/modules/workspaces/pages/WorkspaceEditPage.js +1 -0
  40. package/dist/organization-management/modules/workspaces/pages/WorkspaceEditPage.js.map +1 -1
  41. package/dist/organization-management/modules/workspaces/pages/WorkspacesListPage.js +10 -0
  42. package/dist/organization-management/modules/workspaces/pages/WorkspacesListPage.js.map +1 -1
  43. package/dist/organization-management/providers/OrgConsoleProvider.js +1 -1
  44. package/dist/organization-management/providers/OrgConsoleProvider.js.map +1 -1
  45. package/dist/organization-management/shared/components/dialog/ConfirmDialog.js +25 -86
  46. package/dist/organization-management/shared/components/dialog/ConfirmDialog.js.map +1 -1
  47. package/dist/organization-management/shared/components/dialog/ConfirmDialogView.js +69 -0
  48. package/dist/organization-management/shared/components/dialog/ConfirmDialogView.js.map +1 -0
  49. package/dist/organization-management/shared/components/feedback/EmptyState.js +1 -0
  50. package/dist/organization-management/shared/components/feedback/EmptyState.js.map +1 -1
  51. package/dist/organization-management/shared/components/feedback/ErrorState.js +2 -1
  52. package/dist/organization-management/shared/components/feedback/ErrorState.js.map +1 -1
  53. package/dist/organization-management/shared/components/feedback/LoadingState.js +1 -2
  54. package/dist/organization-management/shared/components/feedback/LoadingState.js.map +1 -1
  55. package/dist/organization-management/shared/components/input/SearchInput.js +1 -0
  56. package/dist/organization-management/shared/components/input/SearchInput.js.map +1 -1
  57. package/dist/organization-management/shared/components/input/SelectionCheckbox.js +1 -1
  58. package/dist/organization-management/shared/components/input/SelectionCheckbox.js.map +1 -1
  59. package/dist/organization-management/shared/types/graphql.js.map +1 -1
  60. package/package.json +2 -1
@@ -8,10 +8,10 @@ function o({ workspace: o, onClick: s, onEdit: c, onDelete: l, showActions: u =
8
8
  s && s(o);
9
9
  };
10
10
  return /* @__PURE__ */ a("div", {
11
- onClick: f,
12
- onKeyDown: (e) => {
13
- s && (e.key === "Enter" || e.key === " ") && (e.preventDefault(), f());
14
- },
11
+ onClick: s ? f : void 0,
12
+ onKeyDown: s ? (e) => {
13
+ (e.key === "Enter" || e.key === " ") && (e.preventDefault(), f());
14
+ } : void 0,
15
15
  className: `
16
16
  w-full text-left
17
17
  bg-[var(--color-bg-surface)]
@@ -31,7 +31,7 @@ function o({ workspace: o, onClick: s, onEdit: c, onDelete: l, showActions: u =
31
31
  children: [/* @__PURE__ */ a("div", {
32
32
  className: "flex items-center gap-3",
33
33
  children: [/* @__PURE__ */ i("div", {
34
- className: "w-12 h-12 rounded-lg bg-[var(--color-status-info-muted)] flex items-center justify-center",
34
+ className: "size-12 rounded-lg bg-[var(--color-status-info-muted)] flex items-center justify-center",
35
35
  children: /* @__PURE__ */ i(n, {
36
36
  size: 24,
37
37
  className: "text-[var(--color-status-info)]"
@@ -1 +1 @@
1
- {"version":3,"file":"WorkspaceCard.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/components/WorkspaceCard.tsx"],"sourcesContent":["import { Briefcase, MoreVertical } from 'lucide-react';\nimport { WorkspaceStatusBadge } from './WorkspaceStatusBadge';\nimport type { Workspace } from '../types';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface WorkspaceCardProps {\n workspace: Workspace;\n onClick?: (workspace: Workspace) => void;\n onEdit?: (workspace: Workspace) => void;\n onDelete?: (workspace: Workspace) => void;\n showActions?: boolean;\n}\n\n/**\n * WorkspaceCard\n * Displays a workspace in a card format for grid views\n */\nexport function WorkspaceCard({\n workspace,\n onClick,\n onEdit,\n onDelete,\n showActions = true,\n}: WorkspaceCardProps) {\n const tr = useTr();\n const handleCardClick = () => {\n if (onClick) {\n onClick(workspace);\n }\n };\n\n const handleEdit = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (onEdit) {\n onEdit(workspace);\n }\n };\n\n const handleDelete = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (onDelete) {\n onDelete(workspace);\n }\n };\n\n return (\n <div\n onClick={handleCardClick}\n onKeyDown={(event) => {\n if (!onClick) return;\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n handleCardClick();\n }\n }}\n className={`\n w-full text-left\n bg-[var(--color-bg-surface)]\n border border-[var(--color-border-default)]\n rounded-lg\n p-6\n shadow-[var(--shadow-elevation-1)]\n transition-all\n ${onClick ? 'cursor-pointer hover:shadow-[var(--shadow-elevation-2)] hover:border-[var(--color-border-hover)]' : ''}\n `}\n aria-label={\n onClick ? `${tr('workspaces.card.open', 'Open workspace')} ${workspace.name}` : undefined\n }\n role={onClick ? 'button' : undefined}\n tabIndex={onClick ? 0 : undefined}\n >\n {/* Header */}\n <div className=\"flex items-start justify-between mb-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"w-12 h-12 rounded-lg bg-[var(--color-status-info-muted)] flex items-center justify-center\">\n <Briefcase size={24} className=\"text-[var(--color-status-info)]\" />\n </div>\n <div className=\"flex-1\">\n <h3 className=\"font-semibold text-[var(--color-text-primary)] text-lg\">\n {workspace.name}\n </h3>\n <p className=\"text-sm text-[var(--color-text-muted)] font-mono\">/{workspace.slug}</p>\n </div>\n </div>\n\n {showActions && (\n <button\n type=\"button\"\n onClick={(e) => e.stopPropagation()}\n className=\"\n p-1.5 rounded-lg\n text-[var(--color-text-secondary)]\n hover:bg-[var(--color-bg-subtle)]\n active:scale-95\n transition-all duration-200\n \"\n aria-label={`${tr('workspaces.card.actionsFor', 'Workspace actions for')} ${workspace.name}`}\n >\n <MoreVertical size={18} />\n </button>\n )}\n </div>\n\n {/* Badges */}\n <div className=\"flex gap-2 mb-4\">\n <WorkspaceStatusBadge status={workspace.status} />\n <span className=\"inline-flex items-center px-2 py-1 rounded-md text-xs font-medium bg-[var(--color-bg-subtle)] text-[var(--color-text-secondary)]\">\n {workspace.type}\n </span>\n </div>\n\n {/* Member Count */}\n {workspace.memberCount !== undefined && (\n <p className=\"text-sm text-[var(--color-text-secondary)] mb-4\">\n {workspace.memberCount}{' '}\n {workspace.memberCount === 1\n ? tr('members.role.member', 'Member').toLowerCase()\n : tr('workspaces.list.members', 'Members').toLowerCase()}\n </p>\n )}\n\n {/* Metadata */}\n <div className=\"pt-2 border-t border-[var(--color-border-default)]\">\n <p className=\"text-xs text-[var(--color-text-muted)]\">\n {tr('common.created', 'Created')} {new Date(workspace.createdAt).toLocaleDateString()}\n </p>\n </div>\n\n {/* Footer Actions */}\n {showActions && (onEdit || onDelete) && (\n <div className=\"flex gap-2 mt-4 pt-4 border-t border-[var(--color-border-default)]\">\n {onEdit && (\n <button\n type=\"button\"\n onClick={handleEdit}\n className=\"\n flex-1 px-3 py-1.5 text-sm\n bg-[var(--color-bg-subtle)]\n text-[var(--color-text-primary)]\n rounded-lg\n hover:bg-[var(--color-bg-muted)]\n active:scale-[0.98]\n transition-all duration-200\n font-medium\n \"\n >\n {tr('common.edit', 'Edit')}\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n onClick={handleDelete}\n className=\"\n flex-1 px-3 py-1.5 text-sm\n bg-[var(--color-status-error-muted)]\n text-[var(--color-status-error)]\n rounded-lg\n hover:opacity-80\n active:scale-[0.98]\n transition-all duration-200\n font-medium\n \"\n >\n {tr('common.delete', 'Delete')}\n </button>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;AAiBA,SAAgB,EAAc,EAC5B,cACA,YACA,WACA,aACA,iBAAc,MACO;CACrB,IAAM,IAAK,GAAO,EACZ,UAAwB;AAC5B,EAAI,KACF,EAAQ,EAAU;;AAkBtB,QACE,kBAAC,OAAD;EACE,SAAS;EACT,YAAY,MAAU;AACf,SACD,EAAM,QAAQ,WAAW,EAAM,QAAQ,SACzC,EAAM,gBAAgB,EACtB,GAAiB;;EAGrB,WAAW;;;;;;;;UAQP,IAAU,qGAAqG,GAAG;;EAEtH,cACE,IAAU,GAAG,EAAG,wBAAwB,iBAAiB,CAAC,GAAG,EAAU,SAAS,KAAA;EAElF,MAAM,IAAU,WAAW,KAAA;EAC3B,UAAU,IAAU,IAAI,KAAA;YAvB1B;GA0BE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,GAAD;OAAW,MAAM;OAAI,WAAU;OAAoC,CAAA;MAC/D,CAAA,EACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAU;OACR,CAAA,EACL,kBAAC,KAAD;OAAG,WAAU;iBAAb,CAAgE,KAAE,EAAU,KAAS;SACjF;QACF;QAEL,KACC,kBAAC,UAAD;KACE,MAAK;KACL,UAAU,MAAM,EAAE,iBAAiB;KACnC,WAAU;KAOV,cAAY,GAAG,EAAG,8BAA8B,wBAAwB,CAAC,GAAG,EAAU;eAEtF,kBAAC,GAAD,EAAc,MAAM,IAAM,CAAA;KACnB,CAAA,CAEP;;GAGN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD,EAAsB,QAAQ,EAAU,QAAU,CAAA,EAClD,kBAAC,QAAD;KAAM,WAAU;eACb,EAAU;KACN,CAAA,CACH;;GAGL,EAAU,gBAAgB,KAAA,KACzB,kBAAC,KAAD;IAAG,WAAU;cAAb;KACG,EAAU;KAAa;KACvB,EAAU,gBAAgB,IACvB,EAAG,uBAAuB,SAAS,CAAC,aAAa,GACjD,EAAG,2BAA2B,UAAU,CAAC,aAAa;KACxD;;GAIN,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,KAAD;KAAG,WAAU;eAAb;MACG,EAAG,kBAAkB,UAAU;MAAC;MAAE,IAAI,KAAK,EAAU,UAAU,CAAC,oBAAoB;MACnF;;IACA,CAAA;GAGL,MAAgB,KAAU,MACzB,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,KACC,kBAAC,UAAD;KACE,MAAK;KACL,UAvGQ,MAAwB;AAE1C,MADA,EAAE,iBAAiB,EACf,KACF,EAAO,EAAU;;KAqGT,WAAU;eAWT,EAAG,eAAe,OAAO;KACnB,CAAA,EAEV,KACC,kBAAC,UAAD;KACE,MAAK;KACL,UAlHU,MAAwB;AAE5C,MADA,EAAE,iBAAiB,EACf,KACF,EAAS,EAAU;;KAgHX,WAAU;eAWT,EAAG,iBAAiB,SAAS;KACvB,CAAA,CAEP;;GAEJ"}
1
+ {"version":3,"file":"WorkspaceCard.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/components/WorkspaceCard.tsx"],"sourcesContent":["import { Briefcase, MoreVertical } from 'lucide-react';\nimport { WorkspaceStatusBadge } from './WorkspaceStatusBadge';\nimport type { Workspace } from '../types';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface WorkspaceCardProps {\n workspace: Workspace;\n onClick?: (workspace: Workspace) => void;\n onEdit?: (workspace: Workspace) => void;\n onDelete?: (workspace: Workspace) => void;\n showActions?: boolean;\n}\n\n/**\n * WorkspaceCard\n * Displays a workspace in a card format for grid views\n */\nexport function WorkspaceCard({\n workspace,\n onClick,\n onEdit,\n onDelete,\n showActions = true,\n}: WorkspaceCardProps) {\n const tr = useTr();\n const handleCardClick = () => {\n if (onClick) {\n onClick(workspace);\n }\n };\n\n const handleEdit = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (onEdit) {\n onEdit(workspace);\n }\n };\n\n const handleDelete = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (onDelete) {\n onDelete(workspace);\n }\n };\n\n return (\n // react-doctor-disable-next-line react-doctor/no-static-element-interactions\n <div\n onClick={onClick ? handleCardClick : undefined}\n onKeyDown={\n onClick\n ? (event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n handleCardClick();\n }\n }\n : undefined\n }\n className={`\n w-full text-left\n bg-[var(--color-bg-surface)]\n border border-[var(--color-border-default)]\n rounded-lg\n p-6\n shadow-[var(--shadow-elevation-1)]\n transition-all\n ${onClick ? 'cursor-pointer hover:shadow-[var(--shadow-elevation-2)] hover:border-[var(--color-border-hover)]' : ''}\n `}\n aria-label={\n onClick ? `${tr('workspaces.card.open', 'Open workspace')} ${workspace.name}` : undefined\n }\n role={onClick ? 'button' : undefined}\n tabIndex={onClick ? 0 : undefined}\n >\n {/* Header */}\n <div className=\"flex items-start justify-between mb-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"size-12 rounded-lg bg-[var(--color-status-info-muted)] flex items-center justify-center\">\n <Briefcase size={24} className=\"text-[var(--color-status-info)]\" />\n </div>\n <div className=\"flex-1\">\n <h3 className=\"font-semibold text-[var(--color-text-primary)] text-lg\">\n {workspace.name}\n </h3>\n <p className=\"text-sm text-[var(--color-text-muted)] font-mono\">/{workspace.slug}</p>\n </div>\n </div>\n\n {showActions && (\n <button\n type=\"button\"\n onClick={(e) => e.stopPropagation()}\n className=\"\n p-1.5 rounded-lg\n text-[var(--color-text-secondary)]\n hover:bg-[var(--color-bg-subtle)]\n active:scale-95\n transition-all duration-200\n \"\n aria-label={`${tr('workspaces.card.actionsFor', 'Workspace actions for')} ${workspace.name}`}\n >\n <MoreVertical size={18} />\n </button>\n )}\n </div>\n\n {/* Badges */}\n <div className=\"flex gap-2 mb-4\">\n <WorkspaceStatusBadge status={workspace.status} />\n <span className=\"inline-flex items-center px-2 py-1 rounded-md text-xs font-medium bg-[var(--color-bg-subtle)] text-[var(--color-text-secondary)]\">\n {workspace.type}\n </span>\n </div>\n\n {/* Member Count */}\n {workspace.memberCount !== undefined && (\n <p className=\"text-sm text-[var(--color-text-secondary)] mb-4\">\n {workspace.memberCount}{' '}\n {workspace.memberCount === 1\n ? tr('members.role.member', 'Member').toLowerCase()\n : tr('workspaces.list.members', 'Members').toLowerCase()}\n </p>\n )}\n\n {/* Metadata */}\n <div className=\"pt-2 border-t border-[var(--color-border-default)]\">\n <p className=\"text-xs text-[var(--color-text-muted)]\">\n {tr('common.created', 'Created')} {new Date(workspace.createdAt).toLocaleDateString()}\n </p>\n </div>\n\n {/* Footer Actions */}\n {showActions && (onEdit || onDelete) && (\n <div className=\"flex gap-2 mt-4 pt-4 border-t border-[var(--color-border-default)]\">\n {onEdit && (\n <button\n type=\"button\"\n onClick={handleEdit}\n className=\"\n flex-1 px-3 py-1.5 text-sm\n bg-[var(--color-bg-subtle)]\n text-[var(--color-text-primary)]\n rounded-lg\n hover:bg-[var(--color-bg-muted)]\n active:scale-[0.98]\n transition-all duration-200\n font-medium\n \"\n >\n {tr('common.edit', 'Edit')}\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n onClick={handleDelete}\n className=\"\n flex-1 px-3 py-1.5 text-sm\n bg-[var(--color-status-error-muted)]\n text-[var(--color-status-error)]\n rounded-lg\n hover:opacity-80\n active:scale-[0.98]\n transition-all duration-200\n font-medium\n \"\n >\n {tr('common.delete', 'Delete')}\n </button>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;AAiBA,SAAgB,EAAc,EAC5B,cACA,YACA,WACA,aACA,iBAAc,MACO;CACrB,IAAM,IAAK,GAAO,EACZ,UAAwB;AAC5B,EAAI,KACF,EAAQ,EAAU;;AAkBtB,QAEE,kBAAC,OAAD;EACE,SAAS,IAAU,IAAkB,KAAA;EACrC,WACE,KACK,MAAU;AACT,IAAI,EAAM,QAAQ,WAAW,EAAM,QAAQ,SACzC,EAAM,gBAAgB,EACtB,GAAiB;MAGrB,KAAA;EAEN,WAAW;;;;;;;;UAQP,IAAU,qGAAqG,GAAG;;EAEtH,cACE,IAAU,GAAG,EAAG,wBAAwB,iBAAiB,CAAC,GAAG,EAAU,SAAS,KAAA;EAElF,MAAM,IAAU,WAAW,KAAA;EAC3B,UAAU,IAAU,IAAI,KAAA;YA1B1B;GA6BE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,GAAD;OAAW,MAAM;OAAI,WAAU;OAAoC,CAAA;MAC/D,CAAA,EACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAU;OACR,CAAA,EACL,kBAAC,KAAD;OAAG,WAAU;iBAAb,CAAgE,KAAE,EAAU,KAAS;SACjF;QACF;QAEL,KACC,kBAAC,UAAD;KACE,MAAK;KACL,UAAU,MAAM,EAAE,iBAAiB;KACnC,WAAU;KAOV,cAAY,GAAG,EAAG,8BAA8B,wBAAwB,CAAC,GAAG,EAAU;eAEtF,kBAAC,GAAD,EAAc,MAAM,IAAM,CAAA;KACnB,CAAA,CAEP;;GAGN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD,EAAsB,QAAQ,EAAU,QAAU,CAAA,EAClD,kBAAC,QAAD;KAAM,WAAU;eACb,EAAU;KACN,CAAA,CACH;;GAGL,EAAU,gBAAgB,KAAA,KACzB,kBAAC,KAAD;IAAG,WAAU;cAAb;KACG,EAAU;KAAa;KACvB,EAAU,gBAAgB,IACvB,EAAG,uBAAuB,SAAS,CAAC,aAAa,GACjD,EAAG,2BAA2B,UAAU,CAAC,aAAa;KACxD;;GAIN,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,KAAD;KAAG,WAAU;eAAb;MACG,EAAG,kBAAkB,UAAU;MAAC;MAAE,IAAI,KAAK,EAAU,UAAU,CAAC,oBAAoB;MACnF;;IACA,CAAA;GAGL,MAAgB,KAAU,MACzB,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,KACC,kBAAC,UAAD;KACE,MAAK;KACL,UA3GQ,MAAwB;AAE1C,MADA,EAAE,iBAAiB,EACf,KACF,EAAO,EAAU;;KAyGT,WAAU;eAWT,EAAG,eAAe,OAAO;KACnB,CAAA,EAEV,KACC,kBAAC,UAAD;KACE,MAAK;KACL,UAtHU,MAAwB;AAE5C,MADA,EAAE,iBAAiB,EACf,KACF,EAAS,EAAU;;KAoHX,WAAU;eAWT,EAAG,iBAAiB,SAAS;KACvB,CAAA,CAEP;;GAEJ"}
@@ -125,7 +125,7 @@ function g({ workspace: g, tenantId: _, tenantName: v, organizationId: y, organi
125
125
  /* @__PURE__ */ m("div", {
126
126
  className: "pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-[var(--color-text-muted)]",
127
127
  children: /* @__PURE__ */ m("svg", {
128
- className: "h-4 w-4",
128
+ className: "size-4",
129
129
  fill: "none",
130
130
  viewBox: "0 0 24 24",
131
131
  stroke: "currentColor",
@@ -151,6 +151,7 @@ function g({ workspace: g, tenantId: _, tenantName: v, organizationId: y, organi
151
151
  id: "tenantId",
152
152
  type: "text",
153
153
  value: B,
154
+ "aria-label": T("organizations.form.tenant", "Tenant"),
154
155
  onChange: (e) => D((t) => ({
155
156
  ...t,
156
157
  tenantId: e.target.value
@@ -219,7 +220,7 @@ function g({ workspace: g, tenantId: _, tenantName: v, organizationId: y, organi
219
220
  /* @__PURE__ */ m("div", {
220
221
  className: "pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-[var(--color-text-muted)]",
221
222
  children: /* @__PURE__ */ m("svg", {
222
- className: "h-4 w-4",
223
+ className: "size-4",
223
224
  fill: "none",
224
225
  viewBox: "0 0 24 24",
225
226
  stroke: "currentColor",
@@ -245,6 +246,7 @@ function g({ workspace: g, tenantId: _, tenantName: v, organizationId: y, organi
245
246
  id: "organizationId",
246
247
  type: "text",
247
248
  value: V,
249
+ "aria-label": T("common.organization", "Organization"),
248
250
  onChange: (e) => D((t) => ({
249
251
  ...t,
250
252
  organizationId: e.target.value
@@ -285,6 +287,7 @@ function g({ workspace: g, tenantId: _, tenantName: v, organizationId: y, organi
285
287
  id: "name",
286
288
  type: "text",
287
289
  value: E.name,
290
+ "aria-label": T("workspaces.form.name", "Workspace Name"),
288
291
  onChange: (e) => D((t) => ({
289
292
  ...t,
290
293
  name: e.target.value
@@ -317,6 +320,7 @@ function g({ workspace: g, tenantId: _, tenantName: v, organizationId: y, organi
317
320
  id: "slug",
318
321
  type: "text",
319
322
  value: E.slug,
323
+ "aria-label": T("common.slug", "Slug"),
320
324
  onChange: (e) => D((t) => ({
321
325
  ...t,
322
326
  slug: e.target.value.toLowerCase().replace(/\s+/g, "-")
@@ -1 +1 @@
1
- {"version":3,"file":"WorkspaceForm.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/components/WorkspaceForm.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport { Building, Home, Loader2 } from 'lucide-react';\nimport { ZodError } from 'zod';\nimport type { CreateWorkspaceInput, UpdateWorkspaceInput, Workspace } from '../types';\nimport { createWorkspaceSchema, updateWorkspaceSchema } from '../schemas';\nimport { useOrganizations } from '../../organizations/hooks/useOrganizations';\nimport { useOrgsWithPermission } from '../../organizations/hooks/useOrgsWithPermission';\nimport { useTenants } from '../hooks/useWorkspaces';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface WorkspaceFormProps {\n workspace?: Workspace | null;\n tenantId?: string;\n tenantName?: string;\n organizationId?: string;\n organizationName?: string;\n showOrganizationSelector?: boolean;\n onSubmit: (data: CreateWorkspaceInput | UpdateWorkspaceInput) => Promise<void>;\n onCancel: () => void;\n loading?: boolean;\n}\n\nexport function WorkspaceForm({\n workspace,\n tenantId,\n tenantName,\n organizationId,\n organizationName,\n showOrganizationSelector = false,\n onSubmit,\n onCancel,\n loading,\n}: WorkspaceFormProps) {\n const tr = useTr();\n const [formData, setFormData] = useState({\n name: workspace?.name || '',\n slug: workspace?.slug || '',\n type: workspace?.type || 'PERSONAL',\n tenantId: tenantId || workspace?.tenantId || '',\n organizationId: organizationId || workspace?.organizationId || '',\n });\n\n const [errors, setErrors] = useState<Record<string, string>>({});\n\n const shouldLoadTenants = !workspace && showOrganizationSelector && !tenantId;\n const shouldLoadOrganizations = !workspace && showOrganizationSelector && !organizationId;\n\n const { tenants, loading: tenantsLoading } = useTenants(100, 0, shouldLoadTenants);\n const { organizations, loading: organizationsLoading } = useOrganizations(\n formData.tenantId ? { tenantId: formData.tenantId } : undefined,\n 100,\n 0,\n shouldLoadOrganizations\n );\n\n // Hide orgs where the user can't actually create a workspace, so the\n // dropdown only surfaces options the gateway @rbac(workspace:create) will\n // accept. Membership alone isn't enough — a Viewer of an org is a member\n // but has workspace=VIEWER (no create). The bulk checkPermissions call is\n // one round-trip regardless of how many orgs are on the list.\n const allOrgIds = useMemo(\n () => organizations.map((organization) => organization.id),\n [organizations]\n );\n const { allowedIds: workspaceCreateAllowedOrgIds, loading: permissionCheckLoading } =\n useOrgsWithPermission(allOrgIds, 'workspace', 'create');\n const filterByPermission = !workspace && showOrganizationSelector && !organizationId;\n const permittedOrganizations = useMemo(\n () =>\n filterByPermission\n ? organizations.filter((organization) => workspaceCreateAllowedOrgIds.has(organization.id))\n : organizations,\n [organizations, workspaceCreateAllowedOrgIds, filterByPermission]\n );\n\n useEffect(() => {\n if (tenantId && tenantId !== formData.tenantId) {\n setFormData((previousState) => ({ ...previousState, tenantId }));\n }\n }, [formData.tenantId, tenantId]);\n\n useEffect(() => {\n if (organizationId && organizationId !== formData.organizationId) {\n setFormData((previousState) => ({ ...previousState, organizationId }));\n }\n }, [formData.organizationId, organizationId]);\n\n useEffect(() => {\n if (!showOrganizationSelector || organizationId || workspace) {\n return;\n }\n\n setFormData((previousState) => {\n if (!previousState.organizationId) {\n return previousState;\n }\n\n const hasMatchingOrganization = permittedOrganizations.some(\n (organization) => organization.id === previousState.organizationId\n );\n\n if (hasMatchingOrganization) {\n return previousState;\n }\n\n return { ...previousState, organizationId: '' };\n });\n }, [organizationId, permittedOrganizations, showOrganizationSelector, workspace]);\n\n const selectedTenantLabel = useMemo(() => {\n if (tenantName) return tenantName;\n\n const selectedTenant = tenants.find((tenant) => tenant.id === formData.tenantId);\n return selectedTenant?.name ?? formData.tenantId;\n }, [formData.tenantId, tenantName, tenants]);\n\n const selectedOrganizationLabel = useMemo(() => {\n if (organizationName) return organizationName;\n\n const selectedOrganization = permittedOrganizations.find(\n (organization) => organization.id === formData.organizationId\n );\n return selectedOrganization?.name ?? formData.organizationId;\n }, [formData.organizationId, organizationName, permittedOrganizations]);\n\n const validate = () => {\n try {\n const schema = workspace ? updateWorkspaceSchema : createWorkspaceSchema;\n schema.parse(formData);\n setErrors({});\n return true;\n } catch (validationError) {\n if (validationError instanceof ZodError) {\n const nextErrors: Record<string, string> = {};\n validationError.issues.forEach((issue) => {\n const path = issue.path.join('.');\n nextErrors[path] = issue.message;\n });\n setErrors(nextErrors);\n }\n\n return false;\n }\n };\n\n const handleSubmit = async (event: React.FormEvent) => {\n event.preventDefault();\n\n if (!validate()) {\n return;\n }\n\n const submitData = workspace\n ? {\n name: formData.name !== workspace.name ? formData.name : undefined,\n type: formData.type !== workspace.type ? formData.type : undefined,\n }\n : {\n tenantId: formData.tenantId,\n organizationId: formData.organizationId,\n name: formData.name,\n slug: formData.slug,\n type: formData.type || undefined,\n };\n\n await onSubmit(submitData);\n };\n\n return (\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n {!workspace ? (\n <>\n <div>\n <label\n htmlFor=\"tenantId\"\n className=\"mb-1 block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr('organizations.form.tenant', 'Tenant')}{' '}\n <span className=\"text-[var(--color-status-error-text)]\">*</span>\n </label>\n\n {showOrganizationSelector && !tenantId ? (\n <div className=\"relative\">\n <select\n id=\"tenantId\"\n value={formData.tenantId}\n onChange={(event) =>\n setFormData((previousState) => ({\n ...previousState,\n tenantId: event.target.value,\n organizationId: '',\n }))\n }\n className=\"w-full appearance-none rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] py-2 pl-10 pr-10 text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-border-focus)] disabled:cursor-not-allowed disabled:bg-[var(--color-bg-muted)]\"\n disabled={loading || tenantsLoading}\n required\n >\n <option value=\"\">\n {tr('workspaces.form.selectTenant', 'Select a tenant...')}\n </option>\n {tenants.map((tenant) => (\n <option key={tenant.id} value={tenant.id}>\n {tenant.name} ({tenant.slug})\n </option>\n ))}\n </select>\n <Home\n size={18}\n className=\"pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-[var(--color-text-muted)]\"\n />\n <div className=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-[var(--color-text-muted)]\">\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 9l-7 7-7-7\"\n />\n </svg>\n </div>\n {tenantsLoading ? (\n <div className=\"absolute right-10 top-1/2 -translate-y-1/2\">\n <Loader2 size={16} className=\"animate-spin text-[var(--color-text-muted)]\" />\n </div>\n ) : null}\n </div>\n ) : (\n <div className=\"relative\">\n <input\n id=\"tenantId\"\n type=\"text\"\n value={selectedTenantLabel}\n onChange={(event) =>\n setFormData((previousState) => ({\n ...previousState,\n tenantId: event.target.value,\n }))\n }\n className=\"w-full rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] py-2 pl-10 pr-4 text-[var(--color-text-primary)] placeholder:text-[var(--color-text-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--color-border-focus)] disabled:cursor-not-allowed disabled:bg-[var(--color-bg-muted)]\"\n placeholder={tr('organizations.form.tenantPlaceholder', 'Enter tenant ID')}\n disabled={loading || Boolean(tenantId)}\n required\n autoComplete=\"off\"\n />\n <Home\n size={18}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-[var(--color-text-muted)]\"\n />\n </div>\n )}\n\n {(tenantId || formData.tenantId) && (\n <p className=\"mt-1 text-xs text-[var(--color-text-muted)]\">\n {tr(\n 'workspaces.form.creatingUnderTenant',\n 'Creating workspace under the selected tenant.'\n )}\n </p>\n )}\n {errors.tenantId ? (\n <p className=\"mt-1 text-sm text-[var(--color-status-error-text)]\">\n {errors.tenantId}\n </p>\n ) : null}\n </div>\n\n <div>\n <label\n htmlFor=\"organizationId\"\n className=\"mb-1 block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr('common.organization', 'Organization')}{' '}\n <span className=\"text-[var(--color-status-error-text)]\">*</span>\n </label>\n\n {showOrganizationSelector && !organizationId ? (\n <div className=\"relative\">\n <select\n id=\"organizationId\"\n value={formData.organizationId}\n onChange={(event) =>\n setFormData((previousState) => ({\n ...previousState,\n organizationId: event.target.value,\n }))\n }\n className=\"w-full appearance-none rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] py-2 pl-10 pr-10 text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-border-focus)] disabled:cursor-not-allowed disabled:bg-[var(--color-bg-muted)]\"\n disabled={\n loading || organizationsLoading || permissionCheckLoading || !formData.tenantId\n }\n required\n >\n <option value=\"\">\n {!formData.tenantId\n ? tr('workspaces.form.selectTenantFirst', 'Select a tenant first')\n : permittedOrganizations.length === 0 &&\n !organizationsLoading &&\n !permissionCheckLoading\n ? tr(\n 'workspaces.form.noOrganizationsAvailable',\n 'No organizations available — you need workspace create permission'\n )\n : tr('workspaces.form.selectOrganization', 'Select an organization...')}\n </option>\n {permittedOrganizations.map((organization) => (\n <option key={organization.id} value={organization.id}>\n {organization.name} ({organization.slug})\n </option>\n ))}\n </select>\n <Building\n size={18}\n className=\"pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-[var(--color-text-muted)]\"\n />\n <div className=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-[var(--color-text-muted)]\">\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 9l-7 7-7-7\"\n />\n </svg>\n </div>\n {organizationsLoading || permissionCheckLoading ? (\n <div className=\"absolute right-10 top-1/2 -translate-y-1/2\">\n <Loader2 size={16} className=\"animate-spin text-[var(--color-text-muted)]\" />\n </div>\n ) : null}\n </div>\n ) : (\n <div className=\"relative\">\n <input\n id=\"organizationId\"\n type=\"text\"\n value={selectedOrganizationLabel}\n onChange={(event) =>\n setFormData((previousState) => ({\n ...previousState,\n organizationId: event.target.value,\n }))\n }\n className=\"w-full rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] py-2 pl-10 pr-4 text-[var(--color-text-primary)] placeholder:text-[var(--color-text-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--color-border-focus)] disabled:cursor-not-allowed disabled:bg-[var(--color-bg-muted)]\"\n placeholder={tr('workspaces.form.orgIdPlaceholder', 'Enter organization ID')}\n disabled={loading || Boolean(organizationId)}\n required\n autoComplete=\"off\"\n />\n <Building\n size={18}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-[var(--color-text-muted)]\"\n />\n </div>\n )}\n\n {(organizationId || formData.organizationId) && (\n <p className=\"mt-1 text-xs text-[var(--color-text-muted)]\">\n {tr(\n 'workspaces.form.creatingUnderOrg',\n 'Creating workspace under the selected organization.'\n )}\n </p>\n )}\n {errors.organizationId ? (\n <p className=\"mt-1 text-sm text-[var(--color-status-error-text)]\">\n {errors.organizationId}\n </p>\n ) : null}\n </div>\n </>\n ) : null}\n\n <div>\n <label\n htmlFor=\"name\"\n className=\"mb-1 block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr('workspaces.form.name', 'Workspace Name')}{' '}\n <span className=\"text-[var(--color-status-error-text)]\">*</span>\n </label>\n <input\n id=\"name\"\n type=\"text\"\n value={formData.name}\n onChange={(event) =>\n setFormData((previousState) => ({ ...previousState, name: event.target.value }))\n }\n className=\"w-full rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-3 py-2 text-[var(--color-text-primary)] placeholder:text-[var(--color-text-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--color-border-focus)] disabled:cursor-not-allowed disabled:bg-[var(--color-bg-muted)]\"\n placeholder={tr('workspaces.form.namePlaceholder', 'Enter workspace name')}\n disabled={loading}\n required\n autoComplete=\"organization-title\"\n />\n {errors.name ? (\n <p className=\"mt-1 text-sm text-[var(--color-status-error-text)]\">{errors.name}</p>\n ) : null}\n </div>\n\n <div>\n <label\n htmlFor=\"slug\"\n className=\"mb-1 block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr('common.slug', 'Slug')}{' '}\n <span className=\"text-[var(--color-status-error-text)]\">*</span>\n </label>\n <input\n id=\"slug\"\n type=\"text\"\n value={formData.slug}\n onChange={(event) =>\n setFormData((previousState) => ({\n ...previousState,\n slug: event.target.value.toLowerCase().replace(/\\s+/g, '-'),\n }))\n }\n className=\"w-full rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-3 py-2 text-[var(--color-text-primary)] placeholder:text-[var(--color-text-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--color-border-focus)] disabled:cursor-not-allowed disabled:bg-[var(--color-bg-muted)]\"\n placeholder={tr('workspaces.form.slugPlaceholder', 'workspace-slug')}\n disabled={loading || Boolean(workspace)}\n required={!workspace}\n autoComplete=\"off\"\n />\n <p className=\"mt-1 text-xs text-[var(--color-text-muted)]\">\n {tr(\n 'organizations.form.slugImmutable',\n 'Lowercase letters, numbers, and hyphens only. Cannot be changed after creation.'\n )}\n </p>\n {errors.slug ? (\n <p className=\"mt-1 text-sm text-[var(--color-status-error-text)]\">{errors.slug}</p>\n ) : null}\n </div>\n\n <div>\n <label\n htmlFor=\"type\"\n className=\"mb-1 block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr('workspaces.list.column.type', 'Type')}\n </label>\n <select\n id=\"type\"\n value={formData.type}\n onChange={(event) =>\n setFormData((previousState) => ({ ...previousState, type: event.target.value }))\n }\n className=\"w-full rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-3 py-2 text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-border-focus)] disabled:cursor-not-allowed disabled:bg-[var(--color-bg-muted)]\"\n disabled={loading}\n >\n <option value=\"PERSONAL\">{tr('workspaces.type.personal', 'Personal')}</option>\n <option value=\"TEAM\">{tr('workspaces.type.team', 'Team')}</option>\n <option value=\"ENTERPRISE\">{tr('workspaces.type.enterprise', 'Enterprise')}</option>\n </select>\n </div>\n\n <div className=\"flex flex-col gap-3 border-t border-[var(--color-border-default)] pt-4 sm:flex-row\">\n <button\n type=\"submit\"\n disabled={loading}\n className=\"inline-flex items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-6 py-2.5 font-medium text-[var(--color-action-primary-text)] transition-all duration-200 hover:opacity-90 hover:scale-[1.02] active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-50 sm:min-w-[220px]\"\n >\n {loading ? <Loader2 size={16} className=\"animate-spin\" /> : null}\n {workspace\n ? tr('workspaces.form.updateSubmit', 'Update Workspace')\n : tr('workspaces.create.button', 'Create Workspace')}\n </button>\n\n <button\n type=\"button\"\n onClick={onCancel}\n disabled={loading}\n className=\"rounded-lg border border-[var(--color-border-default)] bg-transparent px-6 py-2.5 font-medium text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)] active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-50 sm:min-w-[140px]\"\n >\n {tr('common.cancel', 'Cancel')}\n </button>\n </div>\n </form>\n );\n}\n"],"mappings":";;;;;;;;;;AAsBA,SAAgB,EAAc,EAC5B,cACA,aACA,eACA,mBACA,qBACA,8BAA2B,IAC3B,aACA,aACA,cACqB;CACrB,IAAM,IAAK,GAAO,EACZ,CAAC,GAAU,KAAe,EAAS;EACvC,MAAM,GAAW,QAAQ;EACzB,MAAM,GAAW,QAAQ;EACzB,MAAM,GAAW,QAAQ;EACzB,UAAU,KAAY,GAAW,YAAY;EAC7C,gBAAgB,KAAkB,GAAW,kBAAkB;EAChE,CAAC,EAEI,CAAC,GAAQ,KAAa,EAAiC,EAAE,CAAC,EAE1D,IAAoB,CAAC,KAAa,KAA4B,CAAC,GAC/D,IAA0B,CAAC,KAAa,KAA4B,CAAC,GAErE,EAAE,YAAS,SAAS,MAAmB,EAAW,KAAK,GAAG,EAAkB,EAC5E,EAAE,kBAAe,SAAS,MAAyB,EACvD,EAAS,WAAW,EAAE,UAAU,EAAS,UAAU,GAAG,KAAA,GACtD,KACA,GACA,EACD,EAWK,EAAE,YAAY,GAA8B,SAAS,MACzD,EALgB,QACV,EAAc,KAAK,MAAiB,EAAa,GAAG,EAC1D,CAAC,EAAc,CAChB,EAEkC,aAAa,SAAS,EACnD,IAAqB,CAAC,KAAa,KAA4B,CAAC,GAChE,IAAyB,QAE3B,IACI,EAAc,QAAQ,MAAiB,EAA6B,IAAI,EAAa,GAAG,CAAC,GACzF,GACN;EAAC;EAAe;EAA8B;EAAmB,CAClE;AAcD,CAZA,QAAgB;AACd,EAAI,KAAY,MAAa,EAAS,YACpC,GAAa,OAAmB;GAAE,GAAG;GAAe;GAAU,EAAE;IAEjE,CAAC,EAAS,UAAU,EAAS,CAAC,EAEjC,QAAgB;AACd,EAAI,KAAkB,MAAmB,EAAS,kBAChD,GAAa,OAAmB;GAAE,GAAG;GAAe;GAAgB,EAAE;IAEvE,CAAC,EAAS,gBAAgB,EAAe,CAAC,EAE7C,QAAgB;AACV,GAAC,KAA4B,KAAkB,KAInD,GAAa,MACP,CAAC,EAAc,kBAIa,EAAuB,MACpD,MAAiB,EAAa,OAAO,EAAc,eACrD,GAGQ,IAGF;GAAE,GAAG;GAAe,gBAAgB;GAAI,CAC/C;IACD;EAAC;EAAgB;EAAwB;EAA0B;EAAU,CAAC;CAEjF,IAAM,IAAsB,QACtB,MAEmB,EAAQ,MAAM,MAAW,EAAO,OAAO,EAAS,SAAS,EACzD,QAAQ,EAAS,WACvC;EAAC,EAAS;EAAU;EAAY;EAAQ,CAAC,EAEtC,IAA4B,QAC5B,MAEyB,EAAuB,MACjD,MAAiB,EAAa,OAAO,EAAS,eAChD,EAC4B,QAAQ,EAAS,iBAC7C;EAAC,EAAS;EAAgB;EAAkB;EAAuB,CAAC,EAEjE,UAAiB;AACrB,MAAI;AAIF,WAHe,IAAY,IAAwB,GAC5C,MAAM,EAAS,EACtB,EAAU,EAAE,CAAC,EACN;WACA,GAAiB;AACxB,OAAI,aAA2B,GAAU;IACvC,IAAM,IAAqC,EAAE;AAK7C,IAJA,EAAgB,OAAO,SAAS,MAAU;KACxC,IAAM,IAAO,EAAM,KAAK,KAAK,IAAI;AACjC,OAAW,KAAQ,EAAM;MACzB,EACF,EAAU,EAAW;;AAGvB,UAAO;;;AA2BX,QACE,kBAAC,QAAD;EAAM,UAxBa,OAAO,MAA2B;AACrD,KAAM,gBAAgB,EAEjB,GAAU,IAiBf,MAAM,EAba,IACf;IACE,MAAM,EAAS,SAAS,EAAU,OAAuB,KAAA,IAAhB,EAAS;IAClD,MAAM,EAAS,SAAS,EAAU,OAAuB,KAAA,IAAhB,EAAS;IACnD,GACD;IACE,UAAU,EAAS;IACnB,gBAAgB,EAAS;IACzB,MAAM,EAAS;IACf,MAAM,EAAS;IACf,MAAM,EAAS,QAAQ,KAAA;IACxB,CAEqB;;EAII,WAAU;YAAxC;GACI,IAwME,OAvMF,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD,EAAA,UAAA;IACE,kBAAC,SAAD;KACE,SAAQ;KACR,WAAU;eAFZ;MAIG,EAAG,6BAA6B,SAAS;MAAE;MAC5C,kBAAC,QAAD;OAAM,WAAU;iBAAwC;OAAQ,CAAA;MAC1D;;IAEP,KAA4B,CAAC,IAC5B,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,UAAD;OACE,IAAG;OACH,OAAO,EAAS;OAChB,WAAW,MACT,GAAa,OAAmB;QAC9B,GAAG;QACH,UAAU,EAAM,OAAO;QACvB,gBAAgB;QACjB,EAAE;OAEL,WAAU;OACV,UAAU,KAAW;OACrB,UAAA;iBAZF,CAcE,kBAAC,UAAD;QAAQ,OAAM;kBACX,EAAG,gCAAgC,qBAAqB;QAClD,CAAA,EACR,EAAQ,KAAK,MACZ,kBAAC,UAAD;QAAwB,OAAO,EAAO;kBAAtC;SACG,EAAO;SAAK;SAAG,EAAO;SAAK;SACrB;UAFI,EAAO,GAEX,CACT,CACK;;MACT,kBAAC,GAAD;OACE,MAAM;OACN,WAAU;OACV,CAAA;MACF,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,OAAD;QAAK,WAAU;QAAU,MAAK;QAAO,SAAQ;QAAY,QAAO;kBAC9D,kBAAC,QAAD;SACE,eAAc;SACd,gBAAe;SACf,aAAa;SACb,GAAE;SACF,CAAA;QACE,CAAA;OACF,CAAA;MACL,IACC,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,GAAD;QAAS,MAAM;QAAI,WAAU;QAAgD,CAAA;OACzE,CAAA,GACJ;MACA;SAEN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,SAAD;MACE,IAAG;MACH,MAAK;MACL,OAAO;MACP,WAAW,MACT,GAAa,OAAmB;OAC9B,GAAG;OACH,UAAU,EAAM,OAAO;OACxB,EAAE;MAEL,WAAU;MACV,aAAa,EAAG,wCAAwC,kBAAkB;MAC1E,UAAU,KAAW,EAAQ;MAC7B,UAAA;MACA,cAAa;MACb,CAAA,EACF,kBAAC,GAAD;MACE,MAAM;MACN,WAAU;MACV,CAAA,CACE;;KAGN,KAAY,EAAS,aACrB,kBAAC,KAAD;KAAG,WAAU;eACV,EACC,uCACA,gDACD;KACC,CAAA;IAEL,EAAO,WACN,kBAAC,KAAD;KAAG,WAAU;eACV,EAAO;KACN,CAAA,GACF;IACA,EAAA,CAAA,EAEN,kBAAC,OAAD,EAAA,UAAA;IACE,kBAAC,SAAD;KACE,SAAQ;KACR,WAAU;eAFZ;MAIG,EAAG,uBAAuB,eAAe;MAAE;MAC5C,kBAAC,QAAD;OAAM,WAAU;iBAAwC;OAAQ,CAAA;MAC1D;;IAEP,KAA4B,CAAC,IAC5B,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,UAAD;OACE,IAAG;OACH,OAAO,EAAS;OAChB,WAAW,MACT,GAAa,OAAmB;QAC9B,GAAG;QACH,gBAAgB,EAAM,OAAO;QAC9B,EAAE;OAEL,WAAU;OACV,UACE,KAAW,KAAwB,KAA0B,CAAC,EAAS;OAEzE,UAAA;iBAbF,CAeE,kBAAC,UAAD;QAAQ,OAAM;kBACV,EAAS,WAEP,EAAuB,WAAW,KAChC,CAAC,KACD,CAAC,IACD,EACE,4CACA,oEACD,GACD,EAAG,sCAAsC,4BAA4B,GARvE,EAAG,qCAAqC,wBAAwB;QAS7D,CAAA,EACR,EAAuB,KAAK,MAC3B,kBAAC,UAAD;QAA8B,OAAO,EAAa;kBAAlD;SACG,EAAa;SAAK;SAAG,EAAa;SAAK;SACjC;UAFI,EAAa,GAEjB,CACT,CACK;;MACT,kBAAC,GAAD;OACE,MAAM;OACN,WAAU;OACV,CAAA;MACF,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,OAAD;QAAK,WAAU;QAAU,MAAK;QAAO,SAAQ;QAAY,QAAO;kBAC9D,kBAAC,QAAD;SACE,eAAc;SACd,gBAAe;SACf,aAAa;SACb,GAAE;SACF,CAAA;QACE,CAAA;OACF,CAAA;MACL,KAAwB,IACvB,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,GAAD;QAAS,MAAM;QAAI,WAAU;QAAgD,CAAA;OACzE,CAAA,GACJ;MACA;SAEN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,SAAD;MACE,IAAG;MACH,MAAK;MACL,OAAO;MACP,WAAW,MACT,GAAa,OAAmB;OAC9B,GAAG;OACH,gBAAgB,EAAM,OAAO;OAC9B,EAAE;MAEL,WAAU;MACV,aAAa,EAAG,oCAAoC,wBAAwB;MAC5E,UAAU,KAAW,EAAQ;MAC7B,UAAA;MACA,cAAa;MACb,CAAA,EACF,kBAAC,GAAD;MACE,MAAM;MACN,WAAU;MACV,CAAA,CACE;;KAGN,KAAkB,EAAS,mBAC3B,kBAAC,KAAD;KAAG,WAAU;eACV,EACC,oCACA,sDACD;KACC,CAAA;IAEL,EAAO,iBACN,kBAAC,KAAD;KAAG,WAAU;eACV,EAAO;KACN,CAAA,GACF;IACA,EAAA,CAAA,CACL,EAAA,CAAA;GAGL,kBAAC,OAAD,EAAA,UAAA;IACE,kBAAC,SAAD;KACE,SAAQ;KACR,WAAU;eAFZ;MAIG,EAAG,wBAAwB,iBAAiB;MAAE;MAC/C,kBAAC,QAAD;OAAM,WAAU;iBAAwC;OAAQ,CAAA;MAC1D;;IACR,kBAAC,SAAD;KACE,IAAG;KACH,MAAK;KACL,OAAO,EAAS;KAChB,WAAW,MACT,GAAa,OAAmB;MAAE,GAAG;MAAe,MAAM,EAAM,OAAO;MAAO,EAAE;KAElF,WAAU;KACV,aAAa,EAAG,mCAAmC,uBAAuB;KAC1E,UAAU;KACV,UAAA;KACA,cAAa;KACb,CAAA;IACD,EAAO,OACN,kBAAC,KAAD;KAAG,WAAU;eAAsD,EAAO;KAAS,CAAA,GACjF;IACA,EAAA,CAAA;GAEN,kBAAC,OAAD,EAAA,UAAA;IACE,kBAAC,SAAD;KACE,SAAQ;KACR,WAAU;eAFZ;MAIG,EAAG,eAAe,OAAO;MAAE;MAC5B,kBAAC,QAAD;OAAM,WAAU;iBAAwC;OAAQ,CAAA;MAC1D;;IACR,kBAAC,SAAD;KACE,IAAG;KACH,MAAK;KACL,OAAO,EAAS;KAChB,WAAW,MACT,GAAa,OAAmB;MAC9B,GAAG;MACH,MAAM,EAAM,OAAO,MAAM,aAAa,CAAC,QAAQ,QAAQ,IAAI;MAC5D,EAAE;KAEL,WAAU;KACV,aAAa,EAAG,mCAAmC,iBAAiB;KACpE,UAAU,KAAW,EAAQ;KAC7B,UAAU,CAAC;KACX,cAAa;KACb,CAAA;IACF,kBAAC,KAAD;KAAG,WAAU;eACV,EACC,oCACA,kFACD;KACC,CAAA;IACH,EAAO,OACN,kBAAC,KAAD;KAAG,WAAU;eAAsD,EAAO;KAAS,CAAA,GACjF;IACA,EAAA,CAAA;GAEN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;IACE,SAAQ;IACR,WAAU;cAET,EAAG,+BAA+B,OAAO;IACpC,CAAA,EACR,kBAAC,UAAD;IACE,IAAG;IACH,OAAO,EAAS;IAChB,WAAW,MACT,GAAa,OAAmB;KAAE,GAAG;KAAe,MAAM,EAAM,OAAO;KAAO,EAAE;IAElF,WAAU;IACV,UAAU;cAPZ;KASE,kBAAC,UAAD;MAAQ,OAAM;gBAAY,EAAG,4BAA4B,WAAW;MAAU,CAAA;KAC9E,kBAAC,UAAD;MAAQ,OAAM;gBAAQ,EAAG,wBAAwB,OAAO;MAAU,CAAA;KAClE,kBAAC,UAAD;MAAQ,OAAM;gBAAc,EAAG,8BAA8B,aAAa;MAAU,CAAA;KAC7E;MACL,EAAA,CAAA;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,UAAD;KACE,MAAK;KACL,UAAU;KACV,WAAU;eAHZ,CAKG,IAAU,kBAAC,GAAD;MAAS,MAAM;MAAI,WAAU;MAAiB,CAAA,GAAG,MAC3D,IACG,EAAG,gCAAgC,mBAAmB,GACtD,EAAG,4BAA4B,mBAAmB,CAC/C;QAET,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,UAAU;KACV,WAAU;eAET,EAAG,iBAAiB,SAAS;KACvB,CAAA,CACL;;GACD"}
1
+ {"version":3,"file":"WorkspaceForm.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/components/WorkspaceForm.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport { Building, Home, Loader2 } from 'lucide-react';\nimport { ZodError } from 'zod';\nimport type { CreateWorkspaceInput, UpdateWorkspaceInput, Workspace } from '../types';\nimport { createWorkspaceSchema, updateWorkspaceSchema } from '../schemas';\nimport { useOrganizations } from '../../organizations/hooks/useOrganizations';\nimport { useOrgsWithPermission } from '../../organizations/hooks/useOrgsWithPermission';\nimport { useTenants } from '../hooks/useWorkspaces';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface WorkspaceFormProps {\n workspace?: Workspace | null;\n tenantId?: string;\n tenantName?: string;\n organizationId?: string;\n organizationName?: string;\n showOrganizationSelector?: boolean;\n onSubmit: (data: CreateWorkspaceInput | UpdateWorkspaceInput) => Promise<void>;\n onCancel: () => void;\n loading?: boolean;\n}\n\nexport function WorkspaceForm({\n workspace,\n tenantId,\n tenantName,\n organizationId,\n organizationName,\n showOrganizationSelector = false,\n onSubmit,\n onCancel,\n loading,\n}: WorkspaceFormProps) {\n const tr = useTr();\n const [formData, setFormData] = useState({\n // react-doctor-disable-next-line react-doctor/no-event-handler\n name: workspace?.name || '',\n slug: workspace?.slug || '',\n type: workspace?.type || 'PERSONAL',\n // react-doctor-disable-next-line react-doctor/no-event-handler\n tenantId: tenantId || workspace?.tenantId || '',\n // react-doctor-disable-next-line react-doctor/no-event-handler\n organizationId: organizationId || workspace?.organizationId || '',\n });\n\n const [errors, setErrors] = useState<Record<string, string>>({});\n\n const shouldLoadTenants = !workspace && showOrganizationSelector && !tenantId;\n const shouldLoadOrganizations = !workspace && showOrganizationSelector && !organizationId;\n\n const { tenants, loading: tenantsLoading } = useTenants(100, 0, shouldLoadTenants);\n const { organizations, loading: organizationsLoading } = useOrganizations(\n formData.tenantId ? { tenantId: formData.tenantId } : undefined,\n 100,\n 0,\n shouldLoadOrganizations\n );\n\n // Hide orgs where the user can't actually create a workspace, so the\n // dropdown only surfaces options the gateway @rbac(workspace:create) will\n // accept. Membership alone isn't enough — a Viewer of an org is a member\n // but has workspace=VIEWER (no create). The bulk checkPermissions call is\n // one round-trip regardless of how many orgs are on the list.\n const allOrgIds = useMemo(\n () => organizations.map((organization) => organization.id),\n [organizations]\n );\n const { allowedIds: workspaceCreateAllowedOrgIds, loading: permissionCheckLoading } =\n useOrgsWithPermission(allOrgIds, 'workspace', 'create');\n const filterByPermission = !workspace && showOrganizationSelector && !organizationId;\n const permittedOrganizations = useMemo(\n () =>\n filterByPermission\n ? organizations.filter((organization) => workspaceCreateAllowedOrgIds.has(organization.id))\n : organizations,\n [organizations, workspaceCreateAllowedOrgIds, filterByPermission]\n );\n\n useEffect(() => {\n // react-doctor-disable-next-line react-doctor/no-event-handler\n if (tenantId && tenantId !== formData.tenantId) {\n setFormData((previousState) => ({ ...previousState, tenantId }));\n }\n }, [formData.tenantId, tenantId]);\n\n useEffect(() => {\n // react-doctor-disable-next-line react-doctor/no-event-handler\n if (organizationId && organizationId !== formData.organizationId) {\n setFormData((previousState) => ({ ...previousState, organizationId }));\n }\n }, [formData.organizationId, organizationId]);\n\n useEffect(() => {\n if (!showOrganizationSelector || organizationId || workspace) {\n return;\n }\n\n setFormData((previousState) => {\n if (!previousState.organizationId) {\n return previousState;\n }\n\n const hasMatchingOrganization = permittedOrganizations.some(\n (organization) => organization.id === previousState.organizationId\n );\n\n if (hasMatchingOrganization) {\n return previousState;\n }\n\n return { ...previousState, organizationId: '' };\n });\n }, [organizationId, permittedOrganizations, showOrganizationSelector, workspace]);\n\n const selectedTenantLabel = useMemo(() => {\n if (tenantName) return tenantName;\n\n const selectedTenant = tenants.find((tenant) => tenant.id === formData.tenantId);\n return selectedTenant?.name ?? formData.tenantId;\n }, [formData.tenantId, tenantName, tenants]);\n\n const selectedOrganizationLabel = useMemo(() => {\n if (organizationName) return organizationName;\n\n const selectedOrganization = permittedOrganizations.find(\n (organization) => organization.id === formData.organizationId\n );\n return selectedOrganization?.name ?? formData.organizationId;\n }, [formData.organizationId, organizationName, permittedOrganizations]);\n\n const validate = () => {\n try {\n const schema = workspace ? updateWorkspaceSchema : createWorkspaceSchema;\n schema.parse(formData);\n setErrors({});\n return true;\n } catch (validationError) {\n if (validationError instanceof ZodError) {\n const nextErrors: Record<string, string> = {};\n validationError.issues.forEach((issue) => {\n const path = issue.path.join('.');\n nextErrors[path] = issue.message;\n });\n setErrors(nextErrors);\n }\n\n return false;\n }\n };\n\n const handleSubmit = async (event: React.FormEvent) => {\n event.preventDefault();\n\n if (!validate()) {\n return;\n }\n\n const submitData = workspace\n ? {\n name: formData.name !== workspace.name ? formData.name : undefined,\n type: formData.type !== workspace.type ? formData.type : undefined,\n }\n : {\n tenantId: formData.tenantId,\n organizationId: formData.organizationId,\n name: formData.name,\n slug: formData.slug,\n type: formData.type || undefined,\n };\n\n await onSubmit(submitData);\n };\n\n return (\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n {!workspace ? (\n <>\n <div>\n <label\n htmlFor=\"tenantId\"\n className=\"mb-1 block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr('organizations.form.tenant', 'Tenant')}{' '}\n <span className=\"text-[var(--color-status-error-text)]\">*</span>\n </label>\n\n {showOrganizationSelector && !tenantId ? (\n <div className=\"relative\">\n <select\n id=\"tenantId\"\n value={formData.tenantId}\n onChange={(event) =>\n setFormData((previousState) => ({\n ...previousState,\n tenantId: event.target.value,\n organizationId: '',\n }))\n }\n className=\"w-full appearance-none rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] py-2 pl-10 pr-10 text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-border-focus)] disabled:cursor-not-allowed disabled:bg-[var(--color-bg-muted)]\"\n disabled={loading || tenantsLoading}\n required\n >\n <option value=\"\">\n {tr('workspaces.form.selectTenant', 'Select a tenant...')}\n </option>\n {tenants.map((tenant) => (\n <option key={tenant.id} value={tenant.id}>\n {tenant.name} ({tenant.slug})\n </option>\n ))}\n </select>\n <Home\n size={18}\n className=\"pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-[var(--color-text-muted)]\"\n />\n <div className=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-[var(--color-text-muted)]\">\n <svg className=\"size-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 9l-7 7-7-7\"\n />\n </svg>\n </div>\n {tenantsLoading ? (\n <div className=\"absolute right-10 top-1/2 -translate-y-1/2\">\n <Loader2 size={16} className=\"animate-spin text-[var(--color-text-muted)]\" />\n </div>\n ) : null}\n </div>\n ) : (\n <div className=\"relative\">\n <input\n id=\"tenantId\"\n type=\"text\"\n value={selectedTenantLabel}\n aria-label={tr('organizations.form.tenant', 'Tenant')}\n onChange={(event) =>\n setFormData((previousState) => ({\n ...previousState,\n tenantId: event.target.value,\n }))\n }\n className=\"w-full rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] py-2 pl-10 pr-4 text-[var(--color-text-primary)] placeholder:text-[var(--color-text-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--color-border-focus)] disabled:cursor-not-allowed disabled:bg-[var(--color-bg-muted)]\"\n placeholder={tr('organizations.form.tenantPlaceholder', 'Enter tenant ID')}\n disabled={loading || Boolean(tenantId)}\n required\n autoComplete=\"off\"\n />\n <Home\n size={18}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-[var(--color-text-muted)]\"\n />\n </div>\n )}\n\n {(tenantId || formData.tenantId) && (\n <p className=\"mt-1 text-xs text-[var(--color-text-muted)]\">\n {tr(\n 'workspaces.form.creatingUnderTenant',\n 'Creating workspace under the selected tenant.'\n )}\n </p>\n )}\n {errors.tenantId ? (\n <p className=\"mt-1 text-sm text-[var(--color-status-error-text)]\">\n {errors.tenantId}\n </p>\n ) : null}\n </div>\n\n <div>\n <label\n htmlFor=\"organizationId\"\n className=\"mb-1 block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr('common.organization', 'Organization')}{' '}\n <span className=\"text-[var(--color-status-error-text)]\">*</span>\n </label>\n\n {showOrganizationSelector && !organizationId ? (\n <div className=\"relative\">\n <select\n id=\"organizationId\"\n value={formData.organizationId}\n onChange={(event) =>\n setFormData((previousState) => ({\n ...previousState,\n organizationId: event.target.value,\n }))\n }\n className=\"w-full appearance-none rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] py-2 pl-10 pr-10 text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-border-focus)] disabled:cursor-not-allowed disabled:bg-[var(--color-bg-muted)]\"\n disabled={\n loading || organizationsLoading || permissionCheckLoading || !formData.tenantId\n }\n required\n >\n <option value=\"\">\n {!formData.tenantId\n ? tr('workspaces.form.selectTenantFirst', 'Select a tenant first')\n : permittedOrganizations.length === 0 &&\n !organizationsLoading &&\n !permissionCheckLoading\n ? tr(\n 'workspaces.form.noOrganizationsAvailable',\n 'No organizations available — you need workspace create permission'\n )\n : tr('workspaces.form.selectOrganization', 'Select an organization...')}\n </option>\n {permittedOrganizations.map((organization) => (\n <option key={organization.id} value={organization.id}>\n {organization.name} ({organization.slug})\n </option>\n ))}\n </select>\n <Building\n size={18}\n className=\"pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-[var(--color-text-muted)]\"\n />\n <div className=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-[var(--color-text-muted)]\">\n <svg className=\"size-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 9l-7 7-7-7\"\n />\n </svg>\n </div>\n {organizationsLoading || permissionCheckLoading ? (\n <div className=\"absolute right-10 top-1/2 -translate-y-1/2\">\n <Loader2 size={16} className=\"animate-spin text-[var(--color-text-muted)]\" />\n </div>\n ) : null}\n </div>\n ) : (\n <div className=\"relative\">\n <input\n id=\"organizationId\"\n type=\"text\"\n value={selectedOrganizationLabel}\n aria-label={tr('common.organization', 'Organization')}\n onChange={(event) =>\n setFormData((previousState) => ({\n ...previousState,\n organizationId: event.target.value,\n }))\n }\n className=\"w-full rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] py-2 pl-10 pr-4 text-[var(--color-text-primary)] placeholder:text-[var(--color-text-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--color-border-focus)] disabled:cursor-not-allowed disabled:bg-[var(--color-bg-muted)]\"\n placeholder={tr('workspaces.form.orgIdPlaceholder', 'Enter organization ID')}\n disabled={loading || Boolean(organizationId)}\n required\n autoComplete=\"off\"\n />\n <Building\n size={18}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-[var(--color-text-muted)]\"\n />\n </div>\n )}\n\n {(organizationId || formData.organizationId) && (\n <p className=\"mt-1 text-xs text-[var(--color-text-muted)]\">\n {tr(\n 'workspaces.form.creatingUnderOrg',\n 'Creating workspace under the selected organization.'\n )}\n </p>\n )}\n {errors.organizationId ? (\n <p className=\"mt-1 text-sm text-[var(--color-status-error-text)]\">\n {errors.organizationId}\n </p>\n ) : null}\n </div>\n </>\n ) : null}\n\n <div>\n <label\n htmlFor=\"name\"\n className=\"mb-1 block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr('workspaces.form.name', 'Workspace Name')}{' '}\n <span className=\"text-[var(--color-status-error-text)]\">*</span>\n </label>\n <input\n id=\"name\"\n type=\"text\"\n value={formData.name}\n aria-label={tr('workspaces.form.name', 'Workspace Name')}\n onChange={(event) =>\n setFormData((previousState) => ({ ...previousState, name: event.target.value }))\n }\n className=\"w-full rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-3 py-2 text-[var(--color-text-primary)] placeholder:text-[var(--color-text-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--color-border-focus)] disabled:cursor-not-allowed disabled:bg-[var(--color-bg-muted)]\"\n placeholder={tr('workspaces.form.namePlaceholder', 'Enter workspace name')}\n disabled={loading}\n required\n autoComplete=\"organization-title\"\n />\n {errors.name ? (\n <p className=\"mt-1 text-sm text-[var(--color-status-error-text)]\">{errors.name}</p>\n ) : null}\n </div>\n\n <div>\n <label\n htmlFor=\"slug\"\n className=\"mb-1 block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr('common.slug', 'Slug')}{' '}\n <span className=\"text-[var(--color-status-error-text)]\">*</span>\n </label>\n <input\n id=\"slug\"\n type=\"text\"\n value={formData.slug}\n aria-label={tr('common.slug', 'Slug')}\n onChange={(event) =>\n setFormData((previousState) => ({\n ...previousState,\n slug: event.target.value.toLowerCase().replace(/\\s+/g, '-'),\n }))\n }\n className=\"w-full rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-3 py-2 text-[var(--color-text-primary)] placeholder:text-[var(--color-text-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--color-border-focus)] disabled:cursor-not-allowed disabled:bg-[var(--color-bg-muted)]\"\n placeholder={tr('workspaces.form.slugPlaceholder', 'workspace-slug')}\n disabled={loading || Boolean(workspace)}\n required={!workspace}\n autoComplete=\"off\"\n />\n <p className=\"mt-1 text-xs text-[var(--color-text-muted)]\">\n {tr(\n 'organizations.form.slugImmutable',\n 'Lowercase letters, numbers, and hyphens only. Cannot be changed after creation.'\n )}\n </p>\n {errors.slug ? (\n <p className=\"mt-1 text-sm text-[var(--color-status-error-text)]\">{errors.slug}</p>\n ) : null}\n </div>\n\n <div>\n <label\n htmlFor=\"type\"\n className=\"mb-1 block text-sm font-medium text-[var(--color-text-primary)]\"\n >\n {tr('workspaces.list.column.type', 'Type')}\n </label>\n <select\n id=\"type\"\n value={formData.type}\n onChange={(event) =>\n setFormData((previousState) => ({ ...previousState, type: event.target.value }))\n }\n className=\"w-full rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-3 py-2 text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-border-focus)] disabled:cursor-not-allowed disabled:bg-[var(--color-bg-muted)]\"\n disabled={loading}\n >\n <option value=\"PERSONAL\">{tr('workspaces.type.personal', 'Personal')}</option>\n <option value=\"TEAM\">{tr('workspaces.type.team', 'Team')}</option>\n <option value=\"ENTERPRISE\">{tr('workspaces.type.enterprise', 'Enterprise')}</option>\n </select>\n </div>\n\n <div className=\"flex flex-col gap-3 border-t border-[var(--color-border-default)] pt-4 sm:flex-row\">\n <button\n type=\"submit\"\n disabled={loading}\n className=\"inline-flex items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-6 py-2.5 font-medium text-[var(--color-action-primary-text)] transition-all duration-200 hover:opacity-90 hover:scale-[1.02] active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-50 sm:min-w-[220px]\"\n >\n {loading ? <Loader2 size={16} className=\"animate-spin\" /> : null}\n {workspace\n ? tr('workspaces.form.updateSubmit', 'Update Workspace')\n : tr('workspaces.create.button', 'Create Workspace')}\n </button>\n\n <button\n type=\"button\"\n onClick={onCancel}\n disabled={loading}\n className=\"rounded-lg border border-[var(--color-border-default)] bg-transparent px-6 py-2.5 font-medium text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)] active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-50 sm:min-w-[140px]\"\n >\n {tr('common.cancel', 'Cancel')}\n </button>\n </div>\n </form>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"useWorkspaceMembers.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/hooks/useWorkspaceMembers.ts"],"sourcesContent":["import {\n GetWorkspaceMembersDocument,\n useAddWorkspaceMemberMutation,\n useGetWorkspaceMembersQuery,\n useGetWorkspaceMemberQuery,\n useRemoveWorkspaceMemberMutation,\n} from '../../../../generated/global-operations';\nimport type { AddWorkspaceMemberInput, WorkspaceMember } from '../types';\n\n/**\n * Hook to fetch workspace members with pagination\n * Requires an explicit workspace ID from the route/page context.\n *\n * @param limit - Number of members to fetch (default: 50)\n * @param offset - Offset for pagination (default: 0)\n * @returns Query result with members, loading state, and error\n */\nexport function useWorkspaceMembers(workspaceId: string, limit = 50, offset = 0) {\n const { data, loading, error, refetch, fetchMore } = useGetWorkspaceMembersQuery({\n variables: {\n workspaceId,\n limit,\n offset,\n },\n skip: !workspaceId,\n fetchPolicy: 'cache-first',\n nextFetchPolicy: 'cache-first',\n });\n\n return {\n members: (data?.workspaceMembers?.items as WorkspaceMember[]) ?? [],\n total: data?.workspaceMembers?.total ?? 0,\n hasMore: data?.workspaceMembers?.hasMore ?? false,\n loading,\n error,\n refetch,\n fetchMore,\n };\n}\n\n/**\n * Hook to fetch a single workspace member by userId\n *\n * @param userId - The user ID to find\n * @returns Query result with the member, loading state, and error\n */\nexport function useWorkspaceMember(workspaceId: string, userId: string) {\n const { data, loading, error, refetch } = useGetWorkspaceMemberQuery({\n variables: {\n workspaceId,\n userId,\n },\n skip: !workspaceId || !userId,\n fetchPolicy: 'cache-first',\n nextFetchPolicy: 'cache-first',\n });\n\n // Find the member matching the userId from the list\n const member = data?.workspaceMembers?.items?.find(\n (m: { userId: string }) => m.userId === userId\n ) as WorkspaceMember | undefined;\n\n return {\n member,\n loading,\n error,\n refetch,\n };\n}\n\nexport function useAddWorkspaceMember() {\n const [addWorkspaceMember, { loading, error }] = useAddWorkspaceMemberMutation({\n refetchQueries: [GetWorkspaceMembersDocument],\n });\n\n return {\n addWorkspaceMember: async (input: AddWorkspaceMemberInput) => {\n return addWorkspaceMember({ variables: { input } });\n },\n loading,\n error,\n };\n}\n\nexport function useRemoveWorkspaceMember() {\n const [removeWorkspaceMember, { loading, error }] = useRemoveWorkspaceMemberMutation({\n refetchQueries: [GetWorkspaceMembersDocument],\n });\n\n return {\n removeWorkspaceMember: async (workspaceId: string, userId: string) => {\n return removeWorkspaceMember({ variables: { workspaceId, userId } });\n },\n loading,\n error,\n };\n}\n"],"mappings":";;AAiBA,SAAgB,EAAoB,GAAqB,IAAQ,IAAI,IAAS,GAAG;CAC/E,IAAM,EAAE,SAAM,YAAS,UAAO,YAAS,iBAAc,EAA4B;EAC/E,WAAW;GACT;GACA;GACA;GACD;EACD,MAAM,CAAC;EACP,aAAa;EACb,iBAAiB;EAClB,CAAC;AAEF,QAAO;EACL,SAAU,GAAM,kBAAkB,SAA+B,EAAE;EACnE,OAAO,GAAM,kBAAkB,SAAS;EACxC,SAAS,GAAM,kBAAkB,WAAW;EAC5C;EACA;EACA;EACA;EACD;;AAiCH,SAAgB,IAAwB;CACtC,IAAM,CAAC,GAAoB,EAAE,YAAS,cAAW,EAA8B,EAC7E,gBAAgB,CAAC,EAA4B,EAC9C,CAAC;AAEF,QAAO;EACL,oBAAoB,OAAO,MAClB,EAAmB,EAAE,WAAW,EAAE,UAAO,EAAE,CAAC;EAErD;EACA;EACD;;AAGH,SAAgB,IAA2B;CACzC,IAAM,CAAC,GAAuB,EAAE,YAAS,cAAW,EAAiC,EACnF,gBAAgB,CAAC,EAA4B,EAC9C,CAAC;AAEF,QAAO;EACL,uBAAuB,OAAO,GAAqB,MAC1C,EAAsB,EAAE,WAAW;GAAE;GAAa;GAAQ,EAAE,CAAC;EAEtE;EACA;EACD"}
1
+ {"version":3,"file":"useWorkspaceMembers.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/hooks/useWorkspaceMembers.ts"],"sourcesContent":["import {\n GetWorkspaceMembersDocument,\n useAddWorkspaceMemberMutation,\n useGetWorkspaceMembersQuery,\n useRemoveWorkspaceMemberMutation,\n} from '../../../../generated/global-operations';\nimport type { AddWorkspaceMemberInput, WorkspaceMember } from '../types';\n\n/**\n * Hook to fetch workspace members with pagination\n * Requires an explicit workspace ID from the route/page context.\n *\n * @param limit - Number of members to fetch (default: 50)\n * @param offset - Offset for pagination (default: 0)\n * @returns Query result with members, loading state, and error\n */\nexport function useWorkspaceMembers(workspaceId: string, limit = 50, offset = 0) {\n const { data, loading, error, refetch, fetchMore } = useGetWorkspaceMembersQuery({\n variables: {\n workspaceId,\n limit,\n offset,\n },\n skip: !workspaceId,\n fetchPolicy: 'cache-first',\n nextFetchPolicy: 'cache-first',\n });\n\n return {\n members: (data?.workspaceMembers?.items as WorkspaceMember[]) ?? [],\n total: data?.workspaceMembers?.total ?? 0,\n hasMore: data?.workspaceMembers?.hasMore ?? false,\n loading,\n error,\n refetch,\n fetchMore,\n };\n}\n\nexport function useAddWorkspaceMember() {\n const [addWorkspaceMember, { loading, error }] = useAddWorkspaceMemberMutation({\n refetchQueries: [GetWorkspaceMembersDocument],\n });\n\n return {\n addWorkspaceMember: async (input: AddWorkspaceMemberInput) => {\n return addWorkspaceMember({ variables: { input } });\n },\n loading,\n error,\n };\n}\n\nexport function useRemoveWorkspaceMember() {\n const [removeWorkspaceMember, { loading, error }] = useRemoveWorkspaceMemberMutation({\n refetchQueries: [GetWorkspaceMembersDocument],\n });\n\n return {\n removeWorkspaceMember: async (workspaceId: string, userId: string) => {\n return removeWorkspaceMember({ variables: { workspaceId, userId } });\n },\n loading,\n error,\n };\n}\n"],"mappings":";;AAgBA,SAAgB,EAAoB,GAAqB,IAAQ,IAAI,IAAS,GAAG;CAC/E,IAAM,EAAE,SAAM,YAAS,UAAO,YAAS,iBAAc,EAA4B;EAC/E,WAAW;GACT;GACA;GACA;GACD;EACD,MAAM,CAAC;EACP,aAAa;EACb,iBAAiB;EAClB,CAAC;AAEF,QAAO;EACL,SAAU,GAAM,kBAAkB,SAA+B,EAAE;EACnE,OAAO,GAAM,kBAAkB,SAAS;EACxC,SAAS,GAAM,kBAAkB,WAAW;EAC5C;EACA;EACA;EACA;EACD;;AAGH,SAAgB,IAAwB;CACtC,IAAM,CAAC,GAAoB,EAAE,YAAS,cAAW,EAA8B,EAC7E,gBAAgB,CAAC,EAA4B,EAC9C,CAAC;AAEF,QAAO;EACL,oBAAoB,OAAO,MAClB,EAAmB,EAAE,WAAW,EAAE,UAAO,EAAE,CAAC;EAErD;EACA;EACD;;AAGH,SAAgB,IAA2B;CACzC,IAAM,CAAC,GAAuB,EAAE,YAAS,cAAW,EAAiC,EACnF,gBAAgB,CAAC,EAA4B,EAC9C,CAAC;AAEF,QAAO;EACL,uBAAuB,OAAO,GAAqB,MAC1C,EAAsB,EAAE,WAAW;GAAE;GAAa;GAAQ,EAAE,CAAC;EAEtE;EACA;EACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"useWorkspaces.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/hooks/useWorkspaces.ts"],"sourcesContent":["import {\n useGetWorkspacesQuery,\n useGetWorkspaceQuery,\n useGetWorkspaceBySlugQuery,\n useGetWorkspacesByOrganizationQuery,\n useGetTenantsQuery,\n useCreateWorkspaceMutation,\n useUpdateWorkspaceMutation,\n useSuspendWorkspaceMutation,\n useActivateWorkspaceMutation,\n useArchiveWorkspaceMutation,\n GetWorkspacesDocument,\n} from '../../../../generated/global-operations';\nimport type {\n Workspace,\n WorkspaceFilterInput,\n CreateWorkspaceInput,\n UpdateWorkspaceInput,\n} from '../types';\n\n/**\n * Hook to fetch workspaces with filtering and pagination\n * Updated to use offset-based pagination (limit/offset) instead of cursor-based\n */\nexport function useWorkspaces(\n filter?: WorkspaceFilterInput,\n limit: number = 20,\n offset: number = 0\n) {\n const { data, loading, error, refetch, fetchMore } = useGetWorkspacesQuery({\n variables: { filter, limit, offset },\n fetchPolicy: 'cache-first',\n nextFetchPolicy: 'cache-first',\n });\n\n return {\n workspaces: (data?.workspaces?.items as Workspace[]) || [],\n total: data?.workspaces?.total || 0,\n limit: data?.workspaces?.limit || limit,\n offset: data?.workspaces?.offset || offset,\n hasMore: data?.workspaces?.hasMore || false,\n loading,\n error,\n refetch,\n fetchMore,\n };\n}\n\n/**\n * Hook to fetch a single workspace by ID\n */\nexport function useWorkspace(id: string) {\n const { data, loading, error, refetch } = useGetWorkspaceQuery({\n variables: { id },\n skip: !id,\n fetchPolicy: 'cache-and-network',\n nextFetchPolicy: 'cache-first',\n });\n\n return {\n workspace: data?.workspace as Workspace | undefined,\n loading,\n error,\n refetch,\n };\n}\n\n/**\n * Hook to fetch a workspace by slug\n */\nexport function useWorkspaceBySlug(tenantId: string, slug: string) {\n const { data, loading, error, refetch } = useGetWorkspaceBySlugQuery({\n variables: { tenantId, slug },\n skip: !tenantId || !slug,\n fetchPolicy: 'cache-first',\n nextFetchPolicy: 'cache-first',\n });\n\n return {\n workspace: data?.workspaceBySlug as Workspace | undefined,\n loading,\n error,\n refetch,\n };\n}\n\n/**\n * Hook to fetch workspaces by organization ID\n */\nexport function useWorkspacesByOrganization(\n organizationId: string,\n limit: number = 20,\n offset: number = 0\n) {\n const { data, loading, error, refetch, fetchMore } = useGetWorkspacesByOrganizationQuery({\n variables: { organizationId, limit, offset },\n skip: !organizationId,\n fetchPolicy: 'cache-and-network',\n nextFetchPolicy: 'cache-first',\n });\n\n return {\n workspaces: (data?.workspaces?.items as Workspace[]) || [],\n total: data?.workspaces?.total || 0,\n hasMore: data?.workspaces?.hasMore || false,\n loading,\n error,\n refetch,\n fetchMore,\n };\n}\n\n/**\n * Hook to create a new workspace\n */\nexport function useCreateWorkspace() {\n const [createWorkspace, { data, loading, error }] = useCreateWorkspaceMutation({\n refetchQueries: [GetWorkspacesDocument],\n });\n\n return {\n createWorkspace: (input: CreateWorkspaceInput) => createWorkspace({ variables: { input } }),\n data,\n loading,\n error,\n };\n}\n\n/**\n * Hook to update a workspace\n */\nexport function useUpdateWorkspace() {\n const [updateWorkspace, { data, loading, error }] = useUpdateWorkspaceMutation();\n\n return {\n updateWorkspace: (id: string, input: UpdateWorkspaceInput) =>\n updateWorkspace({ variables: { id, input } }),\n data,\n loading,\n error,\n };\n}\n\n/**\n * Hook to delete (suspend) a workspace\n * Note: Backend doesn't have deleteWorkspace, using suspendWorkspace instead\n */\nexport function useDeleteWorkspace() {\n const [deleteWorkspace, { data, loading, error }] = useSuspendWorkspaceMutation({\n refetchQueries: [GetWorkspacesDocument],\n });\n\n return {\n deleteWorkspace: (id: string) => deleteWorkspace({ variables: { id } }),\n data,\n loading,\n error,\n };\n}\n\n/**\n * Hook to activate a workspace\n */\nexport function useActivateWorkspace() {\n const [activateWorkspace, { data, loading, error }] = useActivateWorkspaceMutation();\n\n return {\n activateWorkspace: (id: string) => activateWorkspace({ variables: { id } }),\n data,\n loading,\n error,\n };\n}\n\n/**\n * Hook to deactivate (suspend) a workspace\n */\nexport function useDeactivateWorkspace() {\n const [deactivateWorkspace, { data, loading, error }] = useSuspendWorkspaceMutation();\n\n return {\n deactivateWorkspace: (id: string) => deactivateWorkspace({ variables: { id } }),\n data,\n loading,\n error,\n };\n}\n\n/**\n * Hook to archive a workspace\n */\nexport function useArchiveWorkspace() {\n const [archiveWorkspace, { data, loading, error }] = useArchiveWorkspaceMutation();\n\n return {\n archiveWorkspace: (id: string) => archiveWorkspace({ variables: { id } }),\n data,\n loading,\n error,\n };\n}\n\n/**\n * Tenant type for the tenants query\n */\ninterface Tenant {\n id: string;\n name: string;\n slug: string;\n status: string;\n}\n\n/**\n * Hook to fetch tenants available to the current actor for workspace creation\n */\nexport function useTenants(limit: number = 100, offset: number = 0, enabled: boolean = true) {\n const { data, loading, error, refetch } = useGetTenantsQuery({\n variables: { limit, offset },\n skip: !enabled,\n fetchPolicy: 'cache-first',\n nextFetchPolicy: 'cache-first',\n });\n\n return {\n tenants: (data?.myTenants?.items as Tenant[]) || [],\n total: data?.myTenants?.total || 0,\n loading,\n error,\n refetch,\n };\n}\n"],"mappings":";;AAwBA,SAAgB,EACd,GACA,IAAgB,IAChB,IAAiB,GACjB;CACA,IAAM,EAAE,SAAM,YAAS,UAAO,YAAS,iBAAc,EAAsB;EACzE,WAAW;GAAE;GAAQ;GAAO;GAAQ;EACpC,aAAa;EACb,iBAAiB;EAClB,CAAC;AAEF,QAAO;EACL,YAAa,GAAM,YAAY,SAAyB,EAAE;EAC1D,OAAO,GAAM,YAAY,SAAS;EAClC,OAAO,GAAM,YAAY,SAAS;EAClC,QAAQ,GAAM,YAAY,UAAU;EACpC,SAAS,GAAM,YAAY,WAAW;EACtC;EACA;EACA;EACA;EACD;;AAMH,SAAgB,EAAa,GAAY;CACvC,IAAM,EAAE,SAAM,YAAS,UAAO,eAAY,EAAqB;EAC7D,WAAW,EAAE,OAAI;EACjB,MAAM,CAAC;EACP,aAAa;EACb,iBAAiB;EAClB,CAAC;AAEF,QAAO;EACL,WAAW,GAAM;EACjB;EACA;EACA;EACD;;AAyBH,SAAgB,EACd,GACA,IAAgB,IAChB,IAAiB,GACjB;CACA,IAAM,EAAE,SAAM,YAAS,UAAO,YAAS,iBAAc,EAAoC;EACvF,WAAW;GAAE;GAAgB;GAAO;GAAQ;EAC5C,MAAM,CAAC;EACP,aAAa;EACb,iBAAiB;EAClB,CAAC;AAEF,QAAO;EACL,YAAa,GAAM,YAAY,SAAyB,EAAE;EAC1D,OAAO,GAAM,YAAY,SAAS;EAClC,SAAS,GAAM,YAAY,WAAW;EACtC;EACA;EACA;EACA;EACD;;AAMH,SAAgB,IAAqB;CACnC,IAAM,CAAC,GAAiB,EAAE,SAAM,YAAS,cAAW,EAA2B,EAC7E,gBAAgB,CAAC,EAAsB,EACxC,CAAC;AAEF,QAAO;EACL,kBAAkB,MAAgC,EAAgB,EAAE,WAAW,EAAE,UAAO,EAAE,CAAC;EAC3F;EACA;EACA;EACD;;AAMH,SAAgB,IAAqB;CACnC,IAAM,CAAC,GAAiB,EAAE,SAAM,YAAS,cAAW,GAA4B;AAEhF,QAAO;EACL,kBAAkB,GAAY,MAC5B,EAAgB,EAAE,WAAW;GAAE;GAAI;GAAO,EAAE,CAAC;EAC/C;EACA;EACA;EACD;;AAOH,SAAgB,IAAqB;CACnC,IAAM,CAAC,GAAiB,EAAE,SAAM,YAAS,cAAW,EAA4B,EAC9E,gBAAgB,CAAC,EAAsB,EACxC,CAAC;AAEF,QAAO;EACL,kBAAkB,MAAe,EAAgB,EAAE,WAAW,EAAE,OAAI,EAAE,CAAC;EACvE;EACA;EACA;EACD;;AA0DH,SAAgB,EAAW,IAAgB,KAAK,IAAiB,GAAG,IAAmB,IAAM;CAC3F,IAAM,EAAE,SAAM,YAAS,UAAO,eAAY,EAAmB;EAC3D,WAAW;GAAE;GAAO;GAAQ;EAC5B,MAAM,CAAC;EACP,aAAa;EACb,iBAAiB;EAClB,CAAC;AAEF,QAAO;EACL,SAAU,GAAM,WAAW,SAAsB,EAAE;EACnD,OAAO,GAAM,WAAW,SAAS;EACjC;EACA;EACA;EACD"}
1
+ {"version":3,"file":"useWorkspaces.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/hooks/useWorkspaces.ts"],"sourcesContent":["import {\n useGetWorkspacesQuery,\n useGetWorkspaceQuery,\n useGetWorkspacesByOrganizationQuery,\n useGetTenantsQuery,\n useCreateWorkspaceMutation,\n useUpdateWorkspaceMutation,\n useSuspendWorkspaceMutation,\n GetWorkspacesDocument,\n} from '../../../../generated/global-operations';\nimport type {\n Workspace,\n WorkspaceFilterInput,\n CreateWorkspaceInput,\n UpdateWorkspaceInput,\n} from '../types';\n\n/**\n * Hook to fetch workspaces with filtering and pagination\n * Updated to use offset-based pagination (limit/offset) instead of cursor-based\n */\nexport function useWorkspaces(\n filter?: WorkspaceFilterInput,\n limit: number = 20,\n offset: number = 0\n) {\n const { data, loading, error, refetch, fetchMore } = useGetWorkspacesQuery({\n variables: { filter, limit, offset },\n fetchPolicy: 'cache-first',\n nextFetchPolicy: 'cache-first',\n });\n\n return {\n workspaces: (data?.workspaces?.items as Workspace[]) || [],\n total: data?.workspaces?.total || 0,\n limit: data?.workspaces?.limit || limit,\n offset: data?.workspaces?.offset || offset,\n hasMore: data?.workspaces?.hasMore || false,\n loading,\n error,\n refetch,\n fetchMore,\n };\n}\n\n/**\n * Hook to fetch a single workspace by ID\n */\nexport function useWorkspace(id: string) {\n const { data, loading, error, refetch } = useGetWorkspaceQuery({\n variables: { id },\n skip: !id,\n fetchPolicy: 'cache-and-network',\n nextFetchPolicy: 'cache-first',\n });\n\n return {\n workspace: data?.workspace as Workspace | undefined,\n loading,\n error,\n refetch,\n };\n}\n\n/**\n * Hook to fetch workspaces by organization ID\n */\nexport function useWorkspacesByOrganization(\n organizationId: string,\n limit: number = 20,\n offset: number = 0\n) {\n const { data, loading, error, refetch, fetchMore } = useGetWorkspacesByOrganizationQuery({\n variables: { organizationId, limit, offset },\n skip: !organizationId,\n fetchPolicy: 'cache-and-network',\n nextFetchPolicy: 'cache-first',\n });\n\n return {\n workspaces: (data?.workspaces?.items as Workspace[]) || [],\n total: data?.workspaces?.total || 0,\n hasMore: data?.workspaces?.hasMore || false,\n loading,\n error,\n refetch,\n fetchMore,\n };\n}\n\n/**\n * Hook to create a new workspace\n */\nexport function useCreateWorkspace() {\n const [createWorkspace, { data, loading, error }] = useCreateWorkspaceMutation({\n refetchQueries: [GetWorkspacesDocument],\n });\n\n return {\n createWorkspace: (input: CreateWorkspaceInput) => createWorkspace({ variables: { input } }),\n data,\n loading,\n error,\n };\n}\n\n/**\n * Hook to update a workspace\n */\nexport function useUpdateWorkspace() {\n const [updateWorkspace, { data, loading, error }] = useUpdateWorkspaceMutation();\n\n return {\n updateWorkspace: (id: string, input: UpdateWorkspaceInput) =>\n updateWorkspace({ variables: { id, input } }),\n data,\n loading,\n error,\n };\n}\n\n/**\n * Hook to delete (suspend) a workspace\n * Note: Backend doesn't have deleteWorkspace, using suspendWorkspace instead\n */\nexport function useDeleteWorkspace() {\n const [deleteWorkspace, { data, loading, error }] = useSuspendWorkspaceMutation({\n refetchQueries: [GetWorkspacesDocument],\n });\n\n return {\n deleteWorkspace: (id: string) => deleteWorkspace({ variables: { id } }),\n data,\n loading,\n error,\n };\n}\n\n/**\n * Tenant type for the tenants query\n */\ninterface Tenant {\n id: string;\n name: string;\n slug: string;\n status: string;\n}\n\n/**\n * Hook to fetch tenants available to the current actor for workspace creation\n */\nexport function useTenants(limit: number = 100, offset: number = 0, enabled: boolean = true) {\n const { data, loading, error, refetch } = useGetTenantsQuery({\n variables: { limit, offset },\n skip: !enabled,\n fetchPolicy: 'cache-first',\n nextFetchPolicy: 'cache-first',\n });\n\n return {\n tenants: (data?.myTenants?.items as Tenant[]) || [],\n total: data?.myTenants?.total || 0,\n loading,\n error,\n refetch,\n };\n}\n"],"mappings":";;AAqBA,SAAgB,EACd,GACA,IAAgB,IAChB,IAAiB,GACjB;CACA,IAAM,EAAE,SAAM,YAAS,UAAO,YAAS,iBAAc,EAAsB;EACzE,WAAW;GAAE;GAAQ;GAAO;GAAQ;EACpC,aAAa;EACb,iBAAiB;EAClB,CAAC;AAEF,QAAO;EACL,YAAa,GAAM,YAAY,SAAyB,EAAE;EAC1D,OAAO,GAAM,YAAY,SAAS;EAClC,OAAO,GAAM,YAAY,SAAS;EAClC,QAAQ,GAAM,YAAY,UAAU;EACpC,SAAS,GAAM,YAAY,WAAW;EACtC;EACA;EACA;EACA;EACD;;AAMH,SAAgB,EAAa,GAAY;CACvC,IAAM,EAAE,SAAM,YAAS,UAAO,eAAY,EAAqB;EAC7D,WAAW,EAAE,OAAI;EACjB,MAAM,CAAC;EACP,aAAa;EACb,iBAAiB;EAClB,CAAC;AAEF,QAAO;EACL,WAAW,GAAM;EACjB;EACA;EACA;EACD;;AAMH,SAAgB,EACd,GACA,IAAgB,IAChB,IAAiB,GACjB;CACA,IAAM,EAAE,SAAM,YAAS,UAAO,YAAS,iBAAc,EAAoC;EACvF,WAAW;GAAE;GAAgB;GAAO;GAAQ;EAC5C,MAAM,CAAC;EACP,aAAa;EACb,iBAAiB;EAClB,CAAC;AAEF,QAAO;EACL,YAAa,GAAM,YAAY,SAAyB,EAAE;EAC1D,OAAO,GAAM,YAAY,SAAS;EAClC,SAAS,GAAM,YAAY,WAAW;EACtC;EACA;EACA;EACA;EACD;;AAMH,SAAgB,IAAqB;CACnC,IAAM,CAAC,GAAiB,EAAE,SAAM,YAAS,cAAW,EAA2B,EAC7E,gBAAgB,CAAC,EAAsB,EACxC,CAAC;AAEF,QAAO;EACL,kBAAkB,MAAgC,EAAgB,EAAE,WAAW,EAAE,UAAO,EAAE,CAAC;EAC3F;EACA;EACA;EACD;;AAMH,SAAgB,IAAqB;CACnC,IAAM,CAAC,GAAiB,EAAE,SAAM,YAAS,cAAW,GAA4B;AAEhF,QAAO;EACL,kBAAkB,GAAY,MAC5B,EAAgB,EAAE,WAAW;GAAE;GAAI;GAAO,EAAE,CAAC;EAC/C;EACA;EACA;EACD;;AAOH,SAAgB,IAAqB;CACnC,IAAM,CAAC,GAAiB,EAAE,SAAM,YAAS,cAAW,EAA4B,EAC9E,gBAAgB,CAAC,EAAsB,EACxC,CAAC;AAEF,QAAO;EACL,kBAAkB,MAAe,EAAgB,EAAE,WAAW,EAAE,OAAI,EAAE,CAAC;EACvE;EACA;EACA;EACD;;AAgBH,SAAgB,EAAW,IAAgB,KAAK,IAAiB,GAAG,IAAmB,IAAM;CAC3F,IAAM,EAAE,SAAM,YAAS,UAAO,eAAY,EAAmB;EAC3D,WAAW;GAAE;GAAO;GAAQ;EAC5B,MAAM,CAAC;EACP,aAAa;EACb,iBAAiB;EAClB,CAAC;AAEF,QAAO;EACL,SAAU,GAAM,WAAW,SAAsB,EAAE;EACnD,OAAO,GAAM,WAAW,SAAS;EACjC;EACA;EACA;EACD"}
@@ -35,6 +35,7 @@ function f() {
35
35
  className: "mb-6",
36
36
  children: [
37
37
  /* @__PURE__ */ u("button", {
38
+ type: "button",
38
39
  onClick: S,
39
40
  className: "\n inline-flex items-center gap-2 mb-4\n text-[var(--color-text-secondary)]\n hover:text-[var(--color-text-primary)]\n active:scale-[0.98]\n transition-all duration-200\n ",
40
41
  children: [/* @__PURE__ */ l(s, { size: 20 }), /* @__PURE__ */ l("span", {
@@ -1 +1 @@
1
- {"version":3,"file":"WorkspaceCreatePage.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/pages/WorkspaceCreatePage.tsx"],"sourcesContent":["import { ArrowLeft } from 'lucide-react';\nimport { useSearchParams } from 'react-router-dom';\nimport { toast } from 'sonner';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\nimport { useCreateWorkspace } from '../hooks/useWorkspaces';\nimport { useOrganization } from '../../organizations/hooks/useOrganizations';\nimport { WorkspaceForm } from '../components/WorkspaceForm';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { useTr } from '../../../shared/hooks/useTr';\nimport type { CreateWorkspaceInput, UpdateWorkspaceInput } from '../types';\n\nexport function WorkspaceCreatePage() {\n const tr = useTr();\n const { navigate, basePath = '/organizations' } = useOrgConsole();\n // `usePermissions` is still used for the permissionsLoading gate below\n // even though the static workspace:create page-level guard was removed\n // (see comment further down) — keep the hook call so the loading\n // skeleton still waits for the provider to settle before mounting the\n // form.\n const { isLoading: permissionsLoading } = usePermissions();\n const { createWorkspace, loading } = useCreateWorkspace();\n const [searchParams] = useSearchParams();\n\n // Get organizationId from URL query params (e.g., ?organizationId=xxx)\n const organizationIdFromUrl = searchParams.get('organizationId') || undefined;\n\n // Fetch organization details if ID is provided (to show org name and get tenantId)\n const { organization } = useOrganization(organizationIdFromUrl || '');\n\n const handleSubmit = async (data: CreateWorkspaceInput | UpdateWorkspaceInput) => {\n try {\n const createData = data as CreateWorkspaceInput;\n const result = await createWorkspace(createData);\n if (result.data?.createWorkspace) {\n toast.success(tr('workspaces.create.success', 'Workspace created successfully'));\n if (organizationIdFromUrl) {\n navigate(`${basePath}/${organizationIdFromUrl}`);\n } else {\n navigate(`${basePath}/workspaces/${result.data.createWorkspace.id}`);\n }\n } else if (result.errors && result.errors.length > 0) {\n // Handle GraphQL errors returned in result\n const errorMessage =\n result.errors[0]?.message || tr('workspaces.create.failed', 'Failed to create workspace');\n const errorCode = result.errors[0]?.extensions?.code;\n\n if (errorCode === 'UNAUTHENTICATED') {\n toast.error(tr('common.authRequired', 'Authentication required. Please log in again.'));\n } else {\n toast.error(errorMessage);\n }\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error\n ? error.message\n : tr('common.unexpectedError', 'An unexpected error occurred');\n toast.error(errorMessage);\n }\n };\n\n const handleCancel = () => {\n // Navigate back to organization if came from there, otherwise to workspaces list\n if (organizationIdFromUrl) {\n navigate(`${basePath}/${organizationIdFromUrl}`);\n } else {\n navigate(`${basePath}/workspaces`);\n }\n };\n\n if (permissionsLoading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <LoadingState message={tr('common.loadingPermissions', 'Loading permissions...')} />\n </div>\n );\n }\n\n // NOTE: deliberately NOT gating on hasPermission(WORKSPACE_CREATE) at the\n // page level. `usePermissions()` here resolves at the outer tenant scope\n // (from OrgConsoleProvider), and `workspace:create` is an org-scope\n // permission — a user who is Owner of even one org would be incorrectly\n // denied entry to the form. WorkspaceForm's organization dropdown is\n // permission-filtered (only orgs where the user actually has\n // workspace:create are listed), and the backend @rbac directive on the\n // createWorkspace mutation is the authoritative enforcement point. If a\n // user has no orgs they can create a workspace in, the dropdown will\n // surface that message and submit will stay disabled.\n\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6 animate-in fade-in duration-300\">\n <div className=\"mb-6\">\n <button\n onClick={handleCancel}\n className=\"\n inline-flex items-center gap-2 mb-4\n text-[var(--color-text-secondary)]\n hover:text-[var(--color-text-primary)]\n active:scale-[0.98]\n transition-all duration-200\n \"\n >\n <ArrowLeft size={20} />\n <span className=\"text-sm font-medium\">\n {organizationIdFromUrl\n ? `${tr('common.backTo', 'Back to')} ${organization?.name || tr('common.organization', 'Organization')}`\n : tr('workspaces.create.backToWorkspaces', 'Back to Workspaces')}\n </span>\n </button>\n\n <h1 className=\"text-3xl font-bold text-[var(--color-text-primary)] mb-2\">\n {tr('workspaces.create.title', 'Create Workspace')}\n </h1>\n <p className=\"text-[var(--color-text-secondary)]\">\n {organizationIdFromUrl && organization\n ? `${tr('workspaces.create.subtitleForOrg', 'Add a new workspace to')} ${organization.name}`\n : tr('workspaces.create.subtitle', 'Add a new workspace to an organization')}\n </p>\n </div>\n\n <div className=\"max-w-2xl\">\n <div className=\"bg-[var(--color-bg-surface)] border border-[var(--color-border-default)] rounded-lg p-6 shadow-[var(--shadow-elevation-1)]\">\n <WorkspaceForm\n tenantId={organization?.tenantId}\n tenantName={organization?.tenantId}\n organizationId={organizationIdFromUrl}\n organizationName={organization?.name}\n showOrganizationSelector={!organizationIdFromUrl}\n onSubmit={handleSubmit}\n onCancel={handleCancel}\n loading={loading}\n />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAYA,SAAgB,IAAsB;CACpC,IAAM,IAAK,GAAO,EACZ,EAAE,aAAU,cAAW,qBAAqB,GAAe,EAM3D,EAAE,WAAW,MAAuB,GAAgB,EACpD,EAAE,oBAAiB,eAAY,GAAoB,EACnD,CAAC,KAAgB,GAAiB,EAGlC,IAAwB,EAAa,IAAI,iBAAiB,IAAI,KAAA,GAG9D,EAAE,oBAAiB,EAAgB,KAAyB,GAAG,EAE/D,IAAe,OAAO,MAAsD;AAChF,MAAI;GAEF,IAAM,IAAS,MAAM,EADF,EAC6B;AAChD,OAAI,EAAO,MAAM,gBAEf,CADA,EAAM,QAAQ,EAAG,6BAA6B,iCAAiC,CAAC,EAE9E,EADE,IACO,GAAG,EAAS,GAAG,MAEf,GAAG,EAAS,cAAc,EAAO,KAAK,gBAAgB,KAAK;YAE7D,EAAO,UAAU,EAAO,OAAO,SAAS,GAAG;IAEpD,IAAM,IACJ,EAAO,OAAO,IAAI,WAAW,EAAG,4BAA4B,6BAA6B;AAG3F,IAFkB,EAAO,OAAO,IAAI,YAAY,SAE9B,oBAChB,EAAM,MAAM,EAAG,uBAAuB,gDAAgD,CAAC,GAEvF,EAAM,MAAM,EAAa;;WAGtB,GAAO;GACd,IAAM,IACJ,aAAiB,QACb,EAAM,UACN,EAAG,0BAA0B,+BAA+B;AAClE,KAAM,MAAM,EAAa;;IAIvB,UAAqB;AAEzB,EACE,EADE,IACO,GAAG,EAAS,GAAG,MAEf,GAAG,EAAS,aAAa;;AAuBtC,QAnBI,IAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD,EAAc,SAAS,EAAG,6BAA6B,yBAAyB,EAAI,CAAA;EAChF,CAAA,GAgBR,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,UAAD;KACE,SAAS;KACT,WAAU;eAFZ,CAUE,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA,EACvB,kBAAC,QAAD;MAAM,WAAU;gBACb,IACG,GAAG,EAAG,iBAAiB,UAAU,CAAC,GAAG,GAAc,QAAQ,EAAG,uBAAuB,eAAe,KACpG,EAAG,sCAAsC,qBAAqB;MAC7D,CAAA,CACA;;IAET,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,2BAA2B,mBAAmB;KAC/C,CAAA;IACL,kBAAC,KAAD;KAAG,WAAU;eACV,KAAyB,IACtB,GAAG,EAAG,oCAAoC,yBAAyB,CAAC,GAAG,EAAa,SACpF,EAAG,8BAA8B,yCAAyC;KAC5E,CAAA;IACA;MAEN,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD;KACE,UAAU,GAAc;KACxB,YAAY,GAAc;KAC1B,gBAAgB;KAChB,kBAAkB,GAAc;KAChC,0BAA0B,CAAC;KAC3B,UAAU;KACV,UAAU;KACD;KACT,CAAA;IACE,CAAA;GACF,CAAA,CACF"}
1
+ {"version":3,"file":"WorkspaceCreatePage.js","names":[],"sources":["../../../../../src/organization-management/modules/workspaces/pages/WorkspaceCreatePage.tsx"],"sourcesContent":["import { ArrowLeft } from 'lucide-react';\nimport { useSearchParams } from 'react-router-dom';\nimport { toast } from 'sonner';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\nimport { useCreateWorkspace } from '../hooks/useWorkspaces';\nimport { useOrganization } from '../../organizations/hooks/useOrganizations';\nimport { WorkspaceForm } from '../components/WorkspaceForm';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { useTr } from '../../../shared/hooks/useTr';\nimport type { CreateWorkspaceInput, UpdateWorkspaceInput } from '../types';\n\nexport function WorkspaceCreatePage() {\n const tr = useTr();\n const { navigate, basePath = '/organizations' } = useOrgConsole();\n // `usePermissions` is still used for the permissionsLoading gate below\n // even though the static workspace:create page-level guard was removed\n // (see comment further down) — keep the hook call so the loading\n // skeleton still waits for the provider to settle before mounting the\n // form.\n const { isLoading: permissionsLoading } = usePermissions();\n const { createWorkspace, loading } = useCreateWorkspace();\n const [searchParams] = useSearchParams();\n\n // Get organizationId from URL query params (e.g., ?organizationId=xxx)\n const organizationIdFromUrl = searchParams.get('organizationId') || undefined;\n\n // Fetch organization details if ID is provided (to show org name and get tenantId)\n const { organization } = useOrganization(organizationIdFromUrl || '');\n\n const handleSubmit = async (data: CreateWorkspaceInput | UpdateWorkspaceInput) => {\n try {\n const createData = data as CreateWorkspaceInput;\n const result = await createWorkspace(createData);\n if (result.data?.createWorkspace) {\n toast.success(tr('workspaces.create.success', 'Workspace created successfully'));\n if (organizationIdFromUrl) {\n navigate(`${basePath}/${organizationIdFromUrl}`);\n } else {\n navigate(`${basePath}/workspaces/${result.data.createWorkspace.id}`);\n }\n } else if (result.errors && result.errors.length > 0) {\n // Handle GraphQL errors returned in result\n const errorMessage =\n result.errors[0]?.message || tr('workspaces.create.failed', 'Failed to create workspace');\n const errorCode = result.errors[0]?.extensions?.code;\n\n if (errorCode === 'UNAUTHENTICATED') {\n toast.error(tr('common.authRequired', 'Authentication required. Please log in again.'));\n } else {\n toast.error(errorMessage);\n }\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error\n ? error.message\n : tr('common.unexpectedError', 'An unexpected error occurred');\n toast.error(errorMessage);\n }\n };\n\n const handleCancel = () => {\n // Navigate back to organization if came from there, otherwise to workspaces list\n if (organizationIdFromUrl) {\n navigate(`${basePath}/${organizationIdFromUrl}`);\n } else {\n navigate(`${basePath}/workspaces`);\n }\n };\n\n if (permissionsLoading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <LoadingState message={tr('common.loadingPermissions', 'Loading permissions...')} />\n </div>\n );\n }\n\n // NOTE: deliberately NOT gating on hasPermission(WORKSPACE_CREATE) at the\n // page level. `usePermissions()` here resolves at the outer tenant scope\n // (from OrgConsoleProvider), and `workspace:create` is an org-scope\n // permission — a user who is Owner of even one org would be incorrectly\n // denied entry to the form. WorkspaceForm's organization dropdown is\n // permission-filtered (only orgs where the user actually has\n // workspace:create are listed), and the backend @rbac directive on the\n // createWorkspace mutation is the authoritative enforcement point. If a\n // user has no orgs they can create a workspace in, the dropdown will\n // surface that message and submit will stay disabled.\n\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6 animate-in fade-in duration-300\">\n <div className=\"mb-6\">\n <button type=\"button\"\n onClick={handleCancel}\n className=\"\n inline-flex items-center gap-2 mb-4\n text-[var(--color-text-secondary)]\n hover:text-[var(--color-text-primary)]\n active:scale-[0.98]\n transition-all duration-200\n \"\n >\n <ArrowLeft size={20} />\n <span className=\"text-sm font-medium\">\n {organizationIdFromUrl\n ? `${tr('common.backTo', 'Back to')} ${organization?.name || tr('common.organization', 'Organization')}`\n : tr('workspaces.create.backToWorkspaces', 'Back to Workspaces')}\n </span>\n </button>\n\n <h1 className=\"text-3xl font-bold text-[var(--color-text-primary)] mb-2\">\n {tr('workspaces.create.title', 'Create Workspace')}\n </h1>\n <p className=\"text-[var(--color-text-secondary)]\">\n {organizationIdFromUrl && organization\n ? `${tr('workspaces.create.subtitleForOrg', 'Add a new workspace to')} ${organization.name}`\n : tr('workspaces.create.subtitle', 'Add a new workspace to an organization')}\n </p>\n </div>\n\n <div className=\"max-w-2xl\">\n <div className=\"bg-[var(--color-bg-surface)] border border-[var(--color-border-default)] rounded-lg p-6 shadow-[var(--shadow-elevation-1)]\">\n <WorkspaceForm\n tenantId={organization?.tenantId}\n tenantName={organization?.tenantId}\n organizationId={organizationIdFromUrl}\n organizationName={organization?.name}\n showOrganizationSelector={!organizationIdFromUrl}\n onSubmit={handleSubmit}\n onCancel={handleCancel}\n loading={loading}\n />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAYA,SAAgB,IAAsB;CACpC,IAAM,IAAK,GAAO,EACZ,EAAE,aAAU,cAAW,qBAAqB,GAAe,EAM3D,EAAE,WAAW,MAAuB,GAAgB,EACpD,EAAE,oBAAiB,eAAY,GAAoB,EACnD,CAAC,KAAgB,GAAiB,EAGlC,IAAwB,EAAa,IAAI,iBAAiB,IAAI,KAAA,GAG9D,EAAE,oBAAiB,EAAgB,KAAyB,GAAG,EAE/D,IAAe,OAAO,MAAsD;AAChF,MAAI;GAEF,IAAM,IAAS,MAAM,EADF,EAC6B;AAChD,OAAI,EAAO,MAAM,gBAEf,CADA,EAAM,QAAQ,EAAG,6BAA6B,iCAAiC,CAAC,EAE9E,EADE,IACO,GAAG,EAAS,GAAG,MAEf,GAAG,EAAS,cAAc,EAAO,KAAK,gBAAgB,KAAK;YAE7D,EAAO,UAAU,EAAO,OAAO,SAAS,GAAG;IAEpD,IAAM,IACJ,EAAO,OAAO,IAAI,WAAW,EAAG,4BAA4B,6BAA6B;AAG3F,IAFkB,EAAO,OAAO,IAAI,YAAY,SAE9B,oBAChB,EAAM,MAAM,EAAG,uBAAuB,gDAAgD,CAAC,GAEvF,EAAM,MAAM,EAAa;;WAGtB,GAAO;GACd,IAAM,IACJ,aAAiB,QACb,EAAM,UACN,EAAG,0BAA0B,+BAA+B;AAClE,KAAM,MAAM,EAAa;;IAIvB,UAAqB;AAEzB,EACE,EADE,IACO,GAAG,EAAS,GAAG,MAEf,GAAG,EAAS,aAAa;;AAuBtC,QAnBI,IAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD,EAAc,SAAS,EAAG,6BAA6B,yBAAyB,EAAI,CAAA;EAChF,CAAA,GAgBR,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,UAAD;KAAQ,MAAK;KACX,SAAS;KACT,WAAU;eAFZ,CAUE,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA,EACvB,kBAAC,QAAD;MAAM,WAAU;gBACb,IACG,GAAG,EAAG,iBAAiB,UAAU,CAAC,GAAG,GAAc,QAAQ,EAAG,uBAAuB,eAAe,KACpG,EAAG,sCAAsC,qBAAqB;MAC7D,CAAA,CACA;;IAET,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,2BAA2B,mBAAmB;KAC/C,CAAA;IACL,kBAAC,KAAD;KAAG,WAAU;eACV,KAAyB,IACtB,GAAG,EAAG,oCAAoC,yBAAyB,CAAC,GAAG,EAAa,SACpF,EAAG,8BAA8B,yCAAyC;KAC5E,CAAA;IACA;MAEN,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD;KACE,UAAU,GAAc;KACxB,YAAY,GAAc;KAC1B,gBAAgB;KAChB,kBAAkB,GAAc;KAChC,0BAA0B,CAAC;KAC3B,UAAU;KACV,UAAU;KACD;KACT,CAAA;IACE,CAAA;GACF,CAAA,CACF"}
@@ -75,6 +75,7 @@ function O() {
75
75
  children: [/* @__PURE__ */ T("div", {
76
76
  className: "space-y-4",
77
77
  children: [/* @__PURE__ */ T("button", {
78
+ type: "button",
78
79
  onClick: () => A(`${j}/workspaces`),
79
80
  className: "inline-flex min-h-10 items-center gap-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:text-[var(--color-text-primary)] active:scale-[0.98]",
80
81
  children: [/* @__PURE__ */ w(g, {
@@ -89,7 +90,7 @@ function O() {
89
90
  children: [/* @__PURE__ */ T("div", {
90
91
  className: "flex min-w-0 items-start gap-4",
91
92
  children: [/* @__PURE__ */ w("div", {
92
- className: "flex h-16 w-16 items-center justify-center rounded-xl bg-[var(--color-status-info-bgSubtle)] text-[var(--color-status-info-text)]",
93
+ className: "flex size-16 items-center justify-center rounded-xl bg-[var(--color-status-info-bgSubtle)] text-[var(--color-status-info-text)]",
93
94
  children: /* @__PURE__ */ w(_, {
94
95
  size: 28,
95
96
  "aria-hidden": "true"
@@ -117,6 +118,7 @@ function O() {
117
118
  }), /* @__PURE__ */ T("div", {
118
119
  className: "flex flex-col gap-3 sm:flex-row",
119
120
  children: [/* @__PURE__ */ T("button", {
121
+ type: "button",
120
122
  onClick: () => A(`${j}/${P.organizationId}`),
121
123
  className: "inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-border-default)] px-4 py-2.5 text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]",
122
124
  children: [/* @__PURE__ */ w(x, {
@@ -124,6 +126,7 @@ function O() {
124
126
  "aria-hidden": "true"
125
127
  }), /* @__PURE__ */ w("span", { children: O("workspaces.detail.viewOrganization", "View Organization") })]
126
128
  }), M(s.WORKSPACE_UPDATE) && /* @__PURE__ */ T("button", {
129
+ type: "button",
127
130
  onClick: () => A(`${j}/workspaces/${k}/edit`),
128
131
  className: "inline-flex min-h-11 items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-4 py-2.5 text-[var(--color-action-primary-text)] transition-all duration-200 hover:opacity-90 active:scale-[0.98]",
129
132
  children: [/* @__PURE__ */ w(v, {
@@ -142,6 +145,7 @@ function O() {
142
145
  children: X.map((e) => {
143
146
  let t = L === e.id;
144
147
  return /* @__PURE__ */ w("button", {
148
+ type: "button",
145
149
  onClick: () => R(e.id),
146
150
  className: `inline-flex min-h-11 items-center rounded-t-lg border-b-2 px-4 py-3 text-sm font-medium transition-colors ${t ? "border-[var(--color-action-primary-bg)] text-[var(--color-action-primary-bg)]" : "border-transparent text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)]"}`,
147
151
  "aria-pressed": t,
@@ -261,6 +265,7 @@ function O() {
261
265
  className: "text-sm text-[var(--color-text-secondary)]",
262
266
  children: O("workspaces.detail.membersSubtitle", "Add organization members to this workspace and manage access.")
263
267
  })] }), M(s.MEMBER_INVITE) && /* @__PURE__ */ T("button", {
268
+ type: "button",
264
269
  onClick: () => B(!0),
265
270
  className: "inline-flex min-h-11 items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-4 py-2.5 text-[var(--color-action-primary-text)] transition-all duration-200 hover:opacity-90 active:scale-[0.98]",
266
271
  children: [/* @__PURE__ */ w(b, {
@@ -314,6 +319,7 @@ function O() {
314
319
  })] })
315
320
  }),
316
321
  /* @__PURE__ */ T("button", {
322
+ type: "button",
317
323
  onClick: () => Z(e.userId),
318
324
  disabled: J,
319
325
  className: "inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-status-error-border)] px-3 py-2 text-sm text-[var(--color-status-error-text)] transition-all duration-200 hover:bg-[var(--color-status-error-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50",
@@ -379,6 +385,7 @@ function O() {
379
385
  /* @__PURE__ */ w("td", {
380
386
  className: "px-6 py-4 text-right",
381
387
  children: /* @__PURE__ */ w("button", {
388
+ type: "button",
382
389
  onClick: () => Z(e.userId),
383
390
  disabled: J,
384
391
  className: "rounded-lg p-2 text-[var(--color-status-error-text)] transition-all duration-200 hover:bg-[var(--color-status-error-bgSubtle)] disabled:cursor-not-allowed disabled:opacity-50",