@wopr-network/platform-ui-core 1.27.8 → 1.27.9
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/next.config.ts +1 -2
- package/package.json +17 -17
- package/src/__tests__/account-switcher.test.tsx +21 -20
- package/src/__tests__/activity-page.test.tsx +2 -6
- package/src/__tests__/add-payment-method-dialog.test.tsx +9 -32
- package/src/__tests__/admin-api.test.ts +1 -6
- package/src/__tests__/admin-gpu-api.test.ts +1 -3
- package/src/__tests__/admin-marketplace-api.test.ts +1 -4
- package/src/__tests__/admin-middleware.test.ts +76 -83
- package/src/__tests__/affiliate-dashboard.test.tsx +3 -3
- package/src/__tests__/api-401-redirect.test.ts +46 -9
- package/src/__tests__/api-client.test.ts +3 -5
- package/src/__tests__/api-config.test.ts +22 -42
- package/src/__tests__/api-fleet-resources.test.ts +1 -2
- package/src/__tests__/api-fleet-trpc.test.ts +2 -8
- package/src/__tests__/api-null-guards.test.ts +3 -1
- package/src/__tests__/audit-log-table-pagination.test.tsx +2 -6
- package/src/__tests__/auth-password-reset.test.tsx +7 -21
- package/src/__tests__/auth-redirect.test.tsx +8 -2
- package/src/__tests__/auth.test.tsx +25 -23
- package/src/__tests__/auto-topup-card.test.tsx +4 -12
- package/src/__tests__/backups-tab.test.tsx +3 -4
- package/src/__tests__/billing-layout-nav-hidden.test.tsx +5 -37
- package/src/__tests__/billing-payment-org-invoices.test.tsx +2 -18
- package/src/__tests__/billing.test.tsx +8 -39
- package/src/__tests__/bot-settings/resources-tab.test.tsx +1 -3
- package/src/__tests__/bot-settings/storage-tab.test.tsx +1 -3
- package/src/__tests__/bot-settings/vps-upgrade-card.test.tsx +1 -3
- package/src/__tests__/bot-settings-restart.test.tsx +1 -3
- package/src/__tests__/bot-settings.test.tsx +2 -6
- package/src/__tests__/brand.test.ts +6 -26
- package/src/__tests__/buy-credits-panel.test.tsx +1 -3
- package/src/__tests__/buy-crypto-credits-panel.test.tsx +101 -119
- package/src/__tests__/capability-conflicts.test.ts +2 -8
- package/src/__tests__/capability-resolver.test.tsx +2 -12
- package/src/__tests__/channel-wizard.test.tsx +4 -17
- package/src/__tests__/chat/chat-panel.test.tsx +1 -4
- package/src/__tests__/chat-store.test.ts +5 -15
- package/src/__tests__/command-center.test.tsx +10 -12
- package/src/__tests__/compliance-retention-edit.test.tsx +3 -6
- package/src/__tests__/confirmation-tracker.test.tsx +3 -18
- package/src/__tests__/coupon-input.test.tsx +1 -3
- package/src/__tests__/create-instance.test.tsx +1 -3
- package/src/__tests__/credit-balance.test.tsx +4 -12
- package/src/__tests__/credits.test.tsx +32 -85
- package/src/__tests__/email-verification-banner.test.tsx +2 -6
- package/src/__tests__/error-boundaries.test.tsx +0 -1
- package/src/__tests__/fetch-pricing.test.ts +2 -1
- package/src/__tests__/field-oauth.test.tsx +2 -6
- package/src/__tests__/fixtures/mock-manifests-data.js +1 -3
- package/src/__tests__/fixtures/mock-manifests.ts +2 -4
- package/src/__tests__/fleet-health-timestamp.test.tsx +1 -8
- package/src/__tests__/fleet-health-update.test.tsx +1 -8
- package/src/__tests__/gpu-dashboard.test.tsx +2 -6
- package/src/__tests__/instance-detail.test.tsx +3 -9
- package/src/__tests__/instance-list.test.tsx +1 -5
- package/src/__tests__/layout-snapshots.test.tsx +64 -11
- package/src/__tests__/marketplace-admin.test.tsx +2 -6
- package/src/__tests__/marketplace.test.tsx +11 -35
- package/src/__tests__/merge-api-rates.test.ts +1 -6
- package/src/__tests__/middleware.test.ts +32 -219
- package/src/__tests__/next-config-headers.test.ts +1 -3
- package/src/__tests__/notifications.test.tsx +4 -11
- package/src/__tests__/oauth-buttons.test.tsx +36 -59
- package/src/__tests__/oauth-error-mapping.test.tsx +2 -6
- package/src/__tests__/observability.test.tsx +23 -36
- package/src/__tests__/onboarding-page.test.tsx +4 -6
- package/src/__tests__/org-billing-api.test.tsx +1 -6
- package/src/__tests__/plugin-install-flow.test.tsx +28 -58
- package/src/__tests__/plugin-registry.test.tsx +3 -11
- package/src/__tests__/plugin-tool-sync.test.ts +1 -3
- package/src/__tests__/plugins-catalog-error.test.tsx +2 -6
- package/src/__tests__/plugins-toggle-race.test.tsx +3 -5
- package/src/__tests__/portfolio-chart.test.tsx +2 -6
- package/src/__tests__/promotion-form.test.tsx +2 -6
- package/src/__tests__/promotions-list.test.tsx +1 -3
- package/src/__tests__/provider-key-api.test.ts +2 -1
- package/src/__tests__/resend-verification-button.test.tsx +8 -24
- package/src/__tests__/secrets-audit-pagination.test.tsx +1 -3
- package/src/__tests__/settings.test.tsx +11 -21
- package/src/__tests__/setup-checklist.test.tsx +3 -9
- package/src/__tests__/setup.ts +25 -6
- package/src/__tests__/snapshot-api.test.ts +2 -1
- package/src/__tests__/step-superpowers.test.tsx +1 -3
- package/src/__tests__/tenant-context.test.tsx +1 -6
- package/src/__tests__/tenant-keys-api.test.ts +3 -4
- package/src/__tests__/tenant-table-pagination.test.tsx +2 -6
- package/src/__tests__/terminal-log-cleanup.test.tsx +0 -1
- package/src/__tests__/transaction-history.test.tsx +190 -238
- package/src/__tests__/trpc-types.test.ts +2 -6
- package/src/__tests__/use-chat.test.ts +1 -3
- package/src/__tests__/use-plugin-setup-chat-stale-closure.test.ts +1 -4
- package/src/__tests__/use-sidecar-bridge.test.tsx +105 -0
- package/src/__tests__/use-webmcp.test.ts +1 -3
- package/src/__tests__/validate-elevenlabs-key.test.ts +2 -1
- package/src/__tests__/verify-page.test.tsx +4 -13
- package/src/__tests__/verify-redirect.test.tsx +2 -6
- package/src/app/(auth)/error.tsx +1 -7
- package/src/app/(auth)/forgot-password/page.tsx +4 -18
- package/src/app/(auth)/login/page.tsx +5 -22
- package/src/app/(auth)/reset-password/page.tsx +2 -12
- package/src/app/(auth)/signup/page.tsx +10 -44
- package/src/app/(auth)/verify/page.tsx +47 -0
- package/src/app/(dashboard)/billing/credits/page.tsx +14 -67
- package/src/app/(dashboard)/billing/error.tsx +2 -10
- package/src/app/(dashboard)/billing/layout.tsx +12 -62
- package/src/app/(dashboard)/billing/payment/page.tsx +17 -68
- package/src/app/(dashboard)/billing/plans/page.tsx +3 -9
- package/src/app/(dashboard)/billing/usage/hosted/page.tsx +8 -25
- package/src/app/(dashboard)/billing/usage/page.tsx +63 -103
- package/src/app/(dashboard)/changesets/[id]/changeset-detail-client.tsx +9 -27
- package/src/app/(dashboard)/changesets/[id]/error.tsx +2 -6
- package/src/app/(dashboard)/changesets/error.tsx +1 -7
- package/src/app/(dashboard)/chat/page.tsx +2 -6
- package/src/app/(dashboard)/dashboard/network/page.tsx +5 -19
- package/src/app/(dashboard)/error.tsx +1 -7
- package/src/app/(dashboard)/layout.tsx +15 -36
- package/src/app/(dashboard)/marketplace/[plugin]/page.tsx +14 -51
- package/src/app/(dashboard)/marketplace/error.tsx +1 -7
- package/src/app/(dashboard)/marketplace/page.tsx +6 -27
- package/src/app/(dashboard)/not-found.tsx +2 -5
- package/src/app/(dashboard)/onboarding/page.tsx +5 -22
- package/src/app/(dashboard)/settings/account/page.tsx +1 -6
- package/src/app/(dashboard)/settings/activity/page.tsx +8 -34
- package/src/app/(dashboard)/settings/api-keys/page.tsx +15 -60
- package/src/app/(dashboard)/settings/brain/page.tsx +9 -31
- package/src/app/(dashboard)/settings/error.tsx +2 -10
- package/src/app/(dashboard)/settings/notifications/page.tsx +2 -6
- package/src/app/(dashboard)/settings/org/page.tsx +13 -56
- package/src/app/(dashboard)/settings/page.tsx +1 -0
- package/src/app/(dashboard)/settings/profile/page.tsx +126 -73
- package/src/app/(dashboard)/settings/providers/page.tsx +21 -78
- package/src/app/(dashboard)/settings/secrets/page.tsx +13 -58
- package/src/app/(dashboard)/settings/security/page.tsx +31 -111
- package/src/app/admin/email-templates/email-templates-client.tsx +15 -58
- package/src/app/admin/error.tsx +1 -7
- package/src/app/admin/fleet-updates/error.tsx +1 -7
- package/src/app/admin/fleet-updates/fleet-updates-client.tsx +10 -50
- package/src/app/admin/layout.tsx +4 -0
- package/src/app/admin/payment-methods/page.tsx +9 -38
- package/src/app/admin/products/error.tsx +2 -7
- package/src/app/admin/products/page.tsx +1 -4
- package/src/app/admin/promotions/[id]/page.tsx +9 -38
- package/src/app/admin/promotions/page.tsx +9 -36
- package/src/app/admin/rate-overrides/page.tsx +9 -45
- package/src/app/auth/callback/[provider]/page.tsx +1 -8
- package/src/app/auth/verify/page.tsx +9 -36
- package/src/app/channels/error.tsx +2 -10
- package/src/app/channels/layout.tsx +9 -0
- package/src/app/channels/page.tsx +8 -20
- package/src/app/channels/setup/[plugin]/page.tsx +3 -5
- package/src/app/error.tsx +1 -7
- package/src/app/fleet/error.tsx +1 -7
- package/src/app/fleet/layout.tsx +5 -0
- package/src/app/fleet/settings/page.tsx +1 -3
- package/src/app/global-error.tsx +2 -10
- package/src/app/globals.css +1 -4
- package/src/app/instances/[id]/instance-detail-client.tsx +51 -125
- package/src/app/instances/error.tsx +2 -10
- package/src/app/instances/instance-list-client.tsx +20 -69
- package/src/app/instances/layout.tsx +9 -0
- package/src/app/instances/new/create-instance-client.tsx +10 -31
- package/src/app/layout.tsx +2 -10
- package/src/app/not-found.tsx +1 -3
- package/src/app/page.tsx +1 -2
- package/src/app/plugins/error.tsx +2 -10
- package/src/app/plugins/layout.tsx +5 -0
- package/src/app/plugins/page.tsx +16 -48
- package/src/app/pricing/error.tsx +1 -7
- package/src/app/privacy/page.tsx +93 -150
- package/src/app/status/error.tsx +1 -7
- package/src/app/terms/page.tsx +89 -144
- package/src/components/account-switcher.tsx +25 -52
- package/src/components/admin/accounting-dashboard.tsx +1 -3
- package/src/components/admin/admin-guard.tsx +1 -3
- package/src/components/admin/admin-nav.tsx +1 -3
- package/src/components/admin/affiliate-dashboard.tsx +25 -94
- package/src/components/admin/audit-log-table.tsx +13 -49
- package/src/components/admin/billing-health-dashboard.tsx +7 -25
- package/src/components/admin/bulk-actions-bar.test.tsx +1 -7
- package/src/components/admin/bulk-actions-bar.tsx +1 -3
- package/src/components/admin/bulk-export-dialog.test.tsx +1 -7
- package/src/components/admin/bulk-export-dialog.tsx +6 -32
- package/src/components/admin/bulk-grant-dialog.test.tsx +2 -6
- package/src/components/admin/bulk-grant-dialog.tsx +4 -15
- package/src/components/admin/bulk-preview-dialog.tsx +3 -12
- package/src/components/admin/bulk-reactivate-dialog.tsx +1 -7
- package/src/components/admin/bulk-select-all-banner.tsx +1 -6
- package/src/components/admin/bulk-suspend-dialog.tsx +5 -12
- package/src/components/admin/bulk-undo-toast.tsx +1 -2
- package/src/components/admin/compliance-dashboard.tsx +31 -101
- package/src/components/admin/gpu-dashboard.tsx +21 -70
- package/src/components/admin/grant-credits-dialog.tsx +4 -17
- package/src/components/admin/incident-dashboard.tsx +10 -25
- package/src/components/admin/inference-dashboard.tsx +14 -54
- package/src/components/admin/marketplace-admin.tsx +18 -60
- package/src/components/admin/migrations-dashboard.tsx +9 -42
- package/src/components/admin/onboarding-dashboard.tsx +14 -64
- package/src/components/admin/pool-config-dashboard.tsx +4 -10
- package/src/components/admin/products/fleet-form.tsx +2 -11
- package/src/components/admin/products/nav-editor.tsx +3 -10
- package/src/components/admin/promotions/promotion-form.tsx +9 -42
- package/src/components/admin/roles-dashboard.tsx +7 -34
- package/src/components/admin/suspend-dialog.tsx +4 -11
- package/src/components/admin/tenant-notes-panel.tsx +1 -3
- package/src/components/admin/tenant-row-actions.tsx +4 -20
- package/src/components/admin/tenant-table.tsx +12 -49
- package/src/components/auth/auth-redirect.tsx +11 -3
- package/src/components/auth/email-verification-result-banner.tsx +1 -3
- package/src/components/auth/resend-verification-button.tsx +2 -10
- package/src/components/auth/wopr-wordmark.tsx +1 -3
- package/src/components/billing/add-payment-method-dialog.tsx +1 -2
- package/src/components/billing/affiliate-dashboard.tsx +4 -16
- package/src/components/billing/amount-selector.tsx +1 -3
- package/src/components/billing/auto-topup-card.tsx +2 -11
- package/src/components/billing/buy-credits-panel.tsx +4 -14
- package/src/components/billing/byok-callout.tsx +6 -8
- package/src/components/billing/confirmation-tracker.tsx +4 -14
- package/src/components/billing/credit-balance-badge.tsx +22 -0
- package/src/components/billing/credit-balance.tsx +3 -9
- package/src/components/billing/crypto-checkout.tsx +5 -24
- package/src/components/billing/degraded-state-banner.tsx +1 -3
- package/src/components/billing/deposit-view.tsx +301 -41
- package/src/components/billing/dividend-banner.tsx +1 -3
- package/src/components/billing/dividend-eligibility.tsx +3 -12
- package/src/components/billing/dividend-pool-stats.tsx +6 -20
- package/src/components/billing/first-dividend-dialog.tsx +2 -2
- package/src/components/billing/org-billing-page.tsx +8 -31
- package/src/components/billing/payment-method-picker.tsx +2 -10
- package/src/components/billing/suspension-banner.tsx +2 -7
- package/src/components/billing/transaction-history.tsx +10 -58
- package/src/components/billing/unified-checkout.tsx +547 -0
- package/src/components/bot-settings/backups-tab.tsx +9 -33
- package/src/components/bot-settings/bot-settings-client.tsx +32 -134
- package/src/components/bot-settings/resources-tab.tsx +2 -9
- package/src/components/bot-settings/storage-tab.tsx +19 -48
- package/src/components/bot-settings/vps-info-panel.tsx +3 -11
- package/src/components/bot-settings/vps-upgrade-card.tsx +3 -4
- package/src/components/brand-hydrator.tsx +13 -0
- package/src/components/channel-wizard/field-interactive.tsx +1 -3
- package/src/components/channel-wizard/field-qr.tsx +10 -39
- package/src/components/channel-wizard/step-renderer.tsx +5 -28
- package/src/components/channel-wizard/wizard.tsx +6 -31
- package/src/components/chat/chat-message.tsx +1 -4
- package/src/components/chat/chat-panel.tsx +4 -18
- package/src/components/chat/chat-widget.tsx +3 -14
- package/src/components/dashboard/command-center.tsx +15 -61
- package/src/components/fleet/update-settings-card.tsx +7 -23
- package/src/components/instance-update-banner.tsx +130 -0
- package/src/components/instances/friends-tab.test.tsx +2 -9
- package/src/components/instances/friends-tab.tsx +18 -74
- package/src/components/instances/update-available-badge.tsx +2 -11
- package/src/components/landing/hero.tsx +3 -9
- package/src/components/landing/landing-page.tsx +1 -3
- package/src/components/landing/portfolio-chart.tsx +4 -9
- package/src/components/landing/story-sections.tsx +1 -3
- package/src/components/landing/terminal-sequence.tsx +4 -17
- package/src/components/marketplace/empty-state.tsx +2 -6
- package/src/components/marketplace/first-visit-hero.tsx +1 -3
- package/src/components/marketplace/install-wizard.tsx +20 -77
- package/src/components/marketplace/marketplace-tabs.tsx +1 -4
- package/src/components/marketplace/plugin-card.tsx +2 -9
- package/src/components/marketplace/superpower-content.tsx +1 -3
- package/src/components/marketplace/terminal-search.tsx +2 -8
- package/src/components/oauth-buttons.tsx +29 -14
- package/src/components/observability/fleet-health.tsx +5 -18
- package/src/components/observability/health-overview.tsx +7 -20
- package/src/components/observability/logs-viewer.tsx +8 -32
- package/src/components/observability/metrics-dashboard.tsx +2 -15
- package/src/components/onboarding/fallback-setup.tsx +6 -25
- package/src/components/onboarding/setup-checklist.tsx +18 -51
- package/src/components/onboarding/step-superpowers.tsx +1 -4
- package/src/components/plugin-setup/setup-chat-panel.tsx +6 -22
- package/src/components/pricing/dividend-calculator.tsx +6 -12
- package/src/components/pricing/dividend-stats.tsx +5 -17
- package/src/components/pricing/pricing-page.tsx +17 -36
- package/src/components/settings/create-org-wizard.tsx +2 -5
- package/src/components/sidebar.tsx +7 -42
- package/src/components/sidecar-frame.tsx +78 -0
- package/src/components/status/status-page.tsx +6 -28
- package/src/components/ui/alert-dialog.tsx +8 -25
- package/src/components/ui/badge.tsx +2 -8
- package/src/components/ui/banner.tsx +1 -6
- package/src/components/ui/card.tsx +5 -24
- package/src/components/ui/checkbox.tsx +1 -5
- package/src/components/ui/collapsible.tsx +3 -8
- package/src/components/ui/dialog.tsx +4 -10
- package/src/components/ui/dropdown-menu.tsx +9 -18
- package/src/components/ui/form.tsx +2 -16
- package/src/components/ui/popover.tsx +3 -23
- package/src/components/ui/progress.tsx +1 -5
- package/src/components/ui/radio-group.tsx +3 -15
- package/src/components/ui/select.tsx +4 -17
- package/src/components/ui/sheet.tsx +5 -19
- package/src/components/ui/skeleton.tsx +1 -7
- package/src/components/ui/table.tsx +5 -22
- package/src/components/ui/tabs.tsx +3 -13
- package/src/components/ui/tooltip.tsx +1 -1
- package/src/components/unified-sidebar.tsx +493 -0
- package/src/hooks/__tests__/use-fleet-sse.test.ts +1 -4
- package/src/hooks/__tests__/use-save-queue.test.ts +2 -8
- package/src/hooks/use-credit-balance.ts +27 -0
- package/src/hooks/use-my-org-role.ts +1 -3
- package/src/hooks/use-plugin-registry.ts +8 -14
- package/src/hooks/use-plugin-setup-chat.ts +2 -5
- package/src/hooks/use-sidecar-bridge.tsx +148 -0
- package/src/hooks/use-webmcp.ts +1 -4
- package/src/lib/__tests__/admin-api.test.ts +1 -3
- package/src/lib/__tests__/api-bot-crud.test.ts +8 -18
- package/src/lib/__tests__/api-fetch.test.ts +4 -16
- package/src/lib/__tests__/org-billing-api.test.ts +1 -3
- package/src/lib/__tests__/pricing-data.test.ts +0 -8
- package/src/lib/__tests__/settings-api.test.ts +1 -3
- package/src/lib/admin-affiliate-api.ts +2 -7
- package/src/lib/admin-api.ts +6 -26
- package/src/lib/admin-incident-api.ts +11 -19
- package/src/lib/admin-marketplace-api.ts +1 -5
- package/src/lib/api-config.test.ts +5 -50
- package/src/lib/api.ts +143 -122
- package/src/lib/auth-client.ts +1 -2
- package/src/lib/bot-settings-data.ts +11 -36
- package/src/lib/brand-config.ts +56 -115
- package/src/lib/brand.ts +2 -15
- package/src/lib/chat/use-chat.ts +2 -7
- package/src/lib/cost-comparison-data.test.ts +1 -3
- package/src/lib/cost-comparison-data.ts +1 -4
- package/src/lib/errors.ts +1 -4
- package/src/lib/fetch-utils.test.ts +26 -9
- package/src/lib/fetch-utils.ts +40 -11
- package/src/lib/logger.ts +2 -0
- package/src/lib/marketplace-data.ts +3 -11
- package/src/lib/oauth-errors.ts +2 -4
- package/src/lib/onboarding-data.ts +3 -11
- package/src/lib/org-api.ts +2 -10
- package/src/lib/org-billing-api.ts +5 -19
- package/src/lib/plugin/tool-definitions.ts +1 -2
- package/src/lib/require-auth.ts +57 -0
- package/src/lib/settings-api.ts +1 -4
- package/src/lib/sidecar-routes.ts +43 -0
- package/src/lib/trpc-server.ts +49 -0
- package/src/lib/trpc-types.ts +4 -6
- package/src/lib/trpc.tsx +12 -4
- package/src/lib/validate-redirect-url.ts +1 -4
- package/src/lib/webmcp/marketplace-onboarding-tools.ts +6 -16
- package/src/lib/webmcp/register.ts +1 -4
- package/src/lib/webmcp/tools.ts +2 -9
- package/src/proxy.ts +35 -212
- package/src/types/missing-deps.d.ts +2 -8
- package/tsconfig.json +1 -8
- package/biome.json +0 -52
- package/src/__tests__/__snapshots__/layout-snapshots.test.tsx.snap +0 -741
- package/src/__tests__/billing-byok-callout.test.tsx +0 -76
- package/src/lib/__tests__/__snapshots__/pricing-data.test.ts.snap +0 -112
|
@@ -61,17 +61,14 @@ function BulkSuspendDialog({
|
|
|
61
61
|
<DialogHeader>
|
|
62
62
|
<DialogTitle className="flex items-center gap-2">
|
|
63
63
|
<ShieldBan className="size-5 text-amber-500" />
|
|
64
|
-
<span className="text-amber-500">Suspend</span>{" "}
|
|
65
|
-
|
|
64
|
+
<span className="text-amber-500">Suspend</span> <span className="font-semibold">{selectedCount}</span>{" "}
|
|
65
|
+
accounts
|
|
66
66
|
</DialogTitle>
|
|
67
|
-
<DialogDescription>
|
|
68
|
-
Suspended accounts will immediately lose platform access.
|
|
69
|
-
</DialogDescription>
|
|
67
|
+
<DialogDescription>Suspended accounts will immediately lose platform access.</DialogDescription>
|
|
70
68
|
</DialogHeader>
|
|
71
69
|
|
|
72
70
|
<Banner variant="warning">
|
|
73
|
-
This will immediately prevent these accounts from using the platform. Users will be locked
|
|
74
|
-
out.
|
|
71
|
+
This will immediately prevent these accounts from using the platform. Users will be locked out.
|
|
75
72
|
</Banner>
|
|
76
73
|
|
|
77
74
|
<div className="flex flex-col gap-4">
|
|
@@ -113,11 +110,7 @@ function BulkSuspendDialog({
|
|
|
113
110
|
<Button variant="outline" onClick={() => handleOpenChange(false)} disabled={isLoading}>
|
|
114
111
|
Cancel
|
|
115
112
|
</Button>
|
|
116
|
-
<Button
|
|
117
|
-
variant="destructive"
|
|
118
|
-
onClick={handleConfirm}
|
|
119
|
-
disabled={!reason.trim() || isLoading}
|
|
120
|
-
>
|
|
113
|
+
<Button variant="destructive" onClick={handleConfirm} disabled={!reason.trim() || isLoading}>
|
|
121
114
|
Suspend {selectedCount} accounts
|
|
122
115
|
</Button>
|
|
123
116
|
</DialogFooter>
|
|
@@ -59,8 +59,7 @@ function BulkUndoToast({
|
|
|
59
59
|
|
|
60
60
|
const progressPercent = (remainingMs / windowMs) * 100;
|
|
61
61
|
|
|
62
|
-
const barColor =
|
|
63
|
-
remainingMs > 180_000 ? "bg-terminal" : remainingMs > 60_000 ? "bg-amber-500" : "bg-red-500";
|
|
62
|
+
const barColor = remainingMs > 180_000 ? "bg-terminal" : remainingMs > 60_000 ? "bg-amber-500" : "bg-red-500";
|
|
64
63
|
|
|
65
64
|
return (
|
|
66
65
|
<AnimatePresence>
|
|
@@ -14,23 +14,10 @@ import {
|
|
|
14
14
|
} from "@/components/ui/dialog";
|
|
15
15
|
import { Input } from "@/components/ui/input";
|
|
16
16
|
import { Label } from "@/components/ui/label";
|
|
17
|
-
import {
|
|
18
|
-
Select,
|
|
19
|
-
SelectContent,
|
|
20
|
-
SelectItem,
|
|
21
|
-
SelectTrigger,
|
|
22
|
-
SelectValue,
|
|
23
|
-
} from "@/components/ui/select";
|
|
17
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
|
24
18
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
25
19
|
import { Switch } from "@/components/ui/switch";
|
|
26
|
-
import {
|
|
27
|
-
Table,
|
|
28
|
-
TableBody,
|
|
29
|
-
TableCell,
|
|
30
|
-
TableHead,
|
|
31
|
-
TableHeader,
|
|
32
|
-
TableRow,
|
|
33
|
-
} from "@/components/ui/table";
|
|
20
|
+
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
|
34
21
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
35
22
|
import { Textarea } from "@/components/ui/textarea";
|
|
36
23
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
|
@@ -106,8 +93,7 @@ function complianceActionBadgeClasses(action: string): string {
|
|
|
106
93
|
return "bg-destructive/15 text-red-400 border border-destructive/20";
|
|
107
94
|
if (action.includes("trigger_export") || action.includes("complete_export"))
|
|
108
95
|
return "bg-terminal/15 text-terminal border border-terminal/20";
|
|
109
|
-
if (action.includes("policy_update"))
|
|
110
|
-
return "bg-amber-500/15 text-amber-400 border border-amber-500/20";
|
|
96
|
+
if (action.includes("policy_update")) return "bg-amber-500/15 text-amber-400 border border-amber-500/20";
|
|
111
97
|
return "bg-secondary text-muted-foreground border border-border";
|
|
112
98
|
}
|
|
113
99
|
|
|
@@ -202,9 +188,7 @@ function TriggerDialog({
|
|
|
202
188
|
<Dialog open={open} onOpenChange={handleOpenChange}>
|
|
203
189
|
<DialogContent>
|
|
204
190
|
<DialogHeader>
|
|
205
|
-
<DialogTitle className="text-base font-semibold uppercase tracking-wider">
|
|
206
|
-
{title}
|
|
207
|
-
</DialogTitle>
|
|
191
|
+
<DialogTitle className="text-base font-semibold uppercase tracking-wider">{title}</DialogTitle>
|
|
208
192
|
<DialogDescription>{description}</DialogDescription>
|
|
209
193
|
</DialogHeader>
|
|
210
194
|
<div className="space-y-3">
|
|
@@ -270,12 +254,7 @@ function Pagination({
|
|
|
270
254
|
>
|
|
271
255
|
Previous
|
|
272
256
|
</Button>
|
|
273
|
-
<Button
|
|
274
|
-
variant="ghost"
|
|
275
|
-
size="sm"
|
|
276
|
-
disabled={!hasMore}
|
|
277
|
-
onClick={() => onNavigate(offset + PAGE_SIZE)}
|
|
278
|
-
>
|
|
257
|
+
<Button variant="ghost" size="sm" disabled={!hasMore} onClick={() => onNavigate(offset + PAGE_SIZE)}>
|
|
279
258
|
Next
|
|
280
259
|
</Button>
|
|
281
260
|
<Button
|
|
@@ -417,8 +396,8 @@ function DeletionRequestsTab() {
|
|
|
417
396
|
<span className="animate-ellipsis" />
|
|
418
397
|
</p>
|
|
419
398
|
<p className="mt-2 text-xs text-muted-foreground">
|
|
420
|
-
The admin.complianceDeletionRequests procedure is not yet available. This section will
|
|
421
|
-
|
|
399
|
+
The admin.complianceDeletionRequests procedure is not yet available. This section will activate
|
|
400
|
+
automatically once deployed.
|
|
422
401
|
</p>
|
|
423
402
|
</div>
|
|
424
403
|
<TriggerDialog
|
|
@@ -485,27 +464,15 @@ function DeletionRequestsTab() {
|
|
|
485
464
|
<Table>
|
|
486
465
|
<TableHeader>
|
|
487
466
|
<TableRow className="bg-secondary crt-scanlines">
|
|
488
|
-
<TableHead className="text-xs font-medium uppercase tracking-wider w-[140px]">
|
|
489
|
-
|
|
490
|
-
</TableHead>
|
|
491
|
-
<TableHead className="text-xs font-medium uppercase tracking-wider">
|
|
492
|
-
Requested By
|
|
493
|
-
</TableHead>
|
|
467
|
+
<TableHead className="text-xs font-medium uppercase tracking-wider w-[140px]">Tenant ID</TableHead>
|
|
468
|
+
<TableHead className="text-xs font-medium uppercase tracking-wider">Requested By</TableHead>
|
|
494
469
|
<TableHead className="text-xs font-medium uppercase tracking-wider">Status</TableHead>
|
|
495
|
-
<TableHead className="text-xs font-medium uppercase tracking-wider">
|
|
496
|
-
|
|
497
|
-
</TableHead>
|
|
498
|
-
<TableHead className="text-xs font-medium uppercase tracking-wider">
|
|
499
|
-
Created
|
|
500
|
-
</TableHead>
|
|
501
|
-
<TableHead className="text-xs font-medium uppercase tracking-wider w-[80px]">
|
|
502
|
-
Actions
|
|
503
|
-
</TableHead>
|
|
470
|
+
<TableHead className="text-xs font-medium uppercase tracking-wider">Delete After</TableHead>
|
|
471
|
+
<TableHead className="text-xs font-medium uppercase tracking-wider">Created</TableHead>
|
|
472
|
+
<TableHead className="text-xs font-medium uppercase tracking-wider w-[80px]">Actions</TableHead>
|
|
504
473
|
</TableRow>
|
|
505
474
|
</TableHeader>
|
|
506
|
-
<TableBody
|
|
507
|
-
className={cn("transition-opacity duration-150", loading && data && "opacity-60")}
|
|
508
|
-
>
|
|
475
|
+
<TableBody className={cn("transition-opacity duration-150", loading && data && "opacity-60")}>
|
|
509
476
|
{loading && !data ? (
|
|
510
477
|
<SkeletonRows cols={6} />
|
|
511
478
|
) : filteredRequests.length === 0 && !loading ? (
|
|
@@ -697,8 +664,8 @@ function DataExportsTab() {
|
|
|
697
664
|
<span className="animate-ellipsis" />
|
|
698
665
|
</p>
|
|
699
666
|
<p className="mt-2 text-xs text-muted-foreground">
|
|
700
|
-
The admin.complianceExportRequests procedure is not yet available. This section will
|
|
701
|
-
|
|
667
|
+
The admin.complianceExportRequests procedure is not yet available. This section will activate automatically
|
|
668
|
+
once deployed.
|
|
702
669
|
</p>
|
|
703
670
|
</div>
|
|
704
671
|
<TriggerDialog
|
|
@@ -765,25 +732,15 @@ function DataExportsTab() {
|
|
|
765
732
|
<Table>
|
|
766
733
|
<TableHeader>
|
|
767
734
|
<TableRow className="bg-secondary crt-scanlines">
|
|
768
|
-
<TableHead className="text-xs font-medium uppercase tracking-wider w-[140px]">
|
|
769
|
-
|
|
770
|
-
</TableHead>
|
|
771
|
-
<TableHead className="text-xs font-medium uppercase tracking-wider">
|
|
772
|
-
Requested By
|
|
773
|
-
</TableHead>
|
|
735
|
+
<TableHead className="text-xs font-medium uppercase tracking-wider w-[140px]">Tenant ID</TableHead>
|
|
736
|
+
<TableHead className="text-xs font-medium uppercase tracking-wider">Requested By</TableHead>
|
|
774
737
|
<TableHead className="text-xs font-medium uppercase tracking-wider">Status</TableHead>
|
|
775
738
|
<TableHead className="text-xs font-medium uppercase tracking-wider">Format</TableHead>
|
|
776
|
-
<TableHead className="text-xs font-medium uppercase tracking-wider">
|
|
777
|
-
|
|
778
|
-
</TableHead>
|
|
779
|
-
<TableHead className="text-xs font-medium uppercase tracking-wider w-[80px]">
|
|
780
|
-
Actions
|
|
781
|
-
</TableHead>
|
|
739
|
+
<TableHead className="text-xs font-medium uppercase tracking-wider">Created</TableHead>
|
|
740
|
+
<TableHead className="text-xs font-medium uppercase tracking-wider w-[80px]">Actions</TableHead>
|
|
782
741
|
</TableRow>
|
|
783
742
|
</TableHeader>
|
|
784
|
-
<TableBody
|
|
785
|
-
className={cn("transition-opacity duration-150", loading && data && "opacity-60")}
|
|
786
|
-
>
|
|
743
|
+
<TableBody className={cn("transition-opacity duration-150", loading && data && "opacity-60")}>
|
|
787
744
|
{loading && !data ? (
|
|
788
745
|
<SkeletonRows cols={6} />
|
|
789
746
|
) : filteredRequests.length === 0 && !loading ? (
|
|
@@ -882,9 +839,7 @@ function ComplianceAuditTab() {
|
|
|
882
839
|
setLoadError(false);
|
|
883
840
|
try {
|
|
884
841
|
const since =
|
|
885
|
-
dateRange === "all"
|
|
886
|
-
? undefined
|
|
887
|
-
: new Date(Date.now() - Number(dateRange) * 86400000).toISOString();
|
|
842
|
+
dateRange === "all" ? undefined : new Date(Date.now() - Number(dateRange) * 86400000).toISOString();
|
|
888
843
|
const result = await fetchAuditLog({
|
|
889
844
|
limit: PAGE_SIZE,
|
|
890
845
|
offset: newOffset,
|
|
@@ -976,21 +931,13 @@ function ComplianceAuditTab() {
|
|
|
976
931
|
<Table>
|
|
977
932
|
<TableHeader>
|
|
978
933
|
<TableRow className="bg-secondary crt-scanlines">
|
|
979
|
-
<TableHead className="text-xs font-medium uppercase tracking-wider w-[100px]">
|
|
980
|
-
Time
|
|
981
|
-
</TableHead>
|
|
934
|
+
<TableHead className="text-xs font-medium uppercase tracking-wider w-[100px]">Time</TableHead>
|
|
982
935
|
<TableHead className="text-xs font-medium uppercase tracking-wider">Action</TableHead>
|
|
983
|
-
<TableHead className="text-xs font-medium uppercase tracking-wider">
|
|
984
|
-
|
|
985
|
-
</TableHead>
|
|
986
|
-
<TableHead className="text-xs font-medium uppercase tracking-wider">
|
|
987
|
-
Details
|
|
988
|
-
</TableHead>
|
|
936
|
+
<TableHead className="text-xs font-medium uppercase tracking-wider">Resource</TableHead>
|
|
937
|
+
<TableHead className="text-xs font-medium uppercase tracking-wider">Details</TableHead>
|
|
989
938
|
</TableRow>
|
|
990
939
|
</TableHeader>
|
|
991
|
-
<TableBody
|
|
992
|
-
className={cn("transition-opacity duration-150", loading && data && "opacity-60")}
|
|
993
|
-
>
|
|
940
|
+
<TableBody className={cn("transition-opacity duration-150", loading && data && "opacity-60")}>
|
|
994
941
|
{loading && !data ? (
|
|
995
942
|
<SkeletonRows cols={4} rows={8} />
|
|
996
943
|
) : filteredEvents.length === 0 && !loading ? (
|
|
@@ -1017,12 +964,8 @@ function ComplianceAuditTab() {
|
|
|
1017
964
|
</span>
|
|
1018
965
|
</TableCell>
|
|
1019
966
|
<TableCell className="text-sm">
|
|
1020
|
-
<span className="text-xs uppercase tracking-wide text-muted-foreground">
|
|
1021
|
-
|
|
1022
|
-
</span>{" "}
|
|
1023
|
-
<span className="font-mono text-xs">
|
|
1024
|
-
{event.resourceName ?? event.resourceId}
|
|
1025
|
-
</span>
|
|
967
|
+
<span className="text-xs uppercase tracking-wide text-muted-foreground">{event.resourceType}</span>{" "}
|
|
968
|
+
<span className="font-mono text-xs">{event.resourceName ?? event.resourceId}</span>
|
|
1026
969
|
</TableCell>
|
|
1027
970
|
<TableCell className="text-xs text-muted-foreground max-w-[300px] truncate">
|
|
1028
971
|
{event.details ?? "\u2014"}
|
|
@@ -1034,14 +977,7 @@ function ComplianceAuditTab() {
|
|
|
1034
977
|
</Table>
|
|
1035
978
|
</div>
|
|
1036
979
|
|
|
1037
|
-
{data && (
|
|
1038
|
-
<Pagination
|
|
1039
|
-
offset={offset}
|
|
1040
|
-
total={data.total}
|
|
1041
|
-
hasMore={data.hasMore}
|
|
1042
|
-
onNavigate={(o) => load(o)}
|
|
1043
|
-
/>
|
|
1044
|
-
)}
|
|
980
|
+
{data && <Pagination offset={offset} total={data.total} hasMore={data.hasMore} onNavigate={(o) => load(o)} />}
|
|
1045
981
|
</div>
|
|
1046
982
|
);
|
|
1047
983
|
}
|
|
@@ -1098,9 +1034,7 @@ function EditRetentionPolicyDialog({
|
|
|
1098
1034
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
1099
1035
|
<DialogContent>
|
|
1100
1036
|
<DialogHeader>
|
|
1101
|
-
<DialogTitle className="text-base font-semibold uppercase tracking-wider">
|
|
1102
|
-
Edit Retention Policy
|
|
1103
|
-
</DialogTitle>
|
|
1037
|
+
<DialogTitle className="text-base font-semibold uppercase tracking-wider">Edit Retention Policy</DialogTitle>
|
|
1104
1038
|
<DialogDescription>Update retention settings for {policy.dataType}</DialogDescription>
|
|
1105
1039
|
</DialogHeader>
|
|
1106
1040
|
<div className="space-y-4 py-2">
|
|
@@ -1215,9 +1149,7 @@ function RetentionPoliciesTab() {
|
|
|
1215
1149
|
key={policy.dataType}
|
|
1216
1150
|
className="rounded-sm border border-terminal/10 bg-card p-4 transition-colors duration-150 hover:border-terminal/20"
|
|
1217
1151
|
>
|
|
1218
|
-
<h3 className="text-sm font-semibold uppercase tracking-wider text-foreground">
|
|
1219
|
-
{policy.dataType}
|
|
1220
|
-
</h3>
|
|
1152
|
+
<h3 className="text-sm font-semibold uppercase tracking-wider text-foreground">{policy.dataType}</h3>
|
|
1221
1153
|
<dl className="mt-3 space-y-1.5 text-xs font-mono text-muted-foreground">
|
|
1222
1154
|
<div className="flex justify-between">
|
|
1223
1155
|
<dt>Retention period</dt>
|
|
@@ -1271,9 +1203,7 @@ function RetentionPoliciesTab() {
|
|
|
1271
1203
|
if (!open) setEditingPolicy(null);
|
|
1272
1204
|
}}
|
|
1273
1205
|
onSaved={(updated) => {
|
|
1274
|
-
setPolicies((prev) =>
|
|
1275
|
-
prev ? prev.map((p) => (p.dataType === updated.dataType ? updated : p)) : prev,
|
|
1276
|
-
);
|
|
1206
|
+
setPolicies((prev) => (prev ? prev.map((p) => (p.dataType === updated.dataType ? updated : p)) : prev));
|
|
1277
1207
|
setEditingPolicy(null);
|
|
1278
1208
|
}}
|
|
1279
1209
|
/>
|
|
@@ -73,9 +73,7 @@ function KpiCard({ label, value, subtext, valueClassName, loading, index }: KpiC
|
|
|
73
73
|
{loading ? (
|
|
74
74
|
<div className="h-8 w-24 bg-muted animate-pulse rounded-sm" />
|
|
75
75
|
) : (
|
|
76
|
-
<div className={cn("text-2xl font-bold tabular-nums", valueClassName ?? "text-foreground")}>
|
|
77
|
-
{value}
|
|
78
|
-
</div>
|
|
76
|
+
<div className={cn("text-2xl font-bold tabular-nums", valueClassName ?? "text-foreground")}>{value}</div>
|
|
79
77
|
)}
|
|
80
78
|
{subtext && <div className="text-xs text-muted-foreground mt-1">{subtext}</div>}
|
|
81
79
|
</motion.div>
|
|
@@ -122,9 +120,7 @@ function ProvisionForm({ regions, sizes, onProvision, onCancel }: ProvisionFormP
|
|
|
122
120
|
transition={{ duration: 0.2 }}
|
|
123
121
|
className="mx-6 mb-4 bg-card border border-terminal/20 rounded-sm p-4"
|
|
124
122
|
>
|
|
125
|
-
<div className="text-xs uppercase tracking-widest text-muted-foreground mb-3">
|
|
126
|
-
Provision New GPU Node
|
|
127
|
-
</div>
|
|
123
|
+
<div className="text-xs uppercase tracking-widest text-muted-foreground mb-3">Provision New GPU Node</div>
|
|
128
124
|
<form onSubmit={handleSubmit} className="grid grid-cols-4 gap-3 items-end">
|
|
129
125
|
<div>
|
|
130
126
|
<label htmlFor="gpu-name" className="text-xs text-muted-foreground block mb-1">
|
|
@@ -143,12 +139,7 @@ function ProvisionForm({ regions, sizes, onProvision, onCancel }: ProvisionFormP
|
|
|
143
139
|
<label htmlFor="gpu-region" className="text-xs text-muted-foreground block mb-1">
|
|
144
140
|
Region
|
|
145
141
|
</label>
|
|
146
|
-
<select
|
|
147
|
-
id="gpu-region"
|
|
148
|
-
className={inputCls}
|
|
149
|
-
value={region}
|
|
150
|
-
onChange={(e) => setRegion(e.target.value)}
|
|
151
|
-
>
|
|
142
|
+
<select id="gpu-region" className={inputCls} value={region} onChange={(e) => setRegion(e.target.value)}>
|
|
152
143
|
{regions.map((r) => (
|
|
153
144
|
<option key={r.slug} value={r.slug} disabled={!r.available}>
|
|
154
145
|
{r.name}
|
|
@@ -160,12 +151,7 @@ function ProvisionForm({ regions, sizes, onProvision, onCancel }: ProvisionFormP
|
|
|
160
151
|
<label htmlFor="gpu-size" className="text-xs text-muted-foreground block mb-1">
|
|
161
152
|
Size
|
|
162
153
|
</label>
|
|
163
|
-
<select
|
|
164
|
-
id="gpu-size"
|
|
165
|
-
className={inputCls}
|
|
166
|
-
value={size}
|
|
167
|
-
onChange={(e) => setSize(e.target.value)}
|
|
168
|
-
>
|
|
154
|
+
<select id="gpu-size" className={inputCls} value={size} onChange={(e) => setSize(e.target.value)}>
|
|
169
155
|
{sizes.map((s) => (
|
|
170
156
|
<option key={s.slug} value={s.slug}>
|
|
171
157
|
{s.name} — ${s.priceMonthly}/mo
|
|
@@ -202,11 +188,7 @@ export function GpuDashboard() {
|
|
|
202
188
|
setLoading(true);
|
|
203
189
|
setError(null);
|
|
204
190
|
try {
|
|
205
|
-
const [nodeList, regionList, sizeList] = await Promise.all([
|
|
206
|
-
listGpuNodes(),
|
|
207
|
-
listGpuRegions(),
|
|
208
|
-
listGpuSizes(),
|
|
209
|
-
]);
|
|
191
|
+
const [nodeList, regionList, sizeList] = await Promise.all([listGpuNodes(), listGpuRegions(), listGpuSizes()]);
|
|
210
192
|
setNodes(nodeList);
|
|
211
193
|
setRegions(regionList);
|
|
212
194
|
setSizes(sizeList);
|
|
@@ -269,18 +251,13 @@ export function GpuDashboard() {
|
|
|
269
251
|
// KPI computations
|
|
270
252
|
const runningNodes = nodes.filter((n) => n.status === "running");
|
|
271
253
|
const errorNodes = nodes.filter((n) => n.status === "error");
|
|
272
|
-
const utilizationValues = runningNodes
|
|
273
|
-
.filter((n) => n.utilization != null)
|
|
274
|
-
.map((n) => n.utilization as number);
|
|
254
|
+
const utilizationValues = runningNodes.filter((n) => n.utilization != null).map((n) => n.utilization as number);
|
|
275
255
|
const avgUtilization =
|
|
276
|
-
utilizationValues.length > 0
|
|
277
|
-
? utilizationValues.reduce((a, b) => a + b, 0) / utilizationValues.length
|
|
278
|
-
: null;
|
|
256
|
+
utilizationValues.length > 0 ? utilizationValues.reduce((a, b) => a + b, 0) / utilizationValues.length : null;
|
|
279
257
|
const tempValues = runningNodes
|
|
280
258
|
.filter((n) => n.temperatureCelsius != null)
|
|
281
259
|
.map((n) => n.temperatureCelsius as number);
|
|
282
|
-
const avgTemp =
|
|
283
|
-
tempValues.length > 0 ? tempValues.reduce((a, b) => a + b, 0) / tempValues.length : null;
|
|
260
|
+
const avgTemp = tempValues.length > 0 ? tempValues.reduce((a, b) => a + b, 0) / tempValues.length : null;
|
|
284
261
|
|
|
285
262
|
return (
|
|
286
263
|
<div className="space-y-4 max-w-7xl mx-auto">
|
|
@@ -301,12 +278,7 @@ export function GpuDashboard() {
|
|
|
301
278
|
<RefreshCw size={12} className={loading ? "animate-spin" : ""} />
|
|
302
279
|
Refresh
|
|
303
280
|
</Button>
|
|
304
|
-
<Button
|
|
305
|
-
type="button"
|
|
306
|
-
size="xs"
|
|
307
|
-
onClick={() => setShowProvision((v) => !v)}
|
|
308
|
-
className="font-mono"
|
|
309
|
-
>
|
|
281
|
+
<Button type="button" size="xs" onClick={() => setShowProvision((v) => !v)} className="font-mono">
|
|
310
282
|
<Zap size={12} />
|
|
311
283
|
Provision Node
|
|
312
284
|
</Button>
|
|
@@ -323,12 +295,7 @@ export function GpuDashboard() {
|
|
|
323
295
|
|
|
324
296
|
{/* KPI Cards */}
|
|
325
297
|
<div className="grid grid-cols-2 xl:grid-cols-4 gap-3 px-6">
|
|
326
|
-
<KpiCard
|
|
327
|
-
index={0}
|
|
328
|
-
label="Total Nodes"
|
|
329
|
-
value={loading ? "" : String(nodes.length)}
|
|
330
|
-
loading={loading}
|
|
331
|
-
/>
|
|
298
|
+
<KpiCard index={0} label="Total Nodes" value={loading ? "" : String(nodes.length)} loading={loading} />
|
|
332
299
|
<KpiCard
|
|
333
300
|
index={1}
|
|
334
301
|
label="Running"
|
|
@@ -340,9 +307,7 @@ export function GpuDashboard() {
|
|
|
340
307
|
index={2}
|
|
341
308
|
label="Avg Utilization"
|
|
342
309
|
value={loading ? "" : avgUtilization != null ? `${avgUtilization.toFixed(1)}%` : "—"}
|
|
343
|
-
valueClassName={
|
|
344
|
-
avgUtilization != null && avgUtilization > 85 ? "text-amber-400" : "text-foreground"
|
|
345
|
-
}
|
|
310
|
+
valueClassName={avgUtilization != null && avgUtilization > 85 ? "text-amber-400" : "text-foreground"}
|
|
346
311
|
subtext="running nodes"
|
|
347
312
|
loading={loading}
|
|
348
313
|
/>
|
|
@@ -380,9 +345,7 @@ export function GpuDashboard() {
|
|
|
380
345
|
className="mx-6 bg-card border border-border rounded-sm"
|
|
381
346
|
>
|
|
382
347
|
<div className="px-4 py-3 border-b border-border">
|
|
383
|
-
<div className="text-xs uppercase tracking-widest text-muted-foreground">
|
|
384
|
-
GPU Inventory
|
|
385
|
-
</div>
|
|
348
|
+
<div className="text-xs uppercase tracking-widest text-muted-foreground">GPU Inventory</div>
|
|
386
349
|
</div>
|
|
387
350
|
|
|
388
351
|
{loading ? (
|
|
@@ -399,9 +362,7 @@ export function GpuDashboard() {
|
|
|
399
362
|
))}
|
|
400
363
|
</div>
|
|
401
364
|
) : nodes.length === 0 ? (
|
|
402
|
-
<div className="text-center text-muted-foreground text-xs py-12">
|
|
403
|
-
No GPU nodes provisioned
|
|
404
|
-
</div>
|
|
365
|
+
<div className="text-center text-muted-foreground text-xs py-12">No GPU nodes provisioned</div>
|
|
405
366
|
) : (
|
|
406
367
|
<>
|
|
407
368
|
{/* Table header */}
|
|
@@ -439,9 +400,7 @@ export function GpuDashboard() {
|
|
|
439
400
|
<div
|
|
440
401
|
className={cn(
|
|
441
402
|
"w-24 text-right tabular-nums text-sm",
|
|
442
|
-
node.utilization != null && node.utilization > 85
|
|
443
|
-
? "text-amber-400"
|
|
444
|
-
: "text-foreground",
|
|
403
|
+
node.utilization != null && node.utilization > 85 ? "text-amber-400" : "text-foreground",
|
|
445
404
|
)}
|
|
446
405
|
>
|
|
447
406
|
{node.utilization != null ? `${node.utilization}%` : "—"}
|
|
@@ -459,9 +418,7 @@ export function GpuDashboard() {
|
|
|
459
418
|
{node.temperatureCelsius != null ? `${node.temperatureCelsius}°C` : "—"}
|
|
460
419
|
</div>
|
|
461
420
|
<div className="flex-1 text-right tabular-nums text-sm text-muted-foreground">
|
|
462
|
-
{vramPct != null
|
|
463
|
-
? `${vramPct} (${node.memoryUsedMib} / ${node.memoryTotalMib} MiB)`
|
|
464
|
-
: "—"}
|
|
421
|
+
{vramPct != null ? `${vramPct} (${node.memoryUsedMib} / ${node.memoryTotalMib} MiB)` : "—"}
|
|
465
422
|
</div>
|
|
466
423
|
<div className="w-28 flex justify-end gap-1">
|
|
467
424
|
<Button
|
|
@@ -495,25 +452,19 @@ export function GpuDashboard() {
|
|
|
495
452
|
|
|
496
453
|
{/* Allocation — stubbed */}
|
|
497
454
|
<div className="mx-6 bg-card border border-border rounded-sm p-4">
|
|
498
|
-
<div className="text-xs uppercase tracking-widest text-muted-foreground mb-2">
|
|
499
|
-
Allocation / Tenant Mapping
|
|
500
|
-
</div>
|
|
455
|
+
<div className="text-xs uppercase tracking-widest text-muted-foreground mb-2">Allocation / Tenant Mapping</div>
|
|
501
456
|
<p className="text-xs text-muted-foreground">
|
|
502
|
-
Tenant-to-GPU allocation endpoints are not yet available. This section will display which
|
|
503
|
-
|
|
504
|
-
API.
|
|
457
|
+
Tenant-to-GPU allocation endpoints are not yet available. This section will display which bots and tenants are
|
|
458
|
+
assigned to each GPU node once the backend implements the allocation API.
|
|
505
459
|
</p>
|
|
506
460
|
</div>
|
|
507
461
|
|
|
508
462
|
{/* Configuration — stubbed */}
|
|
509
463
|
<div className="mx-6 mb-6 bg-card border border-border rounded-sm p-4">
|
|
510
|
-
<div className="text-xs uppercase tracking-widest text-muted-foreground mb-2">
|
|
511
|
-
GPU Configuration
|
|
512
|
-
</div>
|
|
464
|
+
<div className="text-xs uppercase tracking-widest text-muted-foreground mb-2">GPU Configuration</div>
|
|
513
465
|
<p className="text-xs text-muted-foreground">
|
|
514
|
-
GPU capability enable/disable and allocation limit configuration endpoints are not yet
|
|
515
|
-
|
|
516
|
-
API.
|
|
466
|
+
GPU capability enable/disable and allocation limit configuration endpoints are not yet available. This section
|
|
467
|
+
will provide controls once the backend exposes the configuration API.
|
|
517
468
|
</p>
|
|
518
469
|
</div>
|
|
519
470
|
|
|
@@ -29,12 +29,7 @@ interface GrantCreditsDialogProps {
|
|
|
29
29
|
onComplete: () => void;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export function GrantCreditsDialog({
|
|
33
|
-
open,
|
|
34
|
-
onOpenChange,
|
|
35
|
-
user,
|
|
36
|
-
onComplete,
|
|
37
|
-
}: GrantCreditsDialogProps) {
|
|
32
|
+
export function GrantCreditsDialog({ open, onOpenChange, user, onComplete }: GrantCreditsDialogProps) {
|
|
38
33
|
const [amount, setAmount] = useState("");
|
|
39
34
|
const [reason, setReason] = useState("");
|
|
40
35
|
const [submitting, setSubmitting] = useState(false);
|
|
@@ -70,9 +65,7 @@ export function GrantCreditsDialog({
|
|
|
70
65
|
<div className="space-y-2">
|
|
71
66
|
<Label htmlFor="grant-amount">Amount</Label>
|
|
72
67
|
<div className="relative">
|
|
73
|
-
<span className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground">
|
|
74
|
-
$
|
|
75
|
-
</span>
|
|
68
|
+
<span className="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground">$</span>
|
|
76
69
|
<Input
|
|
77
70
|
id="grant-amount"
|
|
78
71
|
type="number"
|
|
@@ -105,14 +98,8 @@ export function GrantCreditsDialog({
|
|
|
105
98
|
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
|
106
99
|
Cancel
|
|
107
100
|
</Button>
|
|
108
|
-
<Button
|
|
109
|
-
|
|
110
|
-
disabled={!isValidAmount || !reason.trim() || submitting}
|
|
111
|
-
onClick={handleGrant}
|
|
112
|
-
>
|
|
113
|
-
{submitting
|
|
114
|
-
? "Granting..."
|
|
115
|
-
: `Grant ${isValidAmount ? formatCreditStandard(parsedAmount) : "$0.00"}`}
|
|
101
|
+
<Button variant="terminal" disabled={!isValidAmount || !reason.trim() || submitting} onClick={handleGrant}>
|
|
102
|
+
{submitting ? "Granting..." : `Grant ${isValidAmount ? formatCreditStandard(parsedAmount) : "$0.00"}`}
|
|
116
103
|
</Button>
|
|
117
104
|
</DialogFooter>
|
|
118
105
|
</DialogContent>
|
|
@@ -37,10 +37,7 @@ function SeverityBadge({ severity }: { severity: IncidentSeverity }) {
|
|
|
37
37
|
SEV3: "bg-yellow-500/15 text-yellow-400 border-yellow-500/20",
|
|
38
38
|
};
|
|
39
39
|
return (
|
|
40
|
-
<Badge
|
|
41
|
-
variant="secondary"
|
|
42
|
-
className={cn("text-xs px-2 py-0.5 border font-mono", colors[severity])}
|
|
43
|
-
>
|
|
40
|
+
<Badge variant="secondary" className={cn("text-xs px-2 py-0.5 border font-mono", colors[severity])}>
|
|
44
41
|
{severity}
|
|
45
42
|
</Badge>
|
|
46
43
|
);
|
|
@@ -134,9 +131,7 @@ function SeverityClassifierPanel() {
|
|
|
134
131
|
type="number"
|
|
135
132
|
min={0}
|
|
136
133
|
value={signals.dlqDepth}
|
|
137
|
-
onChange={(e) =>
|
|
138
|
-
setSignals((s) => ({ ...s, dlqDepth: Number.parseInt(e.target.value, 10) || 0 }))
|
|
139
|
-
}
|
|
134
|
+
onChange={(e) => setSignals((s) => ({ ...s, dlqDepth: Number.parseInt(e.target.value, 10) || 0 }))}
|
|
140
135
|
className="h-7 text-xs"
|
|
141
136
|
/>
|
|
142
137
|
</div>
|
|
@@ -272,14 +267,13 @@ function EscalationPanel() {
|
|
|
272
267
|
<div className="space-y-2">
|
|
273
268
|
{result.contacts.map((contact: EscalationContact, i: number) => (
|
|
274
269
|
<div
|
|
270
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: static list, index key is safe
|
|
275
271
|
key={`${contact.role}-${i}`}
|
|
276
272
|
className="flex items-center justify-between py-2 border-b border-border/50 last:border-0 text-sm"
|
|
277
273
|
>
|
|
278
274
|
<div>
|
|
279
275
|
<span className="font-medium">{contact.role}</span>
|
|
280
|
-
{contact.name &&
|
|
281
|
-
<span className="text-muted-foreground ml-2">— {contact.name}</span>
|
|
282
|
-
)}
|
|
276
|
+
{contact.name && <span className="text-muted-foreground ml-2">— {contact.name}</span>}
|
|
283
277
|
</div>
|
|
284
278
|
<div className="text-xs text-muted-foreground">
|
|
285
279
|
{contact.method} · within {contact.within}
|
|
@@ -346,6 +340,7 @@ function ResponseProcedurePanel() {
|
|
|
346
340
|
{procedure && (
|
|
347
341
|
<ol className="space-y-2 list-decimal list-inside">
|
|
348
342
|
{procedure.steps.map((step: string, index: number) => (
|
|
343
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: static list, index key is safe
|
|
349
344
|
<li key={`${index}-${step.slice(0, 20)}`} className="text-sm text-muted-foreground">
|
|
350
345
|
{step}
|
|
351
346
|
</li>
|
|
@@ -442,9 +437,7 @@ function CommunicationPanel() {
|
|
|
442
437
|
/>
|
|
443
438
|
</div>
|
|
444
439
|
<div className="space-y-1">
|
|
445
|
-
<Label className="text-xs text-muted-foreground">
|
|
446
|
-
Affected Systems (comma-separated)
|
|
447
|
-
</Label>
|
|
440
|
+
<Label className="text-xs text-muted-foreground">Affected Systems (comma-separated)</Label>
|
|
448
441
|
<Input
|
|
449
442
|
value={affectedSystemsText}
|
|
450
443
|
onChange={(e) => setAffectedSystemsText(e.target.value)}
|
|
@@ -477,17 +470,13 @@ function CommunicationPanel() {
|
|
|
477
470
|
{templates && (
|
|
478
471
|
<div className="space-y-3">
|
|
479
472
|
<div>
|
|
480
|
-
<div className="text-xs font-medium text-muted-foreground mb-1">
|
|
481
|
-
Customer Template
|
|
482
|
-
</div>
|
|
473
|
+
<div className="text-xs font-medium text-muted-foreground mb-1">Customer Template</div>
|
|
483
474
|
<pre className="text-xs bg-muted/30 rounded p-3 whitespace-pre-wrap font-mono border border-border/50">
|
|
484
475
|
{templates.customer}
|
|
485
476
|
</pre>
|
|
486
477
|
</div>
|
|
487
478
|
<div>
|
|
488
|
-
<div className="text-xs font-medium text-muted-foreground mb-1">
|
|
489
|
-
Internal Template
|
|
490
|
-
</div>
|
|
479
|
+
<div className="text-xs font-medium text-muted-foreground mb-1">Internal Template</div>
|
|
491
480
|
<pre className="text-xs bg-muted/30 rounded p-3 whitespace-pre-wrap font-mono border border-border/50">
|
|
492
481
|
{templates.internal}
|
|
493
482
|
</pre>
|
|
@@ -628,9 +617,7 @@ function PostmortemPanel() {
|
|
|
628
617
|
/>
|
|
629
618
|
</div>
|
|
630
619
|
<div className="space-y-1">
|
|
631
|
-
<Label className="text-xs text-muted-foreground">
|
|
632
|
-
Affected Systems (comma-separated)
|
|
633
|
-
</Label>
|
|
620
|
+
<Label className="text-xs text-muted-foreground">Affected Systems (comma-separated)</Label>
|
|
634
621
|
<Input
|
|
635
622
|
value={affectedSystemsText}
|
|
636
623
|
onChange={(e) => setAffectedSystemsText(e.target.value)}
|
|
@@ -696,9 +683,7 @@ export function IncidentDashboard() {
|
|
|
696
683
|
onClick={() => setTab(t.id)}
|
|
697
684
|
className={cn(
|
|
698
685
|
"text-sm px-3 py-1.5 rounded-sm transition-colors",
|
|
699
|
-
tab === t.id
|
|
700
|
-
? "bg-terminal/10 text-terminal font-medium"
|
|
701
|
-
: "text-muted-foreground hover:text-foreground",
|
|
686
|
+
tab === t.id ? "bg-terminal/10 text-terminal font-medium" : "text-muted-foreground hover:text-foreground",
|
|
702
687
|
)}
|
|
703
688
|
>
|
|
704
689
|
{t.label}
|