@elevasis/ui 1.2.1 → 1.3.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 (52) hide show
  1. package/dist/api/hooks/useApiClient.d.ts +54 -0
  2. package/dist/api/hooks/useApiClient.d.ts.map +1 -0
  3. package/dist/api/hooks/useApiClient.js +185 -0
  4. package/dist/api/index.d.ts +49 -11
  5. package/dist/api/index.js +3 -2
  6. package/dist/auth/index.d.ts +88 -2
  7. package/dist/auth/index.js +5 -1
  8. package/dist/{chunk-5UWFGBFM.js → chunk-4KAG5U7A.js} +18 -4
  9. package/dist/chunk-4VGWQ5AN.js +91 -0
  10. package/dist/{chunk-JKERRYVS.js → chunk-BLO4SISK.js} +7 -3
  11. package/dist/chunk-BWCC6ZJC.js +202 -0
  12. package/dist/{chunk-WNWKOCGJ.js → chunk-BZTA7IIL.js} +1 -1
  13. package/dist/chunk-DD3CCMCZ.js +15 -0
  14. package/dist/{chunk-GEFB5YIR.js → chunk-EZMRFWZQ.js} +1 -1
  15. package/dist/chunk-FDCVFCOQ.js +105 -0
  16. package/dist/chunk-FLJXZ7YC.js +150 -0
  17. package/dist/{chunk-7AI5ZYJ4.js → chunk-JVAZHVNV.js} +2 -94
  18. package/dist/{chunk-ZGHDPDTF.js → chunk-JYSYHVLU.js} +3 -3
  19. package/dist/{chunk-J3FALDQE.js → chunk-NXHL23JW.js} +7 -13
  20. package/dist/{chunk-OUHGHTE7.js → chunk-O3PY6B6E.js} +3 -2
  21. package/dist/{chunk-ZQVPUAGR.js → chunk-OLD3NQLI.js} +33 -31
  22. package/dist/{chunk-B64YDSAY.js → chunk-PCBXNHKY.js} +53 -97
  23. package/dist/chunk-QQOLC46E.js +75 -0
  24. package/dist/chunk-RNP5R5I3.js +1 -0
  25. package/dist/{chunk-YULUKCS6.js → chunk-SITSZUFW.js} +1 -1
  26. package/dist/chunk-TIRMFDM4.js +33 -0
  27. package/dist/{chunk-PYL4XW6H.js → chunk-TMFCNFLW.js} +1 -1
  28. package/dist/{chunk-S66I2PYB.js → chunk-TN3PU2WK.js} +1 -1
  29. package/dist/components/command-queue/index.js +6 -4
  30. package/dist/components/index.js +9 -7
  31. package/dist/components/notifications/index.js +4 -3
  32. package/dist/display/index.js +3 -2
  33. package/dist/hooks/index.d.ts +1 -1
  34. package/dist/hooks/index.js +5 -4
  35. package/dist/hooks/published.d.ts +1 -1
  36. package/dist/hooks/published.js +4 -3
  37. package/dist/index.d.ts +447 -117
  38. package/dist/index.js +22 -16
  39. package/dist/initialization/index.d.ts +49 -1
  40. package/dist/initialization/index.js +5 -2
  41. package/dist/organization/index.d.ts +61 -2
  42. package/dist/organization/index.js +5 -2
  43. package/dist/profile/index.d.ts +30 -2
  44. package/dist/profile/index.js +2 -1
  45. package/dist/provider/index.d.ts +112 -27
  46. package/dist/provider/index.js +11 -6
  47. package/dist/provider/published.d.ts +85 -13
  48. package/dist/provider/published.js +10 -4
  49. package/dist/utils/index.js +2 -1
  50. package/package.json +17 -4
  51. package/dist/chunk-GDV44UWF.js +0 -138
  52. package/dist/chunk-HBRMWW6V.js +0 -43
