@burdenoff/microfe-organization 2026.1013.2 → 2026.1101.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generated/global-operations.js +57 -58
- package/dist/generated/global-operations.js.map +1 -1
- package/dist/generated/global-types.js +1 -2
- package/dist/generated/global-types.js.map +1 -1
- package/dist/node_modules/sonner/dist/index.js +2 -3
- package/dist/node_modules/sonner/dist/index.js.map +1 -1
- package/dist/node_modules/zod/v4/classic/errors.js +44 -0
- package/dist/node_modules/zod/v4/classic/errors.js.map +1 -0
- package/dist/node_modules/zod/v4/classic/parse.js +7 -0
- package/dist/node_modules/zod/v4/classic/parse.js.map +1 -0
- package/dist/node_modules/zod/v4/classic/schemas.js +652 -0
- package/dist/node_modules/zod/v4/classic/schemas.js.map +1 -0
- package/dist/node_modules/zod/v4/core/api.js +429 -0
- package/dist/node_modules/zod/v4/core/api.js.map +1 -0
- package/dist/node_modules/zod/v4/core/checks.js +143 -0
- package/dist/node_modules/zod/v4/core/checks.js.map +1 -0
- package/dist/node_modules/zod/v4/core/core.js +84 -0
- package/dist/node_modules/zod/v4/core/core.js.map +1 -0
- package/dist/node_modules/zod/v4/core/doc.js +29 -0
- package/dist/node_modules/zod/v4/core/doc.js.map +1 -0
- package/dist/node_modules/zod/v4/core/errors.js +90 -0
- package/dist/node_modules/zod/v4/core/errors.js.map +1 -0
- package/dist/node_modules/zod/v4/core/json-schema-processors.js +285 -0
- package/dist/node_modules/zod/v4/core/json-schema-processors.js.map +1 -0
- package/dist/node_modules/zod/v4/core/memoizer.js +188 -0
- package/dist/node_modules/zod/v4/core/memoizer.js.map +1 -0
- package/dist/node_modules/zod/v4/core/parse.js +159 -0
- package/dist/node_modules/zod/v4/core/parse.js.map +1 -0
- package/dist/node_modules/zod/v4/core/regexes.js +34 -0
- package/dist/node_modules/zod/v4/core/regexes.js.map +1 -0
- package/dist/node_modules/zod/v4/core/registries.js +41 -0
- package/dist/node_modules/zod/v4/core/registries.js.map +1 -0
- package/dist/node_modules/zod/v4/core/schemas.js +979 -0
- package/dist/node_modules/zod/v4/core/schemas.js.map +1 -0
- package/dist/node_modules/zod/v4/core/to-json-schema.js +330 -0
- package/dist/node_modules/zod/v4/core/to-json-schema.js.map +1 -0
- package/dist/node_modules/zod/v4/core/util.js +417 -0
- package/dist/node_modules/zod/v4/core/util.js.map +1 -0
- package/dist/node_modules/zod/v4/core/versions.js +9 -0
- package/dist/node_modules/zod/v4/core/versions.js.map +1 -0
- package/dist/node_modules/zod/v4/locales/en.js +96 -0
- package/dist/node_modules/zod/v4/locales/en.js.map +1 -0
- package/dist/organization-management/AdminOrganizationRoot.js +13 -10
- package/dist/organization-management/AdminOrganizationRoot.js.map +1 -1
- package/dist/organization-management/AdminOrganizationRoutes.js +53 -47
- package/dist/organization-management/AdminOrganizationRoutes.js.map +1 -1
- package/dist/organization-management/UserOrganizationRoot.js +13 -10
- package/dist/organization-management/UserOrganizationRoot.js.map +1 -1
- package/dist/organization-management/UserOrganizationRoutes.js +52 -46
- package/dist/organization-management/UserOrganizationRoutes.js.map +1 -1
- package/dist/organization-management/constants/permissions.js +1 -2
- package/dist/organization-management/constants/permissions.js.map +1 -1
- package/dist/organization-management/hooks/useOrganizationEventEmitter.js +1 -2
- package/dist/organization-management/hooks/useOrganizationEventEmitter.js.map +1 -1
- package/dist/organization-management/hooks/useOrganizationPageView.js +1 -2
- package/dist/organization-management/hooks/useOrganizationPageView.js.map +1 -1
- package/dist/organization-management/modules/members/components/BulkInviteForm.js +3 -3
- package/dist/organization-management/modules/members/components/BulkInviteForm.js.map +1 -1
- package/dist/organization-management/modules/members/components/InviteMemberForm.js +1 -2
- package/dist/organization-management/modules/members/components/InviteMemberForm.js.map +1 -1
- package/dist/organization-management/modules/members/components/InviteStatusBadge.js +1 -2
- package/dist/organization-management/modules/members/components/InviteStatusBadge.js.map +1 -1
- package/dist/organization-management/modules/members/components/MemberRoleBadge.js +1 -2
- package/dist/organization-management/modules/members/components/MemberRoleBadge.js.map +1 -1
- package/dist/organization-management/modules/members/components/MyInviteCard.js +5 -6
- package/dist/organization-management/modules/members/components/MyInviteCard.js.map +1 -1
- package/dist/organization-management/modules/members/components/PendingInvitesList.js +8 -9
- package/dist/organization-management/modules/members/components/PendingInvitesList.js.map +1 -1
- package/dist/organization-management/modules/members/hooks/useInvites.js +2 -3
- package/dist/organization-management/modules/members/hooks/useInvites.js.map +1 -1
- package/dist/organization-management/modules/members/hooks/useMembers.js +1 -2
- package/dist/organization-management/modules/members/hooks/useMembers.js.map +1 -1
- package/dist/organization-management/modules/members/hooks/useWorkspaceInvites.js +1 -2
- package/dist/organization-management/modules/members/hooks/useWorkspaceInvites.js.map +1 -1
- package/dist/organization-management/modules/members/pages/InviteMemberPage.js +16 -17
- package/dist/organization-management/modules/members/pages/InviteMemberPage.js.map +1 -1
- package/dist/organization-management/modules/members/pages/InvitePeoplePage.js +14 -15
- package/dist/organization-management/modules/members/pages/InvitePeoplePage.js.map +1 -1
- package/dist/organization-management/modules/members/pages/MemberDetailPage.js +18 -19
- package/dist/organization-management/modules/members/pages/MemberDetailPage.js.map +1 -1
- package/dist/organization-management/modules/members/pages/MembersListPage.js +142 -143
- package/dist/organization-management/modules/members/pages/MembersListPage.js.map +1 -1
- package/dist/organization-management/modules/members/pages/MyInvitesPage.js +168 -169
- package/dist/organization-management/modules/members/pages/MyInvitesPage.js.map +1 -1
- package/dist/organization-management/modules/members/pages/OrganizationInviteAcceptancePage.js +13 -14
- package/dist/organization-management/modules/members/pages/OrganizationInviteAcceptancePage.js.map +1 -1
- package/dist/organization-management/modules/members/utils/bulkInviteCsv.js +4 -10
- package/dist/organization-management/modules/members/utils/bulkInviteCsv.js.map +1 -1
- package/dist/organization-management/modules/members/utils/workspaceInvitationDisplay.js +1 -2
- package/dist/organization-management/modules/members/utils/workspaceInvitationDisplay.js.map +1 -1
- package/dist/organization-management/modules/organizations/components/OrganizationForm.js +14 -15
- package/dist/organization-management/modules/organizations/components/OrganizationForm.js.map +1 -1
- package/dist/organization-management/modules/organizations/components/OrganizationStatusBadge.js +1 -2
- package/dist/organization-management/modules/organizations/components/OrganizationStatusBadge.js.map +1 -1
- package/dist/organization-management/modules/organizations/hooks/useOrganizations.js +2 -3
- package/dist/organization-management/modules/organizations/hooks/useOrganizations.js.map +1 -1
- package/dist/organization-management/modules/organizations/hooks/useOrgsWithPermission.js +22 -21
- package/dist/organization-management/modules/organizations/hooks/useOrgsWithPermission.js.map +1 -1
- package/dist/organization-management/modules/organizations/pages/OrganizationCreatePage.js +18 -19
- package/dist/organization-management/modules/organizations/pages/OrganizationCreatePage.js.map +1 -1
- package/dist/organization-management/modules/organizations/pages/OrganizationDetailPage.js +29 -30
- package/dist/organization-management/modules/organizations/pages/OrganizationDetailPage.js.map +1 -1
- package/dist/organization-management/modules/organizations/pages/OrganizationEditPage.js +14 -15
- package/dist/organization-management/modules/organizations/pages/OrganizationEditPage.js.map +1 -1
- package/dist/organization-management/modules/organizations/pages/OrganizationsListPage.js +33 -34
- package/dist/organization-management/modules/organizations/pages/OrganizationsListPage.js.map +1 -1
- package/dist/organization-management/modules/organizations/schemas/index.js +11 -12
- package/dist/organization-management/modules/organizations/schemas/index.js.map +1 -1
- package/dist/organization-management/modules/workspaces/components/AddWorkspaceMemberDialog.js +16 -24
- package/dist/organization-management/modules/workspaces/components/AddWorkspaceMemberDialog.js.map +1 -1
- package/dist/organization-management/modules/workspaces/components/WorkspaceCard.js +5 -6
- package/dist/organization-management/modules/workspaces/components/WorkspaceCard.js.map +1 -1
- package/dist/organization-management/modules/workspaces/components/WorkspaceForm.js +31 -32
- package/dist/organization-management/modules/workspaces/components/WorkspaceForm.js.map +1 -1
- package/dist/organization-management/modules/workspaces/components/WorkspaceStatusBadge.js +1 -2
- package/dist/organization-management/modules/workspaces/components/WorkspaceStatusBadge.js.map +1 -1
- package/dist/organization-management/modules/workspaces/hooks/useWorkspaceMembers.js +1 -2
- package/dist/organization-management/modules/workspaces/hooks/useWorkspaceMembers.js.map +1 -1
- package/dist/organization-management/modules/workspaces/hooks/useWorkspaces.js +11 -12
- package/dist/organization-management/modules/workspaces/hooks/useWorkspaces.js.map +1 -1
- package/dist/organization-management/modules/workspaces/pages/WorkspaceCreatePage.js +18 -19
- package/dist/organization-management/modules/workspaces/pages/WorkspaceCreatePage.js.map +1 -1
- package/dist/organization-management/modules/workspaces/pages/WorkspaceDetailPage.js +43 -44
- package/dist/organization-management/modules/workspaces/pages/WorkspaceDetailPage.js.map +1 -1
- package/dist/organization-management/modules/workspaces/pages/WorkspaceEditPage.js +19 -20
- package/dist/organization-management/modules/workspaces/pages/WorkspaceEditPage.js.map +1 -1
- package/dist/organization-management/modules/workspaces/pages/WorkspacesListPage.js +240 -241
- package/dist/organization-management/modules/workspaces/pages/WorkspacesListPage.js.map +1 -1
- package/dist/organization-management/modules/workspaces/schemas/index.js +6 -7
- package/dist/organization-management/modules/workspaces/schemas/index.js.map +1 -1
- package/dist/organization-management/providers/OrgConsoleProvider.js +1 -2
- package/dist/organization-management/providers/OrgConsoleProvider.js.map +1 -1
- package/dist/organization-management/providers/OrgScopedPermissions.js +1 -2
- package/dist/organization-management/providers/OrgScopedPermissions.js.map +1 -1
- package/dist/organization-management/shared/components/dialog/ConfirmDialog.js +1 -2
- package/dist/organization-management/shared/components/dialog/ConfirmDialog.js.map +1 -1
- package/dist/organization-management/shared/components/dialog/ConfirmDialogView.js +1 -2
- package/dist/organization-management/shared/components/dialog/ConfirmDialogView.js.map +1 -1
- package/dist/organization-management/shared/components/feedback/ErrorState.js +1 -2
- package/dist/organization-management/shared/components/feedback/ErrorState.js.map +1 -1
- package/dist/organization-management/shared/components/feedback/LoadingState.js +1 -2
- package/dist/organization-management/shared/components/feedback/LoadingState.js.map +1 -1
- package/dist/organization-management/shared/components/input/SearchInput.js +1 -2
- package/dist/organization-management/shared/components/input/SearchInput.js.map +1 -1
- package/dist/organization-management/shared/components/input/SelectionCheckbox.js +1 -2
- package/dist/organization-management/shared/components/input/SelectionCheckbox.js.map +1 -1
- package/dist/organization-management/shared/hooks/useDebouncedValue.js +1 -2
- package/dist/organization-management/shared/hooks/useDebouncedValue.js.map +1 -1
- package/dist/organization-management/shared/hooks/useTr.js +1 -2
- package/dist/organization-management/shared/hooks/useTr.js.map +1 -1
- package/dist/organization-management/shared/logger.js +1 -2
- package/dist/organization-management/shared/logger.js.map +1 -1
- package/dist/organization-management/shared/recaptcha.js +1 -2
- package/dist/organization-management/shared/recaptcha.js.map +1 -1
- package/dist/organization-management/shared/types/graphql.js +1 -2
- package/dist/organization-management/shared/types/graphql.js.map +1 -1
- package/dist/utils/nativeBridge.js +1 -2
- package/package.json +7 -6
- package/dist/node_modules/zod/v3/ZodError.js +0 -82
- package/dist/node_modules/zod/v3/ZodError.js.map +0 -1
- package/dist/node_modules/zod/v3/errors.js +0 -10
- package/dist/node_modules/zod/v3/errors.js.map +0 -1
- package/dist/node_modules/zod/v3/helpers/errorUtil.js +0 -9
- package/dist/node_modules/zod/v3/helpers/errorUtil.js.map +0 -1
- package/dist/node_modules/zod/v3/helpers/parseUtil.js +0 -93
- package/dist/node_modules/zod/v3/helpers/parseUtil.js.map +0 -1
- package/dist/node_modules/zod/v3/helpers/util.js +0 -76
- package/dist/node_modules/zod/v3/helpers/util.js.map +0 -1
- package/dist/node_modules/zod/v3/locales/en.js +0 -62
- package/dist/node_modules/zod/v3/locales/en.js.map +0 -1
- package/dist/node_modules/zod/v3/types.js +0 -2441
- package/dist/node_modules/zod/v3/types.js.map +0 -1
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { toast as e } from "../../../../node_modules/sonner/dist/index.js";
|
|
2
|
+
import { useOrgConsole as t } from "../../../providers/OrgConsoleProvider.js";
|
|
3
3
|
import { useDeleteOrganization as n, useMyOrganizations as r, useOrganizations as ee } from "../hooks/useOrganizations.js";
|
|
4
|
-
import { useMyInvites as
|
|
5
|
-
import { InviteStatus as
|
|
6
|
-
import { OrganizationStatusBadge as
|
|
7
|
-
import { useTr as ne } from "../../../shared/hooks/useTr.js";
|
|
4
|
+
import { useMyInvites as te } from "../../members/hooks/useInvites.js";
|
|
5
|
+
import { InviteStatus as ne } from "../../../../generated/global-types.js";
|
|
6
|
+
import { OrganizationStatusBadge as i } from "../components/OrganizationStatusBadge.js";
|
|
8
7
|
import { SearchInput as re } from "../../../shared/components/input/SearchInput.js";
|
|
9
|
-
import { SelectionCheckbox as
|
|
10
|
-
import { LoadingState as
|
|
8
|
+
import { SelectionCheckbox as a } from "../../../shared/components/input/SelectionCheckbox.js";
|
|
9
|
+
import { LoadingState as o } from "../../../shared/components/feedback/LoadingState.js";
|
|
11
10
|
import { ErrorState as ie } from "../../../shared/components/feedback/ErrorState.js";
|
|
12
11
|
import { useDebouncedValue as ae } from "../../../shared/hooks/useDebouncedValue.js";
|
|
13
12
|
import { useConfirmDialog as oe } from "../../../shared/components/dialog/ConfirmDialog.js";
|
|
14
|
-
import { PERMISSIONS as
|
|
13
|
+
import { PERMISSIONS as s } from "../../../constants/permissions.js";
|
|
14
|
+
import { useTr as c } from "../../../shared/hooks/useTr.js";
|
|
15
15
|
import { useOrganizationPageView as se } from "../../../hooks/useOrganizationPageView.js";
|
|
16
16
|
import { isNative as l, nativeConfirm as ce, nativeImpact as le, nativeNotify as u, nativeToast as d } from "../../../../utils/nativeBridge.js";
|
|
17
17
|
import { useEffect as ue, useMemo as f, useState as p } from "react";
|
|
@@ -20,13 +20,13 @@ import { AuroraBackground as y, CTAOverflowMenu as fe, GlassCard as b, GradientT
|
|
|
20
20
|
import { useFeatureFlagDetails as w } from "@burdenoff/fe-libs/shared/feature-flags";
|
|
21
21
|
import { usePermissions as pe } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
22
22
|
import { Fragment as me, jsx as T, jsxs as E } from "react/jsx-runtime";
|
|
23
|
-
|
|
23
|
+
// src/organization-management/modules/organizations/pages/OrganizationsListPage.tsx
|
|
24
24
|
function D(e) {
|
|
25
25
|
return new Date(e).toLocaleDateString();
|
|
26
26
|
}
|
|
27
27
|
function O({ mode: O = "my" } = {}) {
|
|
28
28
|
se("organizations.list");
|
|
29
|
-
let k =
|
|
29
|
+
let k = c(), { navigate: A, basePath: j = "/organizations" } = t(), { hasPermission: M, isLoading: he } = pe(), N = w("organization.create"), P = !N || !!N.value, [F, I] = p(""), L = ae(F, 300), [R, z] = p(/* @__PURE__ */ new Set()), { openConfirmDialog: B, ConfirmDialog: ge } = oe(), { total: V } = te(ne.Pending, 1, 0, O === "my"), _e = r(200, 0, O === "my"), ve = ee(void 0, 200, 0, O === "admin"), { organizations: H, loading: ye, error: U, refetch: W } = O === "admin" ? ve : _e, be = L.trim().length > 0, G = f(() => {
|
|
30
30
|
let e = L.trim().toLowerCase();
|
|
31
31
|
return e ? H.filter((t) => t.name?.toLowerCase().includes(e) || t.slug?.toLowerCase().includes(e)) : H;
|
|
32
32
|
}, [H, L]), { deleteOrganization: xe, loading: K } = n();
|
|
@@ -36,19 +36,19 @@ function O({ mode: O = "my" } = {}) {
|
|
|
36
36
|
return n.size === e.size ? e : n;
|
|
37
37
|
});
|
|
38
38
|
}, [G]);
|
|
39
|
-
let q = f(() => G.filter((e) => R.has(e.id)), [G, R]), J = G.length > 0 && G.every((e) => R.has(e.id)), Y = G.some((e) => R.has(e.id)) && !J, X = async (
|
|
39
|
+
let q = f(() => G.filter((e) => R.has(e.id)), [G, R]), J = G.length > 0 && G.every((e) => R.has(e.id)), Y = G.some((e) => R.has(e.id)) && !J, X = async (t) => {
|
|
40
40
|
try {
|
|
41
|
-
let n = (await Promise.allSettled(
|
|
41
|
+
let n = (await Promise.allSettled(t.map(async (e) => {
|
|
42
42
|
let t = await xe(e);
|
|
43
43
|
if (t.errors?.length) throw Error(t.errors[0]?.message ?? "Failed to delete organization");
|
|
44
44
|
}))).find((e) => e.status === "rejected");
|
|
45
45
|
if (n?.status === "rejected") throw n.reason;
|
|
46
46
|
z(/* @__PURE__ */ new Set()), await W();
|
|
47
|
-
let r =
|
|
48
|
-
|
|
49
|
-
} catch (
|
|
50
|
-
let n =
|
|
51
|
-
|
|
47
|
+
let r = t.length === 1 ? k("organizations.delete.successSingle", "Organization deleted successfully") : `${t.length} ${k("organizations.delete.successMany", "organizations deleted successfully")}`;
|
|
48
|
+
e.success(r), u("success"), l() && d(r);
|
|
49
|
+
} catch (t) {
|
|
50
|
+
let n = t instanceof Error ? t.message : k("organizations.delete.failed", "Failed to delete organization");
|
|
51
|
+
e.error(n), u("error"), l() && d(n);
|
|
52
52
|
}
|
|
53
53
|
}, Z = (e, t) => {
|
|
54
54
|
le("medium");
|
|
@@ -93,10 +93,10 @@ function O({ mode: O = "my" } = {}) {
|
|
|
93
93
|
};
|
|
94
94
|
return he ? /* @__PURE__ */ T("div", {
|
|
95
95
|
className: "min-h-full bg-[var(--color-bg-canvas)] p-6",
|
|
96
|
-
children: /* @__PURE__ */ T(
|
|
96
|
+
children: /* @__PURE__ */ T(o, { message: k("common.loadingPermissions", "Loading permissions...") })
|
|
97
97
|
}) : ye ? /* @__PURE__ */ T("div", {
|
|
98
98
|
className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6",
|
|
99
|
-
children: /* @__PURE__ */ T(
|
|
99
|
+
children: /* @__PURE__ */ T(o, { message: k("organizations.list.loading", "Loading organizations...") })
|
|
100
100
|
}) : U ? /* @__PURE__ */ T("div", {
|
|
101
101
|
className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6",
|
|
102
102
|
children: /* @__PURE__ */ T(ie, {
|
|
@@ -138,7 +138,7 @@ function O({ mode: O = "my" } = {}) {
|
|
|
138
138
|
className: "flex flex-wrap items-center gap-2",
|
|
139
139
|
"data-tour": "organizations-create-button",
|
|
140
140
|
children: /* @__PURE__ */ T(fe, {
|
|
141
|
-
primary: P && M(
|
|
141
|
+
primary: P && M(s.ORG_CREATE) ? {
|
|
142
142
|
label: k("organizations.create.button", "Create Organization"),
|
|
143
143
|
icon: /* @__PURE__ */ T(h, {
|
|
144
144
|
size: 18,
|
|
@@ -230,7 +230,7 @@ function O({ mode: O = "my" } = {}) {
|
|
|
230
230
|
className: "flex flex-wrap items-center gap-3",
|
|
231
231
|
children: [/* @__PURE__ */ E("label", {
|
|
232
232
|
className: "flex items-center gap-2 text-sm text-[var(--color-text-primary)]",
|
|
233
|
-
children: [/* @__PURE__ */ T(
|
|
233
|
+
children: [/* @__PURE__ */ T(a, {
|
|
234
234
|
checked: J,
|
|
235
235
|
indeterminate: Y,
|
|
236
236
|
onChange: $,
|
|
@@ -251,7 +251,7 @@ function O({ mode: O = "my" } = {}) {
|
|
|
251
251
|
" ",
|
|
252
252
|
k("common.selected", "selected")
|
|
253
253
|
]
|
|
254
|
-
}), O === "admin" && M(
|
|
254
|
+
}), O === "admin" && M(s.ORG_DELETE) && /* @__PURE__ */ E("button", {
|
|
255
255
|
type: "button",
|
|
256
256
|
onClick: Se,
|
|
257
257
|
disabled: q.length === 0 || K,
|
|
@@ -290,7 +290,7 @@ function O({ mode: O = "my" } = {}) {
|
|
|
290
290
|
illustration: "empty-people",
|
|
291
291
|
title: k("organizations.list.emptyTitle", "No organizations found"),
|
|
292
292
|
description: k("organizations.list.emptyDescription", "Create your first organization to start managing workspaces, members, and invites."),
|
|
293
|
-
action: P && M(
|
|
293
|
+
action: P && M(s.ORG_CREATE) ? /* @__PURE__ */ E("button", {
|
|
294
294
|
type: "button",
|
|
295
295
|
onClick: () => A(`${j}/new`),
|
|
296
296
|
className: "inline-flex min-h-11 items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-4 py-2 font-medium text-[var(--color-action-primary-text)] transition-all duration-200 hover:bg-[var(--color-action-primary-bgHover)]",
|
|
@@ -307,7 +307,7 @@ function O({ mode: O = "my" } = {}) {
|
|
|
307
307
|
className: "border-border-seam p-4",
|
|
308
308
|
children: [/* @__PURE__ */ E("div", {
|
|
309
309
|
className: "flex items-start gap-3",
|
|
310
|
-
children: [/* @__PURE__ */ T(
|
|
310
|
+
children: [/* @__PURE__ */ T(a, {
|
|
311
311
|
checked: R.has(e.id),
|
|
312
312
|
onChange: (t) => Q(e.id, t),
|
|
313
313
|
ariaLabel: `${k("organizations.list.selectOne", "Select organization")} ${e.name}`
|
|
@@ -328,7 +328,7 @@ function O({ mode: O = "my" } = {}) {
|
|
|
328
328
|
children: [/* @__PURE__ */ T("h2", {
|
|
329
329
|
className: "text-base font-semibold text-[var(--color-text-primary)]",
|
|
330
330
|
children: e.name
|
|
331
|
-
}), /* @__PURE__ */ T(
|
|
331
|
+
}), /* @__PURE__ */ T(i, { status: e.status })]
|
|
332
332
|
}),
|
|
333
333
|
/* @__PURE__ */ E("p", {
|
|
334
334
|
className: "mt-1 break-all font-mono text-sm text-[var(--color-text-muted)]",
|
|
@@ -365,7 +365,7 @@ function O({ mode: O = "my" } = {}) {
|
|
|
365
365
|
"aria-hidden": "true"
|
|
366
366
|
}), k("common.view", "View")]
|
|
367
367
|
}),
|
|
368
|
-
M(
|
|
368
|
+
M(s.ORG_UPDATE) && /* @__PURE__ */ E("button", {
|
|
369
369
|
type: "button",
|
|
370
370
|
onClick: () => A(`${j}/${e.id}/edit`),
|
|
371
371
|
className: "inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-border-default)] px-3 py-2 text-sm text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]",
|
|
@@ -374,7 +374,7 @@ function O({ mode: O = "my" } = {}) {
|
|
|
374
374
|
"aria-hidden": "true"
|
|
375
375
|
}), k("common.edit", "Edit")]
|
|
376
376
|
}),
|
|
377
|
-
O === "admin" && M(
|
|
377
|
+
O === "admin" && M(s.ORG_DELETE) && /* @__PURE__ */ E("button", {
|
|
378
378
|
type: "button",
|
|
379
379
|
onClick: () => Z(e.id, e.name),
|
|
380
380
|
disabled: K,
|
|
@@ -400,7 +400,7 @@ function O({ mode: O = "my" } = {}) {
|
|
|
400
400
|
children: /* @__PURE__ */ E("tr", { children: [
|
|
401
401
|
/* @__PURE__ */ T("th", {
|
|
402
402
|
className: "w-12 px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]",
|
|
403
|
-
children: /* @__PURE__ */ T(
|
|
403
|
+
children: /* @__PURE__ */ T(a, {
|
|
404
404
|
checked: J,
|
|
405
405
|
indeterminate: Y,
|
|
406
406
|
onChange: $,
|
|
@@ -435,7 +435,7 @@ function O({ mode: O = "my" } = {}) {
|
|
|
435
435
|
children: [
|
|
436
436
|
/* @__PURE__ */ T("td", {
|
|
437
437
|
className: "px-6 py-4 align-top",
|
|
438
|
-
children: /* @__PURE__ */ T(
|
|
438
|
+
children: /* @__PURE__ */ T(a, {
|
|
439
439
|
checked: R.has(e.id),
|
|
440
440
|
onChange: (t) => Q(e.id, t),
|
|
441
441
|
ariaLabel: `${k("organizations.list.selectOne", "Select organization")} ${e.name}`
|
|
@@ -466,7 +466,7 @@ function O({ mode: O = "my" } = {}) {
|
|
|
466
466
|
}),
|
|
467
467
|
/* @__PURE__ */ T("td", {
|
|
468
468
|
className: "px-6 py-4 align-top",
|
|
469
|
-
children: /* @__PURE__ */ T(
|
|
469
|
+
children: /* @__PURE__ */ T(i, { status: e.status })
|
|
470
470
|
}),
|
|
471
471
|
/* @__PURE__ */ T("td", {
|
|
472
472
|
className: "px-6 py-4 align-top text-[var(--color-text-primary)]",
|
|
@@ -493,7 +493,7 @@ function O({ mode: O = "my" } = {}) {
|
|
|
493
493
|
"aria-hidden": "true"
|
|
494
494
|
})
|
|
495
495
|
}),
|
|
496
|
-
M(
|
|
496
|
+
M(s.ORG_UPDATE) && /* @__PURE__ */ T("button", {
|
|
497
497
|
type: "button",
|
|
498
498
|
onClick: () => A(`${j}/${e.id}/edit`),
|
|
499
499
|
className: "rounded-lg p-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:bg-[var(--color-bg-muted)] hover:text-[var(--color-text-primary)]",
|
|
@@ -504,7 +504,7 @@ function O({ mode: O = "my" } = {}) {
|
|
|
504
504
|
"aria-hidden": "true"
|
|
505
505
|
})
|
|
506
506
|
}),
|
|
507
|
-
O === "admin" && M(
|
|
507
|
+
O === "admin" && M(s.ORG_DELETE) && /* @__PURE__ */ T("button", {
|
|
508
508
|
type: "button",
|
|
509
509
|
onClick: () => Z(e.id, e.name),
|
|
510
510
|
disabled: K,
|
|
@@ -529,7 +529,6 @@ function O({ mode: O = "my" } = {}) {
|
|
|
529
529
|
}), ge]
|
|
530
530
|
});
|
|
531
531
|
}
|
|
532
|
-
//#endregion
|
|
533
532
|
export { O as OrganizationsListPage };
|
|
534
533
|
|
|
535
534
|
//# sourceMappingURL=OrganizationsListPage.js.map
|
package/dist/organization-management/modules/organizations/pages/OrganizationsListPage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OrganizationsListPage.js","names":[],"sources":["../../../../../src/organization-management/modules/organizations/pages/OrganizationsListPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport { Eye, Mail, Plus, RefreshCw, SquarePen, Trash2 } from 'lucide-react';\nimport { toast } from 'sonner';\nimport {\n AuroraBackground,\n CTAOverflowMenu,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useFeatureFlagDetails } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\nimport {\n useDeleteOrganization,\n useMyOrganizations,\n useOrganizations,\n} from '../hooks/useOrganizations';\nimport { useMyInvites } from '../../members/hooks/useInvites';\nimport { InviteStatus } from '../../../../generated/global-types';\nimport { OrganizationStatusBadge } from '../components/OrganizationStatusBadge';\nimport { SearchInput } from '../../../shared/components/input/SearchInput';\nimport { SelectionCheckbox } from '../../../shared/components/input/SelectionCheckbox';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { ErrorState } from '../../../shared/components/feedback/ErrorState';\nimport { useDebouncedValue } from '../../../shared/hooks/useDebouncedValue';\nimport { useConfirmDialog } from '../../../shared/components/dialog/ConfirmDialog';\nimport { PERMISSIONS } from '../../../constants/permissions';\nimport { useTr } from '../../../shared/hooks/useTr';\nimport { useOrganizationPageView } from '../../../hooks/useOrganizationPageView';\nimport {\n isNative,\n nativeConfirm,\n nativeImpact,\n nativeNotify,\n nativeToast,\n} from '../../../../utils/nativeBridge';\n\nfunction formatDate(date: string) {\n return new Date(date).toLocaleDateString();\n}\n\n/**\n * `mode` controls which scope of organizations the page renders:\n *\n * - `'my'` (default) calls `myOrganizations` (gateway @rbac(scopeType:\"self\")).\n * Use this in product-app shells (e.g. vibecontrols) where the user should\n * see only orgs they are a member of. Membership IS the access list, so no\n * client-side permission gate is needed.\n *\n * - `'admin'` calls `allOrganizations` (gateway @rbac(scopeType: \"global\")).\n * Restricted to actors with global `organization:read` (super admins /\n * service / custom global-admin roles). Use this in the admin app where\n * operators need the tenant-wide list.\n */\nexport interface OrganizationsListPageProps {\n mode?: 'my' | 'admin';\n}\n\nexport function OrganizationsListPage({ mode = 'my' }: OrganizationsListPageProps = {}) {\n useOrganizationPageView('organizations.list');\n const tr = useTr();\n const { navigate, basePath = '/organizations' } = useOrgConsole();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n // Follow the platform default-allow feature flag policy: unseeded flags must\n // not disable shipped CRUDL, while an explicit false value still gates create.\n const createDetails = useFeatureFlagDetails('organization.create');\n const createEnabled = createDetails ? Boolean(createDetails.value) : true;\n const [searchQuery, setSearchQuery] = useState('');\n const debouncedSearchQuery = useDebouncedValue(searchQuery, 300);\n const [selectedOrganizationIds, setSelectedOrganizationIds] = useState<Set<string>>(new Set());\n const { openConfirmDialog, ConfirmDialog } = useConfirmDialog();\n\n // Show a count badge of pending invites alongside the Invitations link.\n // Skipped in 'admin' mode since admins land here via tenant-wide management\n // rather than personal invites.\n const { total: pendingInvitesCount } = useMyInvites(InviteStatus.Pending, 1, 0, mode === 'my');\n\n // Page size is large enough to cover realistic memberships / tenant-wide\n // org counts in one round-trip so the client-side search is exhaustive.\n // If a tenant ever exceeds this, wire in fetchMore/pagination instead of\n // silently truncating.\n const ORGANIZATIONS_PAGE_SIZE = 200;\n const myResult = useMyOrganizations(ORGANIZATIONS_PAGE_SIZE, 0, mode === 'my');\n const adminResult = useOrganizations(undefined, ORGANIZATIONS_PAGE_SIZE, 0, mode === 'admin');\n const {\n organizations: allOrganizations,\n loading,\n error,\n refetch,\n } = mode === 'admin' ? adminResult : myResult;\n\n const isSearchFiltered = debouncedSearchQuery.trim().length > 0;\n\n const organizations = useMemo(() => {\n const q = debouncedSearchQuery.trim().toLowerCase();\n if (!q) return allOrganizations;\n return allOrganizations.filter(\n (org) => org.name?.toLowerCase().includes(q) || org.slug?.toLowerCase().includes(q)\n );\n }, [allOrganizations, debouncedSearchQuery]);\n\n const { deleteOrganization, loading: deleteLoading } = useDeleteOrganization();\n\n useEffect(() => {\n setSelectedOrganizationIds((previousSelection) => {\n const visibleIds = new Set(organizations.map((organization) => organization.id));\n const nextSelection = new Set(\n [...previousSelection].filter((organizationId) => visibleIds.has(organizationId))\n );\n\n if (nextSelection.size === previousSelection.size) {\n return previousSelection;\n }\n\n return nextSelection;\n });\n }, [organizations]);\n\n const selectedOrganizations = useMemo(\n () => organizations.filter((organization) => selectedOrganizationIds.has(organization.id)),\n [organizations, selectedOrganizationIds]\n );\n\n const allVisibleSelected =\n organizations.length > 0 &&\n organizations.every((organization) => selectedOrganizationIds.has(organization.id));\n const partiallySelected =\n organizations.some((organization) => selectedOrganizationIds.has(organization.id)) &&\n !allVisibleSelected;\n\n const executeDelete = async (organizationIds: string[]) => {\n try {\n const results = await Promise.allSettled(\n organizationIds.map(async (organizationId) => {\n const result = await deleteOrganization(organizationId);\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message ?? 'Failed to delete organization');\n }\n })\n );\n\n const rejectedResult = results.find((result) => result.status === 'rejected');\n if (rejectedResult?.status === 'rejected') {\n throw rejectedResult.reason;\n }\n\n setSelectedOrganizationIds(new Set());\n await refetch();\n const successMsg =\n organizationIds.length === 1\n ? tr('organizations.delete.successSingle', 'Organization deleted successfully')\n : `${organizationIds.length} ${tr('organizations.delete.successMany', 'organizations deleted successfully')}`;\n toast.success(successMsg);\n void nativeNotify('success');\n if (isNative()) void nativeToast(successMsg);\n } catch (deleteError) {\n const errorMsg =\n deleteError instanceof Error\n ? deleteError.message\n : tr('organizations.delete.failed', 'Failed to delete organization');\n toast.error(errorMsg);\n void nativeNotify('error');\n if (isNative()) void nativeToast(errorMsg);\n }\n };\n\n const handleDelete = (organizationId: string, organizationName: string) => {\n nativeImpact('medium');\n const title = tr('organizations.delete.title', 'Delete organization');\n const description = `${tr('organizations.delete.confirmPrefix', 'Delete')} ${organizationName}? ${tr('common.cannotBeUndone', 'This action cannot be undone.')}`;\n void nativeConfirm({\n title,\n message: description,\n okButtonTitle: tr('common.delete', 'Delete'),\n }).then((nativeResult) => {\n if (nativeResult === null) {\n openConfirmDialog({\n title,\n description,\n confirmText: tr('common.delete', 'Delete'),\n variant: 'danger',\n onConfirm: () => {\n void executeDelete([organizationId]);\n },\n });\n } else if (nativeResult) {\n void executeDelete([organizationId]);\n }\n });\n };\n\n const handleBulkDelete = () => {\n if (selectedOrganizations.length === 0) return;\n\n openConfirmDialog({\n title: tr('organizations.delete.bulkTitle', 'Delete selected organizations'),\n description: `${tr('organizations.delete.bulkPrefix', 'Delete')} ${selectedOrganizations.length} ${tr(\n selectedOrganizations.length === 1\n ? 'organizations.delete.bulkSuffixSingle'\n : 'organizations.delete.bulkSuffixMany',\n selectedOrganizations.length === 1 ? 'selected organization?' : 'selected organizations?'\n )} ${tr('common.cannotBeUndone', 'This action cannot be undone.')}`,\n confirmText: `${tr('common.delete', 'Delete')} ${selectedOrganizations.length}`,\n variant: 'danger',\n onConfirm: () => {\n void executeDelete(selectedOrganizations.map((organization) => organization.id));\n },\n });\n };\n\n const toggleOrganizationSelection = (organizationId: string, checked: boolean) => {\n setSelectedOrganizationIds((previousSelection) => {\n const nextSelection = new Set(previousSelection);\n if (checked) {\n nextSelection.add(organizationId);\n } else {\n nextSelection.delete(organizationId);\n }\n return nextSelection;\n });\n };\n\n const toggleAllOrganizations = (checked: boolean) => {\n setSelectedOrganizationIds((previousSelection) => {\n const nextSelection = new Set(previousSelection);\n organizations.forEach((organization) => {\n if (checked) {\n nextSelection.add(organization.id);\n } else {\n nextSelection.delete(organization.id);\n }\n });\n return nextSelection;\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 // No client-side list gate: this page calls `myOrganizations`\n // (@rbac(scopeType: \"self\")), so the data set IS the access list — if the\n // user is in zero orgs the page renders the empty state, not a deny. The\n // create/delete/edit buttons keep their own per-action `hasPermission`\n // checks below to hide actions the user can't perform on a given org.\n\n if (loading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <LoadingState message={tr('organizations.list.loading', 'Loading organizations...')} />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <ErrorState\n message={error.message}\n action={{\n label: tr('common.retry', 'Retry'),\n onClick: () => {\n void refetch();\n },\n }}\n />\n </div>\n );\n }\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-200\">\n <div className=\"mx-auto flex w-full max-w-7xl flex-col gap-6\">\n <div className=\"relative overflow-hidden rounded-card\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"flex flex-col gap-4 p-1 lg:flex-row lg:items-start lg:justify-between\">\n <div className=\"space-y-2\" data-tour=\"organizations-page-header\">\n <h1 className=\"text-3xl font-bold text-[var(--color-text-primary)]\">\n <GradientText>{tr('organizations.list.title', 'Organizations')}</GradientText>\n </h1>\n <p className=\"max-w-2xl text-[var(--color-text-secondary)]\">\n {tr(\n 'organizations.list.subtitle',\n 'Manage tenant organizations and the workspaces that belong to them.'\n )}\n </p>\n <PagePurpose className=\"max-w-2xl\">\n {tr(\n 'organizations.list.purpose',\n 'An organization is the top-level container that groups your workspaces, members, and invitations under one roof — use it to onboard a company or team, control who belongs, and keep their workspaces organized in one place.'\n )}\n </PagePurpose>\n </div>\n\n <div\n className=\"flex flex-wrap items-center gap-2\"\n data-tour=\"organizations-create-button\"\n >\n <CTAOverflowMenu\n primary={\n createEnabled && hasPermission(PERMISSIONS.ORG_CREATE)\n ? {\n label: tr('organizations.create.button', 'Create Organization'),\n icon: <Plus size={18} aria-hidden=\"true\" />,\n onSelect: () => navigate(`${basePath}/new`),\n }\n : undefined\n }\n actions={\n mode === 'my'\n ? [\n {\n label:\n pendingInvitesCount > 0\n ? `${tr('organizations.invitations.button', 'Invitations')} (${pendingInvitesCount})`\n : tr('organizations.invitations.button', 'Invitations'),\n icon: <Mail size={16} aria-hidden=\"true\" />,\n onSelect: () => navigate(`${basePath}/invites`),\n },\n ]\n : []\n }\n />\n </div>\n </div>\n </div>\n\n {allOrganizations.length > 0 ? (\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3\">\n <GlassCard treatment=\"glass\" glow className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr('organizations.list.title', 'Organizations')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {allOrganizations.length}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr('organizations.list.column.workspaces', 'Workspaces')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {allOrganizations.reduce((sum, org) => sum + (org.workspaceCount ?? 0), 0)}\n </p>\n </GlassCard>\n {mode === 'my' ? (\n <GlassCard treatment=\"metric\" className=\"col-span-2 p-4 sm:col-span-1\">\n <p className=\"text-sm text-text-secondary\">\n {tr('organizations.invitations.button', 'Invitations')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {pendingInvitesCount}\n </p>\n </GlassCard>\n ) : null}\n </div>\n ) : null}\n\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-4\">\n <div\n className=\"flex flex-col gap-3 sm:flex-row sm:items-center\"\n data-tour=\"organizations-search-input\"\n >\n <SearchInput\n value={searchQuery}\n onChange={setSearchQuery}\n placeholder={tr('organizations.list.searchPlaceholder', 'Search organizations...')}\n label={tr('organizations.list.searchLabel', 'Search organizations')}\n inputId=\"organizations-search\"\n className=\"flex-1\"\n />\n\n <button\n type=\"button\"\n onClick={() => {\n void refetch();\n }}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-4 py-2 text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n aria-label={tr('organizations.list.refresh', 'Refresh organizations')}\n title={tr('organizations.list.refresh', 'Refresh organizations')}\n data-tour=\"organizations-refresh-button\"\n >\n <RefreshCw size={18} aria-hidden=\"true\" />\n </button>\n </div>\n\n {organizations.length > 0 ? (\n <div className=\"mt-4 flex flex-col gap-3 rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-canvas)] p-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <label className=\"flex items-center gap-2 text-sm text-[var(--color-text-primary)]\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllOrganizations}\n ariaLabel={tr('organizations.list.selectAll', 'Select all organizations')}\n />\n <span>{tr('common.selectAllVisible', 'Select all visible')}</span>\n </label>\n\n {selectedOrganizationIds.size > 0 ? (\n <button\n type=\"button\"\n onClick={() => setSelectedOrganizationIds(new Set())}\n className=\"text-sm text-[var(--color-text-secondary)] transition-colors hover:text-[var(--color-text-primary)]\"\n >\n {tr('common.clearSelection', 'Clear selection')}\n </button>\n ) : null}\n </div>\n\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <span className=\"text-sm text-[var(--color-text-secondary)]\">\n {selectedOrganizationIds.size} {tr('common.selected', 'selected')}\n </span>\n {mode === 'admin' && hasPermission(PERMISSIONS.ORG_DELETE) && (\n <button\n type=\"button\"\n onClick={handleBulkDelete}\n disabled={selectedOrganizations.length === 0 || deleteLoading}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-status-error-border)] px-3 py-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\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n <span>{tr('common.deleteSelected', 'Delete Selected')}</span>\n {selectedOrganizations.length > 0 ? (\n <span>({selectedOrganizations.length})</span>\n ) : null}\n </button>\n )}\n </div>\n </div>\n ) : null}\n </GlassCard>\n\n {organizations.length === 0 ? (\n <GlassCard\n treatment=\"glass\"\n glow={allOrganizations.length === 0}\n className=\"border-border-seam p-6\"\n >\n {isSearchFiltered && allOrganizations.length > 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title={tr('organizations.list.noMatchesTitle', 'No matching organizations')}\n description={tr(\n 'organizations.list.noMatchesDescription',\n 'No organizations match your search. Try a different name or slug, or clear the search.'\n )}\n action={\n <button\n type=\"button\"\n onClick={() => setSearchQuery('')}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-4 py-2 text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n >\n {tr('common.clearSearch', 'Clear search')}\n </button>\n }\n />\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-people\"\n title={tr('organizations.list.emptyTitle', 'No organizations found')}\n description={tr(\n 'organizations.list.emptyDescription',\n 'Create your first organization to start managing workspaces, members, and invites.'\n )}\n action={\n createEnabled && hasPermission(PERMISSIONS.ORG_CREATE) ? (\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/new`)}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-4 py-2 font-medium text-[var(--color-action-primary-text)] transition-all duration-200 hover:bg-[var(--color-action-primary-bgHover)]\"\n >\n <Plus size={18} aria-hidden=\"true\" />\n {tr('organizations.create.button', 'Create Organization')}\n </button>\n ) : undefined\n }\n />\n )}\n </GlassCard>\n ) : (\n <>\n <div className=\"grid gap-4 md:hidden\">\n {organizations.map((organization) => (\n <GlassCard\n key={organization.id}\n treatment=\"insight\"\n className=\"border-border-seam p-4\"\n >\n <div className=\"flex items-start gap-3\">\n <SelectionCheckbox\n checked={selectedOrganizationIds.has(organization.id)}\n onChange={(checked) => toggleOrganizationSelection(organization.id, checked)}\n ariaLabel={`${tr('organizations.list.selectOne', 'Select organization')} ${organization.name}`}\n />\n\n <div className=\"flex min-w-0 flex-1 gap-3\">\n {organization.logo ? (\n <img\n src={organization.logo}\n alt={`${organization.name} ${tr('common.logo', 'logo')}`}\n className=\"size-12 rounded-lg object-cover\"\n />\n ) : (\n <div className=\"flex size-12 items-center justify-center rounded-lg bg-[var(--color-action-primary-bg)]/12 text-base font-semibold text-[var(--color-action-primary-bg)]\">\n {organization.name[0]}\n </div>\n )}\n\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-start gap-2\">\n <h2 className=\"text-base font-semibold text-[var(--color-text-primary)]\">\n {organization.name}\n </h2>\n <OrganizationStatusBadge status={organization.status} />\n </div>\n <p className=\"mt-1 break-all font-mono text-sm text-[var(--color-text-muted)]\">\n /{organization.slug}\n </p>\n <dl className=\"mt-3 grid grid-cols-2 gap-3 text-sm\">\n <div>\n <dt className=\"text-[var(--color-text-secondary)]\">\n {tr('organizations.list.column.workspaces', 'Workspaces')}\n </dt>\n <dd className=\"font-medium text-[var(--color-text-primary)]\">\n {organization.workspaceCount ?? 0}\n </dd>\n </div>\n <div>\n <dt className=\"text-[var(--color-text-secondary)]\">\n {tr('common.created', 'Created')}\n </dt>\n <dd className=\"font-medium text-[var(--color-text-primary)]\">\n {formatDate(organization.createdAt)}\n </dd>\n </div>\n </dl>\n </div>\n </div>\n </div>\n\n <div className=\"mt-4 flex flex-wrap gap-2 border-t border-[var(--color-border-default)] pt-4\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${organization.id}`)}\n className=\"inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-border-default)] px-3 py-2 text-sm text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n >\n <Eye size={16} aria-hidden=\"true\" />\n {tr('common.view', 'View')}\n </button>\n {hasPermission(PERMISSIONS.ORG_UPDATE) && (\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${organization.id}/edit`)}\n className=\"inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-border-default)] px-3 py-2 text-sm text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n >\n <SquarePen size={16} aria-hidden=\"true\" />\n {tr('common.edit', 'Edit')}\n </button>\n )}\n {mode === 'admin' && hasPermission(PERMISSIONS.ORG_DELETE) && (\n <button\n type=\"button\"\n onClick={() => handleDelete(organization.id, organization.name)}\n disabled={deleteLoading}\n 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\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n {tr('common.delete', 'Delete')}\n </button>\n )}\n </div>\n </GlassCard>\n ))}\n </div>\n\n <GlassCard\n treatment=\"plain\"\n className=\"hidden overflow-hidden border-border-seam p-0 md:block\"\n data-tour=\"organizations-table\"\n >\n <div className=\"overflow-x-auto\">\n <table className=\"min-w-full\">\n <thead className=\"bg-[var(--color-bg-subtle)]\">\n <tr>\n <th className=\"w-12 px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllOrganizations}\n ariaLabel={tr('organizations.list.selectAll', 'Select all organizations')}\n />\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('organizations.list.column.organization', 'Organization')}\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.status', 'Status')}\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('organizations.list.column.workspaces', 'Workspaces')}\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.created', 'Created')}\n </th>\n <th className=\"px-6 py-3 text-right text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.actions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-[var(--color-border-seam)]\">\n {organizations.map((organization) => (\n <tr\n key={organization.id}\n className=\"transition-colors hover:bg-[var(--color-bg-subtle)]\"\n >\n <td className=\"px-6 py-4 align-top\">\n <SelectionCheckbox\n checked={selectedOrganizationIds.has(organization.id)}\n onChange={(checked) =>\n toggleOrganizationSelection(organization.id, checked)\n }\n ariaLabel={`${tr('organizations.list.selectOne', 'Select organization')} ${organization.name}`}\n />\n </td>\n <td className=\"px-6 py-4\">\n <div className=\"flex items-start gap-3\">\n {organization.logo ? (\n <img\n src={organization.logo}\n alt={`${organization.name} ${tr('common.logo', 'logo')}`}\n className=\"size-10 rounded-lg object-cover\"\n />\n ) : (\n <div className=\"flex size-10 items-center justify-center rounded-lg bg-[var(--color-action-primary-bg)]/12 font-semibold text-[var(--color-action-primary-bg)]\">\n {organization.name[0]}\n </div>\n )}\n <div className=\"min-w-0\">\n <p className=\"font-medium text-[var(--color-text-primary)]\">\n {organization.name}\n </p>\n <p className=\"break-all font-mono text-sm text-[var(--color-text-muted)]\">\n /{organization.slug}\n </p>\n </div>\n </div>\n </td>\n <td className=\"px-6 py-4 align-top\">\n <OrganizationStatusBadge status={organization.status} />\n </td>\n <td className=\"px-6 py-4 align-top text-[var(--color-text-primary)]\">\n {organization.workspaceCount ?? 0}\n </td>\n <td className=\"px-6 py-4 align-top text-sm text-[var(--color-text-secondary)]\">\n {formatDate(organization.createdAt)}\n </td>\n <td className=\"px-6 py-4 align-top\">\n <div\n className=\"flex items-center justify-end gap-2\"\n {...(organization === organizations[0]\n ? { 'data-tour': 'organizations-table-actions' }\n : {})}\n >\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${organization.id}`)}\n className=\"rounded-lg p-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:bg-[var(--color-bg-muted)] hover:text-[var(--color-text-primary)]\"\n title={`${tr('common.view', 'View')} ${organization.name}`}\n aria-label={`${tr('common.view', 'View')} ${organization.name}`}\n >\n <Eye size={18} aria-hidden=\"true\" />\n </button>\n {hasPermission(PERMISSIONS.ORG_UPDATE) && (\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${organization.id}/edit`)}\n className=\"rounded-lg p-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:bg-[var(--color-bg-muted)] hover:text-[var(--color-text-primary)]\"\n title={`${tr('common.edit', 'Edit')} ${organization.name}`}\n aria-label={`${tr('common.edit', 'Edit')} ${organization.name}`}\n >\n <SquarePen size={18} aria-hidden=\"true\" />\n </button>\n )}\n {mode === 'admin' && hasPermission(PERMISSIONS.ORG_DELETE) && (\n <button\n type=\"button\"\n onClick={() => handleDelete(organization.id, organization.name)}\n disabled={deleteLoading}\n 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\"\n title={`${tr('common.delete', 'Delete')} ${organization.name}`}\n aria-label={`${tr('common.delete', 'Delete')} ${organization.name}`}\n >\n <Trash2 size={18} aria-hidden=\"true\" />\n </button>\n )}\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </GlassCard>\n </>\n )}\n </div>\n\n {ConfirmDialog}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAuCA,SAAS,EAAW,GAAc;AAChC,QAAO,IAAI,KAAK,EAAK,CAAC,oBAAoB;;AAoB5C,SAAgB,EAAsB,EAAE,UAAO,SAAqC,EAAE,EAAE;AACtF,IAAwB,qBAAqB;CAC7C,IAAM,IAAK,IAAO,EACZ,EAAE,aAAU,cAAW,qBAAqB,GAAe,EAC3D,EAAE,kBAAe,WAAW,OAAuB,IAAgB,EAGnE,IAAgB,EAAsB,sBAAsB,EAC5D,IAAgB,IAAgB,EAAQ,EAAc,QAAS,IAC/D,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,IAAuB,GAAkB,GAAa,IAAI,EAC1D,CAAC,GAAyB,KAA8B,kBAAsB,IAAI,KAAK,CAAC,EACxF,EAAE,sBAAmB,sBAAkB,IAAkB,EAKzD,EAAE,OAAO,MAAwB,EAAa,GAAa,SAAS,GAAG,GAAG,MAAS,KAAK,EAOxF,KAAW,EAAmB,KAAyB,GAAG,MAAS,KAAK,EACxE,KAAc,GAAiB,KAAA,GAAW,KAAyB,GAAG,MAAS,QAAQ,EACvF,EACJ,eAAe,GACf,aACA,UACA,eACE,MAAS,UAAU,KAAc,IAE/B,KAAmB,EAAqB,MAAM,CAAC,SAAS,GAExD,IAAgB,QAAc;EAClC,IAAM,IAAI,EAAqB,MAAM,CAAC,aAAa;AAEnD,SADK,IACE,EAAiB,QACrB,MAAQ,EAAI,MAAM,aAAa,CAAC,SAAS,EAAE,IAAI,EAAI,MAAM,aAAa,CAAC,SAAS,EAAE,CACpF,GAHc;IAId,CAAC,GAAkB,EAAqB,CAAC,EAEtC,EAAE,wBAAoB,SAAS,MAAkB,GAAuB;AAE9E,UAAgB;AACd,KAA4B,MAAsB;GAChD,IAAM,IAAa,IAAI,IAAI,EAAc,KAAK,MAAiB,EAAa,GAAG,CAAC,EAC1E,IAAgB,IAAI,IACxB,CAAC,GAAG,EAAkB,CAAC,QAAQ,MAAmB,EAAW,IAAI,EAAe,CAAC,CAClF;AAMD,UAJI,EAAc,SAAS,EAAkB,OACpC,IAGF;IACP;IACD,CAAC,EAAc,CAAC;CAEnB,IAAM,IAAwB,QACtB,EAAc,QAAQ,MAAiB,EAAwB,IAAI,EAAa,GAAG,CAAC,EAC1F,CAAC,GAAe,EAAwB,CACzC,EAEK,IACJ,EAAc,SAAS,KACvB,EAAc,OAAO,MAAiB,EAAwB,IAAI,EAAa,GAAG,CAAC,EAC/E,IACJ,EAAc,MAAM,MAAiB,EAAwB,IAAI,EAAa,GAAG,CAAC,IAClF,CAAC,GAEG,IAAgB,OAAO,MAA8B;AACzD,MAAI;GAUF,IAAM,KATU,MAAM,QAAQ,WAC5B,EAAgB,IAAI,OAAO,MAAmB;IAC5C,IAAM,IAAS,MAAM,GAAmB,EAAe;AACvD,QAAI,EAAO,QAAQ,OACjB,OAAU,MAAM,EAAO,OAAO,IAAI,WAAW,gCAAgC;KAE/E,CACH,EAE8B,MAAM,MAAW,EAAO,WAAW,WAAW;AAC7E,OAAI,GAAgB,WAAW,WAC7B,OAAM,EAAe;AAIvB,GADA,kBAA2B,IAAI,KAAK,CAAC,EACrC,MAAM,GAAS;GACf,IAAM,IACJ,EAAgB,WAAW,IACvB,EAAG,sCAAsC,oCAAoC,GAC7E,GAAG,EAAgB,OAAO,GAAG,EAAG,oCAAoC,qCAAqC;AAG/G,GAFA,EAAM,QAAQ,EAAW,EACpB,EAAa,UAAU,EACxB,GAAU,IAAO,EAAY,EAAW;WACrC,GAAa;GACpB,IAAM,IACJ,aAAuB,QACnB,EAAY,UACZ,EAAG,+BAA+B,gCAAgC;AAGxE,GAFA,EAAM,MAAM,EAAS,EAChB,EAAa,QAAQ,EACtB,GAAU,IAAO,EAAY,EAAS;;IAIxC,KAAgB,GAAwB,MAA6B;AACzE,KAAa,SAAS;EACtB,IAAM,IAAQ,EAAG,8BAA8B,sBAAsB,EAC/D,IAAc,GAAG,EAAG,sCAAsC,SAAS,CAAC,GAAG,EAAiB,IAAI,EAAG,yBAAyB,gCAAgC;AACzJ,KAAc;GACjB;GACA,SAAS;GACT,eAAe,EAAG,iBAAiB,SAAS;GAC7C,CAAC,CAAC,MAAM,MAAiB;AACxB,GAAI,MAAiB,OACnB,EAAkB;IAChB;IACA;IACA,aAAa,EAAG,iBAAiB,SAAS;IAC1C,SAAS;IACT,iBAAiB;AACV,OAAc,CAAC,EAAe,CAAC;;IAEvC,CAAC,GACO,KACJ,EAAc,CAAC,EAAe,CAAC;IAEtC;IAGE,WAAyB;AACzB,IAAsB,WAAW,KAErC,EAAkB;GAChB,OAAO,EAAG,kCAAkC,gCAAgC;GAC5E,aAAa,GAAG,EAAG,mCAAmC,SAAS,CAAC,GAAG,EAAsB,OAAO,GAAG,EACjG,EAAsB,WAAW,IAC7B,0CACA,uCACJ,EAAsB,WAAW,IAAI,2BAA2B,0BACjE,CAAC,GAAG,EAAG,yBAAyB,gCAAgC;GACjE,aAAa,GAAG,EAAG,iBAAiB,SAAS,CAAC,GAAG,EAAsB;GACvE,SAAS;GACT,iBAAiB;AACV,MAAc,EAAsB,KAAK,MAAiB,EAAa,GAAG,CAAC;;GAEnF,CAAC;IAGE,KAA+B,GAAwB,MAAqB;AAChF,KAA4B,MAAsB;GAChD,IAAM,IAAgB,IAAI,IAAI,EAAkB;AAMhD,UALI,IACF,EAAc,IAAI,EAAe,GAEjC,EAAc,OAAO,EAAe,EAE/B;IACP;IAGE,KAA0B,MAAqB;AACnD,KAA4B,MAAsB;GAChD,IAAM,IAAgB,IAAI,IAAI,EAAkB;AAQhD,UAPA,EAAc,SAAS,MAAiB;AACtC,IAAI,IACF,EAAc,IAAI,EAAa,GAAG,GAElC,EAAc,OAAO,EAAa,GAAG;KAEvC,EACK;IACP;;AAyCJ,QAtCI,KAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD,EAAc,SAAS,EAAG,6BAA6B,yBAAyB,EAAI,CAAA;EAChF,CAAA,GAUN,KAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD,EAAc,SAAS,EAAG,8BAA8B,2BAA2B,EAAI,CAAA;EACnF,CAAA,GAIN,IAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,IAAD;GACE,SAAS,EAAM;GACf,QAAQ;IACN,OAAO,EAAG,gBAAgB,QAAQ;IAClC,eAAe;AACR,QAAS;;IAEjB;GACD,CAAA;EACE,CAAA,GAKR,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAkB,WAAU,UAAW,CAAA,EACvC,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;OAAY,aAAU;iBAArC;QACE,kBAAC,MAAD;SAAI,WAAU;mBACZ,kBAAC,GAAD,EAAA,UAAe,EAAG,4BAA4B,gBAAgB,EAAgB,CAAA;SAC3E,CAAA;QACL,kBAAC,KAAD;SAAG,WAAU;mBACV,EACC,+BACA,sEACD;SACC,CAAA;QACJ,kBAAC,GAAD;SAAa,WAAU;mBACpB,EACC,8BACA,gOACD;SACW,CAAA;QACV;UAEN,kBAAC,OAAD;OACE,WAAU;OACV,aAAU;iBAEV,kBAAC,IAAD;QACE,SACE,KAAiB,EAAc,EAAY,WAAW,GAClD;SACE,OAAO,EAAG,+BAA+B,sBAAsB;SAC/D,MAAM,kBAAC,GAAD;UAAM,MAAM;UAAI,eAAY;UAAS,CAAA;SAC3C,gBAAgB,EAAS,GAAG,EAAS,MAAM;SAC5C,GACD,KAAA;QAEN,SACE,MAAS,OACL,CACE;SACE,OACE,IAAsB,IAClB,GAAG,EAAG,oCAAoC,cAAc,CAAC,IAAI,EAAoB,KACjF,EAAG,oCAAoC,cAAc;SAC3D,MAAM,kBAAC,IAAD;UAAM,MAAM;UAAI,eAAY;UAAS,CAAA;SAC3C,gBAAgB,EAAS,GAAG,EAAS,UAAU;SAChD,CACF,GACD,EAAE;QAER,CAAA;OACE,CAAA,CACF;QACF;;IAEL,EAAiB,SAAS,IACzB,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD;OAAW,WAAU;OAAQ,MAAA;OAAK,WAAU;iBAA5C,CACE,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAG,4BAA4B,gBAAgB;QAC9C,CAAA,EACJ,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAiB;QAChB,CAAA,CACM;;MACZ,kBAAC,GAAD;OAAW,WAAU;OAAS,WAAU;iBAAxC,CACE,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAG,wCAAwC,aAAa;QACvD,CAAA,EACJ,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAiB,QAAQ,GAAK,MAAQ,KAAO,EAAI,kBAAkB,IAAI,EAAE;QACxE,CAAA,CACM;;MACX,MAAS,OACR,kBAAC,GAAD;OAAW,WAAU;OAAS,WAAU;iBAAxC,CACE,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAG,oCAAoC,cAAc;QACpD,CAAA,EACJ,kBAAC,KAAD;QAAG,WAAU;kBACV;QACC,CAAA,CACM;WACV;MACA;SACJ;IAEJ,kBAAC,GAAD;KAAW,WAAU;KAAQ,WAAU;eAAvC,CACE,kBAAC,OAAD;MACE,WAAU;MACV,aAAU;gBAFZ,CAIE,kBAAC,IAAD;OACE,OAAO;OACP,UAAU;OACV,aAAa,EAAG,wCAAwC,0BAA0B;OAClF,OAAO,EAAG,kCAAkC,uBAAuB;OACnE,SAAQ;OACR,WAAU;OACV,CAAA,EAEF,kBAAC,UAAD;OACE,MAAK;OACL,eAAe;AACR,WAAS;;OAEhB,WAAU;OACV,cAAY,EAAG,8BAA8B,wBAAwB;OACrE,OAAO,EAAG,8BAA8B,wBAAwB;OAChE,aAAU;iBAEV,kBAAC,GAAD;QAAW,MAAM;QAAI,eAAY;QAAS,CAAA;OACnC,CAAA,CACL;SAEL,EAAc,SAAS,IACtB,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,SAAD;QAAO,WAAU;kBAAjB,CACE,kBAAC,GAAD;SACE,SAAS;SACT,eAAe;SACf,UAAU;SACV,WAAW,EAAG,gCAAgC,2BAA2B;SACzE,CAAA,EACF,kBAAC,QAAD,EAAA,UAAO,EAAG,2BAA2B,qBAAqB,EAAQ,CAAA,CAC5D;WAEP,EAAwB,OAAO,IAC9B,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,kBAA2B,IAAI,KAAK,CAAC;QACpD,WAAU;kBAET,EAAG,yBAAyB,kBAAkB;QACxC,CAAA,GACP,KACA;UAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAhB;SACG,EAAwB;SAAK;SAAE,EAAG,mBAAmB,WAAW;SAC5D;WACN,MAAS,WAAW,EAAc,EAAY,WAAW,IACxD,kBAAC,UAAD;QACE,MAAK;QACL,SAAS;QACT,UAAU,EAAsB,WAAW,KAAK;QAChD,WAAU;kBAJZ;SAME,kBAAC,GAAD;UAAQ,MAAM;UAAI,eAAY;UAAS,CAAA;SACvC,kBAAC,QAAD,EAAA,UAAO,EAAG,yBAAyB,kBAAkB,EAAQ,CAAA;SAC5D,EAAsB,SAAS,IAC9B,kBAAC,QAAD,EAAA,UAAA;UAAM;UAAE,EAAsB;UAAO;UAAQ,EAAA,CAAA,GAC3C;SACG;UAEP;SACF;UACJ,KACM;;IAEX,EAAc,WAAW,IACxB,kBAAC,GAAD;KACE,WAAU;KACV,MAAM,EAAiB,WAAW;KAClC,WAAU;eAET,MAAoB,EAAiB,SAAS,IAC7C,kBAAC,GAAD;MACE,cAAa;MACb,OAAO,EAAG,qCAAqC,4BAA4B;MAC3E,aAAa,EACX,2CACA,yFACD;MACD,QACE,kBAAC,UAAD;OACE,MAAK;OACL,eAAe,EAAe,GAAG;OACjC,WAAU;iBAET,EAAG,sBAAsB,eAAe;OAClC,CAAA;MAEX,CAAA,GAEF,kBAAC,GAAD;MACE,cAAa;MACb,OAAO,EAAG,iCAAiC,yBAAyB;MACpE,aAAa,EACX,uCACA,qFACD;MACD,QACE,KAAiB,EAAc,EAAY,WAAW,GACpD,kBAAC,UAAD;OACE,MAAK;OACL,eAAe,EAAS,GAAG,EAAS,MAAM;OAC1C,WAAU;iBAHZ,CAKE,kBAAC,GAAD;QAAM,MAAM;QAAI,eAAY;QAAS,CAAA,EACpC,EAAG,+BAA+B,sBAAsB,CAClD;WACP,KAAA;MAEN,CAAA;KAEM,CAAA,GAEZ,kBAAA,IAAA,EAAA,UAAA,CACE,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAc,KAAK,MAClB,kBAAC,GAAD;MAEE,WAAU;MACV,WAAU;gBAHZ,CAKE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QACE,SAAS,EAAwB,IAAI,EAAa,GAAG;QACrD,WAAW,MAAY,EAA4B,EAAa,IAAI,EAAQ;QAC5E,WAAW,GAAG,EAAG,gCAAgC,sBAAsB,CAAC,GAAG,EAAa;QACxF,CAAA,EAEF,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACG,EAAa,OACZ,kBAAC,OAAD;SACE,KAAK,EAAa;SAClB,KAAK,GAAG,EAAa,KAAK,GAAG,EAAG,eAAe,OAAO;SACtD,WAAU;SACV,CAAA,GAEF,kBAAC,OAAD;SAAK,WAAU;mBACZ,EAAa,KAAK;SACf,CAAA,EAGR,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,MAAD;YAAI,WAAU;sBACX,EAAa;YACX,CAAA,EACL,kBAAC,GAAD,EAAyB,QAAQ,EAAa,QAAU,CAAA,CACpD;;UACN,kBAAC,KAAD;WAAG,WAAU;qBAAb,CAA+E,KAC3E,EAAa,KACb;;UACJ,kBAAC,MAAD;WAAI,WAAU;qBAAd,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;YAAI,WAAU;sBACX,EAAG,wCAAwC,aAAa;YACtD,CAAA,EACL,kBAAC,MAAD;YAAI,WAAU;sBACX,EAAa,kBAAkB;YAC7B,CAAA,CACD,EAAA,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;YAAI,WAAU;sBACX,EAAG,kBAAkB,UAAU;YAC7B,CAAA,EACL,kBAAC,MAAD;YAAI,WAAU;sBACX,EAAW,EAAa,UAAU;YAChC,CAAA,CACD,EAAA,CAAA,CACH;;UACD;WACF;UACF;UAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,EAAS,GAAG,EAAS,GAAG,EAAa,KAAK;SACzD,WAAU;mBAHZ,CAKE,kBAAC,GAAD;UAAK,MAAM;UAAI,eAAY;UAAS,CAAA,EACnC,EAAG,eAAe,OAAO,CACnB;;QACR,EAAc,EAAY,WAAW,IACpC,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,EAAS,GAAG,EAAS,GAAG,EAAa,GAAG,OAAO;SAC9D,WAAU;mBAHZ,CAKE,kBAAC,GAAD;UAAW,MAAM;UAAI,eAAY;UAAS,CAAA,EACzC,EAAG,eAAe,OAAO,CACnB;;QAEV,MAAS,WAAW,EAAc,EAAY,WAAW,IACxD,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,EAAa,EAAa,IAAI,EAAa,KAAK;SAC/D,UAAU;SACV,WAAU;mBAJZ,CAME,kBAAC,GAAD;UAAQ,MAAM;UAAI,eAAY;UAAS,CAAA,EACtC,EAAG,iBAAiB,SAAS,CACvB;;QAEP;SACI;QAvFL,EAAa,GAuFR,CACZ;KACE,CAAA,EAEN,kBAAC,GAAD;KACE,WAAU;KACV,WAAU;KACV,aAAU;eAEV,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,SAAD;OAAO,WAAU;iBAAjB,CACE,kBAAC,SAAD;QAAO,WAAU;kBACf,kBAAC,MAAD,EAAA,UAAA;SACE,kBAAC,MAAD;UAAI,WAAU;oBACZ,kBAAC,GAAD;WACE,SAAS;WACT,eAAe;WACf,UAAU;WACV,WAAW,EAAG,gCAAgC,2BAA2B;WACzE,CAAA;UACC,CAAA;SACL,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAG,0CAA0C,eAAe;UAC1D,CAAA;SACL,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAG,iBAAiB,SAAS;UAC3B,CAAA;SACL,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAG,wCAAwC,aAAa;UACtD,CAAA;SACL,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAG,kBAAkB,UAAU;UAC7B,CAAA;SACL,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAG,kBAAkB,UAAU;UAC7B,CAAA;SACF,EAAA,CAAA;QACC,CAAA,EACR,kBAAC,SAAD;QAAO,WAAU;kBACd,EAAc,KAAK,MAClB,kBAAC,MAAD;SAEE,WAAU;mBAFZ;UAIE,kBAAC,MAAD;WAAI,WAAU;qBACZ,kBAAC,GAAD;YACE,SAAS,EAAwB,IAAI,EAAa,GAAG;YACrD,WAAW,MACT,EAA4B,EAAa,IAAI,EAAQ;YAEvD,WAAW,GAAG,EAAG,gCAAgC,sBAAsB,CAAC,GAAG,EAAa;YACxF,CAAA;WACC,CAAA;UACL,kBAAC,MAAD;WAAI,WAAU;qBACZ,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACG,EAAa,OACZ,kBAAC,OAAD;aACE,KAAK,EAAa;aAClB,KAAK,GAAG,EAAa,KAAK,GAAG,EAAG,eAAe,OAAO;aACtD,WAAU;aACV,CAAA,GAEF,kBAAC,OAAD;aAAK,WAAU;uBACZ,EAAa,KAAK;aACf,CAAA,EAER,kBAAC,OAAD;aAAK,WAAU;uBAAf,CACE,kBAAC,KAAD;cAAG,WAAU;wBACV,EAAa;cACZ,CAAA,EACJ,kBAAC,KAAD;cAAG,WAAU;wBAAb,CAA0E,KACtE,EAAa,KACb;gBACA;eACF;;WACH,CAAA;UACL,kBAAC,MAAD;WAAI,WAAU;qBACZ,kBAAC,GAAD,EAAyB,QAAQ,EAAa,QAAU,CAAA;WACrD,CAAA;UACL,kBAAC,MAAD;WAAI,WAAU;qBACX,EAAa,kBAAkB;WAC7B,CAAA;UACL,kBAAC,MAAD;WAAI,WAAU;qBACX,EAAW,EAAa,UAAU;WAChC,CAAA;UACL,kBAAC,MAAD;WAAI,WAAU;qBACZ,kBAAC,OAAD;YACE,WAAU;YACV,GAAK,MAAiB,EAAc,KAChC,EAAE,aAAa,+BAA+B,GAC9C,EAAE;sBAJR;aAME,kBAAC,UAAD;cACE,MAAK;cACL,eAAe,EAAS,GAAG,EAAS,GAAG,EAAa,KAAK;cACzD,WAAU;cACV,OAAO,GAAG,EAAG,eAAe,OAAO,CAAC,GAAG,EAAa;cACpD,cAAY,GAAG,EAAG,eAAe,OAAO,CAAC,GAAG,EAAa;wBAEzD,kBAAC,GAAD;eAAK,MAAM;eAAI,eAAY;eAAS,CAAA;cAC7B,CAAA;aACR,EAAc,EAAY,WAAW,IACpC,kBAAC,UAAD;cACE,MAAK;cACL,eAAe,EAAS,GAAG,EAAS,GAAG,EAAa,GAAG,OAAO;cAC9D,WAAU;cACV,OAAO,GAAG,EAAG,eAAe,OAAO,CAAC,GAAG,EAAa;cACpD,cAAY,GAAG,EAAG,eAAe,OAAO,CAAC,GAAG,EAAa;wBAEzD,kBAAC,GAAD;eAAW,MAAM;eAAI,eAAY;eAAS,CAAA;cACnC,CAAA;aAEV,MAAS,WAAW,EAAc,EAAY,WAAW,IACxD,kBAAC,UAAD;cACE,MAAK;cACL,eAAe,EAAa,EAAa,IAAI,EAAa,KAAK;cAC/D,UAAU;cACV,WAAU;cACV,OAAO,GAAG,EAAG,iBAAiB,SAAS,CAAC,GAAG,EAAa;cACxD,cAAY,GAAG,EAAG,iBAAiB,SAAS,CAAC,GAAG,EAAa;wBAE7D,kBAAC,GAAD;eAAQ,MAAM;eAAI,eAAY;eAAS,CAAA;cAChC,CAAA;aAEP;;WACH,CAAA;UACF;WArFE,EAAa,GAqFf,CACL;QACI,CAAA,CACF;;MACJ,CAAA;KACI,CAAA,CACX,EAAA,CAAA;IAED;MAEL,GACG"}
|
|
1
|
+
{"version":3,"file":"OrganizationsListPage.js","names":["_Fragment","formatDate","date","OrganizationsListPage","tr","useTr","useOrgConsole","permissionsLoading","usePermissions","createDetails","useFeatureFlagDetails","createEnabled","searchQuery","setSearchQuery","useState","debouncedSearchQuery","useDebouncedValue","selectedOrganizationIds","setSelectedOrganizationIds","useConfirmDialog","pendingInvitesCount","useMyInvites","InviteStatus","mode","myResult","useMyOrganizations","adminResult","useOrganizations","allOrganizations","isSearchFiltered","organizations","useMemo","q","org","deleteLoading","useDeleteOrganization","visibleIds","organization","nextSelection","previousSelection","organizationId","selectedOrganizations","allVisibleSelected","partiallySelected","executeDelete","rejectedResult","organizationIds","result","deleteOrganization","refetch","successMsg","toast","nativeNotify","isNative","nativeToast","deleteError","errorMsg","handleDelete","title","description","organizationName","nativeResult","openConfirmDialog","handleBulkDelete","toggleOrganizationSelection","checked","toggleAllOrganizations","LoadingState","loading","error","ErrorState","AuroraBackground","GradientText","PagePurpose","CTAOverflowMenu","hasPermission","PERMISSIONS","Plus","navigate","basePath","Mail","GlassCard","sum","SearchInput","RefreshCw","SelectionCheckbox","Trash2","IllustratedEmptyState","Fragment","OrganizationStatusBadge","Eye","SquarePen","ConfirmDialog"],"sources":["../../../../../src/organization-management/modules/organizations/pages/OrganizationsListPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport { Eye, Mail, Plus, RefreshCw, SquarePen, Trash2 } from 'lucide-react';\nimport { toast } from 'sonner';\nimport {\n AuroraBackground,\n CTAOverflowMenu,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useFeatureFlagDetails } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\nimport {\n useDeleteOrganization,\n useMyOrganizations,\n useOrganizations,\n} from '../hooks/useOrganizations';\nimport { useMyInvites } from '../../members/hooks/useInvites';\nimport { InviteStatus } from '../../../../generated/global-types';\nimport { OrganizationStatusBadge } from '../components/OrganizationStatusBadge';\nimport { SearchInput } from '../../../shared/components/input/SearchInput';\nimport { SelectionCheckbox } from '../../../shared/components/input/SelectionCheckbox';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { ErrorState } from '../../../shared/components/feedback/ErrorState';\nimport { useDebouncedValue } from '../../../shared/hooks/useDebouncedValue';\nimport { useConfirmDialog } from '../../../shared/components/dialog/ConfirmDialog';\nimport { PERMISSIONS } from '../../../constants/permissions';\nimport { useTr } from '../../../shared/hooks/useTr';\nimport { useOrganizationPageView } from '../../../hooks/useOrganizationPageView';\nimport {\n isNative,\n nativeConfirm,\n nativeImpact,\n nativeNotify,\n nativeToast,\n} from '../../../../utils/nativeBridge';\n\nfunction formatDate(date: string) {\n return new Date(date).toLocaleDateString();\n}\n\n/**\n * `mode` controls which scope of organizations the page renders:\n *\n * - `'my'` (default) calls `myOrganizations` (gateway @rbac(scopeType:\"self\")).\n * Use this in product-app shells (e.g. vibecontrols) where the user should\n * see only orgs they are a member of. Membership IS the access list, so no\n * client-side permission gate is needed.\n *\n * - `'admin'` calls `allOrganizations` (gateway @rbac(scopeType: \"global\")).\n * Restricted to actors with global `organization:read` (super admins /\n * service / custom global-admin roles). Use this in the admin app where\n * operators need the tenant-wide list.\n */\nexport interface OrganizationsListPageProps {\n mode?: 'my' | 'admin';\n}\n\nexport function OrganizationsListPage({ mode = 'my' }: OrganizationsListPageProps = {}) {\n useOrganizationPageView('organizations.list');\n const tr = useTr();\n const { navigate, basePath = '/organizations' } = useOrgConsole();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n // Follow the platform default-allow feature flag policy: unseeded flags must\n // not disable shipped CRUDL, while an explicit false value still gates create.\n const createDetails = useFeatureFlagDetails('organization.create');\n const createEnabled = createDetails ? Boolean(createDetails.value) : true;\n const [searchQuery, setSearchQuery] = useState('');\n const debouncedSearchQuery = useDebouncedValue(searchQuery, 300);\n const [selectedOrganizationIds, setSelectedOrganizationIds] = useState<Set<string>>(new Set());\n const { openConfirmDialog, ConfirmDialog } = useConfirmDialog();\n\n // Show a count badge of pending invites alongside the Invitations link.\n // Skipped in 'admin' mode since admins land here via tenant-wide management\n // rather than personal invites.\n const { total: pendingInvitesCount } = useMyInvites(InviteStatus.Pending, 1, 0, mode === 'my');\n\n // Page size is large enough to cover realistic memberships / tenant-wide\n // org counts in one round-trip so the client-side search is exhaustive.\n // If a tenant ever exceeds this, wire in fetchMore/pagination instead of\n // silently truncating.\n const ORGANIZATIONS_PAGE_SIZE = 200;\n const myResult = useMyOrganizations(ORGANIZATIONS_PAGE_SIZE, 0, mode === 'my');\n const adminResult = useOrganizations(undefined, ORGANIZATIONS_PAGE_SIZE, 0, mode === 'admin');\n const {\n organizations: allOrganizations,\n loading,\n error,\n refetch,\n } = mode === 'admin' ? adminResult : myResult;\n\n const isSearchFiltered = debouncedSearchQuery.trim().length > 0;\n\n const organizations = useMemo(() => {\n const q = debouncedSearchQuery.trim().toLowerCase();\n if (!q) return allOrganizations;\n return allOrganizations.filter(\n (org) => org.name?.toLowerCase().includes(q) || org.slug?.toLowerCase().includes(q)\n );\n }, [allOrganizations, debouncedSearchQuery]);\n\n const { deleteOrganization, loading: deleteLoading } = useDeleteOrganization();\n\n useEffect(() => {\n setSelectedOrganizationIds((previousSelection) => {\n const visibleIds = new Set(organizations.map((organization) => organization.id));\n const nextSelection = new Set(\n [...previousSelection].filter((organizationId) => visibleIds.has(organizationId))\n );\n\n if (nextSelection.size === previousSelection.size) {\n return previousSelection;\n }\n\n return nextSelection;\n });\n }, [organizations]);\n\n const selectedOrganizations = useMemo(\n () => organizations.filter((organization) => selectedOrganizationIds.has(organization.id)),\n [organizations, selectedOrganizationIds]\n );\n\n const allVisibleSelected =\n organizations.length > 0 &&\n organizations.every((organization) => selectedOrganizationIds.has(organization.id));\n const partiallySelected =\n organizations.some((organization) => selectedOrganizationIds.has(organization.id)) &&\n !allVisibleSelected;\n\n const executeDelete = async (organizationIds: string[]) => {\n try {\n const results = await Promise.allSettled(\n organizationIds.map(async (organizationId) => {\n const result = await deleteOrganization(organizationId);\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message ?? 'Failed to delete organization');\n }\n })\n );\n\n const rejectedResult = results.find((result) => result.status === 'rejected');\n if (rejectedResult?.status === 'rejected') {\n throw rejectedResult.reason;\n }\n\n setSelectedOrganizationIds(new Set());\n await refetch();\n const successMsg =\n organizationIds.length === 1\n ? tr('organizations.delete.successSingle', 'Organization deleted successfully')\n : `${organizationIds.length} ${tr('organizations.delete.successMany', 'organizations deleted successfully')}`;\n toast.success(successMsg);\n void nativeNotify('success');\n if (isNative()) void nativeToast(successMsg);\n } catch (deleteError) {\n const errorMsg =\n deleteError instanceof Error\n ? deleteError.message\n : tr('organizations.delete.failed', 'Failed to delete organization');\n toast.error(errorMsg);\n void nativeNotify('error');\n if (isNative()) void nativeToast(errorMsg);\n }\n };\n\n const handleDelete = (organizationId: string, organizationName: string) => {\n nativeImpact('medium');\n const title = tr('organizations.delete.title', 'Delete organization');\n const description = `${tr('organizations.delete.confirmPrefix', 'Delete')} ${organizationName}? ${tr('common.cannotBeUndone', 'This action cannot be undone.')}`;\n void nativeConfirm({\n title,\n message: description,\n okButtonTitle: tr('common.delete', 'Delete'),\n }).then((nativeResult) => {\n if (nativeResult === null) {\n openConfirmDialog({\n title,\n description,\n confirmText: tr('common.delete', 'Delete'),\n variant: 'danger',\n onConfirm: () => {\n void executeDelete([organizationId]);\n },\n });\n } else if (nativeResult) {\n void executeDelete([organizationId]);\n }\n });\n };\n\n const handleBulkDelete = () => {\n if (selectedOrganizations.length === 0) return;\n\n openConfirmDialog({\n title: tr('organizations.delete.bulkTitle', 'Delete selected organizations'),\n description: `${tr('organizations.delete.bulkPrefix', 'Delete')} ${selectedOrganizations.length} ${tr(\n selectedOrganizations.length === 1\n ? 'organizations.delete.bulkSuffixSingle'\n : 'organizations.delete.bulkSuffixMany',\n selectedOrganizations.length === 1 ? 'selected organization?' : 'selected organizations?'\n )} ${tr('common.cannotBeUndone', 'This action cannot be undone.')}`,\n confirmText: `${tr('common.delete', 'Delete')} ${selectedOrganizations.length}`,\n variant: 'danger',\n onConfirm: () => {\n void executeDelete(selectedOrganizations.map((organization) => organization.id));\n },\n });\n };\n\n const toggleOrganizationSelection = (organizationId: string, checked: boolean) => {\n setSelectedOrganizationIds((previousSelection) => {\n const nextSelection = new Set(previousSelection);\n if (checked) {\n nextSelection.add(organizationId);\n } else {\n nextSelection.delete(organizationId);\n }\n return nextSelection;\n });\n };\n\n const toggleAllOrganizations = (checked: boolean) => {\n setSelectedOrganizationIds((previousSelection) => {\n const nextSelection = new Set(previousSelection);\n organizations.forEach((organization) => {\n if (checked) {\n nextSelection.add(organization.id);\n } else {\n nextSelection.delete(organization.id);\n }\n });\n return nextSelection;\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 // No client-side list gate: this page calls `myOrganizations`\n // (@rbac(scopeType: \"self\")), so the data set IS the access list — if the\n // user is in zero orgs the page renders the empty state, not a deny. The\n // create/delete/edit buttons keep their own per-action `hasPermission`\n // checks below to hide actions the user can't perform on a given org.\n\n if (loading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <LoadingState message={tr('organizations.list.loading', 'Loading organizations...')} />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <ErrorState\n message={error.message}\n action={{\n label: tr('common.retry', 'Retry'),\n onClick: () => {\n void refetch();\n },\n }}\n />\n </div>\n );\n }\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-200\">\n <div className=\"mx-auto flex w-full max-w-7xl flex-col gap-6\">\n <div className=\"relative overflow-hidden rounded-card\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"flex flex-col gap-4 p-1 lg:flex-row lg:items-start lg:justify-between\">\n <div className=\"space-y-2\" data-tour=\"organizations-page-header\">\n <h1 className=\"text-3xl font-bold text-[var(--color-text-primary)]\">\n <GradientText>{tr('organizations.list.title', 'Organizations')}</GradientText>\n </h1>\n <p className=\"max-w-2xl text-[var(--color-text-secondary)]\">\n {tr(\n 'organizations.list.subtitle',\n 'Manage tenant organizations and the workspaces that belong to them.'\n )}\n </p>\n <PagePurpose className=\"max-w-2xl\">\n {tr(\n 'organizations.list.purpose',\n 'An organization is the top-level container that groups your workspaces, members, and invitations under one roof — use it to onboard a company or team, control who belongs, and keep their workspaces organized in one place.'\n )}\n </PagePurpose>\n </div>\n\n <div\n className=\"flex flex-wrap items-center gap-2\"\n data-tour=\"organizations-create-button\"\n >\n <CTAOverflowMenu\n primary={\n createEnabled && hasPermission(PERMISSIONS.ORG_CREATE)\n ? {\n label: tr('organizations.create.button', 'Create Organization'),\n icon: <Plus size={18} aria-hidden=\"true\" />,\n onSelect: () => navigate(`${basePath}/new`),\n }\n : undefined\n }\n actions={\n mode === 'my'\n ? [\n {\n label:\n pendingInvitesCount > 0\n ? `${tr('organizations.invitations.button', 'Invitations')} (${pendingInvitesCount})`\n : tr('organizations.invitations.button', 'Invitations'),\n icon: <Mail size={16} aria-hidden=\"true\" />,\n onSelect: () => navigate(`${basePath}/invites`),\n },\n ]\n : []\n }\n />\n </div>\n </div>\n </div>\n\n {allOrganizations.length > 0 ? (\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3\">\n <GlassCard treatment=\"glass\" glow className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr('organizations.list.title', 'Organizations')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {allOrganizations.length}\n </p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <p className=\"text-sm text-text-secondary\">\n {tr('organizations.list.column.workspaces', 'Workspaces')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {allOrganizations.reduce((sum, org) => sum + (org.workspaceCount ?? 0), 0)}\n </p>\n </GlassCard>\n {mode === 'my' ? (\n <GlassCard treatment=\"metric\" className=\"col-span-2 p-4 sm:col-span-1\">\n <p className=\"text-sm text-text-secondary\">\n {tr('organizations.invitations.button', 'Invitations')}\n </p>\n <p className=\"mt-1 text-2xl font-semibold tabular-nums text-text-primary\">\n {pendingInvitesCount}\n </p>\n </GlassCard>\n ) : null}\n </div>\n ) : null}\n\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-4\">\n <div\n className=\"flex flex-col gap-3 sm:flex-row sm:items-center\"\n data-tour=\"organizations-search-input\"\n >\n <SearchInput\n value={searchQuery}\n onChange={setSearchQuery}\n placeholder={tr('organizations.list.searchPlaceholder', 'Search organizations...')}\n label={tr('organizations.list.searchLabel', 'Search organizations')}\n inputId=\"organizations-search\"\n className=\"flex-1\"\n />\n\n <button\n type=\"button\"\n onClick={() => {\n void refetch();\n }}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-4 py-2 text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n aria-label={tr('organizations.list.refresh', 'Refresh organizations')}\n title={tr('organizations.list.refresh', 'Refresh organizations')}\n data-tour=\"organizations-refresh-button\"\n >\n <RefreshCw size={18} aria-hidden=\"true\" />\n </button>\n </div>\n\n {organizations.length > 0 ? (\n <div className=\"mt-4 flex flex-col gap-3 rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-canvas)] p-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <label className=\"flex items-center gap-2 text-sm text-[var(--color-text-primary)]\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllOrganizations}\n ariaLabel={tr('organizations.list.selectAll', 'Select all organizations')}\n />\n <span>{tr('common.selectAllVisible', 'Select all visible')}</span>\n </label>\n\n {selectedOrganizationIds.size > 0 ? (\n <button\n type=\"button\"\n onClick={() => setSelectedOrganizationIds(new Set())}\n className=\"text-sm text-[var(--color-text-secondary)] transition-colors hover:text-[var(--color-text-primary)]\"\n >\n {tr('common.clearSelection', 'Clear selection')}\n </button>\n ) : null}\n </div>\n\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <span className=\"text-sm text-[var(--color-text-secondary)]\">\n {selectedOrganizationIds.size} {tr('common.selected', 'selected')}\n </span>\n {mode === 'admin' && hasPermission(PERMISSIONS.ORG_DELETE) && (\n <button\n type=\"button\"\n onClick={handleBulkDelete}\n disabled={selectedOrganizations.length === 0 || deleteLoading}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-status-error-border)] px-3 py-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\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n <span>{tr('common.deleteSelected', 'Delete Selected')}</span>\n {selectedOrganizations.length > 0 ? (\n <span>({selectedOrganizations.length})</span>\n ) : null}\n </button>\n )}\n </div>\n </div>\n ) : null}\n </GlassCard>\n\n {organizations.length === 0 ? (\n <GlassCard\n treatment=\"glass\"\n glow={allOrganizations.length === 0}\n className=\"border-border-seam p-6\"\n >\n {isSearchFiltered && allOrganizations.length > 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title={tr('organizations.list.noMatchesTitle', 'No matching organizations')}\n description={tr(\n 'organizations.list.noMatchesDescription',\n 'No organizations match your search. Try a different name or slug, or clear the search.'\n )}\n action={\n <button\n type=\"button\"\n onClick={() => setSearchQuery('')}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] px-4 py-2 text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n >\n {tr('common.clearSearch', 'Clear search')}\n </button>\n }\n />\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-people\"\n title={tr('organizations.list.emptyTitle', 'No organizations found')}\n description={tr(\n 'organizations.list.emptyDescription',\n 'Create your first organization to start managing workspaces, members, and invites.'\n )}\n action={\n createEnabled && hasPermission(PERMISSIONS.ORG_CREATE) ? (\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/new`)}\n className=\"inline-flex min-h-11 items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-4 py-2 font-medium text-[var(--color-action-primary-text)] transition-all duration-200 hover:bg-[var(--color-action-primary-bgHover)]\"\n >\n <Plus size={18} aria-hidden=\"true\" />\n {tr('organizations.create.button', 'Create Organization')}\n </button>\n ) : undefined\n }\n />\n )}\n </GlassCard>\n ) : (\n <>\n <div className=\"grid gap-4 md:hidden\">\n {organizations.map((organization) => (\n <GlassCard\n key={organization.id}\n treatment=\"insight\"\n className=\"border-border-seam p-4\"\n >\n <div className=\"flex items-start gap-3\">\n <SelectionCheckbox\n checked={selectedOrganizationIds.has(organization.id)}\n onChange={(checked) => toggleOrganizationSelection(organization.id, checked)}\n ariaLabel={`${tr('organizations.list.selectOne', 'Select organization')} ${organization.name}`}\n />\n\n <div className=\"flex min-w-0 flex-1 gap-3\">\n {organization.logo ? (\n <img\n src={organization.logo}\n alt={`${organization.name} ${tr('common.logo', 'logo')}`}\n className=\"size-12 rounded-lg object-cover\"\n />\n ) : (\n <div className=\"flex size-12 items-center justify-center rounded-lg bg-[var(--color-action-primary-bg)]/12 text-base font-semibold text-[var(--color-action-primary-bg)]\">\n {organization.name[0]}\n </div>\n )}\n\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-start gap-2\">\n <h2 className=\"text-base font-semibold text-[var(--color-text-primary)]\">\n {organization.name}\n </h2>\n <OrganizationStatusBadge status={organization.status} />\n </div>\n <p className=\"mt-1 break-all font-mono text-sm text-[var(--color-text-muted)]\">\n /{organization.slug}\n </p>\n <dl className=\"mt-3 grid grid-cols-2 gap-3 text-sm\">\n <div>\n <dt className=\"text-[var(--color-text-secondary)]\">\n {tr('organizations.list.column.workspaces', 'Workspaces')}\n </dt>\n <dd className=\"font-medium text-[var(--color-text-primary)]\">\n {organization.workspaceCount ?? 0}\n </dd>\n </div>\n <div>\n <dt className=\"text-[var(--color-text-secondary)]\">\n {tr('common.created', 'Created')}\n </dt>\n <dd className=\"font-medium text-[var(--color-text-primary)]\">\n {formatDate(organization.createdAt)}\n </dd>\n </div>\n </dl>\n </div>\n </div>\n </div>\n\n <div className=\"mt-4 flex flex-wrap gap-2 border-t border-[var(--color-border-default)] pt-4\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${organization.id}`)}\n className=\"inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-border-default)] px-3 py-2 text-sm text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n >\n <Eye size={16} aria-hidden=\"true\" />\n {tr('common.view', 'View')}\n </button>\n {hasPermission(PERMISSIONS.ORG_UPDATE) && (\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${organization.id}/edit`)}\n className=\"inline-flex min-h-10 items-center gap-2 rounded-lg border border-[var(--color-border-default)] px-3 py-2 text-sm text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]\"\n >\n <SquarePen size={16} aria-hidden=\"true\" />\n {tr('common.edit', 'Edit')}\n </button>\n )}\n {mode === 'admin' && hasPermission(PERMISSIONS.ORG_DELETE) && (\n <button\n type=\"button\"\n onClick={() => handleDelete(organization.id, organization.name)}\n disabled={deleteLoading}\n 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\"\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n {tr('common.delete', 'Delete')}\n </button>\n )}\n </div>\n </GlassCard>\n ))}\n </div>\n\n <GlassCard\n treatment=\"plain\"\n className=\"hidden overflow-hidden border-border-seam p-0 md:block\"\n data-tour=\"organizations-table\"\n >\n <div className=\"overflow-x-auto\">\n <table className=\"min-w-full\">\n <thead className=\"bg-[var(--color-bg-subtle)]\">\n <tr>\n <th className=\"w-12 px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllOrganizations}\n ariaLabel={tr('organizations.list.selectAll', 'Select all organizations')}\n />\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('organizations.list.column.organization', 'Organization')}\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.status', 'Status')}\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('organizations.list.column.workspaces', 'Workspaces')}\n </th>\n <th className=\"px-6 py-3 text-left text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.created', 'Created')}\n </th>\n <th className=\"px-6 py-3 text-right text-xs font-semibold uppercase tracking-wide text-[var(--color-text-secondary)]\">\n {tr('common.actions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-[var(--color-border-seam)]\">\n {organizations.map((organization) => (\n <tr\n key={organization.id}\n className=\"transition-colors hover:bg-[var(--color-bg-subtle)]\"\n >\n <td className=\"px-6 py-4 align-top\">\n <SelectionCheckbox\n checked={selectedOrganizationIds.has(organization.id)}\n onChange={(checked) =>\n toggleOrganizationSelection(organization.id, checked)\n }\n ariaLabel={`${tr('organizations.list.selectOne', 'Select organization')} ${organization.name}`}\n />\n </td>\n <td className=\"px-6 py-4\">\n <div className=\"flex items-start gap-3\">\n {organization.logo ? (\n <img\n src={organization.logo}\n alt={`${organization.name} ${tr('common.logo', 'logo')}`}\n className=\"size-10 rounded-lg object-cover\"\n />\n ) : (\n <div className=\"flex size-10 items-center justify-center rounded-lg bg-[var(--color-action-primary-bg)]/12 font-semibold text-[var(--color-action-primary-bg)]\">\n {organization.name[0]}\n </div>\n )}\n <div className=\"min-w-0\">\n <p className=\"font-medium text-[var(--color-text-primary)]\">\n {organization.name}\n </p>\n <p className=\"break-all font-mono text-sm text-[var(--color-text-muted)]\">\n /{organization.slug}\n </p>\n </div>\n </div>\n </td>\n <td className=\"px-6 py-4 align-top\">\n <OrganizationStatusBadge status={organization.status} />\n </td>\n <td className=\"px-6 py-4 align-top text-[var(--color-text-primary)]\">\n {organization.workspaceCount ?? 0}\n </td>\n <td className=\"px-6 py-4 align-top text-sm text-[var(--color-text-secondary)]\">\n {formatDate(organization.createdAt)}\n </td>\n <td className=\"px-6 py-4 align-top\">\n <div\n className=\"flex items-center justify-end gap-2\"\n {...(organization === organizations[0]\n ? { 'data-tour': 'organizations-table-actions' }\n : {})}\n >\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${organization.id}`)}\n className=\"rounded-lg p-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:bg-[var(--color-bg-muted)] hover:text-[var(--color-text-primary)]\"\n title={`${tr('common.view', 'View')} ${organization.name}`}\n aria-label={`${tr('common.view', 'View')} ${organization.name}`}\n >\n <Eye size={18} aria-hidden=\"true\" />\n </button>\n {hasPermission(PERMISSIONS.ORG_UPDATE) && (\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${organization.id}/edit`)}\n className=\"rounded-lg p-2 text-[var(--color-text-secondary)] transition-all duration-200 hover:bg-[var(--color-bg-muted)] hover:text-[var(--color-text-primary)]\"\n title={`${tr('common.edit', 'Edit')} ${organization.name}`}\n aria-label={`${tr('common.edit', 'Edit')} ${organization.name}`}\n >\n <SquarePen size={18} aria-hidden=\"true\" />\n </button>\n )}\n {mode === 'admin' && hasPermission(PERMISSIONS.ORG_DELETE) && (\n <button\n type=\"button\"\n onClick={() => handleDelete(organization.id, organization.name)}\n disabled={deleteLoading}\n 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\"\n title={`${tr('common.delete', 'Delete')} ${organization.name}`}\n aria-label={`${tr('common.delete', 'Delete')} ${organization.name}`}\n >\n <Trash2 size={18} aria-hidden=\"true\" />\n </button>\n )}\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </GlassCard>\n </>\n )}\n </div>\n\n {ConfirmDialog}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { OrganizationStatus as e } from "../../../shared/types/graphql.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { enum as t, literal as n, object as r, record as i, string as a, unknown as o } from "../../../../node_modules/zod/v4/classic/schemas.js";
|
|
3
|
+
// src/organization-management/modules/organizations/schemas/index.ts
|
|
4
4
|
function s(e) {
|
|
5
5
|
return {
|
|
6
|
-
name: a().min(2, e("organizations.validation.nameMin", "Name must be at least 2 characters")).max(100, e("organizations.validation.nameMax", "Name must not exceed 100 characters"))
|
|
7
|
-
slug: a().min(2, e("organizations.validation.slugMin", "Slug must be at least 2 characters")).max(50, e("organizations.validation.slugMax", "Slug must not exceed 50 characters")).regex(/^[a-z0-9-]+$/, e("organizations.validation.slugPattern", "Slug must contain only lowercase letters, numbers, and hyphens"))
|
|
8
|
-
description: a().max(500, e("organizations.validation.descriptionMax", "Description must not exceed 500 characters")).optional().or(
|
|
9
|
-
logo: a().url(e("organizations.validation.urlInvalid", "Must be a valid URL")).optional().or(
|
|
10
|
-
website: a().url(e("organizations.validation.urlInvalid", "Must be a valid URL")).optional().or(
|
|
6
|
+
name: a().trim().min(2, e("organizations.validation.nameMin", "Name must be at least 2 characters")).max(100, e("organizations.validation.nameMax", "Name must not exceed 100 characters")),
|
|
7
|
+
slug: a().trim().min(2, e("organizations.validation.slugMin", "Slug must be at least 2 characters")).max(50, e("organizations.validation.slugMax", "Slug must not exceed 50 characters")).regex(/^[a-z0-9-]+$/, e("organizations.validation.slugPattern", "Slug must contain only lowercase letters, numbers, and hyphens")),
|
|
8
|
+
description: a().max(500, e("organizations.validation.descriptionMax", "Description must not exceed 500 characters")).optional().or(n("")),
|
|
9
|
+
logo: a().url(e("organizations.validation.urlInvalid", "Must be a valid URL")).optional().or(n("")),
|
|
10
|
+
website: a().url(e("organizations.validation.urlInvalid", "Must be a valid URL")).optional().or(n("")),
|
|
11
11
|
metadata: i(a(), o()).optional()
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
|
-
function c(
|
|
14
|
+
function c(n) {
|
|
15
15
|
return r({
|
|
16
|
-
tenantId: a().min(1,
|
|
17
|
-
...s(
|
|
18
|
-
status:
|
|
16
|
+
tenantId: a().trim().min(1, n("organizations.validation.tenantRequired", "Tenant is required")),
|
|
17
|
+
...s(n),
|
|
18
|
+
status: t(e).optional()
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
21
|
function l(e) {
|
|
@@ -28,7 +28,6 @@ function l(e) {
|
|
|
28
28
|
metadata: t.metadata
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
|
-
//#endregion
|
|
32
31
|
export { c as createOrganizationSchema, l as updateOrganizationSchema };
|
|
33
32
|
|
|
34
33
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../../src/organization-management/modules/organizations/schemas/index.ts"],"sourcesContent":["import { z } from 'zod';\nimport { OrganizationStatus } from '../types';\nimport type { TranslationFn } from '../../../shared/hooks/useTr';\n\n/**\n * Organization Validation Schemas\n * Zod schemas for validating organization form inputs.\n *\n * Exported as factory functions so validation messages can be translated\n * via the same `tr()` helper used by components.\n */\n\nfunction baseOrganizationSchema(tr: TranslationFn) {\n return {\n name: z\n .string()\n .min(2, tr('organizations.validation.nameMin', 'Name must be at least 2 characters'))\n .max(100, tr('organizations.validation.nameMax', 'Name must not exceed 100 characters'))
|
|
1
|
+
{"version":3,"file":"index.js","names":["z.string","z.literal","z.record","z.unknown","z.object","z.enum","_enum","baseOrganizationSchema","string","tr","literal","record","unknown","createOrganizationSchema","object","OrganizationStatus","updateOrganizationSchema","base"],"sources":["../../../../../src/organization-management/modules/organizations/schemas/index.ts"],"sourcesContent":["import { z } from 'zod';\nimport { OrganizationStatus } from '../types';\nimport type { TranslationFn } from '../../../shared/hooks/useTr';\n\n/**\n * Organization Validation Schemas\n * Zod schemas for validating organization form inputs.\n *\n * Exported as factory functions so validation messages can be translated\n * via the same `tr()` helper used by components.\n */\n\nfunction baseOrganizationSchema(tr: TranslationFn) {\n return {\n name: z\n .string()\n .trim()\n .min(2, tr('organizations.validation.nameMin', 'Name must be at least 2 characters'))\n .max(100, tr('organizations.validation.nameMax', 'Name must not exceed 100 characters')),\n slug: z\n .string()\n .trim()\n .min(2, tr('organizations.validation.slugMin', 'Slug must be at least 2 characters'))\n .max(50, tr('organizations.validation.slugMax', 'Slug must not exceed 50 characters'))\n .regex(\n /^[a-z0-9-]+$/,\n tr(\n 'organizations.validation.slugPattern',\n 'Slug must contain only lowercase letters, numbers, and hyphens'\n )\n ),\n description: z\n .string()\n .max(\n 500,\n tr('organizations.validation.descriptionMax', 'Description must not exceed 500 characters')\n )\n .optional()\n .or(z.literal('')),\n logo: z\n .string()\n .url(tr('organizations.validation.urlInvalid', 'Must be a valid URL'))\n .optional()\n .or(z.literal('')),\n website: z\n .string()\n .url(tr('organizations.validation.urlInvalid', 'Must be a valid URL'))\n .optional()\n .or(z.literal('')),\n metadata: z.record(z.string(), z.unknown()).optional(),\n };\n}\n\n// Create Organization Schema\nexport function createOrganizationSchema(tr: TranslationFn) {\n return z.object({\n tenantId: z\n .string()\n .trim()\n .min(1, tr('organizations.validation.tenantRequired', 'Tenant is required')),\n ...baseOrganizationSchema(tr),\n status: z.enum(OrganizationStatus).optional(),\n });\n}\n\n// Update Organization Schema\nexport function updateOrganizationSchema(tr: TranslationFn) {\n const base = baseOrganizationSchema(tr);\n return z.object({\n name: base.name.optional(),\n description: base.description,\n logo: base.logo,\n website: base.website,\n metadata: base.metadata,\n });\n}\n\n// Type exports\nexport type CreateOrganizationFormData = z.infer<ReturnType<typeof createOrganizationSchema>>;\nexport type UpdateOrganizationFormData = z.infer<ReturnType<typeof updateOrganizationSchema>>;\n"],"mappings":";;;AAYA,SAASO,EAAuB,GAAmB;CACjD,OAAO;EACL,MAAMP,EACI,CAAC,CACR,KAAK,CAAC,CACN,IAAI,GAAGS,EAAG,oCAAoC,oCAAoC,CAAC,CAAC,CACpF,IAAI,KAAKA,EAAG,oCAAoC,qCAAqC,CAAC;EACzF,MAAMT,EACI,CAAC,CACR,KAAK,CAAC,CACN,IAAI,GAAGS,EAAG,oCAAoC,oCAAoC,CAAC,CAAC,CACpF,IAAI,IAAIA,EAAG,oCAAoC,oCAAoC,CAAC,CAAC,CACrF,MACC,gBACAA,EACE,wCACA,gEACF,CACF;EACF,aAAaT,EACH,CAAC,CACR,IACC,KACAS,EAAG,2CAA2C,4CAA4C,CAC5F,CAAC,CACA,SAAS,CAAC,CACV,GAAGR,EAAU,EAAE,CAAC;EACnB,MAAMD,EACI,CAAC,CACR,IAAIS,EAAG,uCAAuC,qBAAqB,CAAC,CAAC,CACrE,SAAS,CAAC,CACV,GAAGR,EAAU,EAAE,CAAC;EACnB,SAASD,EACC,CAAC,CACR,IAAIS,EAAG,uCAAuC,qBAAqB,CAAC,CAAC,CACrE,SAAS,CAAC,CACV,GAAGR,EAAU,EAAE,CAAC;EACnB,UAAUC,EAASF,EAAS,GAAGG,EAAU,CAAC,CAAC,CAAC,SAAS;CACvD;AACF;AAGA,SAAgBU,EAAyB,GAAmB;CAC1D,OAAOT,EAAS;EACd,UAAUJ,EACA,CAAC,CACR,KAAK,CAAC,CACN,IAAI,GAAGS,EAAG,2CAA2C,oBAAoB,CAAC;EAC7E,GAAGF,EAAuBE,CAAE;EAC5B,QAAQJ,EAAOU,CAAkB,CAAC,CAAC,SAAS;CAC9C,CAAC;AACH;AAGA,SAAgBC,EAAyB,GAAmB;CAC1D,IAAMC,IAAOV,EAAuBE,CAAE;CACtC,OAAOL,EAAS;EACd,MAAMa,EAAK,KAAK,SAAS;EACzB,aAAaA,EAAK;EAClB,MAAMA,EAAK;EACX,SAASA,EAAK;EACd,UAAUA,EAAK;CACjB,CAAC;AACH"}
|
package/dist/organization-management/modules/workspaces/components/AddWorkspaceMemberDialog.js
CHANGED
|
@@ -1,30 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { toast as e } from "../../../../node_modules/sonner/dist/index.js";
|
|
2
|
+
import { useMembers as t } from "../../members/hooks/useMembers.js";
|
|
3
|
+
import { useAddWorkspaceMember as n } from "../hooks/useWorkspaceMembers.js";
|
|
4
|
+
import { useOrgConsole as r } from "../../../providers/OrgConsoleProvider.js";
|
|
5
|
+
import { useTr as i } from "../../../shared/hooks/useTr.js";
|
|
6
6
|
import { useEffect as a, useMemo as o, useState as s } from "react";
|
|
7
7
|
import { AlertCircle as c, Loader2 as l, UserPlus as u } from "lucide-react";
|
|
8
8
|
import { ResponsiveDialog as d, ResponsiveDialogContent as f, ResponsiveDialogDescription as p, ResponsiveDialogFooter as m, ResponsiveDialogHeader as h, ResponsiveDialogTitle as g } from "@burdenoff/fe-libs/ui";
|
|
9
9
|
import { jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
10
10
|
import { useActorProfiles as y } from "@burdenoff/fe-libs/shared";
|
|
11
|
-
|
|
11
|
+
// src/organization-management/modules/workspaces/components/AddWorkspaceMemberDialog.tsx
|
|
12
12
|
function b({ open: b, onOpenChange: x, workspaceId: S, organizationId: C, existingMembers: w, onInviteOrganizationMember: T }) {
|
|
13
|
-
let E =
|
|
13
|
+
let E = i(), [D, O] = s(""), [k, A] = s("MEMBER"), [j, M] = s(null), { members: N, loading: P } = t(C, 100, 0, b), { addWorkspaceMember: F, loading: I } = n(), L = o(() => new Set(w.map((e) => e.userId)), [w]), R = o(() => N.filter((e) => !L.has(e.userId)), [L, N]), { apiGatewayUrl: z, authToken: B } = r(), V = o(() => R.map((e) => ({
|
|
14
14
|
actorId: e.userId,
|
|
15
15
|
actorType: "user"
|
|
16
|
-
})), [R]), {
|
|
16
|
+
})), [R]), H = y(V, {
|
|
17
17
|
apiGatewayUrl: z,
|
|
18
18
|
authToken: B,
|
|
19
19
|
orgId: C,
|
|
20
20
|
workspaceId: S
|
|
21
21
|
});
|
|
22
22
|
return a(() => {
|
|
23
|
-
|
|
24
|
-
O(""), A("MEMBER"), M(null);
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
!D && R.length > 0 && O(R[0]?.userId ?? "");
|
|
23
|
+
b ? !D && R.length > 0 && O(R[0]?.userId ?? "") : (O(""), A("MEMBER"), M(null));
|
|
28
24
|
}, [
|
|
29
25
|
R,
|
|
30
26
|
b,
|
|
@@ -44,20 +40,17 @@ function b({ open: b, onOpenChange: x, workspaceId: S, organizationId: C, existi
|
|
|
44
40
|
className: "text-[var(--color-text-secondary)]",
|
|
45
41
|
children: E("workspaces.addMember.description", "Choose an existing organization member and assign their workspace role.")
|
|
46
42
|
})] }), /* @__PURE__ */ v("form", {
|
|
47
|
-
onSubmit: async (
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
try {
|
|
43
|
+
onSubmit: async (t) => {
|
|
44
|
+
if (t.preventDefault(), !D) M(E("workspaces.addMember.selectRequired", "Select an organization member to add to this workspace."));
|
|
45
|
+
else try {
|
|
53
46
|
M(null);
|
|
54
|
-
let
|
|
47
|
+
let t = await F({
|
|
55
48
|
workspaceId: S,
|
|
56
49
|
userId: D,
|
|
57
50
|
role: k
|
|
58
51
|
});
|
|
59
|
-
if (
|
|
60
|
-
|
|
52
|
+
if (t.errors?.length) throw Error(t.errors[0]?.message ?? E("workspaces.addMember.failed", "Failed to add workspace member"));
|
|
53
|
+
e.success(E("workspaces.addMember.success", "Workspace member added successfully")), x(!1);
|
|
61
54
|
} catch (e) {
|
|
62
55
|
M(e instanceof Error ? e.message : E("workspaces.addMember.failed", "Failed to add workspace member"));
|
|
63
56
|
}
|
|
@@ -90,7 +83,7 @@ function b({ open: b, onOpenChange: x, workspaceId: S, organizationId: C, existi
|
|
|
90
83
|
}) : null, R.map((e) => /* @__PURE__ */ v("option", {
|
|
91
84
|
value: e.userId,
|
|
92
85
|
children: [
|
|
93
|
-
|
|
86
|
+
H[e.userId]?.displayName ?? e.userId,
|
|
94
87
|
" (",
|
|
95
88
|
e.role,
|
|
96
89
|
")"
|
|
@@ -167,7 +160,6 @@ function b({ open: b, onOpenChange: x, workspaceId: S, organizationId: C, existi
|
|
|
167
160
|
})
|
|
168
161
|
});
|
|
169
162
|
}
|
|
170
|
-
//#endregion
|
|
171
163
|
export { b as AddWorkspaceMemberDialog };
|
|
172
164
|
|
|
173
165
|
//# sourceMappingURL=AddWorkspaceMemberDialog.js.map
|