@elevasis/ui 2.34.0 → 2.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/dist/api/index.js +3 -3
  2. package/dist/app/index.d.ts +12 -12
  3. package/dist/app/index.js +25 -23
  4. package/dist/charts/index.js +3 -5
  5. package/dist/chunk-26HFM4MH.js +41449 -0
  6. package/dist/{chunk-DTFKWZ7A.js → chunk-4U3XAWCN.js} +502 -484
  7. package/dist/{chunk-ND5TDV2J.js → chunk-57OZ3AEG.js} +1 -1
  8. package/dist/{chunk-E4WQGJNS.js → chunk-7FPLLSHN.js} +14 -1
  9. package/dist/{chunk-RQA2EVN3.js → chunk-AKW7KISS.js} +39 -3
  10. package/dist/chunk-AUDNF2Q7.js +2050 -0
  11. package/dist/{chunk-TYRUKGGD.js → chunk-GX6XBRRF.js} +1 -2
  12. package/dist/{chunk-V6SZ4ECN.js → chunk-LUYVRATI.js} +257 -6
  13. package/dist/{chunk-X4WBGKJQ.js → chunk-R3VCBZDC.js} +50 -3
  14. package/dist/chunk-SIQ3P4OR.js +1764 -0
  15. package/dist/{chunk-RIAXZ6AH.js → chunk-VDOOGGBA.js} +1 -1
  16. package/dist/{chunk-3FV6HBXS.js → chunk-WF7CONXF.js} +23 -23
  17. package/dist/{chunk-3QXJK5IY.js → chunk-YYX7OPZQ.js} +1 -1
  18. package/dist/components/index.d.ts +69 -69
  19. package/dist/components/index.js +20 -2795
  20. package/dist/components/navigation/index.js +25 -5
  21. package/dist/execution/index.d.ts +9 -9
  22. package/dist/execution/index.js +1 -2
  23. package/dist/features/auth/index.js +23 -2
  24. package/dist/features/clients/index.js +20 -26
  25. package/dist/features/crm/index.js +20 -30
  26. package/dist/features/dashboard/index.d.ts +68 -68
  27. package/dist/features/dashboard/index.js +20 -28
  28. package/dist/features/delivery/index.js +20 -30
  29. package/dist/features/knowledge/index.js +25 -9
  30. package/dist/features/lead-gen/index.d.ts +9 -9
  31. package/dist/features/lead-gen/index.js +20 -31
  32. package/dist/features/monitoring/index.js +20 -30
  33. package/dist/features/monitoring/requests/index.js +20 -25
  34. package/dist/features/operations/index.d.ts +153 -153
  35. package/dist/features/operations/index.js +18 -37
  36. package/dist/features/seo/index.js +3 -4
  37. package/dist/features/settings/index.js +20 -27
  38. package/dist/graph/index.js +1 -1
  39. package/dist/hooks/delivery/index.js +30 -2
  40. package/dist/hooks/index.d.ts +85 -85
  41. package/dist/hooks/index.js +20 -21
  42. package/dist/hooks/operations/command-view/utils/transformCommandViewData.d.ts +35 -35
  43. package/dist/hooks/published.d.ts +85 -85
  44. package/dist/hooks/published.js +20 -20
  45. package/dist/index.css +532 -532
  46. package/dist/index.d.ts +9256 -5803
  47. package/dist/index.js +22 -26
  48. package/dist/knowledge/index.d.ts +21 -21
  49. package/dist/knowledge/index.js +8 -15
  50. package/dist/layout/index.js +4 -10
  51. package/dist/organization/index.js +27 -1
  52. package/dist/provider/index.d.ts +47 -21
  53. package/dist/provider/index.js +20 -15
  54. package/dist/provider/published.d.ts +15 -16
  55. package/dist/provider/published.js +20 -11
  56. package/dist/test-utils/index.js +3 -3
  57. package/dist/theme/index.js +2 -3
  58. package/dist/theme/presets/index.d.ts +28 -3
  59. package/dist/theme/presets/index.js +1 -1
  60. package/dist/typeform/index.js +1 -2049
  61. package/dist/types/index.d.ts +68 -68
  62. package/dist/utils/index.d.ts +46 -46
  63. package/dist/utils/index.js +1 -1
  64. package/dist/zustand/index.d.ts +6 -6
  65. package/dist/zustand/index.js +0 -3
  66. package/package.json +5 -5
  67. package/dist/chunk-3AJVNMY5.js +0 -4769
  68. package/dist/chunk-3MEXPLWT.js +0 -265
  69. package/dist/chunk-3ZMAGTWF.js +0 -18
  70. package/dist/chunk-4O4MII5S.js +0 -4716
  71. package/dist/chunk-5EYJ2GIN.js +0 -122
  72. package/dist/chunk-7M2VOCYN.js +0 -1
  73. package/dist/chunk-BPQVTIUP.js +0 -105
  74. package/dist/chunk-BZZCNLT6.js +0 -12
  75. package/dist/chunk-CLDCYJQT.js +0 -1
  76. package/dist/chunk-E565XMTQ.js +0 -17
  77. package/dist/chunk-HRWLKKWM.js +0 -758
  78. package/dist/chunk-IGDYWFNE.js +0 -5198
  79. package/dist/chunk-IIMU5YAJ.js +0 -53
  80. package/dist/chunk-IVGI4GDL.js +0 -1593
  81. package/dist/chunk-JFL3GRD4.js +0 -39
  82. package/dist/chunk-LAWLB6CT.js +0 -951
  83. package/dist/chunk-LGKLC5MG.js +0 -44
  84. package/dist/chunk-LRWTWOGP.js +0 -1778
  85. package/dist/chunk-MP3GPBPX.js +0 -1874
  86. package/dist/chunk-N55DVMAG.js +0 -14
  87. package/dist/chunk-NLBQTDOW.js +0 -12051
  88. package/dist/chunk-O6JXQ6UQ.js +0 -468
  89. package/dist/chunk-OBBQ2JCM.js +0 -68
  90. package/dist/chunk-PDHTXPSF.js +0 -12
  91. package/dist/chunk-PLP3NYPL.js +0 -356
  92. package/dist/chunk-R2XR4FCV.js +0 -48
  93. package/dist/chunk-R66W5UDG.js +0 -26
  94. package/dist/chunk-RYTEQBAO.js +0 -37
  95. package/dist/chunk-SDXSB3HN.js +0 -425
  96. package/dist/chunk-TKAYX2SP.js +0 -204
  97. package/dist/chunk-TUMSNGTX.js +0 -35
  98. package/dist/chunk-VNAZTCHA.js +0 -65
  99. package/dist/chunk-VNFR57DF.js +0 -87
  100. package/dist/chunk-VTXTZXAU.js +0 -539
  101. package/dist/chunk-W73ZABT6.js +0 -85
  102. package/dist/chunk-WU4FNWCW.js +0 -2281
  103. package/dist/chunk-XZGSCABI.js +0 -383
  104. package/dist/chunk-YNWZIWJL.js +0 -1863
  105. /package/dist/{chunk-2RJMVWFJ.js → chunk-GEFWMU26.js} +0 -0
  106. /package/dist/{chunk-22UVE3RA.js → chunk-HENXLGVD.js} +0 -0