@@ -0,0 +1,202 @@
1
+ import { APIClientError } from './chunk-4VGWQ5AN.js';
2
+ import { createContext, useContext, useMemo, useCallback } from 'react';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ var ApiClientContext = createContext(null);
6
+ function useApiClientContext() {
7
+ const context = useContext(ApiClientContext);
8
+ if (!context) {
9
+ throw new Error("useApiClient must be used within ApiClientProvider");
10
+ }
11
+ return context;
12
+ }
13
+ function ApiClientProvider({
14
+ children,
15
+ getAccessToken,
16
+ organizationId = null,
17
+ getOrganizationId: getOrganizationIdProp,
18
+ isOrganizationReady,
19
+ onError
20
+ }) {
21
+ const getOrganizationId = useMemo(
22
+ () => getOrganizationIdProp ?? (() => organizationId ?? null),
23
+ // eslint-disable-next-line react-hooks/exhaustive-deps
24
+ [getOrganizationIdProp, organizationId]
25
+ );
26
+ const value = useMemo(
27
+ () => ({
28
+ getAccessToken,
29
+ organizationId: organizationId ?? null,
30
+ isOrganizationReady,
31
+ getOrganizationId,
32
+ onError
33
+ }),
34
+ [getAccessToken, organizationId, isOrganizationReady, getOrganizationId, onError]
35
+ );
36
+ return /* @__PURE__ */ jsx(ApiClientContext.Provider, { value, children });
37
+ }
38
+
39
+ // ../core/src/platform/constants/http.ts
40
+ var HTTP_HEADERS = {
41
+ /**
42
+ * Organization context header
43
+ * Note: Node.js normalizes all headers to lowercase, so we use lowercase consistently
44
+ */
45
+ WORKOS_ORGANIZATION_ID: "workos-organization-id",
46
+ AGENT_ORGANIZATION: "x-agent-organization",
47
+ AGENT_MODE: "x-agent-mode"
48
+ };
49
+
50
+ // src/api/hooks/useApiClient.ts
51
+ var DEFAULT_TIMEOUT_MS = 6e4;
52
+ function buildApiRequest(getAccessToken, getOrganizationId, apiUrl, handleResponseError) {
53
+ return async function apiRequest(endpoint, options = {}) {
54
+ try {
55
+ const token = await getAccessToken();
56
+ const organizationId = getOrganizationId();
57
+ if (organizationId) console.log("[apiRequest]", endpoint, "org:", organizationId);
58
+ const headers = {
59
+ ...options.body ? { "Content-Type": "application/json" } : {},
60
+ ...token ? { Authorization: `Bearer ${token}` } : {},
61
+ ...organizationId && { [HTTP_HEADERS.WORKOS_ORGANIZATION_ID]: organizationId },
62
+ ...options.headers
63
+ };
64
+ const timeoutSignal = AbortSignal.timeout(DEFAULT_TIMEOUT_MS);
65
+ const signal = options.signal ? AbortSignal.any([options.signal, timeoutSignal]) : timeoutSignal;
66
+ const response = await fetch(`${apiUrl}/api${endpoint}`, {
67
+ ...options,
68
+ headers,
69
+ signal
70
+ });
71
+ if (!response.ok) {
72
+ await handleResponseError(endpoint, response, options);
73
+ }
74
+ if (response.status === 204) {
75
+ return void 0;
76
+ }
77
+ return response.json();
78
+ } catch (error) {
79
+ if (error instanceof Error && error.message.includes("No access token")) {
80
+ const headers = {
81
+ ...options.body ? { "Content-Type": "application/json" } : {},
82
+ ...options.headers
83
+ };
84
+ const fallbackTimeoutSignal = AbortSignal.timeout(DEFAULT_TIMEOUT_MS);
85
+ const fallbackSignal = options.signal ? AbortSignal.any([options.signal, fallbackTimeoutSignal]) : fallbackTimeoutSignal;
86
+ const response = await fetch(`${apiUrl}/api${endpoint}`, {
87
+ ...options,
88
+ headers,
89
+ signal: fallbackSignal
90
+ });
91
+ if (!response.ok) {
92
+ await handleResponseError(endpoint, response, options);
93
+ }
94
+ if (response.status === 204) {
95
+ return void 0;
96
+ }
97
+ return response.json();
98
+ }
99
+ throw error;
100
+ }
101
+ };
102
+ }
103
+ function useApiClient(apiUrl) {
104
+ const { getAccessToken, getOrganizationId, isOrganizationReady, onError } = useApiClientContext();
105
+ const handleResponseError = useCallback(
106
+ async (endpoint, response, options) => {
107
+ const errorData = await response.json().catch(() => ({
108
+ error: `HTTP ${response.status}`,
109
+ code: "INTERNAL_SERVER_ERROR"
110
+ }));
111
+ if (response.status >= 500 && onError) {
112
+ onError(endpoint, new Error(errorData.error), {
113
+ method: options.method || "GET",
114
+ statusCode: response.status,
115
+ requestId: errorData.requestId
116
+ });
117
+ }
118
+ throw new APIClientError(
119
+ errorData.error,
120
+ errorData.code,
121
+ response.status,
122
+ errorData.requestId,
123
+ errorData.fields,
124
+ errorData.retryAfter
125
+ );
126
+ },
127
+ [onError]
128
+ );
129
+ const apiRequest = useCallback(
130
+ (endpoint, options = {}) => buildApiRequest(getAccessToken, getOrganizationId, apiUrl, handleResponseError)(endpoint, options),
131
+ [getAccessToken, getOrganizationId, apiUrl, handleResponseError]
132
+ );
133
+ const deferredApiRequest = useCallback(
134
+ async (endpoint, options = {}) => {
135
+ if (!isOrganizationReady) {
136
+ throw new Error("No organization selected. Please select an organization.");
137
+ }
138
+ return apiRequest(endpoint, options);
139
+ },
140
+ [apiRequest, isOrganizationReady]
141
+ );
142
+ return {
143
+ apiRequest,
144
+ deferredApiRequest,
145
+ isOrganizationReady,
146
+ isInitializing: false
147
+ };
148
+ }
149
+ function createUseApiClient(useOrganizations, apiUrl) {
150
+ return function useApiClientCompat() {
151
+ const { getAccessToken, getOrganizationId, isOrganizationReady, onError } = useApiClientContext();
152
+ const { isInitializing, isOrgRefreshing } = useOrganizations();
153
+ const handleResponseError = useCallback(
154
+ async (endpoint, response, options) => {
155
+ const errorData = await response.json().catch(() => ({
156
+ error: `HTTP ${response.status}`,
157
+ code: "INTERNAL_SERVER_ERROR"
158
+ }));
159
+ if (response.status >= 500 && onError) {
160
+ onError(endpoint, new Error(errorData.error), {
161
+ method: options.method || "GET",
162
+ statusCode: response.status,
163
+ requestId: errorData.requestId
164
+ });
165
+ }
166
+ throw new APIClientError(
167
+ errorData.error,
168
+ errorData.code,
169
+ response.status,
170
+ errorData.requestId,
171
+ errorData.fields,
172
+ errorData.retryAfter
173
+ );
174
+ },
175
+ [onError]
176
+ );
177
+ const apiRequest = useCallback(
178
+ (endpoint, options = {}) => buildApiRequest(getAccessToken, getOrganizationId, apiUrl, handleResponseError)(endpoint, options),
179
+ [getAccessToken, getOrganizationId, handleResponseError]
180
+ );
181
+ const deferredApiRequest = useCallback(
182
+ async (endpoint, options = {}) => {
183
+ if (isInitializing || isOrgRefreshing) {
184
+ throw new Error("Organization context is still initializing. Please wait.");
185
+ }
186
+ if (!isOrganizationReady) {
187
+ throw new Error("No organization selected. Please select an organization.");
188
+ }
189
+ return apiRequest(endpoint, options);
190
+ },
191
+ [apiRequest, isInitializing, isOrgRefreshing, isOrganizationReady]
192
+ );
193
+ return {
194
+ apiRequest,
195
+ deferredApiRequest,
196
+ isOrganizationReady,
197
+ isInitializing: isInitializing || isOrgRefreshing
198
+ };
199
+ };
200
+ }
201
+
202
+ export { ApiClientProvider, createUseApiClient, useApiClient, useApiClientContext };
@@ -1,4 +1,4 @@
1
- import { UuidSchema, ResourceTypeSchema, NonEmptyStringSchema, OriginResourceTypeSchema } from './chunk-JKERRYVS.js';
1
+ import { UuidSchema, ResourceTypeSchema, NonEmptyStringSchema, OriginResourceTypeSchema } from './chunk-BLO4SISK.js';
2
2
  import { useElevasisServices } from './chunk-KA7LO7U5.js';
