@nexus-ai-fs/tui 0.9.18
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/README.md +30 -0
- package/package.json +48 -0
- package/src/app.tsx +349 -0
- package/src/index.tsx +137 -0
- package/src/opentui-env.d.ts +61 -0
- package/src/panels/access/access-panel.tsx +597 -0
- package/src/panels/access/alert-list.tsx +77 -0
- package/src/panels/access/constraint-creator.tsx +128 -0
- package/src/panels/access/constraint-list.tsx +72 -0
- package/src/panels/access/credential-list.tsx +68 -0
- package/src/panels/access/delegation-chain-view.tsx +110 -0
- package/src/panels/access/delegation-completer.tsx +120 -0
- package/src/panels/access/delegation-creator.tsx +237 -0
- package/src/panels/access/delegation-list.tsx +74 -0
- package/src/panels/access/fraud-score-view.tsx +94 -0
- package/src/panels/access/manifest-creator.tsx +167 -0
- package/src/panels/access/manifest-list.tsx +105 -0
- package/src/panels/access/namespace-config-view.tsx +525 -0
- package/src/panels/access/permission-checker.tsx +231 -0
- package/src/panels/agents/agent-status-view.tsx +196 -0
- package/src/panels/agents/agents-panel.tsx +493 -0
- package/src/panels/agents/delegation-list.tsx +154 -0
- package/src/panels/agents/inbox-view.tsx +96 -0
- package/src/panels/agents/trajectories-tab.tsx +40 -0
- package/src/panels/api-console/api-console-panel.tsx +189 -0
- package/src/panels/api-console/codegen-viewer.tsx +36 -0
- package/src/panels/api-console/codegen.ts +112 -0
- package/src/panels/api-console/endpoint-list.tsx +57 -0
- package/src/panels/api-console/request-builder.tsx +69 -0
- package/src/panels/api-console/response-viewer.tsx +54 -0
- package/src/panels/connectors/available-tab.tsx +357 -0
- package/src/panels/connectors/connector-row.tsx +121 -0
- package/src/panels/connectors/connectors-panel.tsx +88 -0
- package/src/panels/connectors/error-parser.ts +116 -0
- package/src/panels/connectors/mounted-tab.tsx +179 -0
- package/src/panels/connectors/skills-tab.tsx +235 -0
- package/src/panels/connectors/template-generator.ts +211 -0
- package/src/panels/connectors/write-tab.tsx +514 -0
- package/src/panels/events/audit-tab.tsx +69 -0
- package/src/panels/events/audit-trail.tsx +75 -0
- package/src/panels/events/connector-detail.tsx +49 -0
- package/src/panels/events/connector-list.tsx +73 -0
- package/src/panels/events/connectors-tab.tsx +92 -0
- package/src/panels/events/event-replay.tsx +80 -0
- package/src/panels/events/events-panel.tsx +414 -0
- package/src/panels/events/events-tab.tsx +212 -0
- package/src/panels/events/lock-list.tsx +54 -0
- package/src/panels/events/locks-tab.tsx +103 -0
- package/src/panels/events/mcl-replay.tsx +77 -0
- package/src/panels/events/mcl-tab.tsx +83 -0
- package/src/panels/events/operations-tab-wrapper.tsx +62 -0
- package/src/panels/events/operations-tab.tsx +41 -0
- package/src/panels/events/replay-tab.tsx +76 -0
- package/src/panels/events/secrets-audit.tsx +64 -0
- package/src/panels/events/secrets-tab.tsx +75 -0
- package/src/panels/events/subscription-list.tsx +54 -0
- package/src/panels/events/subscriptions-tab.tsx +82 -0
- package/src/panels/files/file-aspects.tsx +93 -0
- package/src/panels/files/file-editor.tsx +160 -0
- package/src/panels/files/file-explorer-keybindings.ts +468 -0
- package/src/panels/files/file-explorer-panel.tsx +545 -0
- package/src/panels/files/file-lineage.tsx +163 -0
- package/src/panels/files/file-list-item.tsx +28 -0
- package/src/panels/files/file-metadata.tsx +62 -0
- package/src/panels/files/file-preview.tsx +108 -0
- package/src/panels/files/file-schema.tsx +89 -0
- package/src/panels/files/file-tree-node.tsx +44 -0
- package/src/panels/files/file-tree.tsx +169 -0
- package/src/panels/files/share-links-tab.tsx +33 -0
- package/src/panels/files/uploads-tab.tsx +45 -0
- package/src/panels/payments/approval-list.tsx +83 -0
- package/src/panels/payments/balance-card.tsx +43 -0
- package/src/panels/payments/budget-card.tsx +70 -0
- package/src/panels/payments/payments-panel.tsx +451 -0
- package/src/panels/payments/policy-list.tsx +64 -0
- package/src/panels/payments/reservation-list.tsx +78 -0
- package/src/panels/payments/transaction-list.tsx +103 -0
- package/src/panels/payments/transfer-form.tsx +109 -0
- package/src/panels/search/column-search.tsx +79 -0
- package/src/panels/search/knowledge-view.tsx +100 -0
- package/src/panels/search/memory-list.tsx +197 -0
- package/src/panels/search/playbook-list.tsx +77 -0
- package/src/panels/search/rlm-answer-view.tsx +105 -0
- package/src/panels/search/search-panel.tsx +405 -0
- package/src/panels/search/search-results.tsx +116 -0
- package/src/panels/stack/stack-panel.tsx +474 -0
- package/src/panels/versions/conflicts-tab.tsx +59 -0
- package/src/panels/versions/entry-detail.tsx +89 -0
- package/src/panels/versions/transaction-actions.tsx +34 -0
- package/src/panels/versions/transaction-list.tsx +90 -0
- package/src/panels/versions/versions-panel.tsx +276 -0
- package/src/panels/workflows/execution-list.tsx +102 -0
- package/src/panels/workflows/scheduler-view.tsx +135 -0
- package/src/panels/workflows/workflow-list.tsx +88 -0
- package/src/panels/workflows/workflows-panel.tsx +295 -0
- package/src/panels/zones/brick-detail.tsx +136 -0
- package/src/panels/zones/brick-list.tsx +56 -0
- package/src/panels/zones/cache-tab.tsx +118 -0
- package/src/panels/zones/drift-view.tsx +97 -0
- package/src/panels/zones/mcp-mounts-tab.tsx +38 -0
- package/src/panels/zones/memories-tab.tsx +37 -0
- package/src/panels/zones/reindex-status.tsx +84 -0
- package/src/panels/zones/workspaces-tab.tsx +37 -0
- package/src/panels/zones/zone-list.tsx +73 -0
- package/src/panels/zones/zones-panel.tsx +559 -0
- package/src/services/command-runner.ts +303 -0
- package/src/shared/accessibility-announcements.ts +44 -0
- package/src/shared/action-registry.ts +466 -0
- package/src/shared/brick-states.ts +91 -0
- package/src/shared/command-palette.ts +35 -0
- package/src/shared/components/announcement-bar.tsx +30 -0
- package/src/shared/components/app-confirm-dialog.tsx +29 -0
- package/src/shared/components/breadcrumb.tsx +21 -0
- package/src/shared/components/brick-gate.tsx +60 -0
- package/src/shared/components/command-output.tsx +95 -0
- package/src/shared/components/command-palette.tsx +97 -0
- package/src/shared/components/confirm-dialog.tsx +61 -0
- package/src/shared/components/diff-viewer.tsx +219 -0
- package/src/shared/components/empty-state.tsx +36 -0
- package/src/shared/components/error-bar.tsx +60 -0
- package/src/shared/components/error-boundary.tsx +53 -0
- package/src/shared/components/help-overlay.tsx +99 -0
- package/src/shared/components/identity-switcher.tsx +168 -0
- package/src/shared/components/loading-indicator.tsx +40 -0
- package/src/shared/components/pagination-bar.tsx +68 -0
- package/src/shared/components/pre-connection-screen.tsx +398 -0
- package/src/shared/components/scroll-indicator.tsx +46 -0
- package/src/shared/components/side-nav-utils.ts +68 -0
- package/src/shared/components/side-nav.tsx +287 -0
- package/src/shared/components/spinner.tsx +26 -0
- package/src/shared/components/status-bar.tsx +117 -0
- package/src/shared/components/styled-text.tsx +72 -0
- package/src/shared/components/sub-tab-bar-utils.ts +100 -0
- package/src/shared/components/sub-tab-bar.tsx +40 -0
- package/src/shared/components/tab-bar-utils.ts +36 -0
- package/src/shared/components/tab-bar.tsx +50 -0
- package/src/shared/components/text-input.tsx +73 -0
- package/src/shared/components/tooltip.tsx +53 -0
- package/src/shared/components/virtual-list.tsx +93 -0
- package/src/shared/components/welcome-screen.tsx +111 -0
- package/src/shared/hooks/use-api.ts +10 -0
- package/src/shared/hooks/use-brick-available.ts +42 -0
- package/src/shared/hooks/use-confirm.ts +66 -0
- package/src/shared/hooks/use-connection-state.ts +67 -0
- package/src/shared/hooks/use-copy.ts +31 -0
- package/src/shared/hooks/use-fresh-server.ts +62 -0
- package/src/shared/hooks/use-keyboard.ts +58 -0
- package/src/shared/hooks/use-list-navigation.ts +106 -0
- package/src/shared/hooks/use-swr.ts +117 -0
- package/src/shared/hooks/use-tab-fallback.ts +32 -0
- package/src/shared/hooks/use-text-input.ts +113 -0
- package/src/shared/hooks/use-visible-tabs.ts +61 -0
- package/src/shared/lib/circular-buffer.ts +82 -0
- package/src/shared/lib/clipboard.ts +14 -0
- package/src/shared/nav-items.ts +73 -0
- package/src/shared/navigation.ts +110 -0
- package/src/shared/status-breadcrumb.ts +74 -0
- package/src/shared/syntax-style.ts +3 -0
- package/src/shared/tab-visibility.ts +15 -0
- package/src/shared/text-style.ts +23 -0
- package/src/shared/theme.ts +179 -0
- package/src/shared/utils/format-size.ts +20 -0
- package/src/shared/utils/format-text.ts +10 -0
- package/src/shared/utils/format-time.ts +72 -0
- package/src/shared/utils/lru-cache.ts +75 -0
- package/src/stores/access-store-types.ts +154 -0
- package/src/stores/access-store.ts +674 -0
- package/src/stores/agents-store.ts +404 -0
- package/src/stores/announcement-store.ts +46 -0
- package/src/stores/api-console-store.ts +476 -0
- package/src/stores/connectors-store.ts +434 -0
- package/src/stores/create-api-action.ts +140 -0
- package/src/stores/delegation-store.ts +300 -0
- package/src/stores/error-store.ts +102 -0
- package/src/stores/events-store.ts +163 -0
- package/src/stores/files-store.ts +630 -0
- package/src/stores/first-run-store.ts +34 -0
- package/src/stores/global-store.ts +255 -0
- package/src/stores/infra-store.ts +461 -0
- package/src/stores/knowledge-store.ts +358 -0
- package/src/stores/lineage-store.ts +126 -0
- package/src/stores/mcp-store.ts +147 -0
- package/src/stores/payments-store.ts +545 -0
- package/src/stores/search-store-types.ts +155 -0
- package/src/stores/search-store.ts +656 -0
- package/src/stores/share-link-store.ts +151 -0
- package/src/stores/stack-store.ts +352 -0
- package/src/stores/ui-store.ts +161 -0
- package/src/stores/upload-store.ts +131 -0
- package/src/stores/versions-store.ts +355 -0
- package/src/stores/workflows-store.ts +402 -0
- package/src/stores/workspace-store.ts +185 -0
- package/src/stores/zones-store.ts +378 -0
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zustand store for Infrastructure panel: connectors, subscriptions, locks, secrets audit.
|
|
3
|
+
*
|
|
4
|
+
* Complements the events-store (SSE streaming) with REST-based infra management.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { create } from "zustand";
|
|
8
|
+
import type { FetchClient } from "@nexus-ai-fs/api-client";
|
|
9
|
+
import { createApiAction, categorizeError } from "./create-api-action.js";
|
|
10
|
+
import { useErrorStore } from "./error-store.js";
|
|
11
|
+
import { useUiStore } from "./ui-store.js";
|
|
12
|
+
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// Types (snake_case matching API wire format)
|
|
15
|
+
// =============================================================================
|
|
16
|
+
|
|
17
|
+
export interface Connector {
|
|
18
|
+
readonly connector_id: string;
|
|
19
|
+
readonly name: string;
|
|
20
|
+
readonly type: string;
|
|
21
|
+
readonly status: "active" | "inactive" | "error";
|
|
22
|
+
readonly capabilities: readonly string[];
|
|
23
|
+
readonly config: Record<string, unknown>;
|
|
24
|
+
readonly created_at: string;
|
|
25
|
+
readonly last_seen: string | null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface Subscription {
|
|
29
|
+
readonly subscription_id: string;
|
|
30
|
+
readonly event_type: string;
|
|
31
|
+
readonly endpoint: string;
|
|
32
|
+
readonly status: "active" | "paused" | "failed";
|
|
33
|
+
readonly filter: string | null;
|
|
34
|
+
readonly created_at: string;
|
|
35
|
+
readonly last_triggered: string | null;
|
|
36
|
+
readonly trigger_count: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Lock shape matching backend LockInfoMutex / LockInfoSemaphore. */
|
|
40
|
+
export interface Lock {
|
|
41
|
+
readonly lock_id: string;
|
|
42
|
+
readonly mode: "mutex" | "semaphore";
|
|
43
|
+
readonly max_holders: number;
|
|
44
|
+
readonly holder_info: string;
|
|
45
|
+
readonly acquired_at: number;
|
|
46
|
+
readonly expires_at: number;
|
|
47
|
+
readonly fence_token: number;
|
|
48
|
+
/** The resource path this lock is held on (derived from the list key). */
|
|
49
|
+
readonly resource: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Matches backend SecretAuditEventResponse. */
|
|
53
|
+
export interface SecretAuditEntry {
|
|
54
|
+
readonly id: string;
|
|
55
|
+
readonly record_hash: string;
|
|
56
|
+
readonly created_at: string;
|
|
57
|
+
readonly event_type: string;
|
|
58
|
+
readonly actor_id: string;
|
|
59
|
+
readonly provider: string | null;
|
|
60
|
+
readonly credential_id: string | null;
|
|
61
|
+
readonly token_family_id: string | null;
|
|
62
|
+
readonly zone_id: string;
|
|
63
|
+
readonly ip_address: string | null;
|
|
64
|
+
readonly details: string | null;
|
|
65
|
+
readonly metadata_hash: string | null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface OperationItem {
|
|
69
|
+
readonly operation_id: string;
|
|
70
|
+
readonly agent_id: string | null;
|
|
71
|
+
readonly type: string;
|
|
72
|
+
readonly status: string;
|
|
73
|
+
readonly started_at: string | null;
|
|
74
|
+
readonly completed_at: string | null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Audit transaction from /api/v2/audit/transactions. */
|
|
78
|
+
export interface AuditTransaction {
|
|
79
|
+
readonly transaction_id: string;
|
|
80
|
+
readonly actor_id: string;
|
|
81
|
+
readonly action: string;
|
|
82
|
+
readonly resource: string;
|
|
83
|
+
readonly timestamp: string;
|
|
84
|
+
readonly status: string;
|
|
85
|
+
readonly details: string | null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export type InfraTab = "connectors" | "subscriptions" | "locks" | "secrets";
|
|
89
|
+
export type EventsPanelTab = "events" | "mcl" | "replay" | "operations" | "audit" | InfraTab;
|
|
90
|
+
|
|
91
|
+
// =============================================================================
|
|
92
|
+
// Store
|
|
93
|
+
// =============================================================================
|
|
94
|
+
|
|
95
|
+
export interface InfraState {
|
|
96
|
+
// Connectors
|
|
97
|
+
readonly connectors: readonly Connector[];
|
|
98
|
+
readonly selectedConnectorIndex: number;
|
|
99
|
+
readonly connectorsLoading: boolean;
|
|
100
|
+
|
|
101
|
+
// Subscriptions
|
|
102
|
+
readonly subscriptions: readonly Subscription[];
|
|
103
|
+
readonly selectedSubscriptionIndex: number;
|
|
104
|
+
readonly subscriptionsLoading: boolean;
|
|
105
|
+
|
|
106
|
+
// Locks
|
|
107
|
+
readonly locks: readonly Lock[];
|
|
108
|
+
readonly selectedLockIndex: number;
|
|
109
|
+
readonly locksLoading: boolean;
|
|
110
|
+
|
|
111
|
+
// Secrets audit
|
|
112
|
+
readonly secretAuditEntries: readonly SecretAuditEntry[];
|
|
113
|
+
readonly secretsLoading: boolean;
|
|
114
|
+
|
|
115
|
+
// Operations
|
|
116
|
+
readonly operations: readonly OperationItem[];
|
|
117
|
+
readonly operationsLoading: boolean;
|
|
118
|
+
readonly selectedOperationIndex: number;
|
|
119
|
+
|
|
120
|
+
// Connector capabilities
|
|
121
|
+
readonly connectorCapabilities: unknown | null;
|
|
122
|
+
readonly capabilitiesLoading: boolean;
|
|
123
|
+
|
|
124
|
+
// Audit transactions
|
|
125
|
+
readonly auditTransactions: readonly AuditTransaction[];
|
|
126
|
+
readonly auditLoading: boolean;
|
|
127
|
+
readonly auditHasMore: boolean;
|
|
128
|
+
readonly auditNextCursor: string | null;
|
|
129
|
+
|
|
130
|
+
// Navigation
|
|
131
|
+
readonly activeTab: InfraTab;
|
|
132
|
+
readonly activePanelTab: EventsPanelTab;
|
|
133
|
+
|
|
134
|
+
// Error
|
|
135
|
+
readonly error: string | null;
|
|
136
|
+
|
|
137
|
+
// Actions
|
|
138
|
+
readonly fetchConnectors: (client: FetchClient) => Promise<void>;
|
|
139
|
+
readonly fetchSubscriptions: (client: FetchClient) => Promise<void>;
|
|
140
|
+
readonly createSubscription: (
|
|
141
|
+
eventType: string,
|
|
142
|
+
endpoint: string,
|
|
143
|
+
client: FetchClient,
|
|
144
|
+
) => Promise<void>;
|
|
145
|
+
readonly deleteSubscription: (id: string, client: FetchClient) => Promise<void>;
|
|
146
|
+
readonly testSubscription: (id: string, client: FetchClient) => Promise<void>;
|
|
147
|
+
readonly fetchLocks: (client: FetchClient) => Promise<void>;
|
|
148
|
+
readonly acquireLock: (path: string, mode: "mutex" | "semaphore", ttlSeconds: number, client: FetchClient) => Promise<void>;
|
|
149
|
+
readonly releaseLock: (path: string, lockId: string, client: FetchClient) => Promise<void>;
|
|
150
|
+
readonly extendLock: (path: string, lockId: string, ttlSeconds: number, client: FetchClient) => Promise<void>;
|
|
151
|
+
readonly fetchSecretAudit: (client: FetchClient) => Promise<void>;
|
|
152
|
+
readonly fetchOperations: (client: FetchClient) => Promise<void>;
|
|
153
|
+
readonly fetchConnectorCapabilities: (connectorName: string, client: FetchClient) => Promise<void>;
|
|
154
|
+
readonly fetchAuditTransactions: (filters: { cursor?: string; limit?: number }, client: FetchClient) => Promise<void>;
|
|
155
|
+
readonly setActiveTab: (tab: InfraTab) => void;
|
|
156
|
+
readonly setActivePanelTab: (tab: EventsPanelTab) => void;
|
|
157
|
+
readonly setSelectedOperationIndex: (index: number) => void;
|
|
158
|
+
readonly setSelectedConnectorIndex: (index: number) => void;
|
|
159
|
+
readonly setSelectedSubscriptionIndex: (index: number) => void;
|
|
160
|
+
readonly setSelectedLockIndex: (index: number) => void;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const SOURCE = "infrastructure";
|
|
164
|
+
|
|
165
|
+
export const useInfraStore = create<InfraState>((set, get) => ({
|
|
166
|
+
connectors: [],
|
|
167
|
+
selectedConnectorIndex: 0,
|
|
168
|
+
connectorsLoading: false,
|
|
169
|
+
subscriptions: [],
|
|
170
|
+
selectedSubscriptionIndex: 0,
|
|
171
|
+
subscriptionsLoading: false,
|
|
172
|
+
locks: [],
|
|
173
|
+
selectedLockIndex: 0,
|
|
174
|
+
locksLoading: false,
|
|
175
|
+
secretAuditEntries: [],
|
|
176
|
+
secretsLoading: false,
|
|
177
|
+
operations: [],
|
|
178
|
+
operationsLoading: false,
|
|
179
|
+
selectedOperationIndex: 0,
|
|
180
|
+
connectorCapabilities: null,
|
|
181
|
+
capabilitiesLoading: false,
|
|
182
|
+
auditTransactions: [],
|
|
183
|
+
auditLoading: false,
|
|
184
|
+
auditHasMore: false,
|
|
185
|
+
auditNextCursor: null,
|
|
186
|
+
activeTab: "connectors",
|
|
187
|
+
activePanelTab: "events",
|
|
188
|
+
error: null,
|
|
189
|
+
|
|
190
|
+
// =========================================================================
|
|
191
|
+
// Actions with loading keys — createApiAction
|
|
192
|
+
// =========================================================================
|
|
193
|
+
|
|
194
|
+
fetchConnectors: createApiAction<InfraState, [FetchClient]>(set, {
|
|
195
|
+
loadingKey: "connectorsLoading",
|
|
196
|
+
source: SOURCE,
|
|
197
|
+
errorMessage: "Failed to fetch connectors",
|
|
198
|
+
action: async (client) => {
|
|
199
|
+
const response = await client.get<{
|
|
200
|
+
readonly connectors: readonly any[];
|
|
201
|
+
}>("/api/v2/connectors");
|
|
202
|
+
// Normalize: API returns category/name, store expects type/connector_id/status
|
|
203
|
+
const connectors: Connector[] = (response.connectors ?? []).map((c: any) => ({
|
|
204
|
+
connector_id: c.connector_id ?? c.name ?? "",
|
|
205
|
+
name: c.name ?? "",
|
|
206
|
+
type: c.type ?? c.category ?? "",
|
|
207
|
+
status: c.status ?? "active",
|
|
208
|
+
capabilities: c.capabilities ?? [],
|
|
209
|
+
config: c.config ?? {},
|
|
210
|
+
created_at: c.created_at ?? "",
|
|
211
|
+
last_seen: c.last_seen ?? null,
|
|
212
|
+
}));
|
|
213
|
+
return { connectors };
|
|
214
|
+
},
|
|
215
|
+
}),
|
|
216
|
+
|
|
217
|
+
fetchSubscriptions: createApiAction<InfraState, [FetchClient]>(set, {
|
|
218
|
+
loadingKey: "subscriptionsLoading",
|
|
219
|
+
source: SOURCE,
|
|
220
|
+
errorMessage: "Failed to fetch subscriptions",
|
|
221
|
+
action: async (client) => {
|
|
222
|
+
const response = await client.get<{
|
|
223
|
+
readonly subscriptions: readonly Subscription[];
|
|
224
|
+
}>("/api/v2/subscriptions");
|
|
225
|
+
return {
|
|
226
|
+
subscriptions: response.subscriptions ?? [],
|
|
227
|
+
selectedSubscriptionIndex: 0,
|
|
228
|
+
};
|
|
229
|
+
},
|
|
230
|
+
}),
|
|
231
|
+
|
|
232
|
+
fetchLocks: createApiAction<InfraState, [FetchClient]>(set, {
|
|
233
|
+
loadingKey: "locksLoading",
|
|
234
|
+
source: SOURCE,
|
|
235
|
+
errorMessage: "Failed to fetch locks",
|
|
236
|
+
action: async (client) => {
|
|
237
|
+
const response = await client.get<{
|
|
238
|
+
readonly locks: readonly Lock[];
|
|
239
|
+
readonly count: number;
|
|
240
|
+
}>("/api/v2/locks");
|
|
241
|
+
return { locks: response.locks ?? [], selectedLockIndex: 0 };
|
|
242
|
+
},
|
|
243
|
+
}),
|
|
244
|
+
|
|
245
|
+
fetchSecretAudit: createApiAction<InfraState, [FetchClient]>(set, {
|
|
246
|
+
loadingKey: "secretsLoading",
|
|
247
|
+
source: SOURCE,
|
|
248
|
+
errorMessage: "Failed to fetch secrets audit",
|
|
249
|
+
action: async (client) => {
|
|
250
|
+
const response = await client.get<{
|
|
251
|
+
readonly events: readonly SecretAuditEntry[];
|
|
252
|
+
readonly limit: number;
|
|
253
|
+
readonly has_more: boolean;
|
|
254
|
+
readonly total: number | null;
|
|
255
|
+
readonly next_cursor: string | null;
|
|
256
|
+
}>("/api/v2/secrets-audit/events");
|
|
257
|
+
return { secretAuditEntries: response.events ?? [] };
|
|
258
|
+
},
|
|
259
|
+
}),
|
|
260
|
+
|
|
261
|
+
fetchOperations: createApiAction<InfraState, [FetchClient]>(set, {
|
|
262
|
+
loadingKey: "operationsLoading",
|
|
263
|
+
source: SOURCE,
|
|
264
|
+
errorMessage: "Failed to fetch operations",
|
|
265
|
+
action: async (client) => {
|
|
266
|
+
const response = await client.get<{
|
|
267
|
+
readonly operations: readonly any[];
|
|
268
|
+
}>("/api/v2/operations?limit=20");
|
|
269
|
+
// Normalize API fields (id → operation_id, operation_type → type)
|
|
270
|
+
const ops: OperationItem[] = (response.operations ?? []).map((op: any) => ({
|
|
271
|
+
operation_id: op.operation_id ?? op.id ?? "",
|
|
272
|
+
agent_id: op.agent_id ?? null,
|
|
273
|
+
type: op.type ?? op.operation_type ?? "",
|
|
274
|
+
status: op.status ?? "",
|
|
275
|
+
started_at: op.started_at ?? op.timestamp ?? null,
|
|
276
|
+
completed_at: op.completed_at ?? null,
|
|
277
|
+
}));
|
|
278
|
+
return {
|
|
279
|
+
operations: ops,
|
|
280
|
+
selectedOperationIndex: 0,
|
|
281
|
+
};
|
|
282
|
+
},
|
|
283
|
+
}),
|
|
284
|
+
|
|
285
|
+
fetchConnectorCapabilities: createApiAction<InfraState, [string, FetchClient]>(set, {
|
|
286
|
+
loadingKey: "capabilitiesLoading",
|
|
287
|
+
source: SOURCE,
|
|
288
|
+
errorMessage: "Failed to fetch connector capabilities",
|
|
289
|
+
action: async (connectorName, client) => {
|
|
290
|
+
const response = await client.get<{
|
|
291
|
+
readonly capabilities: unknown;
|
|
292
|
+
}>(`/api/v2/connectors/${encodeURIComponent(connectorName)}/capabilities`);
|
|
293
|
+
return { connectorCapabilities: response.capabilities ?? null };
|
|
294
|
+
},
|
|
295
|
+
}),
|
|
296
|
+
|
|
297
|
+
fetchAuditTransactions: async (filters, client) => {
|
|
298
|
+
set({ auditLoading: true, error: null });
|
|
299
|
+
try {
|
|
300
|
+
const params = new URLSearchParams();
|
|
301
|
+
if (filters.cursor) params.set("cursor", filters.cursor);
|
|
302
|
+
params.set("limit", String(filters.limit ?? 50));
|
|
303
|
+
const qs = params.toString();
|
|
304
|
+
const url = `/api/v2/audit/transactions${qs ? `?${qs}` : ""}`;
|
|
305
|
+
const response = await client.get<{
|
|
306
|
+
readonly transactions: readonly AuditTransaction[];
|
|
307
|
+
readonly has_more: boolean;
|
|
308
|
+
readonly next_cursor: string | null;
|
|
309
|
+
}>(url);
|
|
310
|
+
const incoming = (response.transactions ?? []).map((t) => ({
|
|
311
|
+
transaction_id: t.transaction_id ?? "",
|
|
312
|
+
actor_id: t.actor_id ?? "",
|
|
313
|
+
action: t.action ?? "",
|
|
314
|
+
resource: t.resource ?? "",
|
|
315
|
+
timestamp: t.timestamp ?? "",
|
|
316
|
+
status: t.status ?? "",
|
|
317
|
+
details: t.details ?? null,
|
|
318
|
+
}));
|
|
319
|
+
set((state) => {
|
|
320
|
+
const combined = filters.cursor
|
|
321
|
+
? [...state.auditTransactions, ...incoming]
|
|
322
|
+
: incoming;
|
|
323
|
+
return {
|
|
324
|
+
auditTransactions: combined.slice(-1000), // keep latest 1000
|
|
325
|
+
auditLoading: false,
|
|
326
|
+
auditHasMore: response.has_more ?? false,
|
|
327
|
+
auditNextCursor: response.next_cursor ?? null,
|
|
328
|
+
};
|
|
329
|
+
});
|
|
330
|
+
useUiStore.getState().markDataUpdated("infrastructure");
|
|
331
|
+
} catch (err) {
|
|
332
|
+
const message = err instanceof Error ? err.message : "Failed to fetch audit transactions";
|
|
333
|
+
set({ auditLoading: false, error: message });
|
|
334
|
+
useErrorStore.getState().pushError({ message, category: categorizeError(message), source: SOURCE });
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
|
|
338
|
+
// =========================================================================
|
|
339
|
+
// Actions without loading keys — inline with error store integration
|
|
340
|
+
// =========================================================================
|
|
341
|
+
|
|
342
|
+
createSubscription: async (eventType, endpoint, client) => {
|
|
343
|
+
set({ error: null });
|
|
344
|
+
try {
|
|
345
|
+
await client.post<Subscription>("/api/v2/subscriptions", {
|
|
346
|
+
event_type: eventType,
|
|
347
|
+
endpoint,
|
|
348
|
+
});
|
|
349
|
+
await get().fetchSubscriptions(client);
|
|
350
|
+
} catch (err) {
|
|
351
|
+
const message = err instanceof Error ? err.message : "Failed to create subscription";
|
|
352
|
+
set({ error: message });
|
|
353
|
+
useErrorStore.getState().pushError({ message, category: categorizeError(message), source: SOURCE });
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
|
|
357
|
+
deleteSubscription: async (id, client) => {
|
|
358
|
+
set({ error: null });
|
|
359
|
+
try {
|
|
360
|
+
await client.delete(`/api/v2/subscriptions/${encodeURIComponent(id)}`);
|
|
361
|
+
set((state) => ({
|
|
362
|
+
subscriptions: state.subscriptions.filter((s) => s.subscription_id !== id),
|
|
363
|
+
}));
|
|
364
|
+
} catch (err) {
|
|
365
|
+
const message = err instanceof Error ? err.message : "Failed to delete subscription";
|
|
366
|
+
set({ error: message });
|
|
367
|
+
useErrorStore.getState().pushError({ message, category: categorizeError(message), source: SOURCE });
|
|
368
|
+
}
|
|
369
|
+
},
|
|
370
|
+
|
|
371
|
+
testSubscription: async (id, client) => {
|
|
372
|
+
set({ error: null });
|
|
373
|
+
try {
|
|
374
|
+
await client.post(
|
|
375
|
+
`/api/v2/subscriptions/${encodeURIComponent(id)}/test`,
|
|
376
|
+
{},
|
|
377
|
+
);
|
|
378
|
+
} catch (err) {
|
|
379
|
+
const message = err instanceof Error ? err.message : "Failed to test subscription";
|
|
380
|
+
set({ error: message });
|
|
381
|
+
useErrorStore.getState().pushError({ message, category: categorizeError(message), source: SOURCE });
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
|
|
385
|
+
acquireLock: async (path, mode, ttlSeconds, client) => {
|
|
386
|
+
set({ error: null });
|
|
387
|
+
try {
|
|
388
|
+
await client.post(`/api/v2/locks/${encodeURIComponent(path)}/acquire`, {
|
|
389
|
+
mode,
|
|
390
|
+
ttl_seconds: ttlSeconds,
|
|
391
|
+
});
|
|
392
|
+
// Refresh lock list after acquisition
|
|
393
|
+
await get().fetchLocks(client);
|
|
394
|
+
} catch (err) {
|
|
395
|
+
const message = err instanceof Error ? err.message : "Failed to acquire lock";
|
|
396
|
+
set({ error: message });
|
|
397
|
+
useErrorStore.getState().pushError({ message, category: categorizeError(message), source: SOURCE });
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
|
|
401
|
+
releaseLock: async (path, lockId, client) => {
|
|
402
|
+
set({ error: null });
|
|
403
|
+
try {
|
|
404
|
+
await client.deleteNoContent(
|
|
405
|
+
`/api/v2/locks/${encodeURIComponent(path)}?lock_id=${encodeURIComponent(lockId)}`,
|
|
406
|
+
);
|
|
407
|
+
set((state) => ({
|
|
408
|
+
locks: state.locks.filter((l) => l.lock_id !== lockId),
|
|
409
|
+
}));
|
|
410
|
+
} catch (err) {
|
|
411
|
+
const message = err instanceof Error ? err.message : "Failed to release lock";
|
|
412
|
+
set({ error: message });
|
|
413
|
+
useErrorStore.getState().pushError({ message, category: categorizeError(message), source: SOURCE });
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
|
|
417
|
+
extendLock: async (path, lockId, ttlSeconds, client) => {
|
|
418
|
+
set({ error: null });
|
|
419
|
+
try {
|
|
420
|
+
await client.patch(`/api/v2/locks/${encodeURIComponent(path)}`, {
|
|
421
|
+
lock_id: lockId,
|
|
422
|
+
ttl: ttlSeconds,
|
|
423
|
+
});
|
|
424
|
+
await get().fetchLocks(client);
|
|
425
|
+
} catch (err) {
|
|
426
|
+
const message = err instanceof Error ? err.message : "Failed to extend lock";
|
|
427
|
+
set({ error: message });
|
|
428
|
+
useErrorStore.getState().pushError({ message, category: categorizeError(message), source: SOURCE });
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
|
|
432
|
+
setActiveTab: (tab) => {
|
|
433
|
+
set({ activeTab: tab, activePanelTab: tab, error: null });
|
|
434
|
+
},
|
|
435
|
+
|
|
436
|
+
setActivePanelTab: (tab) => {
|
|
437
|
+
set((state) => ({
|
|
438
|
+
activePanelTab: tab,
|
|
439
|
+
activeTab: tab === "events" || tab === "mcl" || tab === "replay" || tab === "operations" || tab === "audit"
|
|
440
|
+
? state.activeTab
|
|
441
|
+
: tab,
|
|
442
|
+
error: null,
|
|
443
|
+
}));
|
|
444
|
+
},
|
|
445
|
+
|
|
446
|
+
setSelectedOperationIndex: (index) => {
|
|
447
|
+
set({ selectedOperationIndex: index });
|
|
448
|
+
},
|
|
449
|
+
|
|
450
|
+
setSelectedConnectorIndex: (index) => {
|
|
451
|
+
set({ selectedConnectorIndex: index });
|
|
452
|
+
},
|
|
453
|
+
|
|
454
|
+
setSelectedSubscriptionIndex: (index) => {
|
|
455
|
+
set({ selectedSubscriptionIndex: index });
|
|
456
|
+
},
|
|
457
|
+
|
|
458
|
+
setSelectedLockIndex: (index) => {
|
|
459
|
+
set({ selectedLockIndex: index });
|
|
460
|
+
},
|
|
461
|
+
}));
|