@burdenoff/microfe-admin 2026.829.1 → 2026.829.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/AdminRoot.js +77 -72
- package/dist/admin/AdminRoot.js.map +1 -1
- package/dist/admin/components/TenantMembersPanel.js +105 -106
- package/dist/admin/components/TenantMembersPanel.js.map +1 -1
- package/dist/admin/hooks/useTr.js +14 -0
- package/dist/admin/hooks/useTr.js.map +1 -0
- package/dist/admin/pages/DashboardPage.js +71 -72
- package/dist/admin/pages/DashboardPage.js.map +1 -1
- package/dist/admin/pages/OrganizationsListPage.js +63 -62
- package/dist/admin/pages/OrganizationsListPage.js.map +1 -1
- package/dist/admin/pages/TenantDetailPage.js +148 -149
- package/dist/admin/pages/TenantDetailPage.js.map +1 -1
- package/dist/admin/pages/TenantsListPage.js +106 -107
- package/dist/admin/pages/TenantsListPage.js.map +1 -1
- package/dist/admin/pages/UsersListPage.js +87 -88
- package/dist/admin/pages/UsersListPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -4,128 +4,127 @@ import { PageLayout as n } from "../components/PageLayout.js";
|
|
|
4
4
|
import { MetricCard as r, MetricsGrid as i } from "../components/MetricCard.js";
|
|
5
5
|
import { ActivityFeed as a } from "../components/ActivityFeed.js";
|
|
6
6
|
import { QuickLinks as o } from "../components/Charts.js";
|
|
7
|
-
import {
|
|
8
|
-
import { PermissionGuard as c } from "../components/PermissionGuard.js";
|
|
7
|
+
import { PermissionGuard as s } from "../components/PermissionGuard.js";
|
|
9
8
|
import "../components/index.js";
|
|
10
|
-
import { joinPath as
|
|
11
|
-
import { mapActivityLogToUi as
|
|
12
|
-
import { useGetDashboardActiveWorkspaceCountQuery as
|
|
9
|
+
import { joinPath as c } from "../utils/navigation.js";
|
|
10
|
+
import { mapActivityLogToUi as l } from "../utils/mappers.js";
|
|
11
|
+
import { useGetDashboardActiveWorkspaceCountQuery as u, useGetDashboardOrganizationCountQuery as d, useGetDashboardTenantCountQuery as f, useGetDashboardUserCountQuery as p, useGetRecentActivityLogsQuery as m } from "../../generated/global-operations.js";
|
|
12
|
+
import { useTr as h } from "../hooks/useTr.js";
|
|
13
13
|
import { useMemo as g } from "react";
|
|
14
14
|
import { Briefcase as _, Building2 as v, FileText as y, HelpCircle as b, Layout as x, Plus as S, UserPlus as C, Users as w } from "lucide-react";
|
|
15
15
|
import { useNavigate as T } from "react-router";
|
|
16
16
|
import { jsx as E, jsxs as D } from "react/jsx-runtime";
|
|
17
|
-
import {
|
|
18
|
-
import { NextSteps as k, PagePurpose as A } from "@burdenoff/fe-libs/ui";
|
|
17
|
+
import { NextSteps as O, PagePurpose as k } from "@burdenoff/fe-libs/ui";
|
|
19
18
|
//#region src/admin/pages/DashboardPage.tsx
|
|
20
|
-
function
|
|
21
|
-
let { canViewDashboard:
|
|
19
|
+
function A() {
|
|
20
|
+
let { canViewDashboard: A, isLoading: j } = t(), { basePath: M = "" } = e(), N = T(), P = h(), F = j || !A, { data: I, loading: L } = f({
|
|
22
21
|
fetchPolicy: "cache-and-network",
|
|
23
|
-
skip:
|
|
24
|
-
}), { data:
|
|
22
|
+
skip: F
|
|
23
|
+
}), { data: R, loading: z } = d({
|
|
25
24
|
fetchPolicy: "cache-and-network",
|
|
26
|
-
skip:
|
|
27
|
-
}), { data:
|
|
25
|
+
skip: F
|
|
26
|
+
}), { data: B, loading: V } = u({
|
|
28
27
|
fetchPolicy: "cache-and-network",
|
|
29
|
-
skip:
|
|
30
|
-
}), { data:
|
|
28
|
+
skip: F
|
|
29
|
+
}), { data: H, loading: U } = p({
|
|
31
30
|
fetchPolicy: "cache-and-network",
|
|
32
|
-
skip:
|
|
33
|
-
}), { data:
|
|
31
|
+
skip: F
|
|
32
|
+
}), { data: W, loading: G } = m({
|
|
34
33
|
variables: { limit: 10 },
|
|
35
34
|
fetchPolicy: "cache-and-network",
|
|
36
|
-
skip:
|
|
37
|
-
}),
|
|
38
|
-
tenants:
|
|
39
|
-
organizations:
|
|
40
|
-
workspaces:
|
|
41
|
-
users:
|
|
42
|
-
},
|
|
35
|
+
skip: F
|
|
36
|
+
}), K = {
|
|
37
|
+
tenants: I?.tenants?.total ?? 0,
|
|
38
|
+
organizations: R?.allOrganizations?.total ?? 0,
|
|
39
|
+
workspaces: B?.allWorkspaces?.total ?? 0,
|
|
40
|
+
users: H?.userCount ?? 0
|
|
41
|
+
}, q = g(() => (W?.activityLogs?.nodes ?? []).map(l), [W]), J = [
|
|
43
42
|
{
|
|
44
|
-
to:
|
|
45
|
-
label:
|
|
43
|
+
to: c(M, "tenants"),
|
|
44
|
+
label: P("admin.dashboard.quickLinks.addTenant", "Add Tenant"),
|
|
46
45
|
icon: /* @__PURE__ */ E(S, { className: "h-4 w-4" }),
|
|
47
|
-
description:
|
|
46
|
+
description: P("admin.dashboard.quickLinks.addTenantDescription", "Create a new tenant")
|
|
48
47
|
},
|
|
49
48
|
{
|
|
50
|
-
to:
|
|
51
|
-
label:
|
|
49
|
+
to: c(M, "users"),
|
|
50
|
+
label: P("admin.dashboard.quickLinks.inviteUser", "Invite User"),
|
|
52
51
|
icon: /* @__PURE__ */ E(C, { className: "h-4 w-4" }),
|
|
53
|
-
description:
|
|
52
|
+
description: P("admin.dashboard.quickLinks.inviteUserDescription", "Invite a new user")
|
|
54
53
|
},
|
|
55
54
|
{
|
|
56
|
-
to:
|
|
57
|
-
label:
|
|
55
|
+
to: c(M, "audit"),
|
|
56
|
+
label: P("admin.dashboard.quickLinks.auditLogs", "Audit Logs"),
|
|
58
57
|
icon: /* @__PURE__ */ E(y, { className: "h-4 w-4" }),
|
|
59
|
-
description:
|
|
58
|
+
description: P("admin.dashboard.quickLinks.auditLogsDescription", "View security audit trail")
|
|
60
59
|
},
|
|
61
60
|
{
|
|
62
|
-
to:
|
|
63
|
-
label:
|
|
61
|
+
to: c(M, "support"),
|
|
62
|
+
label: P("admin.dashboard.quickLinks.support", "Support"),
|
|
64
63
|
icon: /* @__PURE__ */ E(b, { className: "h-4 w-4" }),
|
|
65
|
-
description:
|
|
64
|
+
description: P("admin.dashboard.quickLinks.supportDescription", "Manage support tickets")
|
|
66
65
|
}
|
|
67
|
-
],
|
|
68
|
-
return /* @__PURE__ */ E(
|
|
69
|
-
allowed:
|
|
70
|
-
isLoading:
|
|
71
|
-
pageTitle:
|
|
72
|
-
denyMessage:
|
|
66
|
+
], Y = L || z || V || U;
|
|
67
|
+
return /* @__PURE__ */ E(s, {
|
|
68
|
+
allowed: A,
|
|
69
|
+
isLoading: j,
|
|
70
|
+
pageTitle: P("admin.dashboard.title", "Dashboard"),
|
|
71
|
+
denyMessage: P("admin.dashboard.denyMessage", "You don't have permission to view the admin dashboard."),
|
|
73
72
|
children: /* @__PURE__ */ E(n, {
|
|
74
|
-
title:
|
|
75
|
-
description:
|
|
76
|
-
gradientWord:
|
|
73
|
+
title: P("admin.dashboard.title", "Dashboard"),
|
|
74
|
+
description: P("admin.dashboard.description", "Platform overview and key metrics"),
|
|
75
|
+
gradientWord: P("admin.dashboard.title", "Dashboard"),
|
|
77
76
|
aurora: !0,
|
|
78
77
|
children: /* @__PURE__ */ D("div", {
|
|
79
78
|
className: "space-y-6",
|
|
80
79
|
children: [
|
|
81
|
-
/* @__PURE__ */ E(
|
|
82
|
-
/* @__PURE__ */ E(
|
|
80
|
+
/* @__PURE__ */ E(k, { children: P("admin.dashboard.purpose", "Your control tower for the whole platform. See live tenant, organization, workspace and user counts at a glance, watch the most recent administrative activity, and jump straight into the day-to-day jobs — onboarding a tenant, inviting a user, or reviewing the audit trail.") }),
|
|
81
|
+
/* @__PURE__ */ E(O, {
|
|
83
82
|
storageKey: "admin-dashboard",
|
|
84
83
|
steps: [
|
|
85
84
|
{
|
|
86
85
|
id: "add-tenant",
|
|
87
|
-
label:
|
|
88
|
-
description:
|
|
89
|
-
onClick: () =>
|
|
86
|
+
label: P("admin.dashboard.nextSteps.addTenant", "Onboard a tenant"),
|
|
87
|
+
description: P("admin.dashboard.nextSteps.addTenantDesc", "Provision a new customer tenant to start serving them."),
|
|
88
|
+
onClick: () => N(c(M, "tenants/new"))
|
|
90
89
|
},
|
|
91
90
|
{
|
|
92
91
|
id: "invite-user",
|
|
93
|
-
label:
|
|
94
|
-
description:
|
|
95
|
-
onClick: () =>
|
|
92
|
+
label: P("admin.dashboard.nextSteps.inviteUser", "Invite a teammate"),
|
|
93
|
+
description: P("admin.dashboard.nextSteps.inviteUserDesc", "Bring another operator into the admin console."),
|
|
94
|
+
onClick: () => N(c(M, "users"))
|
|
96
95
|
},
|
|
97
96
|
{
|
|
98
97
|
id: "review-audit",
|
|
99
|
-
label:
|
|
100
|
-
description:
|
|
101
|
-
onClick: () =>
|
|
98
|
+
label: P("admin.dashboard.nextSteps.reviewAudit", "Review the audit trail"),
|
|
99
|
+
description: P("admin.dashboard.nextSteps.reviewAuditDesc", "Check who changed what across the platform."),
|
|
100
|
+
onClick: () => N(c(M, "audit"))
|
|
102
101
|
}
|
|
103
102
|
]
|
|
104
103
|
}),
|
|
105
104
|
/* @__PURE__ */ D(i, { children: [
|
|
106
105
|
/* @__PURE__ */ E(r, {
|
|
107
|
-
title:
|
|
108
|
-
value:
|
|
109
|
-
loading:
|
|
106
|
+
title: P("admin.dashboard.metrics.totalTenants", "Total Tenants"),
|
|
107
|
+
value: K.tenants,
|
|
108
|
+
loading: Y,
|
|
110
109
|
hero: !0,
|
|
111
110
|
icon: /* @__PURE__ */ E(v, { className: "h-5 w-5 text-action-primary-bg" })
|
|
112
111
|
}),
|
|
113
112
|
/* @__PURE__ */ E(r, {
|
|
114
|
-
title:
|
|
115
|
-
value:
|
|
116
|
-
loading:
|
|
113
|
+
title: P("admin.dashboard.metrics.organizations", "Organizations"),
|
|
114
|
+
value: K.organizations,
|
|
115
|
+
loading: Y,
|
|
117
116
|
icon: /* @__PURE__ */ E(_, { className: "h-5 w-5 text-text-secondary" })
|
|
118
117
|
}),
|
|
119
118
|
/* @__PURE__ */ E(r, {
|
|
120
|
-
title:
|
|
121
|
-
value:
|
|
122
|
-
loading:
|
|
119
|
+
title: P("admin.dashboard.metrics.activeWorkspaces", "Active Workspaces"),
|
|
120
|
+
value: K.workspaces,
|
|
121
|
+
loading: Y,
|
|
123
122
|
icon: /* @__PURE__ */ E(x, { className: "h-5 w-5 text-status-success-text" })
|
|
124
123
|
}),
|
|
125
124
|
/* @__PURE__ */ E(r, {
|
|
126
|
-
title:
|
|
127
|
-
value:
|
|
128
|
-
loading:
|
|
125
|
+
title: P("admin.dashboard.metrics.totalUsers", "Total Users"),
|
|
126
|
+
value: K.users,
|
|
127
|
+
loading: Y,
|
|
129
128
|
icon: /* @__PURE__ */ E(w, { className: "h-5 w-5 text-text-secondary" })
|
|
130
129
|
})
|
|
131
130
|
] }),
|
|
@@ -134,12 +133,12 @@ function j() {
|
|
|
134
133
|
children: [/* @__PURE__ */ E("div", {
|
|
135
134
|
className: "lg:col-span-2",
|
|
136
135
|
children: /* @__PURE__ */ E(a, {
|
|
137
|
-
activities:
|
|
138
|
-
loading:
|
|
136
|
+
activities: q,
|
|
137
|
+
loading: G
|
|
139
138
|
})
|
|
140
139
|
}), /* @__PURE__ */ E("div", {
|
|
141
140
|
className: "space-y-4",
|
|
142
|
-
children: /* @__PURE__ */ E(o, { links:
|
|
141
|
+
children: /* @__PURE__ */ E(o, { links: J })
|
|
143
142
|
})]
|
|
144
143
|
})
|
|
145
144
|
]
|
|
@@ -148,6 +147,6 @@ function j() {
|
|
|
148
147
|
});
|
|
149
148
|
}
|
|
150
149
|
//#endregion
|
|
151
|
-
export {
|
|
150
|
+
export { A as DashboardPage };
|
|
152
151
|
|
|
153
152
|
//# sourceMappingURL=DashboardPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/admin/pages/DashboardPage.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport {\n Building2,\n Users,\n Layout,\n Briefcase,\n Plus,\n UserPlus,\n FileText,\n HelpCircle,\n} from 'lucide-react';\nimport { useAdmin } from '../providers/AdminProvider';\nimport { useAdminPermissions } from '../hooks/useAdminPermissions';\nimport {\n PageLayout,\n MetricCard,\n MetricsGrid,\n ActivityFeed,\n QuickLinks,\n PermissionGuard,\n} from '../components';\nimport { useNavigate } from 'react-router';\nimport { PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';\nimport { joinPath } from '../utils/navigation';\nimport { mapActivityLogToUi } from '../utils/mappers';\nimport type { Activity } from '../types';\nimport {\n useGetDashboardTenantCountQuery,\n useGetDashboardOrganizationCountQuery,\n useGetDashboardActiveWorkspaceCountQuery,\n useGetDashboardUserCountQuery,\n useGetRecentActivityLogsQuery,\n} from '../../generated/global-operations';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../utils/i18n';\n\n/**\n * Dashboard page — platform overview with real-time metrics\n */\nexport function DashboardPage() {\n const { canViewDashboard, isLoading: permissionsLoading } = useAdminPermissions();\n const { basePath = '' } = useAdmin();\n const navigate = useNavigate();\n const { t } = useI18n();\n const tr = (key: string, fallback: string, params?: Record<string, string | number>): string =>\n tWithFallback(t, key, fallback, params);\n\n const skipQueries = permissionsLoading || !canViewDashboard;\n\n const { data: tenantData, loading: tenantLoading } = useGetDashboardTenantCountQuery({\n fetchPolicy: 'cache-and-network',\n skip: skipQueries,\n });\n const { data: orgData, loading: orgLoading } = useGetDashboardOrganizationCountQuery({\n fetchPolicy: 'cache-and-network',\n skip: skipQueries,\n });\n const { data: workspaceData, loading: workspaceLoading } =\n useGetDashboardActiveWorkspaceCountQuery({\n fetchPolicy: 'cache-and-network',\n skip: skipQueries,\n });\n const { data: userData, loading: userLoading } = useGetDashboardUserCountQuery({\n fetchPolicy: 'cache-and-network',\n skip: skipQueries,\n });\n const { data: activityData, loading: activityLoading } = useGetRecentActivityLogsQuery({\n variables: { limit: 10 },\n fetchPolicy: 'cache-and-network',\n skip: skipQueries,\n });\n\n const metrics = {\n tenants: tenantData?.tenants?.total ?? 0,\n organizations: orgData?.allOrganizations?.total ?? 0,\n workspaces: workspaceData?.allWorkspaces?.total ?? 0,\n users: userData?.userCount ?? 0,\n };\n\n const recentActivity: Activity[] = useMemo(\n () => (activityData?.activityLogs?.nodes ?? []).map(mapActivityLogToUi),\n [activityData]\n );\n\n const quickLinks = [\n {\n to: joinPath(basePath, 'tenants'),\n label: tr('admin.dashboard.quickLinks.addTenant', 'Add Tenant'),\n icon: <Plus className=\"h-4 w-4\" />,\n description: tr('admin.dashboard.quickLinks.addTenantDescription', 'Create a new tenant'),\n },\n {\n to: joinPath(basePath, 'users'),\n label: tr('admin.dashboard.quickLinks.inviteUser', 'Invite User'),\n icon: <UserPlus className=\"h-4 w-4\" />,\n description: tr('admin.dashboard.quickLinks.inviteUserDescription', 'Invite a new user'),\n },\n {\n to: joinPath(basePath, 'audit'),\n label: tr('admin.dashboard.quickLinks.auditLogs', 'Audit Logs'),\n icon: <FileText className=\"h-4 w-4\" />,\n description: tr(\n 'admin.dashboard.quickLinks.auditLogsDescription',\n 'View security audit trail'\n ),\n },\n {\n to: joinPath(basePath, 'support'),\n label: tr('admin.dashboard.quickLinks.support', 'Support'),\n icon: <HelpCircle className=\"h-4 w-4\" />,\n description: tr('admin.dashboard.quickLinks.supportDescription', 'Manage support tickets'),\n },\n ];\n\n const isLoading = tenantLoading || orgLoading || workspaceLoading || userLoading;\n\n return (\n <PermissionGuard\n allowed={canViewDashboard}\n isLoading={permissionsLoading}\n pageTitle={tr('admin.dashboard.title', 'Dashboard')}\n denyMessage={tr(\n 'admin.dashboard.denyMessage',\n \"You don't have permission to view the admin dashboard.\"\n )}\n >\n <PageLayout\n title={tr('admin.dashboard.title', 'Dashboard')}\n description={tr('admin.dashboard.description', 'Platform overview and key metrics')}\n gradientWord={tr('admin.dashboard.title', 'Dashboard')}\n aurora\n >\n <div className=\"space-y-6\">\n <PagePurpose>\n {tr(\n 'admin.dashboard.purpose',\n 'Your control tower for the whole platform. See live tenant, organization, workspace and user counts at a glance, watch the most recent administrative activity, and jump straight into the day-to-day jobs — onboarding a tenant, inviting a user, or reviewing the audit trail.'\n )}\n </PagePurpose>\n\n <NextSteps\n storageKey=\"admin-dashboard\"\n steps={[\n {\n id: 'add-tenant',\n label: tr('admin.dashboard.nextSteps.addTenant', 'Onboard a tenant'),\n description: tr(\n 'admin.dashboard.nextSteps.addTenantDesc',\n 'Provision a new customer tenant to start serving them.'\n ),\n onClick: () => navigate(joinPath(basePath, 'tenants/new')),\n },\n {\n id: 'invite-user',\n label: tr('admin.dashboard.nextSteps.inviteUser', 'Invite a teammate'),\n description: tr(\n 'admin.dashboard.nextSteps.inviteUserDesc',\n 'Bring another operator into the admin console.'\n ),\n onClick: () => navigate(joinPath(basePath, 'users')),\n },\n {\n id: 'review-audit',\n label: tr('admin.dashboard.nextSteps.reviewAudit', 'Review the audit trail'),\n description: tr(\n 'admin.dashboard.nextSteps.reviewAuditDesc',\n 'Check who changed what across the platform.'\n ),\n onClick: () => navigate(joinPath(basePath, 'audit')),\n },\n ]}\n />\n\n {/* Metrics Grid */}\n <MetricsGrid>\n <MetricCard\n title={tr('admin.dashboard.metrics.totalTenants', 'Total Tenants')}\n value={metrics.tenants}\n loading={isLoading}\n hero\n icon={<Building2 className=\"h-5 w-5 text-action-primary-bg\" />}\n />\n <MetricCard\n title={tr('admin.dashboard.metrics.organizations', 'Organizations')}\n value={metrics.organizations}\n loading={isLoading}\n icon={<Briefcase className=\"h-5 w-5 text-text-secondary\" />}\n />\n <MetricCard\n title={tr('admin.dashboard.metrics.activeWorkspaces', 'Active Workspaces')}\n value={metrics.workspaces}\n loading={isLoading}\n icon={<Layout className=\"h-5 w-5 text-status-success-text\" />}\n />\n <MetricCard\n title={tr('admin.dashboard.metrics.totalUsers', 'Total Users')}\n value={metrics.users}\n loading={isLoading}\n icon={<Users className=\"h-5 w-5 text-text-secondary\" />}\n />\n </MetricsGrid>\n\n {/* Content Area */}\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2\">\n <ActivityFeed activities={recentActivity} loading={activityLoading} />\n </div>\n <div className=\"space-y-4\">\n <QuickLinks links={quickLinks} />\n </div>\n </div>\n </div>\n </PageLayout>\n </PermissionGuard>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/admin/pages/DashboardPage.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport {\n Building2,\n Users,\n Layout,\n Briefcase,\n Plus,\n UserPlus,\n FileText,\n HelpCircle,\n} from 'lucide-react';\nimport { useAdmin } from '../providers/AdminProvider';\nimport { useAdminPermissions } from '../hooks/useAdminPermissions';\nimport {\n PageLayout,\n MetricCard,\n MetricsGrid,\n ActivityFeed,\n QuickLinks,\n PermissionGuard,\n} from '../components';\nimport { useNavigate } from 'react-router';\nimport { PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';\nimport { joinPath } from '../utils/navigation';\nimport { mapActivityLogToUi } from '../utils/mappers';\nimport type { Activity } from '../types';\nimport {\n useGetDashboardTenantCountQuery,\n useGetDashboardOrganizationCountQuery,\n useGetDashboardActiveWorkspaceCountQuery,\n useGetDashboardUserCountQuery,\n useGetRecentActivityLogsQuery,\n} from '../../generated/global-operations';\nimport { useTr } from '../hooks/useTr';\n\n/**\n * Dashboard page — platform overview with real-time metrics\n */\nexport function DashboardPage() {\n const { canViewDashboard, isLoading: permissionsLoading } = useAdminPermissions();\n const { basePath = '' } = useAdmin();\n const navigate = useNavigate();\n const tr = useTr();\n\n const skipQueries = permissionsLoading || !canViewDashboard;\n\n const { data: tenantData, loading: tenantLoading } = useGetDashboardTenantCountQuery({\n fetchPolicy: 'cache-and-network',\n skip: skipQueries,\n });\n const { data: orgData, loading: orgLoading } = useGetDashboardOrganizationCountQuery({\n fetchPolicy: 'cache-and-network',\n skip: skipQueries,\n });\n const { data: workspaceData, loading: workspaceLoading } =\n useGetDashboardActiveWorkspaceCountQuery({\n fetchPolicy: 'cache-and-network',\n skip: skipQueries,\n });\n const { data: userData, loading: userLoading } = useGetDashboardUserCountQuery({\n fetchPolicy: 'cache-and-network',\n skip: skipQueries,\n });\n const { data: activityData, loading: activityLoading } = useGetRecentActivityLogsQuery({\n variables: { limit: 10 },\n fetchPolicy: 'cache-and-network',\n skip: skipQueries,\n });\n\n const metrics = {\n tenants: tenantData?.tenants?.total ?? 0,\n organizations: orgData?.allOrganizations?.total ?? 0,\n workspaces: workspaceData?.allWorkspaces?.total ?? 0,\n users: userData?.userCount ?? 0,\n };\n\n const recentActivity: Activity[] = useMemo(\n () => (activityData?.activityLogs?.nodes ?? []).map(mapActivityLogToUi),\n [activityData]\n );\n\n const quickLinks = [\n {\n to: joinPath(basePath, 'tenants'),\n label: tr('admin.dashboard.quickLinks.addTenant', 'Add Tenant'),\n icon: <Plus className=\"h-4 w-4\" />,\n description: tr('admin.dashboard.quickLinks.addTenantDescription', 'Create a new tenant'),\n },\n {\n to: joinPath(basePath, 'users'),\n label: tr('admin.dashboard.quickLinks.inviteUser', 'Invite User'),\n icon: <UserPlus className=\"h-4 w-4\" />,\n description: tr('admin.dashboard.quickLinks.inviteUserDescription', 'Invite a new user'),\n },\n {\n to: joinPath(basePath, 'audit'),\n label: tr('admin.dashboard.quickLinks.auditLogs', 'Audit Logs'),\n icon: <FileText className=\"h-4 w-4\" />,\n description: tr(\n 'admin.dashboard.quickLinks.auditLogsDescription',\n 'View security audit trail'\n ),\n },\n {\n to: joinPath(basePath, 'support'),\n label: tr('admin.dashboard.quickLinks.support', 'Support'),\n icon: <HelpCircle className=\"h-4 w-4\" />,\n description: tr('admin.dashboard.quickLinks.supportDescription', 'Manage support tickets'),\n },\n ];\n\n const isLoading = tenantLoading || orgLoading || workspaceLoading || userLoading;\n\n return (\n <PermissionGuard\n allowed={canViewDashboard}\n isLoading={permissionsLoading}\n pageTitle={tr('admin.dashboard.title', 'Dashboard')}\n denyMessage={tr(\n 'admin.dashboard.denyMessage',\n \"You don't have permission to view the admin dashboard.\"\n )}\n >\n <PageLayout\n title={tr('admin.dashboard.title', 'Dashboard')}\n description={tr('admin.dashboard.description', 'Platform overview and key metrics')}\n gradientWord={tr('admin.dashboard.title', 'Dashboard')}\n aurora\n >\n <div className=\"space-y-6\">\n <PagePurpose>\n {tr(\n 'admin.dashboard.purpose',\n 'Your control tower for the whole platform. See live tenant, organization, workspace and user counts at a glance, watch the most recent administrative activity, and jump straight into the day-to-day jobs — onboarding a tenant, inviting a user, or reviewing the audit trail.'\n )}\n </PagePurpose>\n\n <NextSteps\n storageKey=\"admin-dashboard\"\n steps={[\n {\n id: 'add-tenant',\n label: tr('admin.dashboard.nextSteps.addTenant', 'Onboard a tenant'),\n description: tr(\n 'admin.dashboard.nextSteps.addTenantDesc',\n 'Provision a new customer tenant to start serving them.'\n ),\n onClick: () => navigate(joinPath(basePath, 'tenants/new')),\n },\n {\n id: 'invite-user',\n label: tr('admin.dashboard.nextSteps.inviteUser', 'Invite a teammate'),\n description: tr(\n 'admin.dashboard.nextSteps.inviteUserDesc',\n 'Bring another operator into the admin console.'\n ),\n onClick: () => navigate(joinPath(basePath, 'users')),\n },\n {\n id: 'review-audit',\n label: tr('admin.dashboard.nextSteps.reviewAudit', 'Review the audit trail'),\n description: tr(\n 'admin.dashboard.nextSteps.reviewAuditDesc',\n 'Check who changed what across the platform.'\n ),\n onClick: () => navigate(joinPath(basePath, 'audit')),\n },\n ]}\n />\n\n {/* Metrics Grid */}\n <MetricsGrid>\n <MetricCard\n title={tr('admin.dashboard.metrics.totalTenants', 'Total Tenants')}\n value={metrics.tenants}\n loading={isLoading}\n hero\n icon={<Building2 className=\"h-5 w-5 text-action-primary-bg\" />}\n />\n <MetricCard\n title={tr('admin.dashboard.metrics.organizations', 'Organizations')}\n value={metrics.organizations}\n loading={isLoading}\n icon={<Briefcase className=\"h-5 w-5 text-text-secondary\" />}\n />\n <MetricCard\n title={tr('admin.dashboard.metrics.activeWorkspaces', 'Active Workspaces')}\n value={metrics.workspaces}\n loading={isLoading}\n icon={<Layout className=\"h-5 w-5 text-status-success-text\" />}\n />\n <MetricCard\n title={tr('admin.dashboard.metrics.totalUsers', 'Total Users')}\n value={metrics.users}\n loading={isLoading}\n icon={<Users className=\"h-5 w-5 text-text-secondary\" />}\n />\n </MetricsGrid>\n\n {/* Content Area */}\n <div className=\"grid gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2\">\n <ActivityFeed activities={recentActivity} loading={activityLoading} />\n </div>\n <div className=\"space-y-4\">\n <QuickLinks links={quickLinks} />\n </div>\n </div>\n </div>\n </PageLayout>\n </PermissionGuard>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAsCA,SAAgB,IAAgB;CAC9B,IAAM,EAAE,qBAAkB,WAAW,MAAuB,GAAqB,EAC3E,EAAE,cAAW,OAAO,GAAU,EAC9B,IAAW,GAAa,EACxB,IAAK,GAAO,EAEZ,IAAc,KAAsB,CAAC,GAErC,EAAE,MAAM,GAAY,SAAS,MAAkB,EAAgC;EACnF,aAAa;EACb,MAAM;EACP,CAAC,EACI,EAAE,MAAM,GAAS,SAAS,MAAe,EAAsC;EACnF,aAAa;EACb,MAAM;EACP,CAAC,EACI,EAAE,MAAM,GAAe,SAAS,MACpC,EAAyC;EACvC,aAAa;EACb,MAAM;EACP,CAAC,EACE,EAAE,MAAM,GAAU,SAAS,MAAgB,EAA8B;EAC7E,aAAa;EACb,MAAM;EACP,CAAC,EACI,EAAE,MAAM,GAAc,SAAS,MAAoB,EAA8B;EACrF,WAAW,EAAE,OAAO,IAAI;EACxB,aAAa;EACb,MAAM;EACP,CAAC,EAEI,IAAU;EACd,SAAS,GAAY,SAAS,SAAS;EACvC,eAAe,GAAS,kBAAkB,SAAS;EACnD,YAAY,GAAe,eAAe,SAAS;EACnD,OAAO,GAAU,aAAa;EAC/B,EAEK,IAA6B,SAC1B,GAAc,cAAc,SAAS,EAAE,EAAE,IAAI,EAAmB,EACvE,CAAC,EAAa,CACf,EAEK,IAAa;EACjB;GACE,IAAI,EAAS,GAAU,UAAU;GACjC,OAAO,EAAG,wCAAwC,aAAa;GAC/D,MAAM,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA;GAClC,aAAa,EAAG,mDAAmD,sBAAsB;GAC1F;EACD;GACE,IAAI,EAAS,GAAU,QAAQ;GAC/B,OAAO,EAAG,yCAAyC,cAAc;GACjE,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;GACtC,aAAa,EAAG,oDAAoD,oBAAoB;GACzF;EACD;GACE,IAAI,EAAS,GAAU,QAAQ;GAC/B,OAAO,EAAG,wCAAwC,aAAa;GAC/D,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;GACtC,aAAa,EACX,mDACA,4BACD;GACF;EACD;GACE,IAAI,EAAS,GAAU,UAAU;GACjC,OAAO,EAAG,sCAAsC,UAAU;GAC1D,MAAM,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA;GACxC,aAAa,EAAG,iDAAiD,yBAAyB;GAC3F;EACF,EAEK,IAAY,KAAiB,KAAc,KAAoB;AAErE,QACE,kBAAC,GAAD;EACE,SAAS;EACT,WAAW;EACX,WAAW,EAAG,yBAAyB,YAAY;EACnD,aAAa,EACX,+BACA,yDACD;YAED,kBAAC,GAAD;GACE,OAAO,EAAG,yBAAyB,YAAY;GAC/C,aAAa,EAAG,+BAA+B,oCAAoC;GACnF,cAAc,EAAG,yBAAyB,YAAY;GACtD,QAAA;aAEA,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD,EAAA,UACG,EACC,2BACA,mRACD,EACW,CAAA;KAEd,kBAAC,GAAD;MACE,YAAW;MACX,OAAO;OACL;QACE,IAAI;QACJ,OAAO,EAAG,uCAAuC,mBAAmB;QACpE,aAAa,EACX,2CACA,yDACD;QACD,eAAe,EAAS,EAAS,GAAU,cAAc,CAAC;QAC3D;OACD;QACE,IAAI;QACJ,OAAO,EAAG,wCAAwC,oBAAoB;QACtE,aAAa,EACX,4CACA,iDACD;QACD,eAAe,EAAS,EAAS,GAAU,QAAQ,CAAC;QACrD;OACD;QACE,IAAI;QACJ,OAAO,EAAG,yCAAyC,yBAAyB;QAC5E,aAAa,EACX,6CACA,8CACD;QACD,eAAe,EAAS,EAAS,GAAU,QAAQ,CAAC;QACrD;OACF;MACD,CAAA;KAGF,kBAAC,GAAD,EAAA,UAAA;MACE,kBAAC,GAAD;OACE,OAAO,EAAG,wCAAwC,gBAAgB;OAClE,OAAO,EAAQ;OACf,SAAS;OACT,MAAA;OACA,MAAM,kBAAC,GAAD,EAAW,WAAU,kCAAmC,CAAA;OAC9D,CAAA;MACF,kBAAC,GAAD;OACE,OAAO,EAAG,yCAAyC,gBAAgB;OACnE,OAAO,EAAQ;OACf,SAAS;OACT,MAAM,kBAAC,GAAD,EAAW,WAAU,+BAAgC,CAAA;OAC3D,CAAA;MACF,kBAAC,GAAD;OACE,OAAO,EAAG,4CAA4C,oBAAoB;OAC1E,OAAO,EAAQ;OACf,SAAS;OACT,MAAM,kBAAC,GAAD,EAAQ,WAAU,oCAAqC,CAAA;OAC7D,CAAA;MACF,kBAAC,GAAD;OACE,OAAO,EAAG,sCAAsC,cAAc;OAC9D,OAAO,EAAQ;OACf,SAAS;OACT,MAAM,kBAAC,GAAD,EAAO,WAAU,+BAAgC,CAAA;OACvD,CAAA;MACU,EAAA,CAAA;KAGd,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,GAAD;QAAc,YAAY;QAAgB,SAAS;QAAmB,CAAA;OAClE,CAAA,EACN,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,GAAD,EAAY,OAAO,GAAc,CAAA;OAC7B,CAAA,CACF;;KACF;;GACK,CAAA;EACG,CAAA"}
|
|
@@ -2,131 +2,132 @@ import { Button as e, EmptyState as t, Input as n } from "../components/ui.js";
|
|
|
2
2
|
import { PageLayout as r } from "../components/PageLayout.js";
|
|
3
3
|
import "../components/index.js";
|
|
4
4
|
import { useListOrganizationsQuery as i, useUpdateOrganizationMutation as a } from "../../generated/global-operations.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
5
|
+
import { useTr as o } from "../hooks/useTr.js";
|
|
6
|
+
import { useState as s } from "react";
|
|
7
|
+
import { Building as c, Loader2 as l, Plus as u, Search as d } from "lucide-react";
|
|
8
|
+
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
9
|
+
import { EmphasisPanel as m, PagePurpose as h } from "@burdenoff/fe-libs/ui";
|
|
9
10
|
//#region src/admin/pages/OrganizationsListPage.tsx
|
|
10
|
-
function
|
|
11
|
-
let [
|
|
12
|
-
filter:
|
|
11
|
+
function g() {
|
|
12
|
+
let [g, _] = s(""), v = o(), { data: y, loading: b, refetch: x } = i({ variables: {
|
|
13
|
+
filter: g ? { search: g } : void 0,
|
|
13
14
|
limit: 50
|
|
14
|
-
} }), [
|
|
15
|
-
await
|
|
15
|
+
} }), [S] = a(), C = async (e, t) => {
|
|
16
|
+
await S({ variables: {
|
|
16
17
|
id: e,
|
|
17
18
|
input: { status: t === "ACTIVE" ? "INACTIVE" : "ACTIVE" }
|
|
18
|
-
} }),
|
|
19
|
-
},
|
|
20
|
-
return /* @__PURE__ */
|
|
21
|
-
title: "Organizations",
|
|
22
|
-
gradientWord: "Organizations",
|
|
23
|
-
description: "Manage and monitor platform organizations",
|
|
24
|
-
actions: /* @__PURE__ */
|
|
25
|
-
children: /* @__PURE__ */
|
|
19
|
+
} }), x();
|
|
20
|
+
}, w = y?.allOrganizations?.items || [], T = y?.allOrganizations?.total ?? w.length;
|
|
21
|
+
return /* @__PURE__ */ f(r, {
|
|
22
|
+
title: v("adminMfe.organizations.title", "Organizations"),
|
|
23
|
+
gradientWord: v("adminMfe.organizations.title", "Organizations"),
|
|
24
|
+
description: v("adminMfe.organizations.description", "Manage and monitor platform organizations"),
|
|
25
|
+
actions: /* @__PURE__ */ p(e, { children: [/* @__PURE__ */ f(u, { className: "mr-2 h-4 w-4" }), v("adminMfe.organizations.create", "Create Organization")] }),
|
|
26
|
+
children: /* @__PURE__ */ p("div", {
|
|
26
27
|
className: "space-y-4",
|
|
27
28
|
children: [
|
|
28
|
-
/* @__PURE__ */
|
|
29
|
-
/* @__PURE__ */
|
|
29
|
+
/* @__PURE__ */ f(h, { children: v("adminMfe.organizations.purpose", "Organizations group people and workspaces within a tenant — think of a company's departments or a customer's teams. Use this page to find an organization, review whether it is active, and toggle access on or off without touching the tenant itself.") }),
|
|
30
|
+
/* @__PURE__ */ p(m, {
|
|
30
31
|
className: "flex items-center gap-4 p-5",
|
|
31
|
-
children: [/* @__PURE__ */
|
|
32
|
+
children: [/* @__PURE__ */ f("div", {
|
|
32
33
|
className: "flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-action-primary-bg/15 text-action-primary-bg",
|
|
33
|
-
children: /* @__PURE__ */
|
|
34
|
-
}), /* @__PURE__ */
|
|
34
|
+
children: /* @__PURE__ */ f(c, { className: "h-6 w-6" })
|
|
35
|
+
}), /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("div", {
|
|
35
36
|
className: "text-3xl font-bold tabular-nums text-text-primary",
|
|
36
|
-
children:
|
|
37
|
-
}), /* @__PURE__ */
|
|
37
|
+
children: T
|
|
38
|
+
}), /* @__PURE__ */ f("p", {
|
|
38
39
|
className: "text-sm text-text-secondary",
|
|
39
|
-
children: "organizations on the platform"
|
|
40
|
+
children: v("adminMfe.organizations.emphasis", "organizations on the platform")
|
|
40
41
|
})] })]
|
|
41
42
|
}),
|
|
42
|
-
/* @__PURE__ */
|
|
43
|
+
/* @__PURE__ */ f("div", {
|
|
43
44
|
className: "flex items-center justify-between",
|
|
44
|
-
children: /* @__PURE__ */
|
|
45
|
+
children: /* @__PURE__ */ p("div", {
|
|
45
46
|
className: "relative max-w-sm flex-1",
|
|
46
|
-
children: [/* @__PURE__ */ d
|
|
47
|
-
placeholder: "Search organizations...",
|
|
47
|
+
children: [/* @__PURE__ */ f(d, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ f(n, {
|
|
48
|
+
placeholder: v("adminMfe.organizations.searchPlaceholder", "Search organizations..."),
|
|
48
49
|
className: "pl-9",
|
|
49
|
-
value:
|
|
50
|
-
onChange: (e) =>
|
|
50
|
+
value: g,
|
|
51
|
+
onChange: (e) => _(e.target.value)
|
|
51
52
|
})]
|
|
52
53
|
})
|
|
53
54
|
}),
|
|
54
|
-
|
|
55
|
+
b ? /* @__PURE__ */ f("div", {
|
|
55
56
|
className: "flex h-64 items-center justify-center",
|
|
56
|
-
children: /* @__PURE__ */
|
|
57
|
-
}) :
|
|
57
|
+
children: /* @__PURE__ */ f(l, { className: "h-8 w-8 animate-spin text-text-secondary" })
|
|
58
|
+
}) : w.length > 0 ? /* @__PURE__ */ f("div", {
|
|
58
59
|
className: "rounded-md border",
|
|
59
|
-
children: /* @__PURE__ */
|
|
60
|
+
children: /* @__PURE__ */ p("table", {
|
|
60
61
|
className: "w-full text-sm",
|
|
61
|
-
children: [/* @__PURE__ */
|
|
62
|
+
children: [/* @__PURE__ */ f("thead", { children: /* @__PURE__ */ p("tr", {
|
|
62
63
|
className: "border-b bg-bg-sunken/50 text-left",
|
|
63
64
|
children: [
|
|
64
|
-
/* @__PURE__ */
|
|
65
|
+
/* @__PURE__ */ f("th", {
|
|
65
66
|
className: "p-4 font-medium",
|
|
66
|
-
children: "Name"
|
|
67
|
+
children: v("adminMfe.organizations.table.name", "Name")
|
|
67
68
|
}),
|
|
68
|
-
/* @__PURE__ */
|
|
69
|
+
/* @__PURE__ */ f("th", {
|
|
69
70
|
className: "p-4 font-medium",
|
|
70
|
-
children: "Slug"
|
|
71
|
+
children: v("adminMfe.organizations.table.slug", "Slug")
|
|
71
72
|
}),
|
|
72
|
-
/* @__PURE__ */
|
|
73
|
+
/* @__PURE__ */ f("th", {
|
|
73
74
|
className: "p-4 font-medium",
|
|
74
|
-
children: "Status"
|
|
75
|
+
children: v("adminMfe.organizations.table.status", "Status")
|
|
75
76
|
}),
|
|
76
|
-
/* @__PURE__ */
|
|
77
|
+
/* @__PURE__ */ f("th", {
|
|
77
78
|
className: "p-4 font-medium",
|
|
78
|
-
children: "Created At"
|
|
79
|
+
children: v("adminMfe.organizations.table.createdAt", "Created At")
|
|
79
80
|
}),
|
|
80
|
-
/* @__PURE__ */
|
|
81
|
+
/* @__PURE__ */ f("th", {
|
|
81
82
|
className: "p-4 font-medium text-right",
|
|
82
|
-
children: "Actions"
|
|
83
|
+
children: v("adminMfe.organizations.table.actions", "Actions")
|
|
83
84
|
})
|
|
84
85
|
]
|
|
85
|
-
}) }), /* @__PURE__ */
|
|
86
|
+
}) }), /* @__PURE__ */ f("tbody", { children: w.map((t) => /* @__PURE__ */ p("tr", {
|
|
86
87
|
className: "border-b transition-colors hover:bg-bg-sunken/50",
|
|
87
88
|
children: [
|
|
88
|
-
/* @__PURE__ */
|
|
89
|
+
/* @__PURE__ */ f("td", {
|
|
89
90
|
className: "p-4 font-medium",
|
|
90
91
|
children: t.name
|
|
91
92
|
}),
|
|
92
|
-
/* @__PURE__ */
|
|
93
|
+
/* @__PURE__ */ f("td", {
|
|
93
94
|
className: "p-4 text-text-secondary",
|
|
94
95
|
children: t.slug
|
|
95
96
|
}),
|
|
96
|
-
/* @__PURE__ */
|
|
97
|
+
/* @__PURE__ */ f("td", {
|
|
97
98
|
className: "p-4",
|
|
98
|
-
children: /* @__PURE__ */
|
|
99
|
+
children: /* @__PURE__ */ f("span", {
|
|
99
100
|
className: `inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold ${t.status === "ACTIVE" ? "bg-status-success-bg text-status-success-text border border-status-success-border" : "bg-status-error-bg text-status-error-text border border-status-error-border"}`,
|
|
100
|
-
children: t.status
|
|
101
|
+
children: t.status === "ACTIVE" ? v("adminMfe.organizations.active", "Active") : v("adminMfe.organizations.inactive", "Inactive")
|
|
101
102
|
})
|
|
102
103
|
}),
|
|
103
|
-
/* @__PURE__ */
|
|
104
|
+
/* @__PURE__ */ f("td", {
|
|
104
105
|
className: "p-4 text-text-secondary",
|
|
105
106
|
children: new Date(t.createdAt).toLocaleDateString()
|
|
106
107
|
}),
|
|
107
|
-
/* @__PURE__ */
|
|
108
|
+
/* @__PURE__ */ f("td", {
|
|
108
109
|
className: "p-4 text-right",
|
|
109
|
-
children: /* @__PURE__ */
|
|
110
|
+
children: /* @__PURE__ */ f(e, {
|
|
110
111
|
variant: "outline",
|
|
111
112
|
size: "sm",
|
|
112
|
-
onClick: () =>
|
|
113
|
-
children: "Toggle Status"
|
|
113
|
+
onClick: () => C(t.id, t.status),
|
|
114
|
+
children: v("adminMfe.organizations.toggleStatus", "Toggle Status")
|
|
114
115
|
})
|
|
115
116
|
})
|
|
116
117
|
]
|
|
117
118
|
}, t.id)) })]
|
|
118
119
|
})
|
|
119
|
-
}) : /* @__PURE__ */
|
|
120
|
+
}) : /* @__PURE__ */ f(t, {
|
|
120
121
|
illustration: "empty-data",
|
|
121
|
-
icon: /* @__PURE__ */
|
|
122
|
-
title: "No organizations found",
|
|
123
|
-
description: "Organizations will appear here when they are created"
|
|
122
|
+
icon: /* @__PURE__ */ f(c, { className: "h-8 w-8" }),
|
|
123
|
+
title: v("adminMfe.organizations.empty.title", "No organizations found"),
|
|
124
|
+
description: v("adminMfe.organizations.empty.description", "Organizations will appear here when they are created")
|
|
124
125
|
})
|
|
125
126
|
]
|
|
126
127
|
})
|
|
127
128
|
});
|
|
128
129
|
}
|
|
129
130
|
//#endregion
|
|
130
|
-
export {
|
|
131
|
+
export { g as OrganizationsListPage };
|
|
131
132
|
|
|
132
133
|
//# sourceMappingURL=OrganizationsListPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OrganizationsListPage.js","names":[],"sources":["../../../src/admin/pages/OrganizationsListPage.tsx"],"sourcesContent":["import { Building, Search, Plus, Loader2 } from 'lucide-react';\nimport { PageLayout, Input, Button, EmptyState } from '../components';\nimport { PagePurpose, EmphasisPanel } from '@burdenoff/fe-libs/ui';\nimport {\n useListOrganizationsQuery,\n useUpdateOrganizationMutation,\n} from '../../generated/global-operations';\nimport { useState } from 'react';\n\nexport function OrganizationsListPage() {\n const [searchTerm, setSearchTerm] = useState('');\n const { data, loading, refetch } = useListOrganizationsQuery({\n variables: {\n filter: searchTerm ? { search: searchTerm } : undefined,\n limit: 50,\n },\n });\n\n const [updateOrganization] = useUpdateOrganizationMutation();\n\n const handleToggleStatus = async (id: string, currentStatus: string) => {\n const newStatus = currentStatus === 'ACTIVE' ? 'INACTIVE' : 'ACTIVE';\n await updateOrganization({\n variables: {\n id,\n input: { status: newStatus },\n },\n });\n refetch();\n };\n\n const organizations = data?.allOrganizations?.items || [];\n\n return (\n <PageLayout\n title
|
|
1
|
+
{"version":3,"file":"OrganizationsListPage.js","names":[],"sources":["../../../src/admin/pages/OrganizationsListPage.tsx"],"sourcesContent":["import { Building, Search, Plus, Loader2 } from 'lucide-react';\nimport { PageLayout, Input, Button, EmptyState } from '../components';\nimport { PagePurpose, EmphasisPanel } from '@burdenoff/fe-libs/ui';\nimport {\n useListOrganizationsQuery,\n useUpdateOrganizationMutation,\n} from '../../generated/global-operations';\nimport { useState } from 'react';\nimport { useTr } from '../hooks/useTr';\n\nexport function OrganizationsListPage() {\n const [searchTerm, setSearchTerm] = useState('');\n const tr = useTr();\n const { data, loading, refetch } = useListOrganizationsQuery({\n variables: {\n filter: searchTerm ? { search: searchTerm } : undefined,\n limit: 50,\n },\n });\n\n const [updateOrganization] = useUpdateOrganizationMutation();\n\n const handleToggleStatus = async (id: string, currentStatus: string) => {\n const newStatus = currentStatus === 'ACTIVE' ? 'INACTIVE' : 'ACTIVE';\n await updateOrganization({\n variables: {\n id,\n input: { status: newStatus },\n },\n });\n refetch();\n };\n\n const organizations = data?.allOrganizations?.items || [];\n const total = data?.allOrganizations?.total ?? organizations.length;\n\n return (\n <PageLayout\n title={tr('adminMfe.organizations.title', 'Organizations')}\n gradientWord={tr('adminMfe.organizations.title', 'Organizations')}\n description={tr(\n 'adminMfe.organizations.description',\n 'Manage and monitor platform organizations'\n )}\n actions={\n <Button>\n <Plus className=\"mr-2 h-4 w-4\" />\n {tr('adminMfe.organizations.create', 'Create Organization')}\n </Button>\n }\n >\n <div className=\"space-y-4\">\n <PagePurpose>\n {tr(\n 'adminMfe.organizations.purpose',\n \"Organizations group people and workspaces within a tenant — think of a company's departments or a customer's teams. Use this page to find an organization, review whether it is active, and toggle access on or off without touching the tenant itself.\"\n )}\n </PagePurpose>\n\n {/* Emphasis: how many organizations exist — the headline stat. */}\n <EmphasisPanel className=\"flex items-center gap-4 p-5\">\n <div className=\"flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-action-primary-bg/15 text-action-primary-bg\">\n <Building className=\"h-6 w-6\" />\n </div>\n <div>\n <div className=\"text-3xl font-bold tabular-nums text-text-primary\">{total}</div>\n <p className=\"text-sm text-text-secondary\">\n {tr('adminMfe.organizations.emphasis', 'organizations on the platform')}\n </p>\n </div>\n </EmphasisPanel>\n\n <div className=\"flex items-center justify-between\">\n <div className=\"relative max-w-sm flex-1\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder={tr(\n 'adminMfe.organizations.searchPlaceholder',\n 'Search organizations...'\n )}\n className=\"pl-9\"\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n />\n </div>\n </div>\n\n {loading ? (\n <div className=\"flex h-64 items-center justify-center\">\n <Loader2 className=\"h-8 w-8 animate-spin text-text-secondary\" />\n </div>\n ) : organizations.length > 0 ? (\n <div className=\"rounded-md border\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-bg-sunken/50 text-left\">\n <th className=\"p-4 font-medium\">\n {tr('adminMfe.organizations.table.name', 'Name')}\n </th>\n <th className=\"p-4 font-medium\">\n {tr('adminMfe.organizations.table.slug', 'Slug')}\n </th>\n <th className=\"p-4 font-medium\">\n {tr('adminMfe.organizations.table.status', 'Status')}\n </th>\n <th className=\"p-4 font-medium\">\n {tr('adminMfe.organizations.table.createdAt', 'Created At')}\n </th>\n <th className=\"p-4 font-medium text-right\">\n {tr('adminMfe.organizations.table.actions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody>\n {organizations.map((org: any) => (\n <tr key={org.id} className=\"border-b transition-colors hover:bg-bg-sunken/50\">\n <td className=\"p-4 font-medium\">{org.name}</td>\n <td className=\"p-4 text-text-secondary\">{org.slug}</td>\n <td className=\"p-4\">\n <span\n className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold ${\n org.status === 'ACTIVE'\n ? 'bg-status-success-bg text-status-success-text border border-status-success-border'\n : 'bg-status-error-bg text-status-error-text border border-status-error-border'\n }`}\n >\n {org.status === 'ACTIVE'\n ? tr('adminMfe.organizations.active', 'Active')\n : tr('adminMfe.organizations.inactive', 'Inactive')}\n </span>\n </td>\n <td className=\"p-4 text-text-secondary\">\n {new Date(org.createdAt).toLocaleDateString()}\n </td>\n <td className=\"p-4 text-right\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => handleToggleStatus(org.id, org.status)}\n >\n {tr('adminMfe.organizations.toggleStatus', 'Toggle Status')}\n </Button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Building className=\"h-8 w-8\" />}\n title={tr('adminMfe.organizations.empty.title', 'No organizations found')}\n description={tr(\n 'adminMfe.organizations.empty.description',\n 'Organizations will appear here when they are created'\n )}\n />\n )}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|