3
3
  import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
4
4
  import { z } from 'zod';
@@ -0,0 +1,15 @@
1
+ import { createContext, useContext } from 'react';
2
+
3
+ // src/organization/context/OrganizationContext.tsx
4
+ var OrganizationContext = createContext(null);
5
+ function useOrganization() {
6
+ const ctx = useContext(OrganizationContext);
7
+ if (!ctx) {
8
+ throw new Error(
9
+ "useOrganization must be used within an OrganizationProvider. Wrap your app (or the relevant subtree) with <OrganizationProvider>."
10
+ );
11
+ }
12
+ return ctx;
13
+ }
14
+
15
+ export { OrganizationContext, useOrganization };
@@ -1,4 +1,4 @@
1
- import { useUserProfile } from './chunk-5UWFGBFM.js';
1
+ import { useUserProfile } from './chunk-4KAG5U7A.js';
2
2
  import { useAuthContext } from './chunk-7PLEQFHO.js';
3
3
  import { useState, useRef, useEffect, useCallback } from 'react';
4
4
  import { Button, Loader, Menu, Text, Badge } from '@mantine/core';
@@ -0,0 +1,105 @@
1
+ import { useInitialization } from './chunk-QQOLC46E.js';
2
+ import { useAuthContext } from './chunk-7PLEQFHO.js';
3
+ import { useRef, useCallback, useEffect } from 'react';
4
+ import { useQueryClient } from '@tanstack/react-query';
5
+ import { useNavigate, useLocation } from '@tanstack/react-router';
6
+ import { jsx, Fragment } from 'react/jsx-runtime';
7
+
8
+ function useStableAccessToken() {
9
+ const { getAccessToken } = useAuthContext();
10
+ const getAccessTokenRef = useRef(getAccessToken);
11
+ getAccessTokenRef.current = getAccessToken;
12
+ return useCallback(() => {
13
+ return getAccessTokenRef.current();
14
+ }, []);
15
+ }
16
+ function useSessionCheck() {
17
+ const { user } = useAuthContext();
18
+ const queryClient = useQueryClient();
19
+ const isCheckingRef = useRef(false);
20
+ useEffect(() => {
21
+ const handleVisibilityChange = async () => {
22
+ if (isCheckingRef.current || document.visibilityState !== "visible") {
23
+ return;
24
+ }
25
+ isCheckingRef.current = true;
26
+ try {
27
+ if (!user) {
28
+ window.location.replace("/login");
29
+ return;
30
+ }
31
+ await queryClient.cancelQueries();
32
+ queryClient.invalidateQueries();
33
+ } finally {
34
+ isCheckingRef.current = false;
35
+ }
36
+ };
37
+ document.addEventListener("visibilitychange", handleVisibilityChange);
38
+ window.addEventListener("focus", handleVisibilityChange);
39
+ return () => {
40
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
41
+ window.removeEventListener("focus", handleVisibilityChange);
42
+ };
43
+ }, [user, queryClient]);
44
+ }
45
+ function ProtectedRoute({
46
+ children,
47
+ redirectTo = "/login",
48
+ fallback = null,
49
+ errorFallback,
50
+ waitForOrganization = true
51
+ }) {
52
+ const { userReady, allReady, isInitializing, error, retry } = useInitialization();
53
+ const navigate = useNavigate();
54
+ const location = useLocation();
55
+ const hasRedirected = useRef(false);
56
+ const unauthenticated = !isInitializing && !userReady && error?.layer !== "profile";
57
+ useEffect(() => {
58
+ if (unauthenticated && !hasRedirected.current) {
59
+ hasRedirected.current = true;
60
+ const searchStr = location.searchStr ?? "";
61
+ const returnTo = location.pathname + searchStr;
62
+ navigate({
63
+ to: redirectTo,
64
+ search: returnTo !== "/" ? { returnTo } : {}
65
+ });
66
+ }
67
+ }, [unauthenticated, navigate, redirectTo, location]);
68
+ if (isInitializing) {
69
+ return /* @__PURE__ */ jsx(Fragment, { children: fallback });
70
+ }
71
+ if (error && error.layer !== "organization") {
72
+ if (errorFallback) {
73
+ return /* @__PURE__ */ jsx(Fragment, { children: errorFallback(error, retry) });
74
+ }
75
+ return null;
76
+ }
77
+ if (unauthenticated) {
78
+ return null;
79
+ }
80
+ if (waitForOrganization && !allReady && error?.layer !== "organization") {
81
+ return /* @__PURE__ */ jsx(Fragment, { children: fallback });
82
+ }
83
+ return /* @__PURE__ */ jsx(Fragment, { children });
84
+ }
85
+ function AdminGuard({ children, redirectTo = "/", fallback = null }) {
86
+ const { userReady, profile } = useInitialization();
87
+ const navigate = useNavigate();
88
+ useEffect(() => {
89
+ if (!userReady || !profile) {
90
+ return;
91
+ }
92
+ if (!profile.is_platform_admin) {
93
+ navigate({ to: redirectTo });
94
+ }
95
+ }, [userReady, profile, navigate, redirectTo]);
96
+ if (!userReady) {
97
+ return /* @__PURE__ */ jsx(Fragment, { children: fallback });
98
+ }
99
+ if (!profile?.is_platform_admin) {
100
+ return null;
101
+ }
102
+ return /* @__PURE__ */ jsx(Fragment, { children });
103
+ }
104
+
105
+ export { AdminGuard, ProtectedRoute, useSessionCheck, useStableAccessToken };
@@ -0,0 +1,150 @@
1
+ import { OrganizationContext } from './chunk-DD3CCMCZ.js';
2
+ import { useProfile } from './chunk-4KAG5U7A.js';
3
+ import { useElevasisServices } from './chunk-KA7LO7U5.js';
4
+ import { useAuthContext } from './chunk-7PLEQFHO.js';
5
+ import { useState, useRef, useEffect, useCallback, createElement } from 'react';
6
+ import { useQueryClient } from '@tanstack/react-query';
7
+
8
+ function OrganizationProvider({ children }) {
9
+ const { user, organizationId: workosOrgId } = useAuthContext();
10
+ const { apiRequest } = useElevasisServices();
11
+ const { profile } = useProfile();
12
+ const queryClient = useQueryClient();
13
+ const [memberships, setMemberships] = useState([]);
14
+ const [currentWorkOSOrganizationId, setCurrentWorkOSOrganizationId] = useState(null);
15
+ const [currentSupabaseOrganizationId, setCurrentSupabaseOrganizationId] = useState(null);
16
+ const [currentMembership, setCurrentMembership] = useState(null);
17
+ const [isInitializing, setIsInitializing] = useState(true);
18
+ const [isOrgRefreshing, setIsOrgRefreshing] = useState(false);
19
+ const [error, setError] = useState(null);
20
+ const hasInitializedRef = useRef(false);
21
+ const [profileLoaded, setProfileLoaded] = useState(false);
22
+ useEffect(() => {
23
+ if (profile !== void 0 && profile !== null) {
24
+ setProfileLoaded(true);
25
+ }
26
+ }, [profile]);
27
+ useEffect(() => {
28
+ if (!user) {
29
+ setMemberships([]);
30
+ setCurrentWorkOSOrganizationId(null);
31
+ setCurrentSupabaseOrganizationId(null);
32
+ setCurrentMembership(null);
33
+ setIsInitializing(false);
34
+ setIsOrgRefreshing(false);
35
+ setError(null);
36
+ hasInitializedRef.current = false;
37
+ setProfileLoaded(false);
38
+ }
39
+ }, [user]);
40
+ const applyMembership = useCallback((membership) => {
41
+ setCurrentMembership(membership);
42
+ setCurrentSupabaseOrganizationId(membership?.organization?.id ?? null);
43
+ setCurrentWorkOSOrganizationId(membership?.organization?.workos_org_id ?? null);
44
+ }, []);
45
+ const selectOrganization = useCallback(
46
+ (data) => {
47
+ let selected = null;
48
+ if (profile?.last_visited_org) {
49
+ selected = data.find((m) => m.organizationId === profile.last_visited_org) ?? null;
50
+ }
51
+ if (!selected && workosOrgId) {
52
+ selected = data.find((m) => m.organization?.workos_org_id === workosOrgId) ?? null;
53
+ }
54
+ if (!selected && data.length > 0) {
55
+ selected = data[0];
56
+ }
57
+ console.log("[OrgProvider] selected:", selected?.organization?.workos_org_id ?? "none");
58
+ if (selected) {
59
+ applyMembership(selected);
60
+ }
61
+ },
62
+ [profile?.last_visited_org, workosOrgId, applyMembership]
63
+ );
64
+ const fetchAndInitialize = useCallback(async () => {
65
+ if (!user?.id || !profileLoaded) return;
66
+ setError(null);
67
+ if (memberships.length === 0) {
68
+ setIsInitializing(true);
69
+ } else {
70
+ setIsOrgRefreshing(true);
71
+ }
72
+ try {
73
+ const data = await apiRequest("/memberships/my-memberships");
74
+ if (!Array.isArray(data)) {
75
+ throw new Error("Invalid memberships response");
76
+ }
77
+ setMemberships(data);
78
+ if (data.length === 0) {
79
+ setError("No organization memberships found. Please contact your administrator or try refreshing the page.");
80
+ hasInitializedRef.current = true;
81
+ return;
82
+ }
83
+ if (!currentWorkOSOrganizationId) {
84
+ selectOrganization(data);
85
+ } else {
86
+ const stillPresent = data.find((m) => m.organization?.workos_org_id === currentWorkOSOrganizationId);
87
+ if (!stillPresent) {
88
+ applyMembership(data[0] ?? null);
89
+ } else if (stillPresent.id !== currentMembership?.id) {
90
+ applyMembership(stillPresent);
91
+ }
92
+ }
93
+ hasInitializedRef.current = true;
94
+ } catch (err) {
95
+ setError(err instanceof Error ? err.message : "Failed to load organizations");
96
+ } finally {
97
+ setIsInitializing(false);
98
+ setIsOrgRefreshing(false);
99
+ }
100
+ }, [
101
+ user?.id,
102
+ profileLoaded,
103
+ memberships.length,
104
+ apiRequest,
105
+ currentWorkOSOrganizationId,
106
+ currentMembership?.id,
107
+ selectOrganization,
108
+ applyMembership
109
+ ]);
110
+ useEffect(() => {
111
+ console.log("[OrgProvider] gate:", { userId: !!user?.id, profileLoaded, initialized: hasInitializedRef.current });
112
+ if (!user?.id || !profileLoaded || hasInitializedRef.current) return;
113
+ fetchAndInitialize();
114
+ }, [user?.id, profileLoaded, fetchAndInitialize]);
115
+ const switchOrganization = useCallback(
116
+ (workosOrgId2) => {
117
+ const target = memberships.find((m) => m.organization?.workos_org_id === workosOrgId2);
118
+ if (!target) return;
119
+ applyMembership(target);
120
+ void queryClient.invalidateQueries();
121
+ void apiRequest("/users/me", {
122
+ method: "PATCH",
123
+ headers: { "Content-Type": "application/json" },
124
+ body: JSON.stringify({ last_visited_org: target.organizationId })
125
+ }).catch((err) => {
126
+ console.warn("Failed to persist last_visited_org preference:", err);
127
+ });
128
+ },
129
+ [memberships, applyMembership, queryClient, apiRequest]
130
+ );
131
+ const retry = useCallback(async () => {
132
+ hasInitializedRef.current = false;
133
+ setError(null);
134
+ await fetchAndInitialize();
135
+ }, [fetchAndInitialize]);
136
+ const value = {
137
+ currentWorkOSOrganizationId,
138
+ currentSupabaseOrganizationId,
139
+ currentMembership,
140
+ memberships,
141
+ isInitializing,
142
+ isOrgRefreshing,
143
+ error,
144
+ switchOrganization,
145
+ retry
146
+ };
147
+ return createElement(OrganizationContext.Provider, { value }, children);
148
+ }
149
+
150
+ export { OrganizationProvider };
@@ -1,99 +1,7 @@
1
+ import { getErrorInfo, formatErrorMessage, getErrorTitle } from './chunk-4VGWQ5AN.js';
1
2
  import { notifications } from '@mantine/notifications';