@@ -1,65 +0,0 @@
1
- import { useElevasisServices } from './chunk-KJ3QUBNU.js';
2
- import { useQuery } from '@tanstack/react-query';
3
-
4
- // src/hooks/observability/queryKeys.ts
5
- var observabilityKeys = {
6
- all: ["observability"],
7
- // Error analysis
8
- errorAnalysis: (organizationId, timeRange) => [...observabilityKeys.all, "error-analysis", organizationId, timeRange],
9
- // Error details list
10
- errorDetails: (organizationId, filters) => [...observabilityKeys.all, "error-details", organizationId, filters],
11
- // Single execution error detail
12
- errorDetail: (organizationId, executionId) => [...observabilityKeys.all, "error-detail", organizationId, executionId],
13
- // Error trends time-series
14
- errorTrends: (organizationId, startDate, endDate, granularity) => [...observabilityKeys.all, "error-trends", organizationId, startDate, endDate, granularity],
15
- // Error distribution breakdown
16
- errorDistribution: (organizationId, startDate, endDate, groupBy) => [...observabilityKeys.all, "error-distribution", organizationId, startDate, endDate, groupBy],
17
- // Top failing resources
18
- topFailingResources: (organizationId, startDate, endDate, limit) => [...observabilityKeys.all, "top-failing-resources", organizationId, startDate, endDate, limit],
19
- // Cost trends time-series
20
- costTrends: (organizationId, timeRange, granularity) => [...observabilityKeys.all, "cost-trends", organizationId, timeRange, granularity],
21
- // Cost by model breakdown
22
- costByModel: (organizationId, timeRange) => [...observabilityKeys.all, "cost-by-model", organizationId, timeRange],
23
- // Cost breakdown per resource/model
24
- costBreakdown: (organizationId, timeRange) => [...observabilityKeys.all, "cost-breakdown", organizationId, timeRange],
25
- // Composite dashboard metrics
26
- dashboardMetrics: (organizationId, timeRange) => [...observabilityKeys.all, "dashboard-metrics", organizationId, timeRange],
27
- // Business impact / automation ROI
28
- businessImpact: (organizationId, timeRange) => [...observabilityKeys.all, "business-impact", organizationId, timeRange],
29
- // Resources health batch
30
- resourcesHealth: (organizationId, resources, startDate, endDate, granularity) => [...observabilityKeys.all, "resources-health", organizationId, resources, startDate, endDate, granularity],
31
- // System-scoped health from direct/descendant resource descriptors
32
- systemHealth: (organizationId, systemPath, timeRange, includeDescendants, descendantMode, resourceSet, startDate, endDate, directResources, descendantResources) => [
33
- ...observabilityKeys.all,
34
- "system-health",
35
- organizationId,
36
- systemPath,
37
- timeRange,
38
- includeDescendants,
39
- descendantMode,
40
- resourceSet,
41
- startDate,
42
- endDate,
43
- directResources,
44
- descendantResources
45
- ],
46
- // Unresolved errors dashboard teaser
47
- unresolvedErrors: (organizationId, startDate, endDate) => [...observabilityKeys.all, "unresolved-errors", organizationId, startDate, endDate],
48
- // Recent executions grouped by resource (dashboard widget)
49
- recentExecutionsByResource: (organizationId, timeRange, limit) => [...observabilityKeys.all, "recent-executions-by-resource", organizationId, timeRange, limit]
50
- };
51
- function useErrorTrends({ startDate, endDate, granularity }) {
52
- const { apiRequest, isReady, workOSOrganizationId } = useElevasisServices();
53
- return useQuery({
54
- queryKey: observabilityKeys.errorTrends(workOSOrganizationId, startDate, endDate, granularity),
55
- queryFn: async () => {
56
- const params = new URLSearchParams({ startDate, endDate, granularity });
57
- return apiRequest(`/observability/error-analytics/trends?${params.toString()}`);
58
- },
59
- enabled: isReady,
60
- refetchInterval: 6e4,
61
- staleTime: 3e4
62
- });
63
- }
64
-
65
- export { observabilityKeys, useErrorTrends };
@@ -1,87 +0,0 @@
1
- import { CustomModal } from './chunk-R66W5UDG.js';
2
- import { cloneElement } from 'react';
3
- import { Center, Space, Text, Button, Title, TextInput } from '@mantine/core';
4
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
-
6
- var ConfirmationModal = ({
7
- opened,
8
- onClose,
9
- loading,
10
- icon,
11
- confirmationHandler,
12
- style,
13
- title,
14
- text,
15
- buttonText,
16
- buttonColor,
17
- centerText
18
- }) => {
19
- const styledIcon = cloneElement(icon, {
20
- size: 55,
21
- strokeWidth: 1.5
22
- });
23
- return /* @__PURE__ */ jsxs(CustomModal, { opened, onClose, loading, style, children: [
24
- /* @__PURE__ */ jsx(Center, { children: styledIcon }),
25
- /* @__PURE__ */ jsx(Space, { h: 16 }),
26
- /* @__PURE__ */ jsx(Center, { style: { textAlign: "center" }, children: /* @__PURE__ */ jsx(Text, { size: "lg", c: "var(--color-text)", children: title }) }),
27
- /* @__PURE__ */ jsx(Space, { h: 16 }),
28
- text && /* @__PURE__ */ jsxs(Fragment, { children: [
29
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "var(--color-text-dimmed)", style: { textAlign: centerText ? "center" : "left" }, children: text }),
30
- /* @__PURE__ */ jsx(Space, { h: 16 })
31
- ] }),
32
- /* @__PURE__ */ jsx(Button, { color: buttonColor || "blue", fullWidth: true, onClick: confirmationHandler, loading, children: buttonText || "Confirm" })
33
- ] });
34
- };
35
- var ConfirmationInputModal = ({
36
- opened,
37
- onClose,
38
- loading,
39
- icon,
40
- confirmationHandler,
41
- style,
42
- title,
43
- text,
44
- buttonText,
45
- buttonColor,
46
- inputValue,
47
- onInputChange,
48
- expectedValue,
49
- placeholder
50
- }) => {
51
- const styledIcon = cloneElement(icon, {
52
- size: 55,
53
- strokeWidth: 1.5
54
- });
55
- return /* @__PURE__ */ jsxs(CustomModal, { opened, onClose, loading, style, children: [
56
- /* @__PURE__ */ jsx(Center, { children: styledIcon }),
57
- /* @__PURE__ */ jsx(Space, { h: 16 }),
58
- /* @__PURE__ */ jsx(Center, { children: /* @__PURE__ */ jsx(Title, { order: 3, children: title }) }),
59
- /* @__PURE__ */ jsx(Space, { h: 16 }),
60
- text && /* @__PURE__ */ jsxs(Fragment, { children: [
61
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "var(--color-text-dimmed)", children: text }),
62
- /* @__PURE__ */ jsx(Space, { h: 8 })
63
- ] }),
64
- /* @__PURE__ */ jsx(
65
- TextInput,
66
- {
67
- placeholder: placeholder || "Enter confirmation text",
68
- value: inputValue,
69
- onChange: (event) => onInputChange(event.currentTarget.value)
70
- }
71
- ),
72
- /* @__PURE__ */ jsx(Space, { h: 16 }),
73
- /* @__PURE__ */ jsx(
74
- Button,
75
- {
76
- color: buttonColor || "blue",
77
- fullWidth: true,
78
- onClick: confirmationHandler,
79
- loading,
80
- disabled: inputValue !== expectedValue,
81
- children: buttonText || "Confirm"
82
- }
83
- )
84
- ] });
85
- };
86
-
87
- export { ConfirmationInputModal, ConfirmationModal };
@@ -1,539 +0,0 @@
1
- import { OrganizationContext, useOrganization } from './chunk-DD3CCMCZ.js';
2
- import { useProfile, useUserProfile } from './chunk-2Q2JQSQO.js';
3
- import { useAuthContext } from './chunk-BRJ3QZ4E.js';
4
- import { useState, useRef, useEffect, useCallback, createElement } from 'react';
5
- import { useQueryClient } from '@tanstack/react-query';
6
- import { Badge, Group, Button, Loader, Menu, Text } from '@mantine/core';
7
- import { IconLock, IconChevronDown, IconBuilding, IconCheck } from '@tabler/icons-react';
8
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
- import { useAuth } from '@workos-inc/authkit-react';
10
-
11
- function OrganizationProvider({ apiRequest, children }) {
12
- const { user, organizationId: workosOrgId } = useAuthContext();
13
- const { profile, error: profileError } = useProfile();
14
- const queryClient = useQueryClient();
15
- const [memberships, setMemberships] = useState([]);
16
- const [currentWorkOSOrganizationId, setCurrentWorkOSOrganizationId] = useState(null);
17
- const [currentSupabaseOrganizationId, setCurrentSupabaseOrganizationId] = useState(null);
18
- const [currentMembership, setCurrentMembership] = useState(null);
19
- const [isInitializing, setIsInitializing] = useState(true);
20
- const [isOrgRefreshing, setIsOrgRefreshing] = useState(false);
21
- const [error, setError] = useState(null);
22
- const hasInitializedRef = useRef(false);
23
- const [profileLoaded, setProfileLoaded] = useState(false);
24
- useEffect(() => {
25
- if (profile !== void 0 && profile !== null) {
26
- setProfileLoaded(true);
27
- }
28
- }, [profile]);
29
- useEffect(() => {
30
- if (profileError && isInitializing && !hasInitializedRef.current) {
31
- setIsInitializing(false);
32
- }
33
- }, [profileError, isInitializing]);
34
- useEffect(() => {
35
- if (!user) {
36
- setMemberships([]);
37
- setCurrentWorkOSOrganizationId(null);
38
- setCurrentSupabaseOrganizationId(null);
39
- setCurrentMembership(null);
40
- setIsInitializing(false);
41
- setIsOrgRefreshing(false);
42
- setError(null);
43
- hasInitializedRef.current = false;
44
- setProfileLoaded(false);
45
- }
46
- }, [user]);
47
- const applyMembership = useCallback((membership) => {
48
- setCurrentMembership(membership);
49
- setCurrentSupabaseOrganizationId(membership?.organization?.id ?? null);
50
- setCurrentWorkOSOrganizationId(membership?.organization?.workos_org_id ?? null);
51
- }, []);
52
- const selectOrganization = useCallback(
53
- (data) => {
54
- let selected = null;
55
- if (profile?.last_visited_org) {
56
- selected = data.find((m) => m.organizationId === profile.last_visited_org) ?? null;
57
- }
58
- if (!selected && workosOrgId) {
59
- selected = data.find((m) => m.organization?.workos_org_id === workosOrgId) ?? null;
60
- }
61
- if (!selected && data.length > 0) {
62
- selected = data[0];
63
- }
64
- if (selected) {
65
- applyMembership(selected);
66
- }
67
- },
68
- [profile?.last_visited_org, workosOrgId, applyMembership]
69
- );
70
- const fetchAndInitialize = useCallback(async () => {
71
- if (!user?.id || !profileLoaded) return;
72
- setError(null);
73
- if (memberships.length === 0) {
74
- setIsInitializing(true);
75
- } else {
76
- setIsOrgRefreshing(true);
77
- }
78
- try {
79
- const data = await apiRequest("/memberships/my-memberships");
80
- if (!Array.isArray(data)) {
81
- throw new Error("Invalid memberships response");
82
- }
83
- setMemberships(data);
84
- if (data.length === 0) {
85
- hasInitializedRef.current = true;
86
- return;
87
- }
88
- if (!currentWorkOSOrganizationId) {
89
- selectOrganization(data);
90
- } else {
91
- const stillPresent = data.find((m) => m.organization?.workos_org_id === currentWorkOSOrganizationId);
92
- if (!stillPresent) {
93
- applyMembership(data[0] ?? null);
94
- } else if (stillPresent.id !== currentMembership?.id) {
95
- applyMembership(stillPresent);
96
- }
97
- }
98
- hasInitializedRef.current = true;
99
- } catch (err) {
100
- setError(err instanceof Error ? err.message : "Failed to load organizations");
101
- } finally {
102
- setIsInitializing(false);
103
- setIsOrgRefreshing(false);
104
- }
105
- }, [
106
- user?.id,
107
- profileLoaded,
108
- memberships.length,
109
- apiRequest,
110
- currentWorkOSOrganizationId,
111
- currentMembership?.id,
112
- selectOrganization,
113
- applyMembership
114
- ]);
115
- useEffect(() => {
116
- if (!user?.id || !profileLoaded || hasInitializedRef.current) return;
117
- fetchAndInitialize();
118
- }, [user?.id, profileLoaded, fetchAndInitialize]);
119
- useEffect(() => {
120
- if (!hasInitializedRef.current) return;
121
- if (!workosOrgId) return;
122
- if (workosOrgId === currentWorkOSOrganizationId) return;
123
- const target = memberships.find((m) => m.organization?.workos_org_id === workosOrgId);
124
- if (!target) return;
125
- applyMembership(target);
126
- void queryClient.invalidateQueries();
127
- }, [workosOrgId, currentWorkOSOrganizationId, memberships, applyMembership, queryClient]);
128
- const switchOrganization = useCallback(
129
- (workosOrgId2) => {
130
- const target = memberships.find((m) => m.organization?.workos_org_id === workosOrgId2);
131
- if (!target) return;
132
- applyMembership(target);
133
- void queryClient.invalidateQueries();
134
- void apiRequest("/users/me", {
135
- method: "PATCH",
136
- headers: { "Content-Type": "application/json" },
137
- body: JSON.stringify({ last_visited_org: target.organizationId })
138
- }).catch((err) => {
139
- console.warn("Failed to persist last_visited_org preference:", err);
140
- });
141
- },
142
- [memberships, applyMembership, queryClient, apiRequest]
143
- );
144
- const retry = useCallback(async () => {
145
- hasInitializedRef.current = false;
146
- setError(null);
147
- await fetchAndInitialize();
148
- }, [fetchAndInitialize]);
149
- const value = {
150
- currentWorkOSOrganizationId,
151
- currentSupabaseOrganizationId,
152
- currentMembership,
153
- memberships,
154
- isInitializing,
155
- isOrgRefreshing,
156
- error,
157
- switchOrganization,
158
- retry
159
- };
160
- return createElement(OrganizationContext.Provider, { value }, children);
161
- }
162
- function RoleBadge({ name, isSystem }) {
163
- return /* @__PURE__ */ jsx(Badge, { color: isSystem ? "gray" : "primary", variant: "light", children: /* @__PURE__ */ jsxs(Group, { gap: 4, wrap: "nowrap", children: [
164
- isSystem && /* @__PURE__ */ jsx(IconLock, { size: 10 }),
165
- name
166
- ] }) });
167
- }
168
- function OrganizationSwitcher({
169
- currentOrganization,
170
- memberships,
171
- isLoading,
172
- onSwitch
173
- }) {
174
- const [opened, setOpened] = useState(false);
175
- const [switching, setSwitching] = useState(false);
176
- const otherMemberships = memberships.filter((m) => m.organizationId !== currentOrganization?.id);
177
- const handleSwitch = async (workosOrgId) => {
178
- setSwitching(true);
179
- try {
180
- await onSwitch(workosOrgId);
181
- setOpened(false);
182
- } catch (error) {
183
- console.error("Failed to switch organization:", error);
184
- } finally {
185
- setSwitching(false);
186
- }
187
- };
188
- if (isLoading) {
189
- return /* @__PURE__ */ jsx(Button, { variant: "light", size: "xs", disabled: true, children: /* @__PURE__ */ jsx(Loader, { size: 14 }) });
190
- }
191
- if (memberships.length === 0) {
192
- return /* @__PURE__ */ jsx(Button, { variant: "light", size: "xs", disabled: true, children: "None" });
193
- }
194
- return /* @__PURE__ */ jsxs(Menu, { opened, onChange: setOpened, position: "bottom-start", withinPortal: true, children: [
195
- /* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(
196
- Button,
197
- {
198
- variant: "light",
199
- size: "xs",
200
- leftSection: /* @__PURE__ */ jsx(IconBuilding, { size: 16 }),
201
- rightSection: /* @__PURE__ */ jsx(IconChevronDown, { size: 14 }),
202
- loading: switching,
203
- children: /* @__PURE__ */ jsx(Text, { truncate: true, style: { maxWidth: 200 }, size: "xs", children: currentOrganization?.name || "Select Organization" })
204
- }
205
- ) }),
206
- /* @__PURE__ */ jsxs(
207
- Menu.Dropdown,
208
- {
209
- style: {
210
- background: "var(--glass-background)",
211
- backdropFilter: "var(--glass-blur)",
212
- WebkitBackdropFilter: "var(--glass-blur)"
213
- },
214
- children: [
215
- currentOrganization && /* @__PURE__ */ jsxs(Fragment, { children: [
216
- /* @__PURE__ */ jsx(Menu.Label, { children: "Current Organization" }),
217
- /* @__PURE__ */ jsx(Menu.Item, { disabled: true, rightSection: /* @__PURE__ */ jsx(IconCheck, { size: 14 }), leftSection: /* @__PURE__ */ jsx(IconBuilding, { size: 14 }), children: currentOrganization.name }),
218
- otherMemberships.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
219
- /* @__PURE__ */ jsx(Menu.Divider, {}),
220
- /* @__PURE__ */ jsx(Menu.Label, { children: "Switch Organization" })
221
- ] })
222
- ] }),
223
- otherMemberships.length > 0 && /* @__PURE__ */ jsx("div", { children: otherMemberships.map((membership, index) => /* @__PURE__ */ jsx(
224
- Menu.Item,
225
- {
226
- leftSection: /* @__PURE__ */ jsx(IconBuilding, { size: 14 }),
227
- rightSection: /* @__PURE__ */ jsx(
228
- RoleBadge,
229
- {
230
- slug: membership.role.slug,
231
- name: membership.role.slug.charAt(0).toUpperCase() + membership.role.slug.slice(1),
232
- isSystem: true
233
- }
234
- ),
235
- onClick: () => {
236
- const workosOrgId = membership.organization?.workos_org_id;
237
- if (!workosOrgId) {
238
- console.error("Organization missing WorkOS ID:", membership.organization?.name);
239
- return;
240
- }
241
- handleSwitch(workosOrgId);
242
- },
243
- disabled: switching,
244
- children: membership.organization?.name || "Unknown Organization"
245
- },
246
- `${membership.organizationId}-${index}`
247
- )) }, "other-memberships"),
248
- !currentOrganization && memberships.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
249
- /* @__PURE__ */ jsx(Menu.Label, { children: "Select Organization" }),
250
- memberships.map((membership) => /* @__PURE__ */ jsx(
251
- Menu.Item,
252
- {
253
- leftSection: /* @__PURE__ */ jsx(IconBuilding, { size: 14 }),
254
- rightSection: /* @__PURE__ */ jsx(
255
- RoleBadge,
256
- {
257
- slug: membership.role.slug,
258
- name: membership.role.slug.charAt(0).toUpperCase() + membership.role.slug.slice(1),
259
- isSystem: true
260
- }
261
- ),
262
- onClick: () => {
263
- const workosOrgId = membership.organization?.workos_org_id;
264
- if (!workosOrgId) {
265
- console.error("Organization missing WorkOS ID:", membership.organization?.name);
266
- return;
267
- }
268
- handleSwitch(workosOrgId);
269
- },
270
- disabled: switching,
271
- children: membership.organization?.name || "Unknown Organization"
272
- },
273
- membership.organizationId
274
- ))
275
- ] })
276
- ]
277
- }
278
- )
279
- ] });
280
- }
281
- function OrganizationSwitcherConnected() {
282
- const { switchToOrganization } = useAuth();
283
- const { currentMembership, memberships, isInitializing, isOrgRefreshing, switchOrganization } = useOrganization();
284
- return /* @__PURE__ */ jsx(
285
- OrganizationSwitcher,
286
- {
287
- currentOrganization: currentMembership?.organization,
288
- memberships,
289
- isLoading: isInitializing || isOrgRefreshing,
290
- onSwitch: async (workosOrgId) => {
291
- await switchToOrganization({ organizationId: workosOrgId });
292
- switchOrganization(workosOrgId);
293
- }
294
- }
295
- );
296
- }
297
-
298
- // src/organization/store/organizationsSlice.ts
299
- var initialOrganizationsState = {
300
- currentWorkOSOrganizationId: null,
301
- currentSupabaseOrganizationId: null,
302
- currentMembership: null,
303
- isInitializing: true,
304
- // Start as initializing
305
- isOrgRefreshing: false,
306
- error: null
307
- };
308
- var createOrganizationsSlice = (set, _get, _store) => ({
309
- // Organizations state
310
- organizations: initialOrganizationsState,
311
- // Organization actions
312
- setCurrentWorkOSOrganizationId: (workOSorgId) => {
313
- set(
314
- (state) => {
315
- state.organizations.currentWorkOSOrganizationId = workOSorgId;
316
- },
317
- void 0,
318
- "organizations/setCurrentWorkOSOrganizationId"
319
- );
320
- },
321
- setCurrentMembership: (membership) => {
322
- set(
323
- (state) => {
324
- state.organizations.currentMembership = membership;
325
- state.organizations.currentSupabaseOrganizationId = membership?.organization?.id || null;
326
- },
327
- void 0,
328
- "organizations/setCurrentMembership"
329
- );
330
- },
331
- setOrganizationsInitializing: (initializing) => set(
332
- (state) => {
333
- state.organizations.isInitializing = initializing;
334
- },
335
- void 0,
336
- "organizations/setInitializing"
337
- ),
338
- setOrganizationsLoading: (loading) => set(
339
- (state) => {
340
- state.organizations.isOrgRefreshing = loading;
341
- },
342
- void 0,
343
- "organizations/setLoading"
344
- ),
345
- setOrganizationsError: (error) => set(
346
- (state) => {
347
- state.organizations.error = error;
348
- },
349
- void 0,
350
- "organizations/setError"
351
- )
352
- });
353
-
354
- // src/organization/hooks/useOrganizations.ts
355
- function createUseOrganizations(useStore) {
356
- return () => {
357
- const organizations = useStore((state) => state.organizations);
358
- const setCurrentWorkOSOrganizationId = useStore((state) => state.setCurrentWorkOSOrganizationId);
359
- const setCurrentMembership = useStore((state) => state.setCurrentMembership);
360
- const setOrganizationsInitializing = useStore((state) => state.setOrganizationsInitializing);
361
- const setOrganizationsLoading = useStore((state) => state.setOrganizationsLoading);
362
- const setOrganizationsError = useStore((state) => state.setOrganizationsError);
363
- return {
364
- ...organizations,
365
- setCurrentWorkOSOrganizationId,
366
- setCurrentMembership,
367
- setOrganizationsInitializing,
368
- setOrganizationsLoading,
369
- setOrganizationsError,
370
- organizations
371
- // Also return the full organizations object for easy access
372
- };
373
- };
374
- }
375
- function createUseOrgInitialization(useOrganizations, useApiClient) {
376
- return function useOrgInitialization() {
377
- const { user, organizationId: workosOrgId } = useAuthContext();
378
- const { apiRequest } = useApiClient();
379
- const { profile } = useUserProfile();
380
- const {
381
- currentWorkOSOrganizationId,
382
- currentMembership,
383
- setCurrentWorkOSOrganizationId,
384
- setCurrentMembership,
385
- setOrganizationsInitializing,
386
- setOrganizationsLoading,
387
- setOrganizationsError,
388
- organizations
389
- } = useOrganizations();
390
- const [memberships, setMemberships] = useState([]);
391
- const [profileLoaded, setProfileLoaded] = useState(false);
392
- const hasInitializedRef = useRef(false);
393
- const currentMembershipIdRef = useRef(null);
394
- currentMembershipIdRef.current = currentMembership?.id ?? null;
395
- useEffect(() => {
396
- if (profile !== void 0 && profile !== null) {
397
- setProfileLoaded(true);
398
- }
399
- }, [profile]);
400
- const selectOrganization = useCallback(
401
- async (data) => {
402
- let selectedMembership = null;
403
- if (profile?.last_visited_org) {
404
- const supabaseLastVisitedOrgId = profile.last_visited_org;
405
- selectedMembership = data.find((m) => m.organizationId === supabaseLastVisitedOrgId) || null;
406
- }
407
- if (!selectedMembership && workosOrgId) {
408
- selectedMembership = data.find((m) => m.organization?.workos_org_id === workosOrgId) || null;
409
- }
410
- if (!selectedMembership && data.length > 0) {
411
- selectedMembership = data[0];
412
- }
413
- if (selectedMembership) {
414
- const workosSelectedOrgId = selectedMembership.organization?.workos_org_id;
415
- if (workosSelectedOrgId) {
416
- setCurrentWorkOSOrganizationId(workosSelectedOrgId);
417
- setCurrentMembership(selectedMembership);
418
- }
419
- }
420
- },
421
- [profile?.last_visited_org, workosOrgId, setCurrentWorkOSOrganizationId, setCurrentMembership]
422
- );
423
- const validateCurrentOrganization = useCallback(
424
- (data) => {
425
- const workosCurrentOrgId = currentWorkOSOrganizationId;
426
- const currentOrg = data.find((m) => m.organization?.workos_org_id === workosCurrentOrgId);
427
- if (!currentOrg) {
428
- setCurrentWorkOSOrganizationId(null);
429
- setCurrentMembership(null);
430
- if (data.length > 0) {
431
- const fallbackOrg = data[0];
432
- const workosFallbackOrgId = fallbackOrg.organization?.workos_org_id;
433
- if (workosFallbackOrgId) {
434
- setCurrentWorkOSOrganizationId(workosFallbackOrgId);
435
- setCurrentMembership(fallbackOrg);
436
- }
437
- }
438
- } else {
439
- if (currentOrg.id !== currentMembershipIdRef.current) {
440
- setCurrentMembership(currentOrg);
441
- }
442
- }
443
- },
444
- [currentWorkOSOrganizationId, setCurrentWorkOSOrganizationId, setCurrentMembership]
445
- );
446
- useEffect(() => {
447
- const initializeOrganizations = async () => {
448
- if (!user?.id || !profileLoaded) {
449
- return;
450
- }
451
- if (hasInitializedRef.current) {
452
- return;
453
- }
454
- if (memberships.length === 0) {
455
- setOrganizationsInitializing(true);
456
- } else {
457
- setOrganizationsLoading(true);
458
- }
459
- setOrganizationsError(null);
460
- try {
461
- const data = await apiRequest("/memberships/my-memberships");
462
- if (!Array.isArray(data)) {
463
- throw new Error("Invalid memberships response");
464
- }
465
- setMemberships(data);
466
- if (data.length === 0) {
467
- setOrganizationsError("No organization memberships found. Please contact your administrator or try refreshing the page.");
468
- hasInitializedRef.current = true;
469
- return;
470
- }
471
- if (!currentWorkOSOrganizationId && data.length > 0) {
472
- await selectOrganization(data);
473
- } else if (currentWorkOSOrganizationId) {
474
- validateCurrentOrganization(data);
475
- }
476
- hasInitializedRef.current = true;
477
- } catch (error) {
478
- setOrganizationsError(error instanceof Error ? error.message : "Failed to load organizations");
479
- } finally {
480
- setOrganizationsInitializing(false);
481
- setOrganizationsLoading(false);
482
- }
483
- };
484
- initializeOrganizations();
485
- }, [
486
- user?.id,
487
- profileLoaded,
488
- profile?.last_visited_org,
489
- currentWorkOSOrganizationId,
490
- apiRequest,
491
- setOrganizationsInitializing,
492
- setOrganizationsLoading,
493
- setOrganizationsError,
494
- selectOrganization,
495
- validateCurrentOrganization
496
- // REMOVED: memberships.length - causes feedback loop (memberships change as RESULT of effect, not INPUT)
497
- ]);
498
- const retryInitialization = useCallback(async () => {
499
- hasInitializedRef.current = false;
500
- setOrganizationsError(null);
501
- setOrganizationsInitializing(true);
502
- try {
503
- const data = await apiRequest("/memberships/my-memberships");
504
- if (!Array.isArray(data)) {
505
- throw new Error("Invalid memberships response");
506
- }
507
- setMemberships(data);
508
- if (!currentWorkOSOrganizationId && data.length > 0) {
509
- await selectOrganization(data);
510
- } else if (currentWorkOSOrganizationId) {
511
- validateCurrentOrganization(data);
512
- }
513
- hasInitializedRef.current = true;
514
- } catch (error) {
515
- setOrganizationsError(error instanceof Error ? error.message : "Failed to load organizations");
516
- } finally {
517
- setOrganizationsInitializing(false);
518
- }
519
- }, [
520
- apiRequest,
521
- currentWorkOSOrganizationId,
522
- setOrganizationsError,
523
- setOrganizationsInitializing,
524
- selectOrganization,
525
- validateCurrentOrganization
526
- ]);
527
- return {
528
- memberships,
529
- isInitializing: organizations.isInitializing,
530
- isLoading: organizations.isOrgRefreshing,
531
- isInitialized: hasInitializedRef.current && !organizations.isInitializing && !organizations.isOrgRefreshing,
532
- error: organizations.error,
533
- currentOrganization: currentMembership?.organization || null,
534
- retry: retryInitialization
535
- };
536
- };
537
- }
538
-
539
- export { OrganizationProvider, OrganizationSwitcher, OrganizationSwitcherConnected, RoleBadge, createOrganizationsSlice, createUseOrgInitialization, createUseOrganizations };