@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
package/theme/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { customTheme } from './flowbite-theme';
|
package/theme/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { customTheme } from './flowbite-theme';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity interface - represents an Entity node in the graph
|
|
3
|
+
* Entity is a base node type that can represent companies, subsidiaries, or other business entities
|
|
4
|
+
*/
|
|
5
|
+
export interface Entity {
|
|
6
|
+
identifier: string
|
|
7
|
+
name: string
|
|
8
|
+
entityType?: string // Entity type: 'corporation', 'llc', 'partnership', etc.
|
|
9
|
+
parentEntityId?: string | null
|
|
10
|
+
isParent?: boolean | null
|
|
11
|
+
[key: string]: any
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Collection of entities
|
|
16
|
+
*/
|
|
17
|
+
export interface Entities {
|
|
18
|
+
entities: Entity[]
|
|
19
|
+
}
|
package/types/index.d.ts
ADDED
package/types/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/types/user.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ComponentType, ReactNode } from 'react';
|
|
2
|
+
interface ConfirmModalProps {
|
|
3
|
+
/** Whether the modal is open. */
|
|
4
|
+
show: boolean;
|
|
5
|
+
/** Dismiss handler (Cancel button + backdrop/close). Ignored while `loading`. */
|
|
6
|
+
onClose: () => void;
|
|
7
|
+
/** Invoked when the confirm button is pressed. */
|
|
8
|
+
onConfirm: () => void;
|
|
9
|
+
/** Header title, e.g. "Delete Document". */
|
|
10
|
+
title: string;
|
|
11
|
+
/** Body content — the warning copy and/or item details. */
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
/** Confirm button label (default "Delete"). */
|
|
14
|
+
confirmLabel?: string;
|
|
15
|
+
/** Confirm button label shown while `loading` (default "Deleting…"). */
|
|
16
|
+
loadingLabel?: string;
|
|
17
|
+
/** Optional icon on the confirm button, e.g. `HiTrash`. */
|
|
18
|
+
confirmIcon?: ComponentType<{
|
|
19
|
+
className?: string;
|
|
20
|
+
'aria-hidden'?: boolean | 'true';
|
|
21
|
+
}>;
|
|
22
|
+
/** Confirm button color (default "failure"). */
|
|
23
|
+
confirmColor?: string;
|
|
24
|
+
/** Cancel button label (default "Cancel"). */
|
|
25
|
+
cancelLabel?: string;
|
|
26
|
+
/** When true, disables both buttons and shows a spinner in the confirm button. */
|
|
27
|
+
loading?: boolean;
|
|
28
|
+
/** Modal size (default "md"). */
|
|
29
|
+
size?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A confirmation dialog for a single irreversible action (delete, etc.). Owns
|
|
33
|
+
* the modal chrome and the Cancel / Confirm buttons — including the
|
|
34
|
+
* disabled-while-pending and confirm-button-spinner behavior — while the caller
|
|
35
|
+
* supplies the warning copy and any item details as `children`.
|
|
36
|
+
*
|
|
37
|
+
* The caller drives the async flow: pass `loading` while the action runs (the
|
|
38
|
+
* dialog can't be dismissed during it), and close the modal in your handler.
|
|
39
|
+
*/
|
|
40
|
+
export declare function ConfirmModal({ show, onClose, onConfirm, title, children, confirmLabel, loadingLabel, confirmIcon: ConfirmIcon, confirmColor, cancelLabel, loading, size, }: ConfirmModalProps): import("react").JSX.Element;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, Modal, ModalBody, ModalFooter, ModalHeader, } from 'flowbite-react';
|
|
3
|
+
import { Spinner } from './Spinner';
|
|
4
|
+
/**
|
|
5
|
+
* A confirmation dialog for a single irreversible action (delete, etc.). Owns
|
|
6
|
+
* the modal chrome and the Cancel / Confirm buttons — including the
|
|
7
|
+
* disabled-while-pending and confirm-button-spinner behavior — while the caller
|
|
8
|
+
* supplies the warning copy and any item details as `children`.
|
|
9
|
+
*
|
|
10
|
+
* The caller drives the async flow: pass `loading` while the action runs (the
|
|
11
|
+
* dialog can't be dismissed during it), and close the modal in your handler.
|
|
12
|
+
*/
|
|
13
|
+
export function ConfirmModal({ show, onClose, onConfirm, title, children, confirmLabel = 'Delete', loadingLabel = 'Deleting…', confirmIcon: ConfirmIcon, confirmColor = 'failure', cancelLabel = 'Cancel', loading = false, size = 'md', }) {
|
|
14
|
+
const handleClose = () => {
|
|
15
|
+
if (!loading)
|
|
16
|
+
onClose();
|
|
17
|
+
};
|
|
18
|
+
return (_jsxs(Modal, { show: show, onClose: handleClose, size: size, children: [_jsx(ModalHeader, { children: title }), _jsx(ModalBody, { children: children }), _jsxs(ModalFooter, { children: [_jsx(Button, { color: confirmColor, onClick: onConfirm, disabled: loading, children: loading ? (_jsxs(_Fragment, { children: [_jsx(Spinner, { size: "sm", className: "mr-2 text-white" }), loadingLabel] })) : (_jsxs(_Fragment, { children: [ConfirmIcon && (_jsx(ConfirmIcon, { className: "mr-2 h-4 w-4", "aria-hidden": "true" })), confirmLabel] })) }), _jsx(Button, { color: "gray", onClick: handleClose, disabled: loading, children: cancelLabel })] })] }));
|
|
19
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ComponentType, ReactNode } from 'react';
|
|
2
|
+
interface EmptyStateProps {
|
|
3
|
+
/** Icon shown above the title — typically a react-icons `Hi*` component. */
|
|
4
|
+
icon: ComponentType<{
|
|
5
|
+
className?: string;
|
|
6
|
+
'aria-hidden'?: boolean | 'true';
|
|
7
|
+
}>;
|
|
8
|
+
title: string;
|
|
9
|
+
/** Supporting copy below the title. Inline content only (rendered in a block). */
|
|
10
|
+
description?: ReactNode;
|
|
11
|
+
/** Optional call-to-action (e.g. a "Create…" button) shown below. */
|
|
12
|
+
action?: ReactNode;
|
|
13
|
+
/** Override the container spacing (default `py-12`). */
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The shared empty state: a muted icon, a title, an optional description, and an
|
|
18
|
+
* optional action — centered. Render it inside whatever container the page uses
|
|
19
|
+
* (often a `<Card>`); this component is just the centered inner block.
|
|
20
|
+
*/
|
|
21
|
+
export declare function EmptyState({ icon: Icon, title, description, action, className, }: EmptyStateProps): import("react").JSX.Element;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
/**
|
|
4
|
+
* The shared empty state: a muted icon, a title, an optional description, and an
|
|
5
|
+
* optional action — centered. Render it inside whatever container the page uses
|
|
6
|
+
* (often a `<Card>`); this component is just the centered inner block.
|
|
7
|
+
*/
|
|
8
|
+
export function EmptyState({ icon: Icon, title, description, action, className, }) {
|
|
9
|
+
return (_jsxs("div", { className: twMerge('py-12 text-center', className), children: [_jsx(Icon, { className: "mx-auto h-12 w-12 text-gray-400", "aria-hidden": "true" }), _jsx("h3", { className: "mt-2 text-sm font-medium text-gray-900 dark:text-white", children: title }), description && (_jsx("div", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: description })), action && _jsx("div", { className: "mt-6", children: action })] }));
|
|
10
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
import { Spinner } from './Spinner';
|
|
3
|
+
interface LoadingStateProps {
|
|
4
|
+
/** Optional message shown below the spinner, e.g. "Loading dashboard…". */
|
|
5
|
+
message?: string;
|
|
6
|
+
/** Spinner size. Defaults to `lg`. */
|
|
7
|
+
size?: ComponentProps<typeof Spinner>['size'];
|
|
8
|
+
/**
|
|
9
|
+
* Override the container's spacing/height. The default is `py-12` (a compact
|
|
10
|
+
* in-content load); pass e.g. `className="h-64"` for a taller reserved area
|
|
11
|
+
* or `className="min-h-screen"` to fill the viewport.
|
|
12
|
+
*/
|
|
13
|
+
className?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Accessible label for screen readers. Defaults to `message` (or "Loading"
|
|
16
|
+
* when neither is provided).
|
|
17
|
+
*/
|
|
18
|
+
'aria-label'?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The shared content-area loader: a spinner with an optional message below,
|
|
22
|
+
* centered with vertical padding. Use for section / page-content loads. For a
|
|
23
|
+
* full-page shell use `<Spinner fullScreen>` / `<BrandSpinner fullScreen>`; for
|
|
24
|
+
* inline button loading use a bare `<Spinner size="sm">`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function LoadingState({ message, size, className, 'aria-label': ariaLabel, }: LoadingStateProps): import("react").JSX.Element;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
import { Spinner } from './Spinner';
|
|
4
|
+
/**
|
|
5
|
+
* The shared content-area loader: a spinner with an optional message below,
|
|
6
|
+
* centered with vertical padding. Use for section / page-content loads. For a
|
|
7
|
+
* full-page shell use `<Spinner fullScreen>` / `<BrandSpinner fullScreen>`; for
|
|
8
|
+
* inline button loading use a bare `<Spinner size="sm">`.
|
|
9
|
+
*/
|
|
10
|
+
export function LoadingState({ message, size = 'lg', className, 'aria-label': ariaLabel, }) {
|
|
11
|
+
return (_jsxs("div", { className: twMerge('flex flex-col items-center justify-center gap-3 py-12', className), children: [_jsx(Spinner, { size: size, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : message }), message && (_jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: message }))] }));
|
|
12
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AppName } from '../auth-core/types';
|
|
2
|
+
export interface AnimatedLogoProps {
|
|
3
|
+
className?: string;
|
|
4
|
+
animate?: 'once' | 'loop';
|
|
5
|
+
app?: AppName;
|
|
6
|
+
/**
|
|
7
|
+
* Render the mark in the app's brand color instead of the inherited text
|
|
8
|
+
* color. Use for cross-app identity (e.g. the AppSwitcher, foreign-app marks)
|
|
9
|
+
* and branded auth screens. Defaults to false so existing monochrome usages
|
|
10
|
+
* (navbar, spinner, search) are unaffected.
|
|
11
|
+
*/
|
|
12
|
+
brand?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function AnimatedLogo({ className, animate, app, brand, }: AnimatedLogoProps): import("react").JSX.Element;
|
|
15
|
+
export interface LogoBadgeProps {
|
|
16
|
+
app?: AppName;
|
|
17
|
+
animate?: 'once' | 'loop';
|
|
18
|
+
/** Sizing/utility classes for the chip, e.g. `h-10 w-10`. */
|
|
19
|
+
className?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The mark rendered as an app-icon: a white AnimatedLogo on the app's
|
|
23
|
+
* brand-gradient rounded chip. At small/icon sizes this reads far crisper than
|
|
24
|
+
* a brand-colored mark on a dark background, and it surfaces the brand color as
|
|
25
|
+
* a background element. Cross-app safe — renders the correct gradient for any
|
|
26
|
+
* `app` from inside any app, so the AppSwitcher shows three distinct chips.
|
|
27
|
+
*/
|
|
28
|
+
export declare function LogoBadge({ app, animate, className, }: LogoBadgeProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useId } from 'react';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
4
|
+
import { BRAND_COLORS, BRAND_GRADIENTS, CURRENT_APP } from '../auth-core/config';
|
|
5
|
+
/* Graph nodes (shared across all three logos) */
|
|
6
|
+
function GraphNodes() {
|
|
7
|
+
return (_jsxs("g", { transform: "matrix(2.49868,0,0,2.59811,-747.255,-135.521)", children: [_jsx("g", { transform: "matrix(0.517664,0.499902,-1.04482,1.08194,387.843,-253.483)", children: _jsx("rect", { x: "451.017", y: "150.798", width: "53.143", height: "13.689" }) }), _jsx("g", { transform: "matrix(-5.28647e-17,-0.5334,1.60446,-4.68862e-17,255.339,491.11)", children: _jsx("rect", { x: "451.017", y: "150.798", width: "53.143", height: "13.689" }) }), _jsx("g", { transform: "matrix(0.549336,-0.58909,1.13654,1.05985,100.455,264.271)", children: _jsx("rect", { x: "451.017", y: "150.798", width: "53.143", height: "13.689" }) }), _jsx("g", { transform: "matrix(1,0,0,1.05096,177.322,-5.45629)", children: _jsx("path", { d: "M250.672,80.255C272.88,80.255 290.91,97.31 290.91,118.316C290.91,139.322 272.88,156.376 250.672,156.376C228.464,156.376 210.433,139.322 210.433,118.316C210.433,97.31 228.464,80.255 250.672,80.255ZM250.672,99.286C261.776,99.286 270.791,107.813 270.791,118.316C270.791,128.819 261.776,137.346 250.672,137.346C239.568,137.346 230.553,128.819 230.553,118.316C230.553,107.813 239.568,99.286 250.672,99.286Z" }) }), _jsx("g", { transform: "matrix(0.869818,0,0,0.919587,289.117,82.161)", children: _jsx("path", { d: "M250.672,80.255C272.88,80.255 290.91,97.31 290.91,118.316C290.91,139.322 272.88,156.376 250.672,156.376C228.464,156.376 210.433,139.322 210.433,118.316C210.433,97.31 228.464,80.255 250.672,80.255ZM250.672,99.286C261.776,99.286 270.791,107.813 270.791,118.316C270.791,128.819 261.776,137.346 250.672,137.346C239.568,137.346 230.553,128.819 230.553,118.316C230.553,107.813 239.568,99.286 250.672,99.286Z" }) }), _jsx("g", { transform: "matrix(1,0,0,1.05096,331.465,-18.1536)", children: _jsx("path", { d: "M250.672,80.255C272.88,80.255 290.91,97.31 290.91,118.316C290.91,139.322 272.88,156.376 250.672,156.376C228.464,156.376 210.433,139.322 210.433,118.316C210.433,97.31 228.464,80.255 250.672,80.255ZM250.672,99.286C261.776,99.286 270.791,107.813 270.791,118.316C270.791,128.819 261.776,137.346 250.672,137.346C239.568,137.346 230.553,128.819 230.553,118.316C230.553,107.813 239.568,99.286 250.672,99.286Z" }) })] }));
|
|
8
|
+
}
|
|
9
|
+
/* Shared book structure elements */
|
|
10
|
+
function BookBase() {
|
|
11
|
+
return (_jsxs(_Fragment, { children: [_jsx("g", { transform: "matrix(1.11678,0.257829,-0.100241,0.43419,24.5867,227.367)", children: _jsx("path", { d: "M494.703,576.843L494.703,600.541C494.703,613.235 490.553,623.542 485.443,623.542L347.276,623.542C342.165,623.542 338.016,613.235 338.016,600.541L338.016,576.843C338.016,564.149 342.165,553.843 347.276,553.843L485.443,553.843C490.553,553.843 494.703,564.149 494.703,576.843Z" }) }), _jsx("g", { transform: "matrix(6.90144e-17,-1.14962,0.464321,-2.15344e-17,77.8997,1125.4)", children: _jsx("path", { d: "M494.703,588.692C494.703,607.926 488.637,623.542 481.166,623.542L351.553,623.542C344.082,623.542 338.016,607.926 338.016,588.692C338.016,569.458 344.082,553.843 351.553,553.843L481.166,553.843C488.637,553.843 494.703,569.458 494.703,588.692Z" }) }), _jsx("g", { transform: "matrix(6.88291e-17,-1.14663,0.464321,-2.14054e-17,388.521,1125.53)", children: _jsx("path", { d: "M494.703,588.692C494.703,607.926 488.621,623.542 481.131,623.542L351.588,623.542C344.098,623.542 338.016,607.926 338.016,588.692C338.016,569.458 344.098,553.843 351.588,553.843L481.131,553.843C488.621,553.843 494.703,569.458 494.703,588.692Z" }) }), _jsx("g", { transform: "matrix(1.12437,0.301274,-0.118553,0.442447,31.5589,355.851)", children: _jsx("path", { d: "M494.703,571.267L494.703,606.117C494.703,615.734 491.525,623.542 487.612,623.542L345.107,623.542C341.193,623.542 338.016,615.734 338.016,606.117L338.016,571.267C338.016,561.65 341.193,553.843 345.107,553.843L487.612,553.843C491.525,553.843 494.703,561.65 494.703,571.267Z" }) }), _jsx("g", { transform: "matrix(1.08457,-0.29061,0.117114,0.437076,64.1786,606.532)", children: _jsx("path", { d: "M494.703,571.267L494.703,606.117C494.703,615.734 491.449,623.542 487.441,623.542L345.278,623.542C341.27,623.542 338.016,615.734 338.016,606.117L338.016,571.267C338.016,561.65 341.27,553.843 345.278,553.843L487.441,553.843C491.449,553.843 494.703,561.65 494.703,571.267Z" }) }), _jsx("g", { transform: "matrix(1.11035,-0.256345,0.0986939,0.42749,65.4073,446.414)", children: _jsx("path", { d: "M494.703,585.207L494.703,592.177C494.703,609.488 489.1,623.542 482.198,623.542L350.521,623.542C343.619,623.542 338.016,609.488 338.016,592.177L338.016,585.207C338.016,567.897 343.619,553.843 350.521,553.843L482.198,553.843C489.1,553.843 494.703,567.897 494.703,585.207Z" }) })] }));
|
|
12
|
+
}
|
|
13
|
+
/* RoboInvestor: bar chart animation */
|
|
14
|
+
function InvestorBook({ animate }) {
|
|
15
|
+
const isOnce = animate === 'once';
|
|
16
|
+
const animName = isOnce ? 'barIntro' : 'barWave';
|
|
17
|
+
const iteration = isOnce ? '1' : 'infinite';
|
|
18
|
+
const fillMode = isOnce ? 'forwards' : 'none';
|
|
19
|
+
return (_jsxs(_Fragment, { children: [_jsx("style", { children: `
|
|
20
|
+
.ri-bar {
|
|
21
|
+
transform-box: fill-box;
|
|
22
|
+
transform-origin: 0% 50%;
|
|
23
|
+
animation: ${animName} 1.4s ease-in-out ${iteration} ${fillMode};
|
|
24
|
+
}
|
|
25
|
+
.ri-bar-1 { animation-delay: 0s; }
|
|
26
|
+
.ri-bar-2 { animation-delay: 0.15s; }
|
|
27
|
+
.ri-bar-3 { animation-delay: 0.3s; }
|
|
28
|
+
@keyframes barWave {
|
|
29
|
+
0%, 100% { transform: scaleX(0.3); }
|
|
30
|
+
50% { transform: scaleX(1); }
|
|
31
|
+
}
|
|
32
|
+
@keyframes barIntro {
|
|
33
|
+
0% { transform: scaleX(0.3); }
|
|
34
|
+
60% { transform: scaleX(1.1); }
|
|
35
|
+
100% { transform: scaleX(1); }
|
|
36
|
+
}
|
|
37
|
+
` }), _jsxs("g", { transform: "matrix(2.49868,0,0,2.59811,-751.016,-1032.21)", children: [_jsx(BookBase, {}), _jsx("g", { transform: "matrix(-1.05969e-17,-0.395984,0.462394,-0.00760872,191.313,902.146)", children: _jsx("g", { className: "ri-bar ri-bar-1", children: _jsx("path", { d: "M494.703,576.843L494.703,600.541C494.703,613.235 483.129,623.542 468.873,623.542L363.846,623.542C349.59,623.542 338.016,613.235 338.016,600.541L338.016,576.843C338.016,564.149 349.59,553.843 363.846,553.843L468.873,553.843C483.129,553.843 494.703,564.149 494.703,576.843Z" }) }) }), _jsx("g", { transform: "matrix(-4.01651e-17,-0.572815,0.462394,-0.00760872,236.173,953.952)", children: _jsx("g", { className: "ri-bar ri-bar-2", children: _jsx("path", { d: "M494.703,576.843L494.703,600.541C494.703,613.235 486.702,623.542 476.846,623.542L355.872,623.542C346.017,623.542 338.016,613.235 338.016,600.541L338.016,576.843C338.016,564.149 346.017,553.843 355.872,553.843L476.846,553.843C486.702,553.843 494.703,564.149 494.703,576.843Z" }) }) }), _jsx("g", { transform: "matrix(-8.47906e-17,-0.839696,0.462394,-0.00760872,281.533,1053.03)", children: _jsx("g", { className: "ri-bar ri-bar-3", children: _jsx("path", { d: "M494.703,576.843L494.703,600.541C494.703,613.235 489.245,623.542 482.522,623.542L350.197,623.542C343.474,623.542 338.016,613.235 338.016,600.541L338.016,576.843C338.016,564.149 343.474,553.843 350.197,553.843L482.522,553.843C489.245,553.843 494.703,564.149 494.703,576.843Z" }) }) }), _jsx("g", { transform: "matrix(-1.89816e-17,-0.22431,0.431709,1.61811e-17,255.945,699.671)", children: _jsx("path", { d: "M494.703,588.692C494.703,607.926 465.799,623.542 430.198,623.542L402.521,623.542C366.92,623.542 338.016,607.926 338.016,588.692C338.016,569.458 366.92,553.843 402.521,553.843L430.198,553.843C465.799,553.843 494.703,569.458 494.703,588.692Z" }) })] })] }));
|
|
38
|
+
}
|
|
39
|
+
/* RoboLedger: T-account eyes wink */
|
|
40
|
+
function LedgerBook({ animate }) {
|
|
41
|
+
const isOnce = animate === 'once';
|
|
42
|
+
const iteration = isOnce ? '1' : 'infinite';
|
|
43
|
+
const fillMode = isOnce ? 'forwards' : 'none';
|
|
44
|
+
return (_jsxs(_Fragment, { children: [_jsx("style", { children: `
|
|
45
|
+
.rl-eye-l {
|
|
46
|
+
animation: ${isOnce ? 'winkIntroL' : 'winkL'} ${isOnce ? '1.2s' : '2s'} ease-in-out ${iteration} ${fillMode};
|
|
47
|
+
}
|
|
48
|
+
.rl-eye-r {
|
|
49
|
+
animation: ${isOnce ? 'winkIntroR' : 'winkR'} ${isOnce ? '1.2s' : '2s'} ease-in-out ${iteration} ${fillMode};
|
|
50
|
+
}
|
|
51
|
+
@keyframes winkL {
|
|
52
|
+
0%, 15%, 30%, 100% { opacity: 1; }
|
|
53
|
+
5%, 12% { opacity: 0; }
|
|
54
|
+
}
|
|
55
|
+
@keyframes winkR {
|
|
56
|
+
0%, 45%, 65%, 100% { opacity: 1; }
|
|
57
|
+
50%, 60% { opacity: 0; }
|
|
58
|
+
}
|
|
59
|
+
@keyframes winkIntroL {
|
|
60
|
+
0% { opacity: 0; }
|
|
61
|
+
30% { opacity: 1; }
|
|
62
|
+
45% { opacity: 0; }
|
|
63
|
+
60%, 100% { opacity: 1; }
|
|
64
|
+
}
|
|
65
|
+
@keyframes winkIntroR {
|
|
66
|
+
0% { opacity: 0; }
|
|
67
|
+
50% { opacity: 1; }
|
|
68
|
+
65% { opacity: 0; }
|
|
69
|
+
80%, 100% { opacity: 1; }
|
|
70
|
+
}
|
|
71
|
+
` }), _jsxs("g", { transform: "matrix(2.49868,0,0,2.59811,-751.016,-1032.21)", children: [_jsx(BookBase, {}), _jsx("g", { transform: "matrix(4.36382e-17,-1.20783,0.431709,-2.43413e-17,255.145,1185.07)", children: _jsx("path", { d: "M494.703,576.843L494.703,600.541C494.703,613.235 491.16,623.542 486.796,623.542L345.922,623.542C341.559,623.542 338.016,613.235 338.016,600.541L338.016,576.843C338.016,564.149 341.559,553.843 345.922,553.843L486.796,553.843C491.16,553.843 494.703,564.149 494.703,576.843Z" }) }), _jsx("g", { transform: "matrix(0.555228,-0.128184,0.0544276,0.235752,324.508,560.439)", children: _jsx("g", { className: "rl-eye-l", children: _jsx("path", { d: "M494.703,588.218L494.703,589.166C494.703,608.138 487.93,623.542 479.588,623.542L353.131,623.542C344.789,623.542 338.016,608.138 338.016,589.166L338.016,588.218C338.016,569.246 344.789,553.843 353.131,553.843L479.588,553.843C487.93,553.843 494.703,569.246 494.703,588.218Z" }) }) }), _jsx("g", { transform: "matrix(0.555228,0.128184,-0.0544276,0.235752,231.691,453.111)", children: _jsx("g", { className: "rl-eye-r", children: _jsx("path", { d: "M494.703,588.218L494.703,589.166C494.703,608.138 487.93,623.542 479.588,623.542L353.131,623.542C344.789,623.542 338.016,608.138 338.016,589.166L338.016,588.218C338.016,569.246 344.789,553.843 353.131,553.843L479.588,553.843C487.93,553.843 494.703,569.246 494.703,588.218Z" }) }) })] })] }));
|
|
72
|
+
}
|
|
73
|
+
/* RoboSystems: infinity S with segment tracing the figure-8 */
|
|
74
|
+
function SystemsBook({ animate }) {
|
|
75
|
+
const isOnce = animate === 'once';
|
|
76
|
+
// Unique per instance so two RoboSystems logos on one page don't share a
|
|
77
|
+
// global mask id (which would break the second logo's trace animation).
|
|
78
|
+
const maskId = `rs-trace-${useId().replace(/:/g, '')}`;
|
|
79
|
+
const motionPath = 'M 16,16 C 22,8 32,10 30,16 C 28,22 22,24 16,16 C 10,8 0,10 2,16 C 4,22 10,24 16,16';
|
|
80
|
+
const infinityPath = 'M0,16C0,17.664 0.405,19.2 1.216,20.608C2.027,22.016 3.136,23.125 4.544,23.936C5.952,24.747 7.488,25.152 9.152,25.152C10.155,25.152 11.179,24.96 12.224,24.576C11.243,23.36 10.485,22.005 9.952,20.512C9.589,20.555 9.323,20.576 9.152,20.576C7.893,20.576 6.816,20.128 5.92,19.232C5.024,18.336 4.576,17.259 4.576,16C4.576,14.741 5.024,13.664 5.92,12.768C6.816,11.872 7.893,11.424 9.152,11.424C10.411,11.424 11.488,11.872 12.384,12.768C13.28,13.664 13.728,14.741 13.728,16C13.728,17.664 14.133,19.2 14.944,20.608C15.755,22.016 16.864,23.125 18.272,23.936C19.68,24.747 21.205,25.152 22.848,25.152C24.491,25.152 26.027,24.747 27.456,23.936C28.885,23.125 29.995,22.016 30.784,20.608C31.573,19.2 31.979,17.664 32,16C32.021,14.336 31.616,12.811 30.784,11.424C29.952,10.037 28.843,8.928 27.456,8.096C26.069,7.264 24.533,6.859 22.848,6.88C21.845,6.88 20.821,7.061 19.776,7.424C20.757,8.64 21.515,10.005 22.048,11.52C22.411,11.456 22.677,11.424 22.848,11.424C24.107,11.424 25.184,11.872 26.08,12.768C26.976,13.664 27.424,14.741 27.424,16C27.424,17.28 26.976,18.368 26.08,19.264C25.184,20.16 24.107,20.597 22.848,20.576C21.589,20.576 20.512,20.139 19.616,19.264C18.72,18.389 18.272,17.301 18.272,16C18.272,14.357 17.867,12.832 17.056,11.424C16.245,10.016 15.136,8.907 13.728,8.096C12.32,7.285 10.795,6.88 9.152,6.88C7.509,6.88 5.973,7.285 4.544,8.096C3.115,8.907 2.005,10.016 1.216,11.424C0.427,12.832 0.021,14.357 -0,16Z';
|
|
81
|
+
return (_jsxs(_Fragment, { children: [_jsxs("g", { transform: "matrix(2.49868,0,0,2.59811,-751.016,-1032.21)", children: [_jsx(BookBase, {}), _jsx("g", { transform: "matrix(-1.89816e-17,-0.22431,0.431709,1.61811e-17,255.945,699.671)", children: _jsx("path", { d: "M494.703,588.692C494.703,607.926 465.799,623.542 430.198,623.542L402.521,623.542C366.92,623.542 338.016,607.926 338.016,588.692C338.016,569.458 366.92,553.843 402.521,553.843L430.198,553.843C465.799,553.843 494.703,569.458 494.703,588.692Z" }) })] }), _jsxs("g", { transform: "matrix(12.8263,0,0,13.3096,313.735,516.868)", children: [_jsx("path", { d: infinityPath, fillRule: "nonzero", children: isOnce ? (_jsx("animate", { attributeName: "opacity", values: "1;0.15;0.15;1", keyTimes: "0;0.1;0.8;1", dur: "1.4s", fill: "freeze" })) : (_jsx("animate", { attributeName: "opacity", values: "1;0.15", dur: "0.3s", fill: "freeze" })) }), _jsx("defs", { children: _jsxs("mask", { id: maskId, maskUnits: "userSpaceOnUse", x: "-2", y: "5", width: "36", height: "22", children: [_jsx("rect", { x: "-2", y: "5", width: "36", height: "22", fill: "black" }), _jsx("circle", { r: "8", fill: "white", children: _jsx("animateMotion", { dur: isOnce ? '1.4s' : '1.2s', repeatCount: isOnce ? '1' : 'indefinite', fill: "freeze", path: motionPath }) })] }) }), _jsx("path", { d: infinityPath, mask: `url(#${maskId})`, fillRule: "nonzero" })] })] }));
|
|
82
|
+
}
|
|
83
|
+
export function AnimatedLogo({ className, animate = 'loop', app = CURRENT_APP, brand = false, }) {
|
|
84
|
+
return (_jsxs("svg", { viewBox: "0 0 1024 1024", fill: "currentColor", className: className, style: brand ? { color: BRAND_COLORS[app] } : undefined, role: "img", "aria-label": "Loading", fillRule: "evenodd", clipRule: "evenodd", shapeRendering: "geometricPrecision", children: [app === 'roboinvestor' && _jsx(InvestorBook, { animate: animate }), app === 'roboledger' && _jsx(LedgerBook, { animate: animate }), app === 'robosystems' && _jsx(SystemsBook, { animate: animate }), _jsx(GraphNodes, {})] }));
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The mark rendered as an app-icon: a white AnimatedLogo on the app's
|
|
88
|
+
* brand-gradient rounded chip. At small/icon sizes this reads far crisper than
|
|
89
|
+
* a brand-colored mark on a dark background, and it surfaces the brand color as
|
|
90
|
+
* a background element. Cross-app safe — renders the correct gradient for any
|
|
91
|
+
* `app` from inside any app, so the AppSwitcher shows three distinct chips.
|
|
92
|
+
*/
|
|
93
|
+
export function LogoBadge({ app = CURRENT_APP, animate = 'once', className, }) {
|
|
94
|
+
return (_jsx("span", { className: twMerge('inline-flex shrink-0 items-center justify-center rounded-xl', className), style: { background: BRAND_GRADIENTS[app] }, children: _jsx(AnimatedLogo, { app: app, animate: animate, className: "h-[68%] w-[68%] text-white" }) }));
|
|
95
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { AppName } from '../auth-core/types';
|
|
2
|
+
type SpinnerSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
3
|
+
interface SpinnerProps {
|
|
4
|
+
size?: SpinnerSize;
|
|
5
|
+
className?: string;
|
|
6
|
+
fullScreen?: boolean;
|
|
7
|
+
/** Accessible label for screen readers. Defaults to "Loading". */
|
|
8
|
+
'aria-label'?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The default app-wide loading indicator: a clean, brand-colored spinning ring.
|
|
12
|
+
*
|
|
13
|
+
* The ring color follows `currentColor` (defaults to the brand `primary`), so
|
|
14
|
+
* on a brand-filled surface like a `Button` you override it with the text
|
|
15
|
+
* color, e.g. `className="text-white"`. For high-impact, brand-centric loads
|
|
16
|
+
* (full-page shells, auth, major transitions) use `BrandSpinner` instead.
|
|
17
|
+
*/
|
|
18
|
+
export declare function Spinner({ size, className, fullScreen, 'aria-label': ariaLabel, }: SpinnerProps): import("react").JSX.Element;
|
|
19
|
+
interface BrandSpinnerProps {
|
|
20
|
+
size?: SpinnerSize;
|
|
21
|
+
className?: string;
|
|
22
|
+
fullScreen?: boolean;
|
|
23
|
+
app?: AppName;
|
|
24
|
+
/** Accessible label for screen readers. Defaults to "Loading". */
|
|
25
|
+
'aria-label'?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* High-impact, brand-centric loader: the app's animated logo, looping. Use
|
|
29
|
+
* sparingly — full-page initial loads, auth screens, major transitions — where
|
|
30
|
+
* the brand moment earns its keep. For routine button / inline / page loading,
|
|
31
|
+
* use the plain `Spinner`.
|
|
32
|
+
*
|
|
33
|
+
* Note: a given `size` renders LARGER here than on `Spinner` (the logo needs
|
|
34
|
+
* more visual weight to read) — e.g. `lg` is 80px vs the ring's 48px.
|
|
35
|
+
*/
|
|
36
|
+
export declare function BrandSpinner({ size, className, fullScreen, app, 'aria-label': ariaLabel, }: BrandSpinnerProps): import("react").JSX.Element;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
import { CURRENT_APP } from '../auth-core/config';
|
|
4
|
+
import { AnimatedLogo } from './Logo';
|
|
5
|
+
// Border width scales with diameter so the ring stays visually proportional.
|
|
6
|
+
const ringSizeClasses = {
|
|
7
|
+
xs: 'h-3.5 w-3.5 border-2',
|
|
8
|
+
sm: 'h-5 w-5 border-2',
|
|
9
|
+
md: 'h-8 w-8 border-[3px]',
|
|
10
|
+
lg: 'h-12 w-12 border-4',
|
|
11
|
+
xl: 'h-16 w-16 border-4',
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* The default app-wide loading indicator: a clean, brand-colored spinning ring.
|
|
15
|
+
*
|
|
16
|
+
* The ring color follows `currentColor` (defaults to the brand `primary`), so
|
|
17
|
+
* on a brand-filled surface like a `Button` you override it with the text
|
|
18
|
+
* color, e.g. `className="text-white"`. For high-impact, brand-centric loads
|
|
19
|
+
* (full-page shells, auth, major transitions) use `BrandSpinner` instead.
|
|
20
|
+
*/
|
|
21
|
+
export function Spinner({ size = 'md', className = '', fullScreen = false, 'aria-label': ariaLabel = 'Loading', }) {
|
|
22
|
+
const ring = (_jsx("span", { role: "status", "aria-label": ariaLabel, className: twMerge('text-primary-600 dark:text-primary-500 inline-block animate-spin rounded-full border-current border-t-transparent', ringSizeClasses[size], className) }));
|
|
23
|
+
if (!fullScreen)
|
|
24
|
+
return ring;
|
|
25
|
+
return (_jsx("div", { className: "flex min-h-screen items-center justify-center bg-zinc-50 dark:bg-black", children: ring }));
|
|
26
|
+
}
|
|
27
|
+
const logoSizeClasses = {
|
|
28
|
+
xs: 'h-6 w-6',
|
|
29
|
+
sm: 'h-8 w-8',
|
|
30
|
+
md: 'h-12 w-12',
|
|
31
|
+
lg: 'h-20 w-20',
|
|
32
|
+
xl: 'h-32 w-32',
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* High-impact, brand-centric loader: the app's animated logo, looping. Use
|
|
36
|
+
* sparingly — full-page initial loads, auth screens, major transitions — where
|
|
37
|
+
* the brand moment earns its keep. For routine button / inline / page loading,
|
|
38
|
+
* use the plain `Spinner`.
|
|
39
|
+
*
|
|
40
|
+
* Note: a given `size` renders LARGER here than on `Spinner` (the logo needs
|
|
41
|
+
* more visual weight to read) — e.g. `lg` is 80px vs the ring's 48px.
|
|
42
|
+
*/
|
|
43
|
+
export function BrandSpinner({ size = 'lg', className = '', fullScreen = false, app = CURRENT_APP, 'aria-label': ariaLabel = 'Loading', }) {
|
|
44
|
+
const logo = (_jsx("span", { role: "status", "aria-label": ariaLabel, children: _jsx(AnimatedLogo, { animate: "loop", app: app, className: twMerge('text-black dark:text-white', logoSizeClasses[size], className) }) }));
|
|
45
|
+
if (!fullScreen)
|
|
46
|
+
return logo;
|
|
47
|
+
return (_jsx("div", { className: "flex min-h-screen items-center justify-center bg-zinc-50 dark:bg-black", children: logo }));
|
|
48
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ComponentType, ReactNode } from 'react';
|
|
2
|
+
interface StatCardProps {
|
|
3
|
+
/** Short muted label above the value, e.g. "Total Graphs". */
|
|
4
|
+
label: string;
|
|
5
|
+
/** The metric value — a formatted string/number (include any unit, e.g. "1.2 GB"). */
|
|
6
|
+
value: ReactNode;
|
|
7
|
+
/** Optional icon, rendered muted and right-aligned. */
|
|
8
|
+
icon?: ComponentType<{
|
|
9
|
+
className?: string;
|
|
10
|
+
'aria-hidden'?: boolean | 'true';
|
|
11
|
+
}>;
|
|
12
|
+
/** Extra classes forwarded to the Card wrapper (e.g. a column span). */
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A dashboard stat tile: a muted label over a large bold value, in a Card.
|
|
17
|
+
* Drop several into a `grid` to form a metrics row. Pass an `icon` to get the
|
|
18
|
+
* value-left / icon-right layout.
|
|
19
|
+
*/
|
|
20
|
+
export declare function StatCard({ label, value, icon: Icon, className, }: StatCardProps): import("react").JSX.Element;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Card } from 'flowbite-react';
|
|
3
|
+
/**
|
|
4
|
+
* A dashboard stat tile: a muted label over a large bold value, in a Card.
|
|
5
|
+
* Drop several into a `grid` to form a metrics row. Pass an `icon` to get the
|
|
6
|
+
* value-left / icon-right layout.
|
|
7
|
+
*/
|
|
8
|
+
export function StatCard({ label, value, icon: Icon, className, }) {
|
|
9
|
+
return (_jsx(Card, { className: className, children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("div", { className: "text-sm font-medium text-gray-500 dark:text-gray-400", children: label }), _jsx("div", { className: "text-2xl font-bold text-gray-900 dark:text-white", children: value })] }), Icon && (_jsx(Icon, { className: "h-10 w-10 shrink-0 text-gray-300 dark:text-gray-600", "aria-hidden": "true" }))] }) }));
|
|
10
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface ApiKeyDisplayProps {
|
|
3
|
+
label: string;
|
|
4
|
+
value: string;
|
|
5
|
+
keyId?: string;
|
|
6
|
+
colorScheme?: 'blue' | 'green';
|
|
7
|
+
theme?: any;
|
|
8
|
+
className?: string;
|
|
9
|
+
onCopy?: () => void;
|
|
10
|
+
onReveal?: () => void;
|
|
11
|
+
onDownload?: () => void;
|
|
12
|
+
}
|
|
13
|
+
export declare const ApiKeyDisplay: React.FC<ApiKeyDisplayProps>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Label } from 'flowbite-react';
|
|
4
|
+
import { SecureApiKeyField } from './SecureApiKeyField';
|
|
5
|
+
export const ApiKeyDisplay = ({ label, value, keyId = 'api-key', theme, className = '', onCopy, onReveal, onDownload, }) => {
|
|
6
|
+
return (_jsxs("div", { className: className, children: [_jsx(Label, { theme: theme === null || theme === void 0 ? void 0 : theme.label, htmlFor: `display-${label}`, className: "text-base font-bold", children: label }), _jsx("div", { className: "mt-2", children: _jsx(SecureApiKeyField, { apiKey: value, keyId: keyId, keyName: label, onCopy: onCopy, onReveal: onReveal, onDownload: onDownload }) })] }));
|
|
7
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { ApiKey } from '../types';
|
|
3
|
+
export interface ApiKeyTableProps {
|
|
4
|
+
apiKeys: ApiKey[];
|
|
5
|
+
onRevokeKey: (keyId: string) => void;
|
|
6
|
+
theme?: any;
|
|
7
|
+
formatDate?: (date: Date | string | null | undefined) => string;
|
|
8
|
+
}
|
|
9
|
+
export declare const ApiKeyTable: React.FC<ApiKeyTableProps>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, Dropdown, DropdownItem, Table, TableBody, TableCell, TableHead, TableHeadCell, TableRow, } from 'flowbite-react';
|
|
3
|
+
import { HiCheckCircle, HiDotsVertical, HiExclamationCircle, HiKey, HiTrash, } from 'react-icons/hi';
|
|
4
|
+
const defaultFormatDate = (date) => {
|
|
5
|
+
if (!date)
|
|
6
|
+
return 'Never';
|
|
7
|
+
return new Date(date).toLocaleDateString('en-US', {
|
|
8
|
+
year: 'numeric',
|
|
9
|
+
month: 'short',
|
|
10
|
+
day: 'numeric',
|
|
11
|
+
});
|
|
12
|
+
};
|
|
13
|
+
export const ApiKeyTable = ({ apiKeys = [], onRevokeKey, theme, formatDate = defaultFormatDate, }) => {
|
|
14
|
+
// Defensive check to ensure apiKeys is always an array
|
|
15
|
+
const safeApiKeys = Array.isArray(apiKeys) ? apiKeys : [];
|
|
16
|
+
return (_jsx("div", { className: "overflow-x-auto", children: _jsxs(Table, { className: "table-fixed", children: [_jsxs(TableHead, { children: [_jsx(TableHeadCell, { className: "w-[40%]", children: "Name" }), _jsx(TableHeadCell, { className: "w-[15%] whitespace-nowrap", children: "Created" }), _jsx(TableHeadCell, { className: "w-[15%] whitespace-nowrap", children: "Last Used" }), _jsx(TableHeadCell, { className: "w-[15%] whitespace-nowrap", children: "Status" }), _jsx(TableHeadCell, { className: "w-[15%] text-right", children: "Actions" })] }), _jsx(TableBody, { className: "divide-y", children: safeApiKeys.map((key) => (_jsxs(TableRow, { className: "dark:border-zinc-700", children: [_jsx(TableCell, { className: "font-medium text-zinc-900 dark:text-zinc-100", children: _jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(HiKey, { className: "h-5 w-5 shrink-0 text-zinc-600 dark:text-zinc-400" }), _jsx("span", { className: "truncate", title: key.name, children: key.name }), key.isSystem && (_jsx("span", { className: "bg-primary-100 text-primary-800 dark:bg-primary-900 dark:text-primary-300 shrink-0 rounded-full px-2.5 py-0.5 text-xs font-medium", children: "System" }))] }) }), _jsx(TableCell, { className: "whitespace-nowrap text-zinc-600 dark:text-zinc-400", children: formatDate(key.createdAt) }), _jsx(TableCell, { className: "whitespace-nowrap text-zinc-600 dark:text-zinc-400", children: formatDate(key.lastUsedAt) }), _jsx(TableCell, { className: "whitespace-nowrap", children: key.isActive ? (_jsxs("div", { className: "inline-flex items-center rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-800 dark:bg-green-800 dark:text-green-100", children: [_jsx(HiCheckCircle, { className: "mr-1 h-3 w-3" }), "Active"] })) : (_jsxs("div", { className: "inline-flex items-center rounded-full bg-red-100 px-2 py-0.5 text-xs font-medium text-red-800 dark:bg-red-800 dark:text-red-100", children: [_jsx(HiExclamationCircle, { className: "mr-1 h-3 w-3" }), "Revoked"] })) }), _jsx(TableCell, { className: "text-right", children: _jsx("div", { className: "inline-flex justify-end", children: _jsx(Dropdown, { theme: theme === null || theme === void 0 ? void 0 : theme.dropdown, label: "", dismissOnClick: true, renderTrigger: () => (_jsx(Button, { theme: theme === null || theme === void 0 ? void 0 : theme.button, size: "sm", pill: true, className: "bg-zinc-100 text-zinc-900 hover:bg-zinc-200 dark:bg-zinc-700 dark:text-zinc-100 dark:hover:bg-zinc-600", children: _jsx(HiDotsVertical, { className: "h-4 w-4" }) })), children: _jsx(DropdownItem, { onClick: () => onRevokeKey(key.id), disabled: !key.isActive || key.isSystem, icon: HiTrash, className: "hover:bg-zinc-100 dark:hover:bg-zinc-700", children: "Revoke" }) }) }) })] }, key.id))) })] }) }));
|
|
17
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as SDK from '@robosystems/client';
|
|
4
|
+
import { Button } from 'flowbite-react';
|
|
5
|
+
import { useEffect, useState } from 'react';
|
|
6
|
+
import { HiKey, HiPlusCircle } from 'react-icons/hi';
|
|
7
|
+
import { Spinner } from '../Spinner';
|
|
8
|
+
import { SettingsCard } from '../forms/SettingsCard';
|
|
9
|
+
import { StatusAlert } from '../forms/StatusAlert';
|
|
10
|
+
import { ApiKeyTable } from './ApiKeyTable';
|
|
11
|
+
import { CreateApiKeyModal } from './CreateApiKeyModal';
|
|
12
|
+
export const ApiKeysCard = ({ theme, className = '', }) => {
|
|
13
|
+
const [apiKeys, setApiKeys] = useState([]);
|
|
14
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
15
|
+
const [isOpenCreateModal, setIsOpenCreateModal] = useState(false);
|
|
16
|
+
const [error, setError] = useState(null);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
fetchApiKeys();
|
|
19
|
+
}, []);
|
|
20
|
+
const fetchApiKeys = async () => {
|
|
21
|
+
var _a;
|
|
22
|
+
setIsLoading(true);
|
|
23
|
+
setError(null);
|
|
24
|
+
try {
|
|
25
|
+
// Always use SDK
|
|
26
|
+
const response = await SDK.listUserApiKeys();
|
|
27
|
+
const sdkKeys = ((_a = response.data) === null || _a === void 0 ? void 0 : _a.api_keys) || [];
|
|
28
|
+
// Map SDK response to component format
|
|
29
|
+
const keys = sdkKeys.map((key) => {
|
|
30
|
+
var _a, _b;
|
|
31
|
+
return ({
|
|
32
|
+
id: key.id,
|
|
33
|
+
name: key.name,
|
|
34
|
+
graphId: key.graph_id,
|
|
35
|
+
createdAt: key.created_at,
|
|
36
|
+
lastUsedAt: key.last_used_at,
|
|
37
|
+
expiresAt: key.expires_at,
|
|
38
|
+
isActive: (_a = key.is_active) !== null && _a !== void 0 ? _a : true,
|
|
39
|
+
isSystem: (_b = key.is_system) !== null && _b !== void 0 ? _b : false,
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
setApiKeys(keys);
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
setError('Failed to load API keys. Please try again.');
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
setIsLoading(false);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const handleCreateKey = async (data) => {
|
|
52
|
+
var _a;
|
|
53
|
+
// Always use SDK to create key
|
|
54
|
+
const response = await SDK.createUserApiKey({
|
|
55
|
+
body: {
|
|
56
|
+
name: data.name,
|
|
57
|
+
description: `API key for ${data.name}`,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
await fetchApiKeys(); // Refresh the list
|
|
61
|
+
// Map SDK response to component format
|
|
62
|
+
const responseData = response.data;
|
|
63
|
+
const apiKeyInfo = responseData === null || responseData === void 0 ? void 0 : responseData.api_key;
|
|
64
|
+
return {
|
|
65
|
+
id: (apiKeyInfo === null || apiKeyInfo === void 0 ? void 0 : apiKeyInfo.id) || '',
|
|
66
|
+
name: (apiKeyInfo === null || apiKeyInfo === void 0 ? void 0 : apiKeyInfo.name) || data.name,
|
|
67
|
+
key: (responseData === null || responseData === void 0 ? void 0 : responseData.key) || '', // The actual API key value
|
|
68
|
+
createdAt: (apiKeyInfo === null || apiKeyInfo === void 0 ? void 0 : apiKeyInfo.created_at) || new Date().toISOString(),
|
|
69
|
+
lastUsedAt: (apiKeyInfo === null || apiKeyInfo === void 0 ? void 0 : apiKeyInfo.last_used_at) || null,
|
|
70
|
+
expiresAt: null,
|
|
71
|
+
isActive: (_a = apiKeyInfo === null || apiKeyInfo === void 0 ? void 0 : apiKeyInfo.is_active) !== null && _a !== void 0 ? _a : true,
|
|
72
|
+
isSystem: false,
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
const handleRevokeKey = async (keyId) => {
|
|
76
|
+
try {
|
|
77
|
+
// Always use SDK to revoke key
|
|
78
|
+
await SDK.revokeUserApiKey({
|
|
79
|
+
path: { api_key_id: keyId },
|
|
80
|
+
});
|
|
81
|
+
await fetchApiKeys(); // Refresh the list
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
setError('Failed to revoke API key. Please try again.');
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const formatDate = (date) => {
|
|
88
|
+
if (!date)
|
|
89
|
+
return 'Never';
|
|
90
|
+
return new Date(date).toLocaleDateString('en-US', {
|
|
91
|
+
year: 'numeric',
|
|
92
|
+
month: 'short',
|
|
93
|
+
day: 'numeric',
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
return (_jsxs(SettingsCard, { title: "API Keys", description: "Manage your API keys for programmatic access", icon: HiKey, theme: theme === null || theme === void 0 ? void 0 : theme.card, className: className, children: [_jsx("div", { className: "mb-4 flex items-center justify-end", children: _jsxs(Button, { theme: theme === null || theme === void 0 ? void 0 : theme.button, color: "blue", onClick: () => setIsOpenCreateModal(true), children: [_jsx(HiPlusCircle, { className: "mr-2 h-5 w-5" }), "Create API Key"] }) }), error && (_jsx(StatusAlert, { type: "error", message: error, theme: theme === null || theme === void 0 ? void 0 : theme.alert })), isLoading ? (_jsx("div", { className: "flex justify-center py-4", children: _jsx(Spinner, { size: "lg" }) })) : !Array.isArray(apiKeys) || apiKeys.length === 0 ? (_jsxs("div", { className: "rounded-lg border border-zinc-200 bg-zinc-50 p-8 text-center dark:border-zinc-700 dark:bg-zinc-800", children: [_jsx(HiKey, { className: "mx-auto mb-3 h-12 w-12 text-zinc-400" }), _jsx("h3", { className: "mb-2 text-lg font-semibold text-zinc-900 dark:text-zinc-100", children: "No API keys yet" }), _jsx("p", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "Create an API key to access your graphs programmatically" })] })) : (_jsx(ApiKeyTable, { apiKeys: apiKeys, onRevokeKey: handleRevokeKey, theme: theme, formatDate: formatDate })), _jsx(CreateApiKeyModal, { isOpen: isOpenCreateModal, onClose: () => setIsOpenCreateModal(false), onCreateKey: handleCreateKey, theme: theme })] }));
|
|
97
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { ApiKeyWithValue } from '../types';
|
|
3
|
+
export interface CreateApiKeyModalProps {
|
|
4
|
+
isOpen: boolean;
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
onCreateKey: (data: {
|
|
7
|
+
name: string;
|
|
8
|
+
}) => Promise<ApiKeyWithValue>;
|
|
9
|
+
theme?: any;
|
|
10
|
+
}
|
|
11
|
+
export declare const CreateApiKeyModal: React.FC<CreateApiKeyModalProps>;
|