@robosystems/core 0.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.
- package/LICENSE +21 -0
- package/README.md +252 -0
- package/actions/entity-actions.d.ts +8 -0
- package/actions/entity-actions.js +16 -0
- package/actions/graph-actions.d.ts +3 -0
- package/actions/graph-actions.js +13 -0
- package/auth-components/AppSwitcher.d.ts +6 -0
- package/auth-components/AppSwitcher.js +28 -0
- package/auth-components/AuthGuard.d.ts +7 -0
- package/auth-components/AuthGuard.js +31 -0
- package/auth-components/AuthProvider.d.ts +9 -0
- package/auth-components/AuthProvider.js +565 -0
- package/auth-components/SessionWarningDialog.d.ts +1 -0
- package/auth-components/SessionWarningDialog.js +51 -0
- package/auth-components/SignInForm.d.ts +20 -0
- package/auth-components/SignInForm.js +139 -0
- package/auth-components/SignUpForm.d.ts +15 -0
- package/auth-components/SignUpForm.js +167 -0
- package/auth-components/TurnstileWidget.d.ts +99 -0
- package/auth-components/TurnstileWidget.js +224 -0
- package/auth-components/index.d.ts +6 -0
- package/auth-components/index.js +6 -0
- package/auth-core/cleanup.d.ts +44 -0
- package/auth-core/cleanup.js +157 -0
- package/auth-core/client.d.ts +121 -0
- package/auth-core/client.js +767 -0
- package/auth-core/config.d.ts +19 -0
- package/auth-core/config.js +56 -0
- package/auth-core/hooks.d.ts +19 -0
- package/auth-core/hooks.js +63 -0
- package/auth-core/index.d.ts +6 -0
- package/auth-core/index.js +6 -0
- package/auth-core/sso.d.ts +42 -0
- package/auth-core/sso.js +281 -0
- package/auth-core/token-storage.d.ts +58 -0
- package/auth-core/token-storage.js +177 -0
- package/auth-core/types.d.ts +145 -0
- package/auth-core/types.js +1 -0
- package/components/EntitySelector.d.ts +44 -0
- package/components/EntitySelector.js +64 -0
- package/components/EntitySelectorCore.d.ts +45 -0
- package/components/EntitySelectorCore.js +67 -0
- package/components/GraphSelectorCore.d.ts +21 -0
- package/components/GraphSelectorCore.js +39 -0
- package/components/PageLayout.d.ts +8 -0
- package/components/PageLayout.js +5 -0
- package/components/RepositoryGuard.d.ts +68 -0
- package/components/RepositoryGuard.js +91 -0
- package/components/console/ConsoleContent.d.ts +4 -0
- package/components/console/ConsoleContent.js +612 -0
- package/components/console/ConsoleMarkdown.d.ts +11 -0
- package/components/console/ConsoleMarkdown.js +49 -0
- package/components/console/ProgressiveText.d.ts +6 -0
- package/components/console/ProgressiveText.js +21 -0
- package/components/console/graphAwareConfig.d.ts +70 -0
- package/components/console/graphAwareConfig.js +411 -0
- package/components/console/index.d.ts +6 -0
- package/components/console/index.js +4 -0
- package/components/console/types.d.ts +84 -0
- package/components/console/types.js +1 -0
- package/components/graph-filters.d.ts +75 -0
- package/components/graph-filters.js +111 -0
- package/components/index.d.ts +10 -0
- package/components/index.js +9 -0
- package/components/repositories/ActiveSubscriptions.d.ts +26 -0
- package/components/repositories/ActiveSubscriptions.js +103 -0
- package/components/repositories/BrowseRepositories.d.ts +11 -0
- package/components/repositories/BrowseRepositories.js +184 -0
- package/components/repositories/index.d.ts +2 -0
- package/components/repositories/index.js +2 -0
- package/components/search/SearchContent.d.ts +4 -0
- package/components/search/SearchContent.js +168 -0
- package/components/search/index.d.ts +2 -0
- package/components/search/index.js +1 -0
- package/components/search/types.d.ts +15 -0
- package/components/search/types.js +1 -0
- package/contexts/entity-context.d.ts +28 -0
- package/contexts/entity-context.js +89 -0
- package/contexts/graph-context.d.ts +27 -0
- package/contexts/graph-context.js +128 -0
- package/contexts/index.d.ts +5 -0
- package/contexts/index.js +5 -0
- package/contexts/org-context.d.ts +25 -0
- package/contexts/org-context.js +64 -0
- package/contexts/service-offerings-context.d.ts +45 -0
- package/contexts/service-offerings-context.js +98 -0
- package/contexts/sidebar-context.d.ts +18 -0
- package/contexts/sidebar-context.js +44 -0
- package/hooks/index.d.ts +6 -0
- package/hooks/index.js +6 -0
- package/hooks/use-api-error.d.ts +3 -0
- package/hooks/use-api-error.js +24 -0
- package/hooks/use-media-query.d.ts +1 -0
- package/hooks/use-media-query.js +21 -0
- package/hooks/use-streaming-query.d.ts +22 -0
- package/hooks/use-streaming-query.js +142 -0
- package/hooks/use-toast.d.ts +37 -0
- package/hooks/use-toast.js +117 -0
- package/hooks/use-user-limits.d.ts +12 -0
- package/hooks/use-user-limits.js +73 -0
- package/hooks/use-user.d.ts +11 -0
- package/hooks/use-user.js +39 -0
- package/index.d.ts +29 -0
- package/index.js +77 -0
- package/lib/entity-cookie.d.ts +10 -0
- package/lib/entity-cookie.js +38 -0
- package/lib/graph-cookie.d.ts +11 -0
- package/lib/graph-cookie.js +62 -0
- package/lib/graph-tiers.d.ts +41 -0
- package/lib/graph-tiers.js +107 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +3 -0
- package/lib/sidebar-cookie.d.ts +11 -0
- package/lib/sidebar-cookie.js +42 -0
- package/library/colors.d.ts +4 -0
- package/library/colors.js +41 -0
- package/library/components/ClassificationPicker.d.ts +8 -0
- package/library/components/ClassificationPicker.js +55 -0
- package/library/components/ElementBrowser.d.ts +11 -0
- package/library/components/ElementBrowser.js +106 -0
- package/library/components/ElementDetail.d.ts +7 -0
- package/library/components/ElementDetail.js +97 -0
- package/library/components/LibraryHierarchy.d.ts +13 -0
- package/library/components/LibraryHierarchy.js +380 -0
- package/library/components/TaxonomySidebar.d.ts +6 -0
- package/library/components/TaxonomySidebar.js +45 -0
- package/library/index.d.ts +8 -0
- package/library/index.js +7 -0
- package/package.json +37 -0
- package/research/CoverageCard.d.ts +12 -0
- package/research/CoverageCard.js +15 -0
- package/research/CoverageGrid.d.ts +6 -0
- package/research/CoverageGrid.js +9 -0
- package/research/CoverageHistory.d.ts +5 -0
- package/research/CoverageHistory.js +7 -0
- package/research/ResearchArticle.d.ts +15 -0
- package/research/ResearchArticle.js +26 -0
- package/research/catalog.d.ts +14 -0
- package/research/catalog.js +42 -0
- package/research/index.d.ts +6 -0
- package/research/index.js +9 -0
- package/research/types.d.ts +38 -0
- package/research/types.js +4 -0
- package/task-monitoring/hooks.d.ts +26 -0
- package/task-monitoring/hooks.js +126 -0
- package/task-monitoring/index.d.ts +5 -0
- package/task-monitoring/index.js +7 -0
- package/task-monitoring/operationErrors.d.ts +82 -0
- package/task-monitoring/operationErrors.js +251 -0
- package/task-monitoring/operationHooks.d.ts +117 -0
- package/task-monitoring/operationHooks.js +536 -0
- package/task-monitoring/operationMonitor.d.ts +78 -0
- package/task-monitoring/operationMonitor.js +200 -0
- package/task-monitoring/operationTypes.d.ts +236 -0
- package/task-monitoring/operationTypes.js +60 -0
- package/task-monitoring/taskMonitor.d.ts +14 -0
- package/task-monitoring/taskMonitor.js +132 -0
- package/task-monitoring/types.d.ts +31 -0
- package/task-monitoring/types.js +1 -0
- package/theme/flowbite-theme.d.ts +758 -0
- package/theme/flowbite-theme.js +765 -0
- package/theme/index.d.ts +1 -0
- package/theme/index.js +1 -0
- package/types/entity.d.ts +19 -0
- package/types/index.d.ts +2 -0
- package/types/index.js +1 -0
- package/types/user.d.ts +6 -0
- package/ui-components/ConfirmModal.d.ts +41 -0
- package/ui-components/ConfirmModal.js +19 -0
- package/ui-components/EmptyState.d.ts +22 -0
- package/ui-components/EmptyState.js +10 -0
- package/ui-components/LoadingState.d.ts +27 -0
- package/ui-components/LoadingState.js +12 -0
- package/ui-components/Logo.d.ts +28 -0
- package/ui-components/Logo.js +95 -0
- package/ui-components/Spinner.d.ts +37 -0
- package/ui-components/Spinner.js +48 -0
- package/ui-components/StatCard.d.ts +21 -0
- package/ui-components/StatCard.js +10 -0
- package/ui-components/api-keys/ApiKeyDisplay.d.ts +13 -0
- package/ui-components/api-keys/ApiKeyDisplay.js +7 -0
- package/ui-components/api-keys/ApiKeyTable.d.ts +9 -0
- package/ui-components/api-keys/ApiKeyTable.js +17 -0
- package/ui-components/api-keys/ApiKeysCard.d.ts +6 -0
- package/ui-components/api-keys/ApiKeysCard.js +97 -0
- package/ui-components/api-keys/CreateApiKeyModal.d.ts +11 -0
- package/ui-components/api-keys/CreateApiKeyModal.js +47 -0
- package/ui-components/api-keys/SecureApiKeyField.d.ts +13 -0
- package/ui-components/api-keys/SecureApiKeyField.js +64 -0
- package/ui-components/api-keys/index.d.ts +5 -0
- package/ui-components/api-keys/index.js +5 -0
- package/ui-components/chat/ChatHeader.d.ts +12 -0
- package/ui-components/chat/ChatHeader.js +5 -0
- package/ui-components/chat/ChatInputArea.d.ts +16 -0
- package/ui-components/chat/ChatInputArea.js +9 -0
- package/ui-components/chat/ChatMessage.d.ts +7 -0
- package/ui-components/chat/ChatMessage.js +24 -0
- package/ui-components/chat/DeepResearchToggle.d.ts +8 -0
- package/ui-components/chat/DeepResearchToggle.js +13 -0
- package/ui-components/chat/index.d.ts +9 -0
- package/ui-components/chat/index.js +8 -0
- package/ui-components/chat/types.d.ts +23 -0
- package/ui-components/chat/types.js +51 -0
- package/ui-components/forms/PasswordRequirements.d.ts +10 -0
- package/ui-components/forms/PasswordRequirements.js +15 -0
- package/ui-components/forms/SettingsCard.d.ts +11 -0
- package/ui-components/forms/SettingsCard.js +5 -0
- package/ui-components/forms/SettingsFormField.d.ts +18 -0
- package/ui-components/forms/SettingsFormField.js +17 -0
- package/ui-components/forms/StatusAlert.d.ts +8 -0
- package/ui-components/forms/StatusAlert.js +7 -0
- package/ui-components/forms/index.d.ts +4 -0
- package/ui-components/forms/index.js +4 -0
- package/ui-components/index.d.ts +13 -0
- package/ui-components/index.js +18 -0
- package/ui-components/layout/CoreNavbar.d.ts +14 -0
- package/ui-components/layout/CoreNavbar.js +53 -0
- package/ui-components/layout/CoreSidebar.d.ts +28 -0
- package/ui-components/layout/CoreSidebar.js +62 -0
- package/ui-components/layout/LandingFooter.d.ts +28 -0
- package/ui-components/layout/LandingFooter.js +34 -0
- package/ui-components/layout/PageContainer.d.ts +8 -0
- package/ui-components/layout/PageContainer.js +17 -0
- package/ui-components/layout/PageHeader.d.ts +23 -0
- package/ui-components/layout/PageHeader.js +12 -0
- package/ui-components/layout/SettingsContainer.d.ts +10 -0
- package/ui-components/layout/SettingsContainer.js +9 -0
- package/ui-components/layout/ThemeToggle.d.ts +4 -0
- package/ui-components/layout/ThemeToggle.js +6 -0
- package/ui-components/layout/index.d.ts +7 -0
- package/ui-components/layout/index.js +7 -0
- package/ui-components/settings/GeneralInformationCard.d.ts +12 -0
- package/ui-components/settings/GeneralInformationCard.js +72 -0
- package/ui-components/settings/PasswordInformationCard.d.ts +10 -0
- package/ui-components/settings/PasswordInformationCard.js +167 -0
- package/ui-components/settings/SettingsPageHeader.d.ts +7 -0
- package/ui-components/settings/SettingsPageHeader.js +6 -0
- package/ui-components/settings/index.d.ts +3 -0
- package/ui-components/settings/index.js +3 -0
- package/ui-components/support/SupportModal.d.ts +15 -0
- package/ui-components/support/SupportModal.js +74 -0
- package/ui-components/support/index.d.ts +2 -0
- package/ui-components/support/index.js +1 -0
- package/ui-components/types/index.d.ts +39 -0
- package/ui-components/types/index.js +1 -0
- package/utils/index.d.ts +31 -0
- package/utils/index.js +38 -0
- package/utils/turnstile-config.d.ts +11 -0
- package/utils/turnstile-config.js +19 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext, useEffect, useState } from 'react';
|
|
4
|
+
import { SDK } from '..';
|
|
5
|
+
const ServiceOfferingsContext = createContext({
|
|
6
|
+
offerings: null,
|
|
7
|
+
isLoading: true,
|
|
8
|
+
error: null,
|
|
9
|
+
refresh: async () => { },
|
|
10
|
+
});
|
|
11
|
+
export function ServiceOfferingsProvider({ children, }) {
|
|
12
|
+
const [offerings, setOfferings] = useState(null);
|
|
13
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
14
|
+
const [error, setError] = useState(null);
|
|
15
|
+
const fetchOfferings = async () => {
|
|
16
|
+
var _a, _b, _c;
|
|
17
|
+
try {
|
|
18
|
+
setIsLoading(true);
|
|
19
|
+
setError(null);
|
|
20
|
+
const response = await SDK.getServiceOfferings();
|
|
21
|
+
if (response.data) {
|
|
22
|
+
// Transform the API response to match our expected structure
|
|
23
|
+
const apiData = response.data;
|
|
24
|
+
// Transform repository_subscriptions.repositories array into repositoryPlans object
|
|
25
|
+
const repositoryPlans = {};
|
|
26
|
+
if ((_a = apiData.repository_subscriptions) === null || _a === void 0 ? void 0 : _a.repositories) {
|
|
27
|
+
apiData.repository_subscriptions.repositories.forEach((repo) => {
|
|
28
|
+
repositoryPlans[repo.type] = {
|
|
29
|
+
name: repo.name,
|
|
30
|
+
description: repo.description,
|
|
31
|
+
enabled: repo.enabled,
|
|
32
|
+
comingSoon: repo.coming_soon,
|
|
33
|
+
plans: repo.plans.map((plan) => ({
|
|
34
|
+
plan: plan.plan,
|
|
35
|
+
name: plan.name,
|
|
36
|
+
monthlyPrice: plan.monthly_price,
|
|
37
|
+
monthlyCredits: plan.monthly_credits,
|
|
38
|
+
features: plan.features,
|
|
39
|
+
})),
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// Transform graph tiers array into graphPlans object
|
|
44
|
+
const graphPlans = {};
|
|
45
|
+
if ((_b = apiData.graph_subscriptions) === null || _b === void 0 ? void 0 : _b.tiers) {
|
|
46
|
+
apiData.graph_subscriptions.tiers.forEach((tier) => {
|
|
47
|
+
var _a, _b;
|
|
48
|
+
// Skip trial tier for selection
|
|
49
|
+
if (tier.name === 'trial')
|
|
50
|
+
return;
|
|
51
|
+
graphPlans[tier.name] = {
|
|
52
|
+
name: tier.name,
|
|
53
|
+
displayName: tier.display_name,
|
|
54
|
+
monthlyPrice: tier.monthly_price,
|
|
55
|
+
monthlyCredits: tier.monthly_credits,
|
|
56
|
+
features: tier.features || [],
|
|
57
|
+
creditMultiplier: ((_b = (_a = apiData.graph_subscriptions) === null || _a === void 0 ? void 0 : _a.tier_multipliers) === null || _b === void 0 ? void 0 : _b[tier.name]) || 1,
|
|
58
|
+
instanceStorageLimitGb: tier.instance_storage_limit_gb,
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
const offerings = {
|
|
63
|
+
billingEnabled: (_c = apiData.billing_enabled) !== null && _c !== void 0 ? _c : true,
|
|
64
|
+
repositoryPlans,
|
|
65
|
+
graphPlans,
|
|
66
|
+
features: apiData.features,
|
|
67
|
+
};
|
|
68
|
+
setOfferings(offerings);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
throw new Error('No data received from service offerings API');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
console.error('Failed to fetch service offerings:', err);
|
|
76
|
+
setError('Failed to load service offerings');
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
setIsLoading(false);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
fetchOfferings();
|
|
84
|
+
}, []);
|
|
85
|
+
return (_jsx(ServiceOfferingsContext.Provider, { value: {
|
|
86
|
+
offerings,
|
|
87
|
+
isLoading,
|
|
88
|
+
error,
|
|
89
|
+
refresh: fetchOfferings,
|
|
90
|
+
}, children: children }));
|
|
91
|
+
}
|
|
92
|
+
export function useServiceOfferings() {
|
|
93
|
+
const context = useContext(ServiceOfferingsContext);
|
|
94
|
+
if (!context) {
|
|
95
|
+
throw new Error('useServiceOfferings must be used within ServiceOfferingsProvider');
|
|
96
|
+
}
|
|
97
|
+
return context;
|
|
98
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PropsWithChildren } from 'react';
|
|
2
|
+
interface SidebarContextProps {
|
|
3
|
+
desktop: {
|
|
4
|
+
isCollapsed: boolean;
|
|
5
|
+
setCollapsed(value: boolean): void;
|
|
6
|
+
toggle(): void;
|
|
7
|
+
};
|
|
8
|
+
mobile: {
|
|
9
|
+
isOpen: boolean;
|
|
10
|
+
close(): void;
|
|
11
|
+
toggle(): void;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export declare function SidebarProvider({ initialCollapsed, children, }: PropsWithChildren<{
|
|
15
|
+
initialCollapsed: boolean;
|
|
16
|
+
}>): import("react").JSX.Element;
|
|
17
|
+
export declare function useSidebarContext(): SidebarContextProps;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext, useState } from 'react';
|
|
4
|
+
const SidebarContext = createContext(null);
|
|
5
|
+
export function SidebarProvider({ initialCollapsed, children, }) {
|
|
6
|
+
const [isOpenMobile, setIsOpenMobile] = useState(false);
|
|
7
|
+
const [isCollapsed, setCollapsed] = useState(initialCollapsed);
|
|
8
|
+
function handleSetCollapsed(value) {
|
|
9
|
+
setCollapsed(value);
|
|
10
|
+
setCookie(value);
|
|
11
|
+
}
|
|
12
|
+
function setCookie(value) {
|
|
13
|
+
fetch('/api/session/sidebar', {
|
|
14
|
+
method: 'POST',
|
|
15
|
+
headers: {
|
|
16
|
+
'Content-Type': 'application/json',
|
|
17
|
+
},
|
|
18
|
+
body: JSON.stringify({
|
|
19
|
+
isCollapsed: value,
|
|
20
|
+
}),
|
|
21
|
+
}).catch((error) => {
|
|
22
|
+
console.error('Failed to save sidebar state:', error);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return (_jsx(SidebarContext.Provider, { value: {
|
|
26
|
+
desktop: {
|
|
27
|
+
isCollapsed,
|
|
28
|
+
setCollapsed: handleSetCollapsed,
|
|
29
|
+
toggle: () => handleSetCollapsed(!isCollapsed),
|
|
30
|
+
},
|
|
31
|
+
mobile: {
|
|
32
|
+
isOpen: isOpenMobile,
|
|
33
|
+
close: () => setIsOpenMobile(false),
|
|
34
|
+
toggle: () => setIsOpenMobile((state) => !state),
|
|
35
|
+
},
|
|
36
|
+
}, children: children }));
|
|
37
|
+
}
|
|
38
|
+
export function useSidebarContext() {
|
|
39
|
+
const context = useContext(SidebarContext);
|
|
40
|
+
if (!context) {
|
|
41
|
+
throw new Error('useSidebarContext must be used within the SidebarContext provider!');
|
|
42
|
+
}
|
|
43
|
+
return context;
|
|
44
|
+
}
|
package/hooks/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { useApiError } from './use-api-error';
|
|
2
|
+
export { useMediaQuery } from './use-media-query';
|
|
3
|
+
export { useStreamingQuery } from './use-streaming-query';
|
|
4
|
+
export { useToast, type ToastMessage } from './use-toast';
|
|
5
|
+
export { useUser } from './use-user';
|
|
6
|
+
export { useOrgLimits, useUserLimits } from './use-user-limits';
|
package/hooks/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { useApiError } from './use-api-error';
|
|
2
|
+
export { useMediaQuery } from './use-media-query';
|
|
3
|
+
export { useStreamingQuery } from './use-streaming-query';
|
|
4
|
+
export { useToast } from './use-toast';
|
|
5
|
+
export { useUser } from './use-user';
|
|
6
|
+
export { useOrgLimits, useUserLimits } from './use-user-limits';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { useToast } from './use-toast';
|
|
3
|
+
export function useApiError() {
|
|
4
|
+
const { showError } = useToast();
|
|
5
|
+
const handleApiError = useCallback((error, defaultMessage) => {
|
|
6
|
+
var _a, _b, _c, _d;
|
|
7
|
+
let errorMessage = defaultMessage;
|
|
8
|
+
if (error instanceof Error) {
|
|
9
|
+
errorMessage = error.message;
|
|
10
|
+
}
|
|
11
|
+
else if ((_b = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.detail) {
|
|
12
|
+
errorMessage = error.response.data.detail;
|
|
13
|
+
}
|
|
14
|
+
else if ((_d = (_c = error === null || error === void 0 ? void 0 : error.response) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.message) {
|
|
15
|
+
errorMessage = error.response.data.message;
|
|
16
|
+
}
|
|
17
|
+
else if (error === null || error === void 0 ? void 0 : error.message) {
|
|
18
|
+
errorMessage = error.message;
|
|
19
|
+
}
|
|
20
|
+
showError(errorMessage);
|
|
21
|
+
return errorMessage;
|
|
22
|
+
}, [showError]);
|
|
23
|
+
return { handleApiError };
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useMediaQuery(query: string): boolean;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
export function useMediaQuery(query) {
|
|
4
|
+
const [matches, setMatches] = useState(getMatches(query));
|
|
5
|
+
function getMatches(query) {
|
|
6
|
+
if (typeof window === 'undefined')
|
|
7
|
+
return false;
|
|
8
|
+
return window.matchMedia(query).matches;
|
|
9
|
+
}
|
|
10
|
+
function handleChange() {
|
|
11
|
+
setMatches(getMatches(query));
|
|
12
|
+
}
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const matchMedia = window.matchMedia(query);
|
|
15
|
+
handleChange();
|
|
16
|
+
matchMedia.addEventListener('change', handleChange);
|
|
17
|
+
return () => matchMedia.removeEventListener('change', handleChange);
|
|
18
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
19
|
+
}, [query]);
|
|
20
|
+
return matches;
|
|
21
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface StreamingQueryState {
|
|
2
|
+
isStreaming: boolean;
|
|
3
|
+
results: any[];
|
|
4
|
+
error: string | null;
|
|
5
|
+
progress: number | null;
|
|
6
|
+
totalRows: number | null;
|
|
7
|
+
currentRow: number | null;
|
|
8
|
+
status: 'idle' | 'connecting' | 'streaming' | 'completed' | 'error' | 'cancelled';
|
|
9
|
+
creditsUsed: number | null;
|
|
10
|
+
cached: boolean;
|
|
11
|
+
duration: number | null;
|
|
12
|
+
}
|
|
13
|
+
export interface UseStreamingQueryResult extends StreamingQueryState {
|
|
14
|
+
executeQuery: (graphId: string, query: string, parameters?: Record<string, any>) => Promise<void>;
|
|
15
|
+
cancelQuery: () => void;
|
|
16
|
+
reset: () => void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Hook for streaming query results using SDK extensions when available
|
|
20
|
+
* Falls back to manual SSE implementation for older SDK versions
|
|
21
|
+
*/
|
|
22
|
+
export declare function useStreamingQuery(): UseStreamingQueryResult;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
3
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
4
|
+
var m = o[Symbol.asyncIterator], i;
|
|
5
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
6
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
7
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
8
|
+
};
|
|
9
|
+
import { useCallback, useRef, useState } from 'react';
|
|
10
|
+
// Import SDK extensions - check at runtime
|
|
11
|
+
const getSDKExtensions = async () => {
|
|
12
|
+
try {
|
|
13
|
+
return await import('@robosystems/client/clients');
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
console.error('SDK extensions not available:', error);
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Hook for streaming query results using SDK extensions when available
|
|
22
|
+
* Falls back to manual SSE implementation for older SDK versions
|
|
23
|
+
*/
|
|
24
|
+
export function useStreamingQuery() {
|
|
25
|
+
const [state, setState] = useState({
|
|
26
|
+
isStreaming: false,
|
|
27
|
+
results: [],
|
|
28
|
+
error: null,
|
|
29
|
+
progress: null,
|
|
30
|
+
totalRows: null,
|
|
31
|
+
currentRow: null,
|
|
32
|
+
status: 'idle',
|
|
33
|
+
creditsUsed: null,
|
|
34
|
+
cached: false,
|
|
35
|
+
duration: null,
|
|
36
|
+
});
|
|
37
|
+
const eventSourceRef = useRef(null);
|
|
38
|
+
const startTimeRef = useRef(null);
|
|
39
|
+
const queryClientRef = useRef(null);
|
|
40
|
+
const reset = useCallback(() => {
|
|
41
|
+
var _a;
|
|
42
|
+
if (eventSourceRef.current) {
|
|
43
|
+
eventSourceRef.current.close();
|
|
44
|
+
eventSourceRef.current = null;
|
|
45
|
+
}
|
|
46
|
+
if ((_a = queryClientRef.current) === null || _a === void 0 ? void 0 : _a.close) {
|
|
47
|
+
queryClientRef.current.close();
|
|
48
|
+
queryClientRef.current = null;
|
|
49
|
+
}
|
|
50
|
+
setState({
|
|
51
|
+
isStreaming: false,
|
|
52
|
+
results: [],
|
|
53
|
+
error: null,
|
|
54
|
+
progress: null,
|
|
55
|
+
totalRows: null,
|
|
56
|
+
currentRow: null,
|
|
57
|
+
status: 'idle',
|
|
58
|
+
creditsUsed: null,
|
|
59
|
+
cached: false,
|
|
60
|
+
duration: null,
|
|
61
|
+
});
|
|
62
|
+
}, []);
|
|
63
|
+
const cancelQuery = useCallback(() => {
|
|
64
|
+
var _a;
|
|
65
|
+
if (eventSourceRef.current) {
|
|
66
|
+
eventSourceRef.current.close();
|
|
67
|
+
eventSourceRef.current = null;
|
|
68
|
+
}
|
|
69
|
+
if ((_a = queryClientRef.current) === null || _a === void 0 ? void 0 : _a.close) {
|
|
70
|
+
queryClientRef.current.close();
|
|
71
|
+
queryClientRef.current = null;
|
|
72
|
+
}
|
|
73
|
+
setState((prev) => (Object.assign(Object.assign({}, prev), { isStreaming: false, status: 'cancelled', error: 'Query was cancelled' })));
|
|
74
|
+
}, []);
|
|
75
|
+
const executeQuery = useCallback(async (graphId, query, parameters) => {
|
|
76
|
+
// Get SDK extensions at runtime
|
|
77
|
+
const sdkExtensions = await getSDKExtensions();
|
|
78
|
+
// Require SDK extensions - fail fast if not available
|
|
79
|
+
if (!(sdkExtensions === null || sdkExtensions === void 0 ? void 0 : sdkExtensions.streamQuery)) {
|
|
80
|
+
throw new Error('SDK extensions not available. Please install @robosystems/client with extensions support.');
|
|
81
|
+
}
|
|
82
|
+
return executeQueryWithExtensions(graphId, query, sdkExtensions, parameters);
|
|
83
|
+
}, []);
|
|
84
|
+
// Helper function to execute query with SDK extensions
|
|
85
|
+
const executeQueryWithExtensions = async (graphId, query, sdkExtensions, parameters) => {
|
|
86
|
+
var _a, e_1, _b, _c;
|
|
87
|
+
try {
|
|
88
|
+
// Reset state for new query
|
|
89
|
+
setState({
|
|
90
|
+
isStreaming: true,
|
|
91
|
+
results: [],
|
|
92
|
+
error: null,
|
|
93
|
+
progress: 0,
|
|
94
|
+
totalRows: null,
|
|
95
|
+
currentRow: 0,
|
|
96
|
+
status: 'connecting',
|
|
97
|
+
creditsUsed: null,
|
|
98
|
+
cached: false,
|
|
99
|
+
duration: null,
|
|
100
|
+
});
|
|
101
|
+
startTimeRef.current = Date.now();
|
|
102
|
+
// Use the centralized streamQuery function with proper authentication
|
|
103
|
+
const iterator = sdkExtensions.streamQuery(graphId, query, parameters, 100);
|
|
104
|
+
setState((prev) => (Object.assign(Object.assign({}, prev), { status: 'streaming' })));
|
|
105
|
+
let rowCount = 0;
|
|
106
|
+
const allResults = [];
|
|
107
|
+
try {
|
|
108
|
+
for (var _d = true, iterator_1 = __asyncValues(iterator), iterator_1_1; iterator_1_1 = await iterator_1.next(), _a = iterator_1_1.done, !_a; _d = true) {
|
|
109
|
+
_c = iterator_1_1.value;
|
|
110
|
+
_d = false;
|
|
111
|
+
const batch = _c;
|
|
112
|
+
// Handle both single rows and batches
|
|
113
|
+
const rows = Array.isArray(batch) ? batch : [batch];
|
|
114
|
+
for (const row of rows) {
|
|
115
|
+
rowCount++;
|
|
116
|
+
allResults.push(row);
|
|
117
|
+
}
|
|
118
|
+
// Update state with progress
|
|
119
|
+
setState((prev) => (Object.assign(Object.assign({}, prev), { results: [...allResults], currentRow: rowCount, progress: prev.totalRows
|
|
120
|
+
? Math.round((rowCount / prev.totalRows) * 100)
|
|
121
|
+
: null })));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
125
|
+
finally {
|
|
126
|
+
try {
|
|
127
|
+
if (!_d && !_a && (_b = iterator_1.return)) await _b.call(iterator_1);
|
|
128
|
+
}
|
|
129
|
+
finally { if (e_1) throw e_1.error; }
|
|
130
|
+
}
|
|
131
|
+
const duration = Date.now() - startTimeRef.current;
|
|
132
|
+
setState((prev) => (Object.assign(Object.assign({}, prev), { isStreaming: false, status: 'completed', results: allResults, totalRows: rowCount, currentRow: rowCount, progress: 100, duration })));
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
const errorMessage = error instanceof Error ? error.message : 'Query execution failed';
|
|
136
|
+
setState((prev) => (Object.assign(Object.assign({}, prev), { isStreaming: false, status: 'error', error: errorMessage })));
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
return Object.assign(Object.assign({}, state), { executeQuery,
|
|
140
|
+
cancelQuery,
|
|
141
|
+
reset });
|
|
142
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface ToastMessage {
|
|
2
|
+
id: string;
|
|
3
|
+
type: 'success' | 'error' | 'warning' | 'info';
|
|
4
|
+
message: string;
|
|
5
|
+
duration?: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* A reusable toast notification hook built on Flowbite React components.
|
|
9
|
+
*
|
|
10
|
+
* Provides toast notifications with auto-dismiss functionality and consistent styling
|
|
11
|
+
* across the RoboSystems ecosystem.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* function MyComponent() {
|
|
16
|
+
* const { showSuccess, showError, ToastContainer } = useToast()
|
|
17
|
+
*
|
|
18
|
+
* const handleSuccess = () => {
|
|
19
|
+
* showSuccess('Operation completed successfully!')
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* return (
|
|
23
|
+
* <>
|
|
24
|
+
* <ToastContainer />
|
|
25
|
+
* <button onClick={handleSuccess}>Show Success Toast</button>
|
|
26
|
+
* </>
|
|
27
|
+
* )
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function useToast(): {
|
|
32
|
+
showSuccess: (message: string, duration?: number) => void;
|
|
33
|
+
showError: (message: string, duration?: number) => void;
|
|
34
|
+
showWarning: (message: string, duration?: number) => void;
|
|
35
|
+
showInfo: (message: string, duration?: number) => void;
|
|
36
|
+
ToastContainer: () => import("react").JSX.Element;
|
|
37
|
+
};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Toast, ToastToggle } from 'flowbite-react';
|
|
4
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
5
|
+
import { HiCheckCircle, HiExclamation, HiInformationCircle, } from 'react-icons/hi';
|
|
6
|
+
/**
|
|
7
|
+
* A reusable toast notification hook built on Flowbite React components.
|
|
8
|
+
*
|
|
9
|
+
* Provides toast notifications with auto-dismiss functionality and consistent styling
|
|
10
|
+
* across the RoboSystems ecosystem.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* function MyComponent() {
|
|
15
|
+
* const { showSuccess, showError, ToastContainer } = useToast()
|
|
16
|
+
*
|
|
17
|
+
* const handleSuccess = () => {
|
|
18
|
+
* showSuccess('Operation completed successfully!')
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* return (
|
|
22
|
+
* <>
|
|
23
|
+
* <ToastContainer />
|
|
24
|
+
* <button onClick={handleSuccess}>Show Success Toast</button>
|
|
25
|
+
* </>
|
|
26
|
+
* )
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function useToast() {
|
|
31
|
+
const [toasts, setToasts] = useState([]);
|
|
32
|
+
const timeoutRefs = useRef({});
|
|
33
|
+
const addToast = useCallback((toast) => {
|
|
34
|
+
const id = Math.random().toString(36).substring(2, 11);
|
|
35
|
+
const newToast = Object.assign({ id, duration: 5000 }, toast);
|
|
36
|
+
setToasts((prev) => [...prev, newToast]);
|
|
37
|
+
if (newToast.duration && newToast.duration > 0) {
|
|
38
|
+
const timeoutId = setTimeout(() => {
|
|
39
|
+
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
40
|
+
delete timeoutRefs.current[id];
|
|
41
|
+
}, newToast.duration);
|
|
42
|
+
timeoutRefs.current[id] = timeoutId;
|
|
43
|
+
}
|
|
44
|
+
}, []);
|
|
45
|
+
const removeToast = useCallback((id) => {
|
|
46
|
+
if (timeoutRefs.current[id]) {
|
|
47
|
+
clearTimeout(timeoutRefs.current[id]);
|
|
48
|
+
delete timeoutRefs.current[id];
|
|
49
|
+
}
|
|
50
|
+
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
51
|
+
}, []);
|
|
52
|
+
const showSuccess = useCallback((message, duration) => {
|
|
53
|
+
addToast({ type: 'success', message, duration });
|
|
54
|
+
}, [addToast]);
|
|
55
|
+
const showError = useCallback((message, duration) => {
|
|
56
|
+
addToast({ type: 'error', message, duration });
|
|
57
|
+
}, [addToast]);
|
|
58
|
+
const showWarning = useCallback((message, duration) => {
|
|
59
|
+
addToast({ type: 'warning', message, duration });
|
|
60
|
+
}, [addToast]);
|
|
61
|
+
const showInfo = useCallback((message, duration) => {
|
|
62
|
+
addToast({ type: 'info', message, duration });
|
|
63
|
+
}, [addToast]);
|
|
64
|
+
// Cleanup all timeouts on unmount
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
const timeouts = timeoutRefs.current;
|
|
67
|
+
return () => {
|
|
68
|
+
Object.values(timeouts).forEach(clearTimeout);
|
|
69
|
+
};
|
|
70
|
+
}, []);
|
|
71
|
+
const ToastContainer = useCallback(() => (_jsx("div", { className: "fixed top-4 right-4 z-50 flex flex-col gap-2", children: toasts.map((toast) => {
|
|
72
|
+
const getIcon = () => {
|
|
73
|
+
switch (toast.type) {
|
|
74
|
+
case 'success':
|
|
75
|
+
return HiCheckCircle;
|
|
76
|
+
case 'error':
|
|
77
|
+
return HiExclamation;
|
|
78
|
+
case 'warning':
|
|
79
|
+
return HiExclamation;
|
|
80
|
+
case 'info':
|
|
81
|
+
return HiInformationCircle;
|
|
82
|
+
default:
|
|
83
|
+
return HiInformationCircle;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const getColor = () => {
|
|
87
|
+
switch (toast.type) {
|
|
88
|
+
case 'success':
|
|
89
|
+
return 'success';
|
|
90
|
+
case 'error':
|
|
91
|
+
return 'failure';
|
|
92
|
+
case 'warning':
|
|
93
|
+
return 'warning';
|
|
94
|
+
case 'info':
|
|
95
|
+
return 'info';
|
|
96
|
+
default:
|
|
97
|
+
return 'info';
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
const Icon = getIcon();
|
|
101
|
+
const color = getColor();
|
|
102
|
+
return (_jsxs(Toast, { className: "min-w-80", color: color, children: [_jsx("div", { className: `inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg ${toast.type === 'success'
|
|
103
|
+
? 'bg-green-100 text-green-500 dark:bg-green-800 dark:text-green-200'
|
|
104
|
+
: toast.type === 'error'
|
|
105
|
+
? 'bg-red-100 text-red-500 dark:bg-red-800 dark:text-red-200'
|
|
106
|
+
: toast.type === 'warning'
|
|
107
|
+
? 'bg-orange-100 text-orange-500 dark:bg-orange-700 dark:text-orange-200'
|
|
108
|
+
: 'bg-primary-100 text-primary-500 dark:bg-primary-800 dark:text-primary-200'}`, children: _jsx(Icon, { className: "h-5 w-5" }) }), _jsx("div", { className: "ml-3 text-sm font-normal", children: toast.message }), _jsx(ToastToggle, { onClick: () => removeToast(toast.id) })] }, toast.id));
|
|
109
|
+
}) })), [toasts, removeToast]);
|
|
110
|
+
return {
|
|
111
|
+
showSuccess,
|
|
112
|
+
showError,
|
|
113
|
+
showWarning,
|
|
114
|
+
showInfo,
|
|
115
|
+
ToastContainer,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { OrgLimitsResponse } from '@robosystems/client';
|
|
2
|
+
interface UseOrgLimitsReturn {
|
|
3
|
+
limits: OrgLimitsResponse | null;
|
|
4
|
+
isLoading: boolean;
|
|
5
|
+
error: string | null;
|
|
6
|
+
canCreateGraph: boolean;
|
|
7
|
+
remainingGraphs: number;
|
|
8
|
+
refetch: () => Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export declare function useOrgLimits(): UseOrgLimitsReturn;
|
|
11
|
+
export declare const useUserLimits: typeof useOrgLimits;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import * as SDK from '@robosystems/client';
|
|
3
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
4
|
+
import { useOrg } from '../contexts/org-context';
|
|
5
|
+
export function useOrgLimits() {
|
|
6
|
+
var _a;
|
|
7
|
+
const [limits, setLimits] = useState(null);
|
|
8
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
9
|
+
const [error, setError] = useState(null);
|
|
10
|
+
const [currentGraphCount, setCurrentGraphCount] = useState(0);
|
|
11
|
+
const { currentOrg } = useOrg();
|
|
12
|
+
const fetchLimits = useCallback(async () => {
|
|
13
|
+
if (!(currentOrg === null || currentOrg === void 0 ? void 0 : currentOrg.id)) {
|
|
14
|
+
setIsLoading(false);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
setIsLoading(true);
|
|
18
|
+
setError(null);
|
|
19
|
+
try {
|
|
20
|
+
// Fetch org limits and graphs in parallel
|
|
21
|
+
const [limitsResponse, graphsResponse] = await Promise.allSettled([
|
|
22
|
+
SDK.getOrgLimits({ path: { org_id: currentOrg.id } }),
|
|
23
|
+
SDK.getGraphs(),
|
|
24
|
+
]);
|
|
25
|
+
// Process org limits
|
|
26
|
+
if (limitsResponse.status === 'fulfilled' && limitsResponse.value.data) {
|
|
27
|
+
setLimits(limitsResponse.value.data);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
setLimits(null);
|
|
31
|
+
}
|
|
32
|
+
// Process graphs to count user graphs (not repositories)
|
|
33
|
+
if (graphsResponse.status === 'fulfilled' && graphsResponse.value.data) {
|
|
34
|
+
const graphsData = graphsResponse.value.data;
|
|
35
|
+
const graphs = graphsData.graphs || [];
|
|
36
|
+
// Only count user graphs, not shared repositories
|
|
37
|
+
const userGraphs = graphs.filter((g) => !g.isRepository);
|
|
38
|
+
setCurrentGraphCount(userGraphs.length);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
// Use structured logging instead of console.error for production
|
|
43
|
+
if (process.env.NODE_ENV === 'development') {
|
|
44
|
+
console.error('Failed to fetch org limits:', err);
|
|
45
|
+
}
|
|
46
|
+
setError('Failed to fetch org limits');
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
setIsLoading(false);
|
|
50
|
+
}
|
|
51
|
+
}, [currentOrg === null || currentOrg === void 0 ? void 0 : currentOrg.id]);
|
|
52
|
+
// Fetch limits on mount
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
fetchLimits();
|
|
55
|
+
}, [fetchLimits]);
|
|
56
|
+
// Calculate derived values
|
|
57
|
+
// Use the can_create_graph field directly from the API response
|
|
58
|
+
// The backend calculates this based on org limits
|
|
59
|
+
const canCreateGraph = (_a = limits === null || limits === void 0 ? void 0 : limits.can_create_graph) !== null && _a !== void 0 ? _a : true;
|
|
60
|
+
const remainingGraphs = limits
|
|
61
|
+
? Math.max(0, limits.max_graphs - currentGraphCount)
|
|
62
|
+
: 999; // Show high number when limits unavailable
|
|
63
|
+
return {
|
|
64
|
+
limits,
|
|
65
|
+
isLoading,
|
|
66
|
+
error,
|
|
67
|
+
canCreateGraph,
|
|
68
|
+
remainingGraphs,
|
|
69
|
+
refetch: fetchLimits,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
// Backward compatibility export
|
|
73
|
+
export const useUserLimits = useOrgLimits;
|