@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,378 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zustand store for Zones & Federation panel.
|
|
3
|
+
*
|
|
4
|
+
* Manages zone listing, brick health, individual brick detail,
|
|
5
|
+
* drift reconciliation reports, and brick lifecycle operations.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { create } from "zustand";
|
|
9
|
+
import type { FetchClient } from "@nexus-ai-fs/api-client";
|
|
10
|
+
import { createApiAction, categorizeError } from "./create-api-action.js";
|
|
11
|
+
import { useErrorStore } from "./error-store.js";
|
|
12
|
+
import { useUiStore } from "./ui-store.js";
|
|
13
|
+
|
|
14
|
+
// =============================================================================
|
|
15
|
+
// Types (snake_case matching API wire format)
|
|
16
|
+
// =============================================================================
|
|
17
|
+
|
|
18
|
+
export interface BrickStatusResponse {
|
|
19
|
+
readonly name: string;
|
|
20
|
+
readonly state: string;
|
|
21
|
+
readonly protocol_name: string;
|
|
22
|
+
readonly error: string | null;
|
|
23
|
+
readonly started_at: number | null;
|
|
24
|
+
readonly stopped_at: number | null;
|
|
25
|
+
readonly unmounted_at: number | null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface BrickTransitionItem {
|
|
29
|
+
readonly timestamp: number;
|
|
30
|
+
readonly event: string;
|
|
31
|
+
readonly from_state: string;
|
|
32
|
+
readonly to_state: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface BrickDetailResponse extends BrickStatusResponse {
|
|
36
|
+
readonly enabled: boolean;
|
|
37
|
+
readonly depends_on: readonly string[];
|
|
38
|
+
readonly depended_by: readonly string[];
|
|
39
|
+
readonly retry_count: number;
|
|
40
|
+
readonly transitions: readonly BrickTransitionItem[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface DriftReportItem {
|
|
44
|
+
readonly brick_name: string;
|
|
45
|
+
readonly spec_state: string;
|
|
46
|
+
readonly actual_state: string;
|
|
47
|
+
readonly action: string;
|
|
48
|
+
readonly detail: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface BricksHealthResponse {
|
|
52
|
+
readonly total: number;
|
|
53
|
+
readonly active: number;
|
|
54
|
+
readonly failed: number;
|
|
55
|
+
readonly bricks: readonly BrickStatusResponse[];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface DriftReportResponse {
|
|
59
|
+
readonly total_bricks: number;
|
|
60
|
+
readonly drifted: number;
|
|
61
|
+
readonly actions_taken: number;
|
|
62
|
+
readonly errors: number;
|
|
63
|
+
readonly drifts: readonly DriftReportItem[];
|
|
64
|
+
readonly last_reconcile_at: number | null;
|
|
65
|
+
readonly reconcile_count: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface ZoneResponse {
|
|
69
|
+
readonly zone_id: string;
|
|
70
|
+
readonly name: string;
|
|
71
|
+
readonly domain: string | null;
|
|
72
|
+
readonly description: string | null;
|
|
73
|
+
readonly phase: string;
|
|
74
|
+
readonly finalizers: readonly string[];
|
|
75
|
+
readonly is_active: boolean;
|
|
76
|
+
readonly created_at: string;
|
|
77
|
+
readonly updated_at: string;
|
|
78
|
+
readonly limits: Record<string, unknown> | null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface ZonesListResponse {
|
|
82
|
+
readonly zones: readonly ZoneResponse[];
|
|
83
|
+
readonly total: number;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// =============================================================================
|
|
87
|
+
// Tab type
|
|
88
|
+
// =============================================================================
|
|
89
|
+
|
|
90
|
+
export type ZoneTab = "zones" | "bricks" | "drift" | "reindex" | "workspaces" | "mcp" | "cache";
|
|
91
|
+
|
|
92
|
+
// =============================================================================
|
|
93
|
+
// Store
|
|
94
|
+
// =============================================================================
|
|
95
|
+
|
|
96
|
+
export interface ZonesState {
|
|
97
|
+
// Zone list
|
|
98
|
+
readonly zones: readonly ZoneResponse[];
|
|
99
|
+
readonly zonesLoading: boolean;
|
|
100
|
+
|
|
101
|
+
// Brick list (from health endpoint)
|
|
102
|
+
readonly bricksHealth: BricksHealthResponse | null;
|
|
103
|
+
readonly bricks: readonly BrickStatusResponse[];
|
|
104
|
+
readonly selectedIndex: number;
|
|
105
|
+
readonly isLoading: boolean;
|
|
106
|
+
readonly error: string | null;
|
|
107
|
+
|
|
108
|
+
// Active tab
|
|
109
|
+
readonly activeTab: ZoneTab;
|
|
110
|
+
|
|
111
|
+
// Brick detail (extended with spec/dependency info)
|
|
112
|
+
readonly brickDetail: BrickDetailResponse | null;
|
|
113
|
+
readonly detailLoading: boolean;
|
|
114
|
+
|
|
115
|
+
// Drift report (global, not per-brick)
|
|
116
|
+
readonly driftReport: DriftReportResponse | null;
|
|
117
|
+
readonly driftLoading: boolean;
|
|
118
|
+
|
|
119
|
+
// Cache management
|
|
120
|
+
readonly cacheStats: unknown | null;
|
|
121
|
+
readonly cacheStatsLoading: boolean;
|
|
122
|
+
readonly hotFiles: readonly unknown[];
|
|
123
|
+
readonly hotFilesLoading: boolean;
|
|
124
|
+
|
|
125
|
+
// Actions
|
|
126
|
+
readonly fetchZones: (client: FetchClient) => Promise<void>;
|
|
127
|
+
readonly fetchBricks: (client: FetchClient) => Promise<void>;
|
|
128
|
+
readonly fetchBrickDetail: (name: string, client: FetchClient) => Promise<void>;
|
|
129
|
+
readonly fetchDrift: (client: FetchClient) => Promise<void>;
|
|
130
|
+
readonly mountBrick: (name: string, client: FetchClient) => Promise<void>;
|
|
131
|
+
readonly unmountBrick: (name: string, client: FetchClient) => Promise<void>;
|
|
132
|
+
readonly unregisterBrick: (name: string, client: FetchClient) => Promise<void>;
|
|
133
|
+
readonly remountBrick: (name: string, client: FetchClient) => Promise<void>;
|
|
134
|
+
readonly resetBrick: (name: string, client: FetchClient) => Promise<void>;
|
|
135
|
+
readonly fetchCacheStats: (client: FetchClient) => Promise<void>;
|
|
136
|
+
readonly fetchHotFiles: (client: FetchClient) => Promise<void>;
|
|
137
|
+
readonly warmupCache: (paths: readonly string[], client: FetchClient) => Promise<void>;
|
|
138
|
+
readonly setSelectedIndex: (index: number) => void;
|
|
139
|
+
readonly setActiveTab: (tab: ZoneTab) => void;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const SOURCE = "zones";
|
|
143
|
+
|
|
144
|
+
export const useZonesStore = create<ZonesState>((set, get) => ({
|
|
145
|
+
zones: [],
|
|
146
|
+
zonesLoading: false,
|
|
147
|
+
bricksHealth: null,
|
|
148
|
+
bricks: [],
|
|
149
|
+
selectedIndex: 0,
|
|
150
|
+
isLoading: false,
|
|
151
|
+
error: null,
|
|
152
|
+
activeTab: "zones",
|
|
153
|
+
brickDetail: null,
|
|
154
|
+
detailLoading: false,
|
|
155
|
+
driftReport: null,
|
|
156
|
+
driftLoading: false,
|
|
157
|
+
cacheStats: null,
|
|
158
|
+
cacheStatsLoading: false,
|
|
159
|
+
hotFiles: [],
|
|
160
|
+
hotFilesLoading: false,
|
|
161
|
+
|
|
162
|
+
// =========================================================================
|
|
163
|
+
// Actions migrated to createApiAction
|
|
164
|
+
// =========================================================================
|
|
165
|
+
|
|
166
|
+
fetchZones: async (client) => {
|
|
167
|
+
set({ zonesLoading: true, error: null });
|
|
168
|
+
try {
|
|
169
|
+
// Use rawRequest to avoid the FetchClient's automatic 3× retry on 503.
|
|
170
|
+
// The /api/zones endpoint returns 503 when DatabaseLocalAuth is not
|
|
171
|
+
// configured, which is expected for API-key-only server setups.
|
|
172
|
+
const raw = await client.rawRequest("GET", "/api/zones");
|
|
173
|
+
if (raw.status === 503) {
|
|
174
|
+
// Auth provider not available — treat as "no zones"
|
|
175
|
+
set({ zones: [], zonesLoading: false });
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (!raw.ok) {
|
|
179
|
+
const body = await raw.json().catch(() => ({ detail: `HTTP ${raw.status}` })) as { detail?: string };
|
|
180
|
+
throw new Error(body.detail ?? `HTTP ${raw.status}`);
|
|
181
|
+
}
|
|
182
|
+
const data = (await raw.json()) as { zones?: ZoneResponse[] };
|
|
183
|
+
set({ zones: data.zones ?? [], zonesLoading: false });
|
|
184
|
+
useUiStore.getState().markDataUpdated("zones");
|
|
185
|
+
} catch (err) {
|
|
186
|
+
const message = err instanceof Error ? err.message : "Failed to fetch zones";
|
|
187
|
+
set({ zones: [], zonesLoading: false, error: message });
|
|
188
|
+
useErrorStore.getState().pushError({ message, category: categorizeError(message), source: SOURCE });
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
fetchBricks: createApiAction<ZonesState, [FetchClient]>(set, {
|
|
193
|
+
loadingKey: "isLoading",
|
|
194
|
+
source: SOURCE,
|
|
195
|
+
errorMessage: "Failed to fetch bricks",
|
|
196
|
+
action: async (client) => {
|
|
197
|
+
const response = await client.get<BricksHealthResponse>(
|
|
198
|
+
"/api/v2/bricks/health",
|
|
199
|
+
);
|
|
200
|
+
const bricks = response.bricks ?? [];
|
|
201
|
+
return { bricksHealth: response, bricks };
|
|
202
|
+
},
|
|
203
|
+
}),
|
|
204
|
+
|
|
205
|
+
fetchCacheStats: createApiAction<ZonesState, [FetchClient]>(set, {
|
|
206
|
+
loadingKey: "cacheStatsLoading",
|
|
207
|
+
source: SOURCE,
|
|
208
|
+
errorMessage: "Failed to fetch cache stats",
|
|
209
|
+
action: async (client) => {
|
|
210
|
+
const stats = await client.get<unknown>("/api/v2/cache/stats");
|
|
211
|
+
return { cacheStats: stats };
|
|
212
|
+
},
|
|
213
|
+
}),
|
|
214
|
+
|
|
215
|
+
fetchHotFiles: createApiAction<ZonesState, [FetchClient]>(set, {
|
|
216
|
+
loadingKey: "hotFilesLoading",
|
|
217
|
+
source: SOURCE,
|
|
218
|
+
errorMessage: "Failed to fetch hot files",
|
|
219
|
+
action: async (client) => {
|
|
220
|
+
const response = await client.get<{ files: readonly unknown[] }>("/api/v2/cache/hot-files");
|
|
221
|
+
return { hotFiles: response.files ?? [] };
|
|
222
|
+
},
|
|
223
|
+
}),
|
|
224
|
+
|
|
225
|
+
// =========================================================================
|
|
226
|
+
// Actions with special error-path state — inline with error store integration
|
|
227
|
+
// =========================================================================
|
|
228
|
+
|
|
229
|
+
fetchBrickDetail: async (name, client) => {
|
|
230
|
+
set({ detailLoading: true, error: null });
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
const detail = await client.get<BrickDetailResponse>(
|
|
234
|
+
`/api/v2/bricks/${encodeURIComponent(name)}`,
|
|
235
|
+
);
|
|
236
|
+
set({ brickDetail: detail, detailLoading: false });
|
|
237
|
+
useUiStore.getState().markDataUpdated("zones");
|
|
238
|
+
} catch (err) {
|
|
239
|
+
const message = err instanceof Error ? err.message : "Failed to fetch brick detail";
|
|
240
|
+
set({
|
|
241
|
+
brickDetail: null,
|
|
242
|
+
detailLoading: false,
|
|
243
|
+
error: message,
|
|
244
|
+
});
|
|
245
|
+
useErrorStore.getState().pushError({ message, category: categorizeError(message), source: SOURCE });
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
fetchDrift: async (client) => {
|
|
250
|
+
set({ driftLoading: true, error: null });
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
const report = await client.get<DriftReportResponse>(
|
|
254
|
+
"/api/v2/bricks/drift",
|
|
255
|
+
);
|
|
256
|
+
set({ driftReport: report, driftLoading: false });
|
|
257
|
+
useUiStore.getState().markDataUpdated("zones");
|
|
258
|
+
} catch (err) {
|
|
259
|
+
const message = err instanceof Error ? err.message : "Failed to fetch drift report";
|
|
260
|
+
set({
|
|
261
|
+
driftReport: null,
|
|
262
|
+
driftLoading: false,
|
|
263
|
+
error: message,
|
|
264
|
+
});
|
|
265
|
+
useErrorStore.getState().pushError({ message, category: categorizeError(message), source: SOURCE });
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
// =========================================================================
|
|
270
|
+
// Actions without loading keys — inline with error store integration
|
|
271
|
+
// =========================================================================
|
|
272
|
+
|
|
273
|
+
mountBrick: async (name, client) => {
|
|
274
|
+
set({ error: null });
|
|
275
|
+
|
|
276
|
+
try {
|
|
277
|
+
await client.post<void>(
|
|
278
|
+
`/api/v2/bricks/${encodeURIComponent(name)}/mount`,
|
|
279
|
+
{},
|
|
280
|
+
);
|
|
281
|
+
await get().fetchBricks(client);
|
|
282
|
+
} catch (err) {
|
|
283
|
+
const message = err instanceof Error ? err.message : "Failed to mount brick";
|
|
284
|
+
set({ error: message });
|
|
285
|
+
useErrorStore.getState().pushError({ message, category: categorizeError(message), source: SOURCE });
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
|
|
289
|
+
unmountBrick: async (name, client) => {
|
|
290
|
+
set({ error: null });
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
await client.post<void>(
|
|
294
|
+
`/api/v2/bricks/${encodeURIComponent(name)}/unmount`,
|
|
295
|
+
{},
|
|
296
|
+
);
|
|
297
|
+
await get().fetchBricks(client);
|
|
298
|
+
} catch (err) {
|
|
299
|
+
const message = err instanceof Error ? err.message : "Failed to unmount brick";
|
|
300
|
+
set({ error: message });
|
|
301
|
+
useErrorStore.getState().pushError({ message, category: categorizeError(message), source: SOURCE });
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
|
|
305
|
+
unregisterBrick: async (name, client) => {
|
|
306
|
+
set({ error: null });
|
|
307
|
+
|
|
308
|
+
try {
|
|
309
|
+
await client.post<void>(
|
|
310
|
+
`/api/v2/bricks/${encodeURIComponent(name)}/unregister`,
|
|
311
|
+
{},
|
|
312
|
+
);
|
|
313
|
+
await get().fetchBricks(client);
|
|
314
|
+
// Clamp selectedIndex and clear stale detail after brick removal
|
|
315
|
+
const { bricks, selectedIndex } = get();
|
|
316
|
+
const clamped = Math.min(selectedIndex, Math.max(0, bricks.length - 1));
|
|
317
|
+
set({ selectedIndex: clamped, brickDetail: null });
|
|
318
|
+
} catch (err) {
|
|
319
|
+
const message = err instanceof Error ? err.message : "Failed to unregister brick";
|
|
320
|
+
set({ error: message });
|
|
321
|
+
useErrorStore.getState().pushError({ message, category: categorizeError(message), source: SOURCE });
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
|
|
325
|
+
remountBrick: async (name, client) => {
|
|
326
|
+
set({ error: null });
|
|
327
|
+
|
|
328
|
+
try {
|
|
329
|
+
await client.post<void>(
|
|
330
|
+
`/api/v2/bricks/${encodeURIComponent(name)}/remount`,
|
|
331
|
+
{},
|
|
332
|
+
);
|
|
333
|
+
await get().fetchBricks(client);
|
|
334
|
+
} catch (err) {
|
|
335
|
+
const message = err instanceof Error ? err.message : "Failed to remount brick";
|
|
336
|
+
set({ error: message });
|
|
337
|
+
useErrorStore.getState().pushError({ message, category: categorizeError(message), source: SOURCE });
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
|
|
341
|
+
resetBrick: async (name, client) => {
|
|
342
|
+
set({ error: null });
|
|
343
|
+
|
|
344
|
+
try {
|
|
345
|
+
await client.post<void>(
|
|
346
|
+
`/api/v2/bricks/${encodeURIComponent(name)}/reset`,
|
|
347
|
+
{},
|
|
348
|
+
);
|
|
349
|
+
await get().fetchBricks(client);
|
|
350
|
+
} catch (err) {
|
|
351
|
+
const message = err instanceof Error ? err.message : "Failed to reset brick";
|
|
352
|
+
set({ error: message });
|
|
353
|
+
useErrorStore.getState().pushError({ message, category: categorizeError(message), source: SOURCE });
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
|
|
357
|
+
warmupCache: async (paths, client) => {
|
|
358
|
+
set({ error: null });
|
|
359
|
+
try {
|
|
360
|
+
await client.post("/api/v2/cache/warmup", { paths });
|
|
361
|
+
} catch (err) {
|
|
362
|
+
const message = err instanceof Error ? err.message : "Failed to warmup cache";
|
|
363
|
+
set({ error: message });
|
|
364
|
+
useErrorStore.getState().pushError({ message, category: categorizeError(message), source: SOURCE });
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
|
|
368
|
+
setSelectedIndex: (index) => {
|
|
369
|
+
set({
|
|
370
|
+
selectedIndex: index,
|
|
371
|
+
brickDetail: null,
|
|
372
|
+
});
|
|
373
|
+
},
|
|
374
|
+
|
|
375
|
+
setActiveTab: (tab) => {
|
|
376
|
+
set({ activeTab: tab });
|
|
377
|
+
},
|
|
378
|
+
}));
|