2
3
  import { IconUser, IconExternalLink, IconPlug, IconBolt, IconGitBranch, IconBrain } from '@tabler/icons-react';
3
4
 
4
- // src/utils/notify.tsx
5
-
6
- // src/utils/error-utils.ts
7
- var APIClientError = class extends Error {
8
- statusCode;
9
- code;
10
- requestId;
11
- fields;
12
- retryAfter;
13
- constructor(message, code, statusCode, requestId, fields, retryAfter) {
14
- super(message);
15
- this.name = "APIClientError";
16
- this.code = code;
17
- this.statusCode = statusCode;
18
- this.requestId = requestId;
19
- this.fields = fields;
20
- this.retryAfter = retryAfter;
21
- }
22
- };
23
- function isAPIClientError(error) {
24
- return error instanceof APIClientError;
25
- }
26
- function getErrorInfo(error) {
27
- if (isAPIClientError(error)) {
28
- return {
29
- message: error.message,
30
- code: error.code,
31
- requestId: error.requestId,
32
- statusCode: error.statusCode,
33
- fields: error.fields,
34
- retryAfter: error.retryAfter
35
- };
36
- }
37
- if (error instanceof Error) {
38
- return {
39
- message: error.message
40
- };
41
- }
42
- return {
43
- message: String(error)
44
- };
45
- }
46
- function getErrorTitle(code) {
47
- if (!code) return "Error";
48
- switch (code) {
49
- case "VALIDATION_ERROR":
50
- return "Validation Error";
51
- case "AUTHENTICATION_FAILED":
52
- return "Authentication Required";
53
- case "FORBIDDEN":
54
- return "Access Denied";
55
- case "NOT_FOUND":
56
- return "Not Found";
57
- case "CONFLICT":
58
- return "Conflict";
59
- case "RATE_LIMIT_EXCEEDED":
60
- return "Rate Limit Exceeded";
61
- case "INTERNAL_SERVER_ERROR":
62
- return "Server Error";
63
- case "SERVICE_UNAVAILABLE":
64
- return "Service Temporarily Unavailable";
65
- default:
66
- return "Error";
67
- }
68
- }
69
- function formatErrorMessage(message, requestId, fields, retryAfter) {
70
- let formatted = message;
71
- if (fields && Object.keys(fields).length > 0) {
72
- const fieldErrors = [];
73
- for (const [field, errors] of Object.entries(fields)) {
74
- const fieldName = field === "root" || field === "_root" ? "Request" : field;
75
- errors.forEach((error) => {
76
- fieldErrors.push(`\u2022 ${fieldName}: ${error}`);
77
- });
78
- }
79
- if (fieldErrors.length > 0) {
80
- formatted = fieldErrors.join("\n");
81
- }
82
- }
83
- if (retryAfter) {
84
- formatted += `
85
-
86
- Please wait ${retryAfter} seconds before retrying.`;
87
- }
88
- if (requestId) {
89
- formatted += `
90
-
91
- Request ID: ${requestId}`;
92
- }
93
- return formatted;
94
- }
95
-
96
- // src/utils/notify.tsx
97
5
  var showInfoNotification = (message) => {
98
6
  notifications.show({
99
7
  title: "Info",
@@ -199,4 +107,4 @@ function getResourceIcon(type) {
199
107
  return iconNameToComponent[iconName];
200
108
  }
201
109
 
202
- export { APIClientError, formatDate, formatErrorMessage, getErrorInfo, getErrorTitle, getResourceColor, getResourceIcon, isAPIClientError, showApiErrorNotification, showErrorNotification, showInfoNotification, showSuccessNotification, showWarningNotification, validateEmail };
110
+ export { formatDate, getResourceColor, getResourceIcon, showApiErrorNotification, showErrorNotification, showInfoNotification, showSuccessNotification, showWarningNotification, validateEmail };
@@ -1,7 +1,7 @@
1
- import { useSubmitAction, useDeleteTask } from './chunk-J3FALDQE.js';
1
+ import { useSubmitAction, useDeleteTask } from './chunk-NXHL23JW.js';
2
2
  import { FormFieldRenderer } from './chunk-PSLKGOBZ.js';
3
- import { ContextViewer, JsonViewer } from './chunk-OUHGHTE7.js';
4
- import { getErrorInfo, formatErrorMessage } from './chunk-7AI5ZYJ4.js';
3
+ import { ContextViewer, JsonViewer } from './chunk-O3PY6B6E.js';
4
+ import { getErrorInfo, formatErrorMessage } from './chunk-4VGWQ5AN.js';
5
5
  import { Modal, Stack, Title, Text, Textarea, Alert, Group, Button, Card, ThemeIcon, Badge, Loader, Menu, ActionIcon, Accordion } from '@mantine/core';
6
6
  import { IconMail, IconSend, IconFileText, IconClock, IconArrowUp, IconMessageCircle, IconRocket, IconEye, IconEdit, IconAlertTriangle, IconRefresh, IconX, IconCheck, IconAlertCircle, IconRobot, IconGitBranch, IconDotsVertical, IconTrash, IconPlayerPlay, IconExternalLink } from '@tabler/icons-react';
7
7
  import { useState } from 'react';
@@ -1,7 +1,6 @@
1
+ import { useNotificationAdapter } from './chunk-TIRMFDM4.js';
1
2
  import { useElevasisServices } from './chunk-KA7LO7U5.js';
2
- import { showApiErrorNotification } from './chunk-7AI5ZYJ4.js';
3
3
  import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
4
- import { notifications } from '@mantine/notifications';
5
4
 
6
5
  function useCommandQueue({
7
6
  status,
@@ -82,6 +81,7 @@ function useSubmitAction() {
82
81
  function useDeleteTask() {
83
82
  const { apiRequest } = useElevasisServices();
84
83
  const queryClient = useQueryClient();
84
+ const notify = useNotificationAdapter();
85
85
  return useMutation({
86
86
  mutationFn: async (taskId) => {
87
87
  await apiRequest(`/command-queue/${taskId}`, {
@@ -95,20 +95,13 @@ function useDeleteTask() {
95
95
  for (const [queryKey, data] of queries) {
96
96
  previousData.set(queryKey, data);
97
97
  if (data) {
98
- queryClient.setQueryData(
99
- queryKey,
100
- (old) => old?.filter((task) => task.id !== taskId)
101
- );
98
+ queryClient.setQueryData(queryKey, (old) => old?.filter((task) => task.id !== taskId));
102
99
  }
103
100
  }
104
101
  return { previousData };
105
102
  },
106
103
  onSuccess: () => {
107
- notifications.show({
108
- title: "Task Deleted",
109
- message: "Task has been removed",
110
- color: "green"
111
- });
104
+ notify.success("Task Deleted", "Task has been removed");
112
105
  queryClient.invalidateQueries({ queryKey: ["command-queue"] });
113
106
  },
114
107
  onError: (error, _taskId, context) => {
@@ -117,7 +110,7 @@ function useDeleteTask() {
117
110
  queryClient.setQueryData(queryKey, data);
118
111
  }
119
112
  }
120
- showApiErrorNotification(error);
113
+ notify.apiError(error);
121
114
  }
122
115
  });
123
116
  }
@@ -146,6 +139,7 @@ function useCommandQueueTotals({
146
139
  function usePatchTask() {
147
140
  const { apiRequest } = useElevasisServices();
148
141
  const queryClient = useQueryClient();
142
+ const notify = useNotificationAdapter();
149
143
  return useMutation({
150
144
  mutationFn: async ({ taskId, params }) => {
151
145
  const response = await apiRequest(`/command-queue/${taskId}`, {
@@ -168,7 +162,7 @@ function usePatchTask() {
168
162
  );
169
163
  },
170
164
  onError: (error) => {
171
- showApiErrorNotification(error);
165
+ notify.apiError(error);
172
166
  }
173
167
  });
174
168
  }
@@ -1,6 +1,7 @@
1
1
  import { StyledMarkdown } from './chunk-3KMDHCAR.js';
2
2
  import { ResourceStatusColors } from './chunk-YZ6GTZXL.js';
3
- import { getErrorInfo, getErrorTitle, getResourceIcon } from './chunk-7AI5ZYJ4.js';
3
+ import { getResourceIcon } from './chunk-JVAZHVNV.js';
4
+ import { getErrorInfo, getErrorTitle } from './chunk-4VGWQ5AN.js';
4
5
  import { useAuthContext } from './chunk-7PLEQFHO.js';
5
6
  import { useRouterContext } from './chunk-Q7DJKLEN.js';
6
7
  import { Alert, Text, Code, Group, Badge, Collapse, ScrollArea, Center, Stack, Title, Button, UnstyledButton, Box, ThemeIcon, Card, Skeleton, Paper, Loader, Select, Grid, Space } from '@mantine/core';
@@ -101,7 +102,7 @@ function CollapsibleSection({
101
102
  function EmptyState({ icon: Icon, title, description, action, py = "xl" }) {
102
103
  return /* @__PURE__ */ jsx(Center, { py, children: /* @__PURE__ */ jsxs(Stack, { align: "center", gap: "xs", children: [
103
104
  /* @__PURE__ */ jsx(Icon, { size: 48, style: { opacity: 0.5 } }),
104
- /* @__PURE__ */ jsx(Title, { order: 3, children: title }),
105
+ /* @__PURE__ */ jsx(Title, { order: 4, children: title }),
105
106
  description && /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", ta: "center", children: description }),
106
107
  action && /* @__PURE__ */ jsx(Button, { variant: "light", onClick: action.onClick, leftSection: action.icon, mt: "sm", children: action.label })
107
108
  ] }) });