@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,536 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { changeSubscriptionPlan, client, createCheckoutSession, createGraph as createGraphAPI, createRepositorySubscription, getOrgBillingCustomer, } from '@robosystems/client';
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
4
|
+
import { operationMonitor } from './operationMonitor';
|
|
5
|
+
/**
|
|
6
|
+
* Hook for monitoring operations using SSE
|
|
7
|
+
*/
|
|
8
|
+
export function useOperationMonitoring() {
|
|
9
|
+
const [state, setState] = useState({
|
|
10
|
+
isLoading: false,
|
|
11
|
+
isMonitoring: false, // Alias for isLoading
|
|
12
|
+
progress: null,
|
|
13
|
+
currentStep: null,
|
|
14
|
+
error: null,
|
|
15
|
+
operationId: null,
|
|
16
|
+
result: null,
|
|
17
|
+
status: null,
|
|
18
|
+
});
|
|
19
|
+
const currentOperationId = useRef(null);
|
|
20
|
+
const reset = useCallback(() => {
|
|
21
|
+
setState({
|
|
22
|
+
isLoading: false,
|
|
23
|
+
isMonitoring: false, // Alias for isLoading
|
|
24
|
+
progress: null,
|
|
25
|
+
currentStep: null,
|
|
26
|
+
error: null,
|
|
27
|
+
operationId: null,
|
|
28
|
+
result: null,
|
|
29
|
+
status: null,
|
|
30
|
+
});
|
|
31
|
+
currentOperationId.current = null;
|
|
32
|
+
}, []);
|
|
33
|
+
const cancelOperation = useCallback(async () => {
|
|
34
|
+
if (currentOperationId.current) {
|
|
35
|
+
try {
|
|
36
|
+
await operationMonitor.cancelOperation(currentOperationId.current);
|
|
37
|
+
setState((prev) => (Object.assign(Object.assign({}, prev), { isLoading: false, isMonitoring: false, status: 'cancelled', error: 'Operation was cancelled', result: null })));
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.error('Failed to cancel operation:', error);
|
|
41
|
+
setState((prev) => (Object.assign(Object.assign({}, prev), { error: 'Failed to cancel operation', result: null })));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}, []);
|
|
45
|
+
const startMonitoring = useCallback(async (operationId, options) => {
|
|
46
|
+
currentOperationId.current = operationId;
|
|
47
|
+
setState({
|
|
48
|
+
isLoading: true,
|
|
49
|
+
isMonitoring: true,
|
|
50
|
+
progress: 0,
|
|
51
|
+
currentStep: 'Starting...',
|
|
52
|
+
error: null,
|
|
53
|
+
operationId,
|
|
54
|
+
result: null,
|
|
55
|
+
status: 'pending',
|
|
56
|
+
});
|
|
57
|
+
try {
|
|
58
|
+
const result = await operationMonitor.monitorOperation({
|
|
59
|
+
operationId,
|
|
60
|
+
timeout: options === null || options === void 0 ? void 0 : options.timeout,
|
|
61
|
+
onProgress: (progress) => {
|
|
62
|
+
setState((prev) => (Object.assign(Object.assign({}, prev), { progress: progress.percent, currentStep: progress.message, status: 'running' })));
|
|
63
|
+
},
|
|
64
|
+
onComplete: (result) => {
|
|
65
|
+
setState((prev) => (Object.assign(Object.assign({}, prev), { isLoading: false, isMonitoring: false, progress: 100, currentStep: 'Completed', result: result, status: 'completed' })));
|
|
66
|
+
},
|
|
67
|
+
onError: (errorMsg) => {
|
|
68
|
+
setState((prev) => (Object.assign(Object.assign({}, prev), { isLoading: false, isMonitoring: false, error: errorMsg, result: null, status: 'failed' })));
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
return result.result || result;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
75
|
+
setState((prev) => (Object.assign(Object.assign({}, prev), { isLoading: false, isMonitoring: false, error: errorMessage, result: null, status: 'failed' })));
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
currentOperationId.current = null;
|
|
80
|
+
}
|
|
81
|
+
}, []);
|
|
82
|
+
// Cleanup on unmount
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
return () => {
|
|
85
|
+
if (currentOperationId.current) {
|
|
86
|
+
operationMonitor.cancelOperation(currentOperationId.current);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}, []);
|
|
90
|
+
return Object.assign(Object.assign({}, state), { startMonitoring,
|
|
91
|
+
cancelOperation, cancelMonitoring: cancelOperation, // Alias for consistency
|
|
92
|
+
reset });
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Hook for graph creation using the new unified endpoint
|
|
96
|
+
*/
|
|
97
|
+
export function useGraphCreation() {
|
|
98
|
+
const operationMonitoring = useOperationMonitoring();
|
|
99
|
+
const [isCreating, setIsCreating] = useState(false);
|
|
100
|
+
const createGraph = useCallback(async (graphData) => {
|
|
101
|
+
var _a, _b, _c;
|
|
102
|
+
setIsCreating(true);
|
|
103
|
+
try {
|
|
104
|
+
// Check if billing is enabled and user needs to complete checkout
|
|
105
|
+
let billingData = null;
|
|
106
|
+
if (graphData.org_id) {
|
|
107
|
+
const billingResponse = await getOrgBillingCustomer({
|
|
108
|
+
client,
|
|
109
|
+
path: { org_id: graphData.org_id },
|
|
110
|
+
});
|
|
111
|
+
// Only set billingData if we got a successful response
|
|
112
|
+
// If billing disabled, getOrgBillingCustomer will return 404 and we skip checkout
|
|
113
|
+
if (!billingResponse.error) {
|
|
114
|
+
billingData = billingResponse.data;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (billingData &&
|
|
118
|
+
!billingData.has_payment_method &&
|
|
119
|
+
!billingData.invoice_billing_enabled) {
|
|
120
|
+
// User needs to add payment method - create checkout session
|
|
121
|
+
const checkoutResponse = await createCheckoutSession({
|
|
122
|
+
client,
|
|
123
|
+
body: {
|
|
124
|
+
resource_type: 'graph',
|
|
125
|
+
plan_name: graphData.instance_tier || 'ladybug-standard',
|
|
126
|
+
resource_config: {
|
|
127
|
+
graph_type: graphData.graph_type,
|
|
128
|
+
graph_name: graphData.graph_name,
|
|
129
|
+
description: graphData.description,
|
|
130
|
+
tags: graphData.tags,
|
|
131
|
+
schema_extensions: graphData.schema_extensions,
|
|
132
|
+
create_entity: graphData.create_entity,
|
|
133
|
+
entity_name: graphData.entity_name,
|
|
134
|
+
entity_identifier: graphData.entity_identifier,
|
|
135
|
+
entity_identifier_type: graphData.entity_identifier_type,
|
|
136
|
+
company_name: graphData.company_name,
|
|
137
|
+
company_identifier: graphData.company_identifier,
|
|
138
|
+
company_identifier_type: graphData.company_identifier_type,
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
if (checkoutResponse.error) {
|
|
143
|
+
const errorMsg = typeof checkoutResponse.error === 'object' &&
|
|
144
|
+
'detail' in checkoutResponse.error
|
|
145
|
+
? String(checkoutResponse.error.detail)
|
|
146
|
+
: 'Failed to create checkout session';
|
|
147
|
+
throw new Error(errorMsg);
|
|
148
|
+
}
|
|
149
|
+
// Check if billing is disabled on the backend
|
|
150
|
+
// @ts-ignore - billing_disabled field will be in next SDK release
|
|
151
|
+
if ((_a = checkoutResponse.data) === null || _a === void 0 ? void 0 : _a.billing_disabled) {
|
|
152
|
+
// Billing disabled - proceed with normal graph creation without payment
|
|
153
|
+
// Fall through to the graph creation logic below
|
|
154
|
+
}
|
|
155
|
+
else if ((_b = checkoutResponse.data) === null || _b === void 0 ? void 0 : _b.checkout_url) {
|
|
156
|
+
// Redirect to Stripe checkout (leave isCreating=true since we're redirecting)
|
|
157
|
+
window.location.href = checkoutResponse.data.checkout_url;
|
|
158
|
+
// Return a pending state to prevent further processing
|
|
159
|
+
return {
|
|
160
|
+
requires_checkout: true,
|
|
161
|
+
checkout_url: checkoutResponse.data.checkout_url,
|
|
162
|
+
session_id: checkoutResponse.data.session_id,
|
|
163
|
+
subscription_id: checkoutResponse.data.subscription_id,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// User has payment method or invoice billing - proceed with normal graph creation
|
|
168
|
+
// Prepare the request in the correct format for CreateGraphRequest
|
|
169
|
+
const requestBody = {
|
|
170
|
+
metadata: {
|
|
171
|
+
graph_name: graphData.graph_name,
|
|
172
|
+
description: graphData.description,
|
|
173
|
+
tags: graphData.tags,
|
|
174
|
+
schema_extensions: graphData.schema_extensions || [],
|
|
175
|
+
},
|
|
176
|
+
instance_tier: graphData.instance_tier || 'ladybug-standard',
|
|
177
|
+
create_entity: graphData.graph_type === 'generic'
|
|
178
|
+
? false
|
|
179
|
+
: ((_c = graphData.create_entity) !== null && _c !== void 0 ? _c : true),
|
|
180
|
+
};
|
|
181
|
+
// Add initial_entity for entity or company graphs
|
|
182
|
+
if (graphData.graph_type === 'entity' && graphData.entity_name) {
|
|
183
|
+
requestBody.initial_entity = {
|
|
184
|
+
name: graphData.entity_name,
|
|
185
|
+
uri: graphData.entity_name.toLowerCase().replace(/\s+/g, '-'),
|
|
186
|
+
ein: graphData.entity_identifier_type === 'ein'
|
|
187
|
+
? graphData.entity_identifier
|
|
188
|
+
: undefined,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
else if (graphData.graph_type === 'company' &&
|
|
192
|
+
graphData.company_name) {
|
|
193
|
+
// Legacy support for company type
|
|
194
|
+
requestBody.initial_entity = {
|
|
195
|
+
name: graphData.company_name,
|
|
196
|
+
uri: graphData.company_name.toLowerCase().replace(/\s+/g, '-'),
|
|
197
|
+
ein: graphData.company_identifier_type === 'ein'
|
|
198
|
+
? graphData.company_identifier
|
|
199
|
+
: undefined,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
// Call the new unified graph creation endpoint
|
|
203
|
+
const response = await createGraphAPI({
|
|
204
|
+
client,
|
|
205
|
+
body: requestBody,
|
|
206
|
+
});
|
|
207
|
+
// Check for error in response
|
|
208
|
+
const apiError = response.error;
|
|
209
|
+
if (apiError) {
|
|
210
|
+
setIsCreating(false);
|
|
211
|
+
// Format validation error message
|
|
212
|
+
let errorMessage = 'Graph creation failed';
|
|
213
|
+
if (Array.isArray(apiError.detail)) {
|
|
214
|
+
errorMessage = apiError.detail
|
|
215
|
+
.map((err) => {
|
|
216
|
+
var _a;
|
|
217
|
+
if (typeof err === 'string')
|
|
218
|
+
return err;
|
|
219
|
+
if (err.msg)
|
|
220
|
+
return `${((_a = err.loc) === null || _a === void 0 ? void 0 : _a.join('.')) || 'field'}: ${err.msg}`;
|
|
221
|
+
return JSON.stringify(err);
|
|
222
|
+
})
|
|
223
|
+
.join(', ');
|
|
224
|
+
}
|
|
225
|
+
else if (typeof apiError.detail === 'string') {
|
|
226
|
+
errorMessage = apiError.detail;
|
|
227
|
+
}
|
|
228
|
+
else if (apiError.message) {
|
|
229
|
+
errorMessage = apiError.message;
|
|
230
|
+
}
|
|
231
|
+
throw new Error(errorMessage);
|
|
232
|
+
}
|
|
233
|
+
// Check if response contains operation_id (async) or direct result
|
|
234
|
+
const responseData = response.data;
|
|
235
|
+
if (responseData === null || responseData === void 0 ? void 0 : responseData.operationId) {
|
|
236
|
+
// Async operation - monitor it
|
|
237
|
+
const result = await operationMonitoring.startMonitoring(responseData.operationId);
|
|
238
|
+
setIsCreating(false);
|
|
239
|
+
return result;
|
|
240
|
+
}
|
|
241
|
+
else if ((responseData === null || responseData === void 0 ? void 0 : responseData.graph_id) || (responseData === null || responseData === void 0 ? void 0 : responseData.graphId)) {
|
|
242
|
+
// Synchronous result - return directly
|
|
243
|
+
// Handle both snake_case and camelCase, normalize initial_entity
|
|
244
|
+
setIsCreating(false);
|
|
245
|
+
return Object.assign({ graph_id: responseData.graph_id || responseData.graphId, initial_entity: responseData.initial_entity || responseData.initialEntity }, responseData);
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
setIsCreating(false);
|
|
249
|
+
throw new Error('Invalid response from graph creation');
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
setIsCreating(false);
|
|
254
|
+
throw error;
|
|
255
|
+
}
|
|
256
|
+
}, [operationMonitoring]);
|
|
257
|
+
const createEntityGraph = useCallback(async (entityData) => {
|
|
258
|
+
return createGraph({
|
|
259
|
+
graph_type: 'entity',
|
|
260
|
+
graph_name: entityData.entity_name,
|
|
261
|
+
entity_name: entityData.entity_name,
|
|
262
|
+
entity_identifier: entityData.entity_identifier,
|
|
263
|
+
entity_identifier_type: entityData.entity_identifier_type,
|
|
264
|
+
instance_tier: entityData.instance_tier,
|
|
265
|
+
schema_extensions: entityData.schema_extensions,
|
|
266
|
+
create_entity: entityData.create_entity,
|
|
267
|
+
description: entityData.description,
|
|
268
|
+
tags: entityData.tags,
|
|
269
|
+
org_id: entityData.org_id,
|
|
270
|
+
});
|
|
271
|
+
}, [createGraph]);
|
|
272
|
+
const createGenericGraph = useCallback(async (graphData) => {
|
|
273
|
+
return createGraph(Object.assign({ graph_type: 'generic' }, graphData));
|
|
274
|
+
}, [createGraph]);
|
|
275
|
+
return Object.assign(Object.assign({}, operationMonitoring), { isLoading: isCreating || operationMonitoring.isLoading, createGraph,
|
|
276
|
+
createEntityGraph,
|
|
277
|
+
createGenericGraph });
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Hook for creating repository subscriptions with billing integration
|
|
281
|
+
* Mirrors the graph creation pattern for consistency
|
|
282
|
+
*/
|
|
283
|
+
export function useRepositorySubscription() {
|
|
284
|
+
const [isSubscribing, setIsSubscribing] = useState(false);
|
|
285
|
+
const subscribe = useCallback(async (subscriptionData) => {
|
|
286
|
+
var _a, _b;
|
|
287
|
+
setIsSubscribing(true);
|
|
288
|
+
try {
|
|
289
|
+
// Check if billing is enabled and user needs to complete checkout
|
|
290
|
+
const billingResponse = await getOrgBillingCustomer({
|
|
291
|
+
client,
|
|
292
|
+
path: { org_id: subscriptionData.org_id },
|
|
293
|
+
});
|
|
294
|
+
const billingData = billingResponse.data;
|
|
295
|
+
// Only check payment if billing is enabled (response exists without error)
|
|
296
|
+
// If billing disabled, getOrgBillingCustomer will return 404 and we skip checkout
|
|
297
|
+
if (!billingResponse.error &&
|
|
298
|
+
billingData &&
|
|
299
|
+
!billingData.has_payment_method &&
|
|
300
|
+
!billingData.invoice_billing_enabled) {
|
|
301
|
+
// User needs to add payment method - create checkout session
|
|
302
|
+
const checkoutResponse = await createCheckoutSession({
|
|
303
|
+
client,
|
|
304
|
+
body: {
|
|
305
|
+
resource_type: 'repository',
|
|
306
|
+
plan_name: subscriptionData.plan_name,
|
|
307
|
+
resource_config: {
|
|
308
|
+
repository_name: subscriptionData.repository_name,
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
});
|
|
312
|
+
if (checkoutResponse.error) {
|
|
313
|
+
const errorMsg = typeof checkoutResponse.error === 'object' &&
|
|
314
|
+
'detail' in checkoutResponse.error
|
|
315
|
+
? String(checkoutResponse.error.detail)
|
|
316
|
+
: 'Failed to create checkout session';
|
|
317
|
+
throw new Error(errorMsg);
|
|
318
|
+
}
|
|
319
|
+
// Check if billing is disabled on the backend
|
|
320
|
+
// @ts-ignore - billing_disabled field will be in next SDK release
|
|
321
|
+
if ((_a = checkoutResponse.data) === null || _a === void 0 ? void 0 : _a.billing_disabled) {
|
|
322
|
+
// Billing disabled - proceed with direct subscription creation
|
|
323
|
+
// Fall through to the subscription creation logic below
|
|
324
|
+
}
|
|
325
|
+
else if ((_b = checkoutResponse.data) === null || _b === void 0 ? void 0 : _b.checkout_url) {
|
|
326
|
+
// Redirect to Stripe checkout
|
|
327
|
+
window.location.href = checkoutResponse.data.checkout_url;
|
|
328
|
+
// Return a pending state to prevent further processing
|
|
329
|
+
return {
|
|
330
|
+
requires_checkout: true,
|
|
331
|
+
checkout_url: checkoutResponse.data.checkout_url,
|
|
332
|
+
session_id: checkoutResponse.data.session_id,
|
|
333
|
+
subscription_id: checkoutResponse.data.subscription_id,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
// User has payment method, invoice billing, or billing is disabled
|
|
338
|
+
// Proceed with direct subscription creation
|
|
339
|
+
const response = await createRepositorySubscription({
|
|
340
|
+
client,
|
|
341
|
+
path: { graph_id: subscriptionData.repository_name },
|
|
342
|
+
body: {
|
|
343
|
+
plan_name: subscriptionData.plan_name,
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
if (response.error) {
|
|
347
|
+
const errorMsg = typeof response.error === 'object' && 'detail' in response.error
|
|
348
|
+
? String(response.error.detail)
|
|
349
|
+
: 'Failed to create repository subscription';
|
|
350
|
+
throw new Error(errorMsg);
|
|
351
|
+
}
|
|
352
|
+
return response.data;
|
|
353
|
+
}
|
|
354
|
+
catch (error) {
|
|
355
|
+
console.error('Repository subscription failed:', error);
|
|
356
|
+
throw error;
|
|
357
|
+
}
|
|
358
|
+
finally {
|
|
359
|
+
setIsSubscribing(false);
|
|
360
|
+
}
|
|
361
|
+
}, []);
|
|
362
|
+
const changePlan = useCallback(async (data) => {
|
|
363
|
+
setIsSubscribing(true);
|
|
364
|
+
try {
|
|
365
|
+
const response = await changeSubscriptionPlan({
|
|
366
|
+
client,
|
|
367
|
+
path: { graph_id: data.repository_name },
|
|
368
|
+
body: { new_plan_name: data.new_plan_name },
|
|
369
|
+
});
|
|
370
|
+
if (response.error) {
|
|
371
|
+
const errorMsg = typeof response.error === 'object' && 'detail' in response.error
|
|
372
|
+
? String(response.error.detail)
|
|
373
|
+
: 'Failed to change plan';
|
|
374
|
+
throw new Error(errorMsg);
|
|
375
|
+
}
|
|
376
|
+
return response.data;
|
|
377
|
+
}
|
|
378
|
+
catch (error) {
|
|
379
|
+
console.error('Plan change failed:', error);
|
|
380
|
+
throw error;
|
|
381
|
+
}
|
|
382
|
+
finally {
|
|
383
|
+
setIsSubscribing(false);
|
|
384
|
+
}
|
|
385
|
+
}, []);
|
|
386
|
+
return {
|
|
387
|
+
isSubscribing,
|
|
388
|
+
subscribe,
|
|
389
|
+
changePlan,
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Hook for monitoring multiple operations simultaneously
|
|
394
|
+
*/
|
|
395
|
+
export function useMultipleOperations() {
|
|
396
|
+
const [operations, setOperations] = useState(new Map());
|
|
397
|
+
// Keep a ref to the latest operations for cleanup without triggering effect re-runs
|
|
398
|
+
const operationsRef = useRef(operations);
|
|
399
|
+
// Update ref whenever operations change
|
|
400
|
+
useEffect(() => {
|
|
401
|
+
operationsRef.current = operations;
|
|
402
|
+
}, [operations]);
|
|
403
|
+
const addOperation = useCallback(async (operationId, options) => {
|
|
404
|
+
// Initialize state for this operation
|
|
405
|
+
setOperations((prev) => {
|
|
406
|
+
const newMap = new Map(prev);
|
|
407
|
+
newMap.set(operationId, {
|
|
408
|
+
isLoading: true,
|
|
409
|
+
isMonitoring: true,
|
|
410
|
+
progress: 0,
|
|
411
|
+
currentStep: 'Starting...',
|
|
412
|
+
error: null,
|
|
413
|
+
operationId,
|
|
414
|
+
result: null,
|
|
415
|
+
status: 'pending',
|
|
416
|
+
});
|
|
417
|
+
return newMap;
|
|
418
|
+
});
|
|
419
|
+
try {
|
|
420
|
+
const result = await operationMonitor.monitorOperation({
|
|
421
|
+
operationId,
|
|
422
|
+
timeout: options === null || options === void 0 ? void 0 : options.timeout,
|
|
423
|
+
onProgress: (progress) => {
|
|
424
|
+
setOperations((prev) => {
|
|
425
|
+
const newMap = new Map(prev);
|
|
426
|
+
const current = newMap.get(operationId);
|
|
427
|
+
if (current) {
|
|
428
|
+
newMap.set(operationId, Object.assign(Object.assign({}, current), { progress: progress.percent, currentStep: progress.message, status: 'running' }));
|
|
429
|
+
}
|
|
430
|
+
return newMap;
|
|
431
|
+
});
|
|
432
|
+
},
|
|
433
|
+
onComplete: (result) => {
|
|
434
|
+
setOperations((prev) => {
|
|
435
|
+
const newMap = new Map(prev);
|
|
436
|
+
const current = newMap.get(operationId);
|
|
437
|
+
if (current) {
|
|
438
|
+
newMap.set(operationId, Object.assign(Object.assign({}, current), { isLoading: false, isMonitoring: false, progress: 100, currentStep: 'Completed', result: result, status: 'completed' }));
|
|
439
|
+
}
|
|
440
|
+
return newMap;
|
|
441
|
+
});
|
|
442
|
+
},
|
|
443
|
+
onError: (errorMsg) => {
|
|
444
|
+
setOperations((prev) => {
|
|
445
|
+
const newMap = new Map(prev);
|
|
446
|
+
const current = newMap.get(operationId);
|
|
447
|
+
if (current) {
|
|
448
|
+
newMap.set(operationId, Object.assign(Object.assign({}, current), { isLoading: false, isMonitoring: false, error: errorMsg, result: null, status: 'failed' }));
|
|
449
|
+
}
|
|
450
|
+
return newMap;
|
|
451
|
+
});
|
|
452
|
+
},
|
|
453
|
+
});
|
|
454
|
+
return result;
|
|
455
|
+
}
|
|
456
|
+
catch (error) {
|
|
457
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
458
|
+
setOperations((prev) => {
|
|
459
|
+
const newMap = new Map(prev);
|
|
460
|
+
const current = newMap.get(operationId);
|
|
461
|
+
if (current) {
|
|
462
|
+
newMap.set(operationId, Object.assign(Object.assign({}, current), { isLoading: false, isMonitoring: false, error: errorMessage, result: null, status: 'failed' }));
|
|
463
|
+
}
|
|
464
|
+
return newMap;
|
|
465
|
+
});
|
|
466
|
+
throw error;
|
|
467
|
+
}
|
|
468
|
+
}, []);
|
|
469
|
+
const cancelOperation = useCallback(async (operationId) => {
|
|
470
|
+
await operationMonitor.cancelOperation(operationId);
|
|
471
|
+
setOperations((prev) => {
|
|
472
|
+
const newMap = new Map(prev);
|
|
473
|
+
const current = newMap.get(operationId);
|
|
474
|
+
if (current) {
|
|
475
|
+
newMap.set(operationId, Object.assign(Object.assign({}, current), { isLoading: false, isMonitoring: false, status: 'cancelled', error: 'Operation was cancelled' }));
|
|
476
|
+
}
|
|
477
|
+
return newMap;
|
|
478
|
+
});
|
|
479
|
+
}, []);
|
|
480
|
+
const removeOperation = useCallback((operationId) => {
|
|
481
|
+
setOperations((prev) => {
|
|
482
|
+
const newMap = new Map(prev);
|
|
483
|
+
newMap.delete(operationId);
|
|
484
|
+
return newMap;
|
|
485
|
+
});
|
|
486
|
+
}, []);
|
|
487
|
+
const clearAll = useCallback(() => {
|
|
488
|
+
// Cancel all active operations
|
|
489
|
+
for (const [operationId, state] of operations) {
|
|
490
|
+
if (state.isLoading) {
|
|
491
|
+
operationMonitor.cancelOperation(operationId);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
setOperations(new Map());
|
|
495
|
+
}, [operations]);
|
|
496
|
+
// Cleanup on unmount - use ref to avoid stale closures
|
|
497
|
+
useEffect(() => {
|
|
498
|
+
return () => {
|
|
499
|
+
for (const [operationId, state] of operationsRef.current) {
|
|
500
|
+
if (state.isLoading) {
|
|
501
|
+
operationMonitor.cancelOperation(operationId);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
}, []);
|
|
506
|
+
return {
|
|
507
|
+
operations: Array.from(operations.values()),
|
|
508
|
+
addOperation,
|
|
509
|
+
cancelOperation,
|
|
510
|
+
removeOperation,
|
|
511
|
+
clearAll,
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Helper to determine if an operation is still active
|
|
516
|
+
*/
|
|
517
|
+
export function isOperationActive(status) {
|
|
518
|
+
return status === 'pending' || status === 'running';
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Helper to get progress color based on status
|
|
522
|
+
*/
|
|
523
|
+
export function getProgressColor(status) {
|
|
524
|
+
switch (status) {
|
|
525
|
+
case 'completed':
|
|
526
|
+
return 'text-green-600';
|
|
527
|
+
case 'failed':
|
|
528
|
+
return 'text-red-600';
|
|
529
|
+
case 'cancelled':
|
|
530
|
+
return 'text-yellow-600';
|
|
531
|
+
case 'running':
|
|
532
|
+
return 'text-blue-600';
|
|
533
|
+
default:
|
|
534
|
+
return 'text-gray-600';
|
|
535
|
+
}
|
|
536
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Operation Monitor - SSE-based monitoring for unified backend operations
|
|
3
|
+
* Replaces the polling-based TaskMonitor with EventSource streaming
|
|
4
|
+
*
|
|
5
|
+
* Uses SDK extensions when available (@robosystems/client v0.1.21+)
|
|
6
|
+
* No fallback - fails fast if SDK extensions not available
|
|
7
|
+
*/
|
|
8
|
+
export type OperationStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
|
|
9
|
+
export interface OperationEvent {
|
|
10
|
+
event: string;
|
|
11
|
+
data: any;
|
|
12
|
+
timestamp?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface OperationProgress {
|
|
15
|
+
percent: number;
|
|
16
|
+
message?: string;
|
|
17
|
+
current_step?: string;
|
|
18
|
+
total_steps?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface OperationResult {
|
|
21
|
+
operation_id: string;
|
|
22
|
+
status: OperationStatus;
|
|
23
|
+
result?: any;
|
|
24
|
+
error?: string;
|
|
25
|
+
duration_ms?: number;
|
|
26
|
+
events?: OperationEvent[];
|
|
27
|
+
}
|
|
28
|
+
export interface OperationMonitorOptions {
|
|
29
|
+
operationId: string;
|
|
30
|
+
onProgress?: (progress: OperationProgress) => void;
|
|
31
|
+
onComplete?: (result: any) => void;
|
|
32
|
+
onError?: (error: string) => void;
|
|
33
|
+
onEvent?: (event: OperationEvent) => void;
|
|
34
|
+
timeout?: number;
|
|
35
|
+
}
|
|
36
|
+
export declare class OperationMonitor {
|
|
37
|
+
private static instance;
|
|
38
|
+
private activeOperations;
|
|
39
|
+
private operationResults;
|
|
40
|
+
static getInstance(): OperationMonitor;
|
|
41
|
+
/**
|
|
42
|
+
* Monitor an operation using SSE streaming
|
|
43
|
+
*/
|
|
44
|
+
monitorOperation({ operationId, onProgress, onComplete, onError, onEvent, timeout, }: OperationMonitorOptions): Promise<OperationResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Cancel operation monitoring (does not cancel the operation itself)
|
|
47
|
+
*/
|
|
48
|
+
cancelOperation(operationId: string): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Get cached operation status/result
|
|
51
|
+
*/
|
|
52
|
+
getOperationStatus(operationId: string): OperationResult | null;
|
|
53
|
+
/**
|
|
54
|
+
* Clean up operation monitoring resources
|
|
55
|
+
*/
|
|
56
|
+
private cleanupOperation;
|
|
57
|
+
/**
|
|
58
|
+
* Monitor operation using SDK extensions
|
|
59
|
+
*/
|
|
60
|
+
private monitorWithSDKExtensions;
|
|
61
|
+
/**
|
|
62
|
+
* Clean up all active operations
|
|
63
|
+
*/
|
|
64
|
+
cleanup(): void;
|
|
65
|
+
/**
|
|
66
|
+
* Get list of active operation IDs
|
|
67
|
+
*/
|
|
68
|
+
getActiveOperations(): string[];
|
|
69
|
+
/**
|
|
70
|
+
* Clear operation results cache
|
|
71
|
+
*/
|
|
72
|
+
clearCache(): void;
|
|
73
|
+
}
|
|
74
|
+
export declare const operationMonitor: OperationMonitor;
|
|
75
|
+
export declare const monitorOperation: (options: OperationMonitorOptions) => Promise<OperationResult>;
|
|
76
|
+
export declare const cancelOperation: (operationId: string) => boolean;
|
|
77
|
+
export declare const getOperationStatus: (operationId: string) => OperationResult;
|
|
78
|
+
export declare const getActiveOperations: () => string[];
|