pi-mega-compact 0.20.59 → 0.20.61

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.
Files changed (102) hide show
  1. package/dist/config/vector-cortex-dash-0c.js +23 -0
  2. package/dist/config/vector-cortex-dash-0d.js +26 -0
  3. package/dist/config/vector-cortex.js +4 -0
  4. package/dist/config.js +1 -1
  5. package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +2 -0
  6. package/dist/src/config/vector-cortex-dash-0c.js +23 -0
  7. package/dist/src/config/vector-cortex-dash-0d.js +26 -0
  8. package/dist/src/config/vector-cortex.js +4 -0
  9. package/dist/src/config.js +1 -1
  10. package/extensions/dashboard-client/dist/assets/AdminTab-DEjVnlwe.js +2 -0
  11. package/extensions/dashboard-client/dist/assets/AdminTab-DEjVnlwe.js.map +1 -0
  12. package/extensions/dashboard-client/dist/assets/{AreaChart-GTwQxOAm.js → AreaChart-B1PoTqKJ.js} +2 -2
  13. package/extensions/dashboard-client/dist/assets/{AreaChart-GTwQxOAm.js.map → AreaChart-B1PoTqKJ.js.map} +1 -1
  14. package/extensions/dashboard-client/dist/assets/{BarChart-BFqUD5L4.js → BarChart-DaoONT_V.js} +2 -2
  15. package/extensions/dashboard-client/dist/assets/{BarChart-BFqUD5L4.js.map → BarChart-DaoONT_V.js.map} +1 -1
  16. package/extensions/dashboard-client/dist/assets/CacheTab-rD5sjlkW.js +2 -0
  17. package/extensions/dashboard-client/dist/assets/CacheTab-rD5sjlkW.js.map +1 -0
  18. package/extensions/dashboard-client/dist/assets/ConfigTab-BQkufK7t.js +2 -0
  19. package/extensions/dashboard-client/dist/assets/ConfigTab-BQkufK7t.js.map +1 -0
  20. package/extensions/dashboard-client/dist/assets/{EventsTab-BYLh6cud.js → EventsTab-DGlQzJaT.js} +2 -2
  21. package/extensions/dashboard-client/dist/assets/{EventsTab-BYLh6cud.js.map → EventsTab-DGlQzJaT.js.map} +1 -1
  22. package/extensions/dashboard-client/dist/assets/{HealthTab-CkJXEbjn.js → HealthTab-DW7kt4qm.js} +2 -2
  23. package/extensions/dashboard-client/dist/assets/{HealthTab-CkJXEbjn.js.map → HealthTab-DW7kt4qm.js.map} +1 -1
  24. package/extensions/dashboard-client/dist/assets/MaintenanceTab-CGiZ0OQ6.js +2 -0
  25. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-Lm3v0nJO.js.map → MaintenanceTab-CGiZ0OQ6.js.map} +1 -1
  26. package/extensions/dashboard-client/dist/assets/MemoryMapTab-BwyrxjuW.js +2 -0
  27. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-C8AeBIQi.js.map → MemoryMapTab-BwyrxjuW.js.map} +1 -1
  28. package/extensions/dashboard-client/dist/assets/{MetricsTab-m410T4vk.js → MetricsCards-IZaCOOXU.js} +2 -2
  29. package/extensions/dashboard-client/dist/assets/MetricsCards-IZaCOOXU.js.map +1 -0
  30. package/extensions/dashboard-client/dist/assets/MetricsTab-wCxVpHlC.js +2 -0
  31. package/extensions/dashboard-client/dist/assets/MetricsTab-wCxVpHlC.js.map +1 -0
  32. package/extensions/dashboard-client/dist/assets/{OverviewTab-BfDfMFXx.js → OverviewTab-DsH08Wr0.js} +2 -2
  33. package/extensions/dashboard-client/dist/assets/{OverviewTab-BfDfMFXx.js.map → OverviewTab-DsH08Wr0.js.map} +1 -1
  34. package/extensions/dashboard-client/dist/assets/{ReposTab-CsFxxqJ6.js → ReposTab-Dpb7sXWB.js} +2 -2
  35. package/extensions/dashboard-client/dist/assets/{ReposTab-CsFxxqJ6.js.map → ReposTab-Dpb7sXWB.js.map} +1 -1
  36. package/extensions/dashboard-client/dist/assets/SessionsTab-DFMo7tKA.js +2 -0
  37. package/extensions/dashboard-client/dist/assets/SessionsTab-DFMo7tKA.js.map +1 -0
  38. package/extensions/dashboard-client/dist/assets/SetupTab-D2IEBt1u.js +3 -0
  39. package/extensions/dashboard-client/dist/assets/SetupTab-D2IEBt1u.js.map +1 -0
  40. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BkRzjyRm.js → TimeSavedCard-BGPvmVFG.js} +2 -2
  41. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BkRzjyRm.js.map → TimeSavedCard-BGPvmVFG.js.map} +1 -1
  42. package/extensions/dashboard-client/dist/assets/TurnMemoryView-BZo09Jri.js +5 -0
  43. package/extensions/dashboard-client/dist/assets/TurnMemoryView-BZo09Jri.js.map +1 -0
  44. package/extensions/dashboard-client/dist/assets/TurnsTab-CosKNvMp.js +2 -0
  45. package/extensions/dashboard-client/dist/assets/TurnsTab-CosKNvMp.js.map +1 -0
  46. package/extensions/dashboard-client/dist/assets/{VcStatusBadge-B8B8RStV.js → VcStatusBadge-UEZLL6Zj.js} +2 -2
  47. package/extensions/dashboard-client/dist/assets/{VcStatusBadge-B8B8RStV.js.map → VcStatusBadge-UEZLL6Zj.js.map} +1 -1
  48. package/extensions/dashboard-client/dist/assets/{VectorCortexTab-CrGANNd_.js → VectorCortexTab-fDAgD2pN.js} +2 -2
  49. package/extensions/dashboard-client/dist/assets/{VectorCortexTab-CrGANNd_.js.map → VectorCortexTab-fDAgD2pN.js.map} +1 -1
  50. package/extensions/dashboard-client/dist/assets/{WikiTab-DyD0yGzI.js → WikiTab-7TIe2MkS.js} +2 -2
  51. package/extensions/dashboard-client/dist/assets/{WikiTab-DyD0yGzI.js.map → WikiTab-7TIe2MkS.js.map} +1 -1
  52. package/extensions/dashboard-client/dist/assets/button-C9qrZYdn.js +2 -0
  53. package/extensions/dashboard-client/dist/assets/{button-Bynl3ONj.js.map → button-C9qrZYdn.js.map} +1 -1
  54. package/extensions/dashboard-client/dist/assets/{card-Daf3pQIu.js → card-DxZRNC4E.js} +2 -2
  55. package/extensions/dashboard-client/dist/assets/{card-Daf3pQIu.js.map → card-DxZRNC4E.js.map} +1 -1
  56. package/extensions/dashboard-client/dist/assets/client-extra-Dj7wJs6Z.js +2 -0
  57. package/extensions/dashboard-client/dist/assets/{client-extra-DqAYZBW1.js.map → client-extra-Dj7wJs6Z.js.map} +1 -1
  58. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-B-fe5jjr.js → generateCategoricalChart-Dj-DYUgL.js} +2 -2
  59. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-B-fe5jjr.js.map → generateCategoricalChart-Dj-DYUgL.js.map} +1 -1
  60. package/extensions/dashboard-client/dist/assets/{index-Bjvv23bp.js → index-Bq2n15a4.js} +31 -31
  61. package/extensions/dashboard-client/dist/assets/index-Bq2n15a4.js.map +1 -0
  62. package/extensions/dashboard-client/dist/assets/switch-1sEgLPHu.js +2 -0
  63. package/extensions/dashboard-client/dist/assets/{switch-CivyERPS.js.map → switch-1sEgLPHu.js.map} +1 -1
  64. package/extensions/dashboard-client/dist/assets/toggle-jMzQoJ2C.js +2 -0
  65. package/extensions/dashboard-client/dist/assets/{toggle-qmdkrAgF.js.map → toggle-jMzQoJ2C.js.map} +1 -1
  66. package/extensions/dashboard-client/dist/assets/{useSSE-uNuduyGe.js → useSSE-Dxy616R1.js} +2 -2
  67. package/extensions/dashboard-client/dist/assets/{useSSE-uNuduyGe.js.map → useSSE-Dxy616R1.js.map} +1 -1
  68. package/extensions/dashboard-client/dist/index.html +1 -1
  69. package/extensions/dashboard-client/src/App.tsx +150 -17
  70. package/extensions/dashboard-client/src/tabs/AdminTab.tsx +81 -0
  71. package/extensions/dashboard-client/src/tabs/CacheTab/MetricsCards.tsx +66 -0
  72. package/extensions/dashboard-client/src/tabs/CacheTab.tsx +46 -0
  73. package/extensions/dashboard-client/src/tabs/MetricsTab.tsx +10 -51
  74. package/extensions/dashboard-client/src/tabs/SetupTab.tsx +33 -4
  75. package/extensions/dashboard-client/src/tabs/TurnsTab.tsx +9 -366
  76. package/extensions/dashboard-client/src/tabs/dashHashRouter.ts +76 -0
  77. package/extensions/dashboard-client/src/tabs/index.ts +7 -6
  78. package/extensions/dashboard-client/src/tabs/registry.ts +26 -1
  79. package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +12 -0
  80. package/package.json +1 -1
  81. package/src/config/vector-cortex-dash-0c.ts +25 -0
  82. package/src/config/vector-cortex-dash-0d.ts +28 -0
  83. package/src/config/vector-cortex.ts +4 -0
  84. package/src/config.ts +2 -0
  85. package/extensions/dashboard-client/dist/assets/CacheTab-BLM6_PQQ.js +0 -2
  86. package/extensions/dashboard-client/dist/assets/CacheTab-BLM6_PQQ.js.map +0 -1
  87. package/extensions/dashboard-client/dist/assets/HydeDetailPanel-Dt9T7kc5.js +0 -5
  88. package/extensions/dashboard-client/dist/assets/HydeDetailPanel-Dt9T7kc5.js.map +0 -1
  89. package/extensions/dashboard-client/dist/assets/MaintenanceTab-Lm3v0nJO.js +0 -2
  90. package/extensions/dashboard-client/dist/assets/MemoryMapTab-C8AeBIQi.js +0 -2
  91. package/extensions/dashboard-client/dist/assets/MetricsTab-m410T4vk.js.map +0 -1
  92. package/extensions/dashboard-client/dist/assets/SessionsTab-DstDOzwu.js +0 -2
  93. package/extensions/dashboard-client/dist/assets/SessionsTab-DstDOzwu.js.map +0 -1
  94. package/extensions/dashboard-client/dist/assets/SetupTab-DVT4PrH0.js +0 -3
  95. package/extensions/dashboard-client/dist/assets/SetupTab-DVT4PrH0.js.map +0 -1
  96. package/extensions/dashboard-client/dist/assets/TurnsTab-D5QTnv52.js +0 -2
  97. package/extensions/dashboard-client/dist/assets/TurnsTab-D5QTnv52.js.map +0 -1
  98. package/extensions/dashboard-client/dist/assets/button-Bynl3ONj.js +0 -2
  99. package/extensions/dashboard-client/dist/assets/client-extra-DqAYZBW1.js +0 -2
  100. package/extensions/dashboard-client/dist/assets/index-Bjvv23bp.js.map +0 -1
  101. package/extensions/dashboard-client/dist/assets/switch-CivyERPS.js +0 -2
  102. package/extensions/dashboard-client/dist/assets/toggle-qmdkrAgF.js +0 -2
@@ -4,39 +4,53 @@
4
4
  * SPRINT-B1: React scaffold with tab routing, header, error boundary.
5
5
  * SPRINT-C1+: tabs wired progressively with real content.
6
6
  * SPRINT-V2: NEW_UI flag splits OldDashboard (legacy) from NewDashboard (AppShell).
7
+ * DASH-0d: the `TabContent` lazy list + switch consolidate onto the 7 fixed
8
+ * navigational surfaces (Overview, Sessions, Cache+Performance, Memory Graph,
9
+ * Diagnostics, Setup, Admin) behind MEGACOMPACT_DASH_0D. An additive hash router
10
+ * maps every legacy #deep-link to a live consolidated surface. Flag-OFF
11
+ * reproduces the pre-rollup 13-tab surface list byte-identically (the
12
+ * DASH-0D-LEGACY region). The consolidated rendering is the DASH-0D-CONSOLIDATED
13
+ * region — both are parsed by scripts/dash-tab-count.mjs.
7
14
  */
8
15
 
9
- import React, { useState, useCallback } from "react";
16
+ import React, { useState, useEffect, useCallback } from "react";
10
17
  import { ErrorBoundary } from "./components/ErrorBoundary";
11
18
  import { TabBar } from "./components/TabBar";
12
19
  import { LoadingSpinner } from "./components/LoadingSpinner";
13
20
  import { useApi } from "./hooks/useApi";
14
- import { fetchSnapshot } from "./api/client";
15
- import type { SnapshotResponse } from "@contracts";
21
+ import { fetchSnapshot, fetchSettings } from "./api/client";
22
+ import type { SnapshotResponse, SettingsResponse } from "@contracts";
16
23
  import { NEW_UI } from "./config";
17
24
  import { AppShell } from "./components/layout/AppShell";
18
25
  import {
19
26
  PRIMARY_TABS,
20
27
  ADVANCED_TABS,
21
28
  ADVANCED_TAB_IDS as advancedTabIds,
29
+ DASH_SURFACE_IDS,
30
+ DASH_SURFACE_LABELS,
22
31
  type TabId,
32
+ type DashTabId,
23
33
  } from "./tabs/registry";
34
+ import { useHashTab } from "./tabs/dashHashRouter";
24
35
  export type { TabId };
25
36
 
26
- // Tab components — lazy-loaded. C1 fills Overview + Events; C2/C3 fill the rest.
37
+ // Tab components — lazy-loaded. DASH-0d: the consolidated 7 host components come
38
+ // from the merged barrel homes; the 13 legacy-only components stay for flag-off.
27
39
  const OverviewTab = React.lazy(() => import("./tabs/OverviewTab"));
40
+ const SessionsTab = React.lazy(() => import("./tabs/SessionsTab"));
41
+ const CacheTab = React.lazy(() => import("./tabs/CacheTab"));
42
+ const MemoryMapTab = React.lazy(() => import("./tabs/MemoryMapTab"));
43
+ const VectorCortexTab = React.lazy(() => import("./tabs/VectorCortexTab"));
44
+ const SetupTab = React.lazy(() => import("./tabs/SetupTab"));
45
+ const AdminTab = React.lazy(() => import("./tabs/AdminTab"));
46
+ // Legacy-only host components (flag-off pre-rollup surface set).
28
47
  const ReposTab = React.lazy(() => import("./tabs/ReposTab"));
29
48
  const EventsTab = React.lazy(() => import("./tabs/EventsTab"));
30
- const SetupTab = React.lazy(() => import("./tabs/SetupTab"));
31
49
  const MetricsTab = React.lazy(() => import("./tabs/MetricsTab"));
32
- const CacheTab = React.lazy(() => import("./tabs/CacheTab"));
33
- const SessionsTab = React.lazy(() => import("./tabs/SessionsTab"));
34
50
  const WikiTab = React.lazy(() => import("./tabs/WikiTab"));
35
51
  const TurnsTab = React.lazy(() => import("./tabs/TurnsTab"));
36
52
  const MaintenanceTab = React.lazy(() => import("./tabs/MaintenanceTab"));
37
- const MemoryMapTab = React.lazy(() => import("./tabs/MemoryMapTab"));
38
53
  const HealthTab = React.lazy(() => import("./tabs/HealthTab"));
39
- const VectorCortexTab = React.lazy(() => import("./tabs/VectorCortexTab"));
40
54
 
41
55
  interface AppState {
42
56
  snapshot: SnapshotResponse | null;
@@ -44,7 +58,52 @@ interface AppState {
44
58
  error: Error | null;
45
59
  }
46
60
 
47
- function TabContent({
61
+ const DASH_0D_KEY = "MEGACOMPACT_DASH_0D";
62
+
63
+ /**
64
+ * Resolve the DASH-0d consolidation flag from the server-authoritative
65
+ * `/api/rag-settings` state (the dashboard client has no `process` global).
66
+ * Absent/not-yet-loaded => true (default ON), matching the server default.
67
+ */
68
+ function dash0dEnabled(settings: SettingsResponse | null): boolean {
69
+ if (!settings) return true;
70
+ for (const cat of settings.categories) {
71
+ for (const s of cat.settings) {
72
+ if (s.key === DASH_0D_KEY && s.type === "boolean") return s.value === true;
73
+ }
74
+ }
75
+ return true;
76
+ }
77
+
78
+ /** The unified active-tab state: a legacy 13-tab TabId OR a consolidated surface. */
79
+ type ActiveTab = TabId | DashTabId;
80
+
81
+ /** Consolidated 7-surface content (DASH-0d). Parsed by scripts/dash-tab-count.mjs. */
82
+ function ConsolidatedContent({
83
+ activeTab,
84
+ snapshot,
85
+ loading,
86
+ error,
87
+ }: AppState & { activeTab: DashTabId }): React.ReactElement {
88
+ return (
89
+ <React.Suspense fallback={<LoadingSpinner />}>
90
+ {/* DASH-0D-CONSOLIDATED */}
91
+ {activeTab === "overview" && (
92
+ <OverviewTab snapshot={snapshot} loading={loading} error={error} />
93
+ )}
94
+ {activeTab === "sessions" && <SessionsTab />}
95
+ {activeTab === "cache-perf" && <CacheTab />}
96
+ {activeTab === "memory-graph" && <MemoryMapTab />}
97
+ {activeTab === "diagnostics" && <VectorCortexTab />}
98
+ {activeTab === "setup" && <SetupTab />}
99
+ {activeTab === "admin" && <AdminTab />}
100
+ {/* DASH-0D-CONSOLIDATED-END */}
101
+ </React.Suspense>
102
+ );
103
+ }
104
+
105
+ /** Pre-rollup 13-tab content (flag-off). Parsed by scripts/dash-tab-count.mjs. */
106
+ function LegacyContent({
48
107
  activeTab,
49
108
  snapshot,
50
109
  loading,
@@ -52,6 +111,7 @@ function TabContent({
52
111
  }: AppState & { activeTab: TabId }): React.ReactElement {
53
112
  return (
54
113
  <React.Suspense fallback={<LoadingSpinner />}>
114
+ {/* DASH-0D-LEGACY */}
55
115
  {activeTab === "overview" && (
56
116
  <OverviewTab snapshot={snapshot} loading={loading} error={error} />
57
117
  )}
@@ -67,6 +127,7 @@ function TabContent({
67
127
  {activeTab === "memory-map" && <MemoryMapTab />}
68
128
  {activeTab === "health" && <HealthTab />}
69
129
  {activeTab === "vector-cortex" && <VectorCortexTab />}
130
+ {/* DASH-0D-LEGACY-END */}
70
131
  </React.Suspense>
71
132
  );
72
133
  }
@@ -102,7 +163,7 @@ function OldDashboard({
102
163
  onTabChange={setActiveTab}
103
164
  />
104
165
  <main className="dashboard-content">
105
- <TabContent activeTab={activeTab} snapshot={snapshot} loading={loading} error={error} />
166
+ <LegacyContent activeTab={activeTab} snapshot={snapshot} loading={loading} error={error} />
106
167
  </main>
107
168
  </div>
108
169
  </ErrorBoundary>
@@ -122,14 +183,40 @@ function NewDashboard({
122
183
  return (
123
184
  <ErrorBoundary>
124
185
  <AppShell active={activeTab} onTabChange={setActiveTab} snapshot={snapshot}>
125
- <TabContent activeTab={activeTab} snapshot={snapshot} loading={loading} error={error} />
186
+ <LegacyContent activeTab={activeTab} snapshot={snapshot} loading={loading} error={error} />
126
187
  </AppShell>
127
188
  </ErrorBoundary>
128
189
  );
129
190
  }
130
191
 
192
+ /** DASH-0d consolidated 7-surface navigation rail (flag-ON New UI path). */
193
+ function ConsolidatedNav({
194
+ active,
195
+ onSelect,
196
+ }: {
197
+ active: DashTabId;
198
+ onSelect: (id: DashTabId) => void;
199
+ }): React.ReactElement {
200
+ return (
201
+ <nav className="consolidated-nav" role="tablist" aria-label="Dashboard surfaces">
202
+ {DASH_SURFACE_IDS.map((id) => (
203
+ <button
204
+ key={id}
205
+ type="button"
206
+ role="tab"
207
+ aria-selected={active === id}
208
+ className={active === id ? "active" : ""}
209
+ onClick={() => onSelect(id)}
210
+ >
211
+ {DASH_SURFACE_LABELS[id] ?? id}
212
+ </button>
213
+ ))}
214
+ </nav>
215
+ );
216
+ }
217
+
131
218
  export default function App(): React.ReactElement {
132
- const [activeTab, setActiveTab] = useState<TabId>("overview");
219
+ const [activeTab, setActiveTab] = useState<ActiveTab>("overview");
133
220
  const {
134
221
  data: snapshot,
135
222
  loading,
@@ -142,11 +229,57 @@ export default function App(): React.ReactElement {
142
229
  },
143
230
  );
144
231
 
232
+ // Server-resolved DASH-0d flag (default ON when settings absent).
233
+ const { data: settingsData } = useApi<SettingsResponse>(
234
+ useCallback(() => fetchSettings(), []),
235
+ { pollInterval: 0, maxRetries: 0 },
236
+ );
237
+ const dash0dOn = dash0dEnabled(settingsData);
238
+
239
+ // Additive hash→surface deep-link router: every legacy #hash maps to a live
240
+ // consolidated surface; empty hash keeps current behavior (default overview).
241
+ // Only active under the DASH-0d 7-surface rendering — flag-off keeps the
242
+ // pre-rollup 13-tab behavior unchanged (hash ignored).
243
+ const hashSurface = useHashTab();
244
+ useEffect(() => {
245
+ if (dash0dOn && hashSurface != null) setActiveTab(hashSurface);
246
+ }, [dash0dOn, hashSurface]);
247
+
248
+ // Flag-ON consolidated New-UI surface: a 7-surface rail + the consolidated
249
+ // content. Flag-OFF (or legacy NEW_UI false) renders the 13-tab path as today.
250
+ if (NEW_UI() && dash0dOn) {
251
+ const current = DASH_SURFACE_IDS.includes(activeTab as DashTabId)
252
+ ? (activeTab as DashTabId)
253
+ : "overview";
254
+ return (
255
+ <ErrorBoundary>
256
+ <div className="dashboard-app">
257
+ <header className="dashboard-header">
258
+ <h1>mega-compact dashboard <span className="tier">{snapshot?.tier ?? "unknown"}</span></h1>
259
+ </header>
260
+ <ConsolidatedNav active={current} onSelect={(id: DashTabId) => setActiveTab(id)} />
261
+ <main className="dashboard-content">
262
+ <ConsolidatedContent
263
+ activeTab={current}
264
+ snapshot={snapshot}
265
+ loading={loading}
266
+ error={error}
267
+ />
268
+ </main>
269
+ </div>
270
+ </ErrorBoundary>
271
+ );
272
+ }
273
+
274
+ // Flag-off (or legacy NEW_UI): always a legacy TabId (hash routing is gated
275
+ // on dash0dOn above, so activeTab stays a 13-tab id here).
276
+ const legacyTab = (activeTab as TabId) ?? "overview";
277
+
145
278
  if (NEW_UI()) {
146
279
  return (
147
280
  <NewDashboard
148
- activeTab={activeTab}
149
- setActiveTab={setActiveTab}
281
+ activeTab={legacyTab}
282
+ setActiveTab={(id: TabId) => setActiveTab(id)}
150
283
  snapshot={snapshot}
151
284
  loading={loading}
152
285
  error={error}
@@ -156,8 +289,8 @@ export default function App(): React.ReactElement {
156
289
 
157
290
  return (
158
291
  <OldDashboard
159
- activeTab={activeTab}
160
- setActiveTab={setActiveTab}
292
+ activeTab={legacyTab}
293
+ setActiveTab={(id: TabId) => setActiveTab(id)}
161
294
  snapshot={snapshot}
162
295
  loading={loading}
163
296
  error={error}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * dashboard-client/src/tabs/AdminTab.tsx — Admin tab (DASH-0c delegate-shell).
3
+ *
4
+ * DASH-0c: the Admin surface combines the maintenance actions with the config
5
+ * editor. A `AdminViews` toggle ("maintenance" / "config") switches between
6
+ * `MaintenanceTab` (the maintenance shell over MaintenanceTab/*) and `ConfigTab`
7
+ * (the config editor). Both bodies are UNCHANGED — only their hosting changes to
8
+ * this new delegate-shell. `MaintenanceTab.tsx` and `ConfigTab.tsx` stay importable
9
+ * from their original hosts (`ConfigTab` also stays wired into SetupTab per the
10
+ * dual-host note). Flag-ON renders the toggle + both views; flag-OFF renders only
11
+ * the maintenance view (the predecessor's `admin → MaintenanceTab` mapping),
12
+ * and App.tsx keeps its current TabId routing this sprint (DASH-0d rewires).
13
+ *
14
+ * Flag: `MEGACOMPACT_DASH_0C` default ON. The dashboard client is a browser
15
+ * bundle with NO `process` global, so the positive sprint flag cannot be read
16
+ * server-side-style (`process.env`) inside the client. Instead the flag is read
17
+ * from the server-authoritative `/api/rag-settings` state: the server resolves
18
+ * `process.env["MEGACOMPACT_DASH_0C"] ?? default` into the `SettingState.value`
19
+ * boolean.
20
+ */
21
+
22
+ import type React from "react";
23
+ import { useCallback, useState } from "react";
24
+ import type { SettingsResponse } from "@contracts";
25
+ import { useApi } from "../hooks/useApi";
26
+ import { fetchSettings } from "../api/client";
27
+ import { Toggle } from "../components/ui/toggle";
28
+ import MaintenanceTab from "./MaintenanceTab";
29
+ import ConfigTab from "./ConfigTab";
30
+
31
+ const DASH_0C_KEY = "MEGACOMPACT_DASH_0C";
32
+
33
+ /** Resolve the DASH-0c consolidation flag from the server settings state.
34
+ * Absent/not-yet-loaded => false (flag-off posture), so flag-off users never
35
+ * see the toggle flash; the toggle appears only once settings confirm it is ON. */
36
+ function dash0cEnabled(settings: SettingsResponse | null): boolean {
37
+ if (!settings) return false;
38
+ for (const cat of settings.categories) {
39
+ for (const s of cat.settings) {
40
+ if (s.key === DASH_0C_KEY && s.type === "boolean") return s.value === true;
41
+ }
42
+ }
43
+ return false;
44
+ }
45
+
46
+ type AdminViews = "maintenance" | "config";
47
+
48
+ export default function AdminTab(): React.ReactElement {
49
+ const [view, setView] = useState<AdminViews>("maintenance");
50
+
51
+ const { data: settingsData } = useApi<SettingsResponse>(
52
+ useCallback(() => fetchSettings(), []),
53
+ { pollInterval: 0, maxRetries: 0 },
54
+ );
55
+ const dash0cOn = dash0cEnabled(settingsData);
56
+
57
+ if (!dash0cOn) {
58
+ return <MaintenanceTab />;
59
+ }
60
+
61
+ return (
62
+ <div className="flex flex-col gap-4">
63
+ <div
64
+ className="flex items-center gap-2"
65
+ role="tablist"
66
+ aria-label="Admin views"
67
+ >
68
+ <Toggle
69
+ pressed={view === "maintenance"}
70
+ onClick={() => setView("maintenance")}
71
+ >
72
+ Maintenance
73
+ </Toggle>
74
+ <Toggle pressed={view === "config"} onClick={() => setView("config")}>
75
+ Config
76
+ </Toggle>
77
+ </div>
78
+ {view === "maintenance" ? <MaintenanceTab /> : <ConfigTab />}
79
+ </div>
80
+ );
81
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * dashboard-client/src/tabs/CacheTab/MetricsCards.tsx — Performance cards (C2),
3
+ * moved VERBATIM from the top-level MetricsTab.tsx.
4
+ *
5
+ * DASH-0c: the Cache+Performance surface absorbs MetricsTab as a Performance
6
+ * section. This file holds the byte-preserved metrics body (the `MetricsCards`
7
+ * component). The standalone `tabs/MetricsTab.tsx` is reduced to a shell that
8
+ * re-exports it (kept for the #metrics deep-link + rollback symmetry). Only the
9
+ * export name changed (MetricsTab → MetricsCards); the render body is otherwise
10
+ * identical.
11
+ *
12
+ * Fetches /api/perf (rolling-window aggregates) + /api/snapshot (for model).
13
+ * Renders ModelBadge + PerfChart + 5 perf cards (latency, throughput, process,
14
+ * snapshot cost, TUI lag proxy). Polls every 10s.
15
+ */
16
+
17
+ import type React from "react";
18
+ import { useCallback } from "react";
19
+ import { useApi } from "../../hooks/useApi";
20
+ import { fetchPerf, fetchSnapshot } from "../../api/client";
21
+ import type { PerfResponse, SnapshotResponse } from "@contracts";
22
+ import { NEW_UI } from "../../config";
23
+ import { PerfChart } from "../../components/PerfChart";
24
+ import { PerfCards } from "../../components/PerfCards";
25
+ import { ModelBadge } from "../../components/ModelBadge";
26
+ import { RagDashboard } from "../../components/RagDashboard";
27
+
28
+ export function MetricsCards(): React.ReactElement {
29
+ const { data: perf, error: perfErr } = useApi<PerfResponse>(
30
+ useCallback(() => fetchPerf({ minutes: 30 }), []),
31
+ { pollInterval: 10_000 },
32
+ );
33
+ const { data: snapshot } = useApi<SnapshotResponse>(
34
+ useCallback(() => fetchSnapshot(), []),
35
+ { pollInterval: 10_000 },
36
+ );
37
+
38
+ if (perfErr && !perf) {
39
+ return (
40
+ <div className="tab-stub">Error loading perf: {perfErr.message}</div>
41
+ );
42
+ }
43
+ if (!perf) {
44
+ return <div className="tab-stub">Loading perf…</div>;
45
+ }
46
+
47
+ return (
48
+ <div className="flex flex-col gap-4">
49
+ {snapshot?.model && (
50
+ <ModelBadge
51
+ name={snapshot.model.name}
52
+ providerName={snapshot.model.providerName}
53
+ provider={snapshot.model.provider}
54
+ inputRate={snapshot.model.inputRate}
55
+ outputRate={snapshot.model.outputRate}
56
+ />
57
+ )}
58
+ <PerfChart perf={perf} />
59
+ <PerfCards perf={perf} />
60
+ <div className="text-xs text-muted-foreground">
61
+ {perf.sampleCount} samples · updated {perf.updatedAt}
62
+ </div>
63
+ {NEW_UI() && <RagDashboard />}
64
+ </div>
65
+ );
66
+ }
@@ -18,6 +18,7 @@ import type {
18
18
  CacheStripesResponse,
19
19
  PerfResponse,
20
20
  PrefixStabilityResponse,
21
+ SettingsResponse,
21
22
  } from "@contracts";
22
23
  import { useApi } from "../hooks/useApi";
23
24
  import {
@@ -26,6 +27,7 @@ import {
26
27
  fetchCacheStripes,
27
28
  fetchPrefixStability,
28
29
  fetchPerf,
30
+ fetchSettings,
29
31
  } from "../api/client";
30
32
  import { CacheHitsCard } from "../components/CacheHitsCard";
31
33
  import { TimeSavedCard } from "../components/TimeSavedCard";
@@ -35,6 +37,25 @@ import { CacheHitRateTrendCard } from "../components/CacheHitRateTrendCard";
35
37
  import { PrefixStabilityCard } from "../components/PrefixStabilityCard";
36
38
  import { Button } from "../components/ui/button";
37
39
  import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card";
40
+ import { MetricsCards } from "./CacheTab/MetricsCards";
41
+
42
+ const DASH_0C_KEY = "MEGACOMPACT_DASH_0C";
43
+
44
+ /** Resolve the DASH-0c consolidation flag from the server settings state.
45
+ * The dashboard client is a browser bundle with NO `process` global, so the
46
+ * positive sprint flag is read from the server-authoritative /api/rag-settings
47
+ * state (the server resolves MEGACOMPACT_DASH_0C into a SettingState boolean).
48
+ * Absent/not-yet-loaded => false (flag-off posture), so flag-off users never
49
+ * see the Performance section flash; it mounts only once settings confirm ON. */
50
+ function dash0cEnabled(settings: SettingsResponse | null): boolean {
51
+ if (!settings) return false;
52
+ for (const cat of settings.categories) {
53
+ for (const s of cat.settings) {
54
+ if (s.key === DASH_0C_KEY && s.type === "boolean") return s.value === true;
55
+ }
56
+ }
57
+ return false;
58
+ }
38
59
 
39
60
  export default function CacheTab(): React.ReactElement {
40
61
  const [infoExpanded, setInfoExpanded] = useState(false);
@@ -87,6 +108,13 @@ export default function CacheTab(): React.ReactElement {
87
108
  { pollInterval: 5000 },
88
109
  );
89
110
 
111
+ /* --- DASH-0c: server-resolved settings state for the flag gate --- */
112
+ const { data: settingsData } = useApi<SettingsResponse>(
113
+ useCallback(() => fetchSettings(), []),
114
+ { pollInterval: 0, maxRetries: 0 },
115
+ );
116
+ const dash0cOn = dash0cEnabled(settingsData);
117
+
90
118
  return (
91
119
  <div className="flex flex-col gap-4">
92
120
  <div>
@@ -223,6 +251,24 @@ export default function CacheTab(): React.ReactElement {
223
251
  );
224
252
  })()
225
253
  )}
254
+ {/* ==============================================================
255
+ Section 5 -- Performance (DASH-0c)
256
+ The metrics body (ModelBadge + PerfChart + PerfCards + RagDashboard)
257
+ absorbed from MetricsTab as a Performance section. Moved VERBATIM to
258
+ ./CacheTab/MetricsCards.tsx. Omitted entirely when flag-off so the
259
+ cache-only body is byte-identical to the predecessor.
260
+ ============================================================== */}
261
+ {dash0cOn && (
262
+ <section aria-labelledby="cache-perf-cards">
263
+ <h2
264
+ id="cache-perf-cards"
265
+ className="font-heading text-lg font-semibold"
266
+ >
267
+ Performance
268
+ </h2>
269
+ <MetricsCards />
270
+ </section>
271
+ )}
226
272
  </div>
227
273
  );
228
274
  }
@@ -1,58 +1,17 @@
1
1
  /**
2
- * dashboard-client/src/tabs/MetricsTab.tsx — Metrics tab (C2).
2
+ * dashboard-client/src/tabs/MetricsTab.tsx — Metrics tab (C2) shell.
3
3
  *
4
- * Fetches /api/perf (rolling-window aggregates) + /api/snapshot (for model).
5
- * Renders ModelBadge + PerfChart + 5 perf cards (latency, throughput, process,
6
- * snapshot cost, TUI lag proxy). Polls every 10s.
4
+ * DASH-0c: the Cache+Performance surface absorbs the metrics body as a
5
+ * Performance section; this file is reduced to a shell that re-exports
6
+ * `MetricsCards` (the byte-preserved body moved to ./CacheTab/MetricsCards.tsx).
7
+ * Kept as a deep-link anchor for #metrics and for rollback symmetry (flag-off
8
+ * renders MetricsTab as a standalone top-level surface). A DASH-0d cleanup deletes
9
+ * this standalone copy after a deep-link audit proves no live consumer points
10
+ * at it. The render body is otherwise identical to the pre-DASH-0c MetricsTab.
7
11
  */
8
12
 
9
- import type React from "react";
10
- import { useCallback } from "react";
11
- import { useApi } from "../hooks/useApi";
12
- import { fetchPerf, fetchSnapshot } from "../api/client";
13
- import type { PerfResponse, SnapshotResponse } from "@contracts";
14
- import { NEW_UI } from "../config";
15
- import { PerfChart } from "../components/PerfChart";
16
- import { PerfCards } from "../components/PerfCards";
17
- import { ModelBadge } from "../components/ModelBadge";
18
- import { RagDashboard } from "../components/RagDashboard";
13
+ import { MetricsCards } from "./CacheTab/MetricsCards";
19
14
 
20
15
  export default function MetricsTab(): React.ReactElement {
21
- const { data: perf, error: perfErr } = useApi<PerfResponse>(
22
- useCallback(() => fetchPerf({ minutes: 30 }), []),
23
- { pollInterval: 10_000 },
24
- );
25
- const { data: snapshot } = useApi<SnapshotResponse>(
26
- useCallback(() => fetchSnapshot(), []),
27
- { pollInterval: 10_000 },
28
- );
29
-
30
- if (perfErr && !perf) {
31
- return (
32
- <div className="tab-stub">Error loading perf: {perfErr.message}</div>
33
- );
34
- }
35
- if (!perf) {
36
- return <div className="tab-stub">Loading perf…</div>;
37
- }
38
-
39
- return (
40
- <div className="flex flex-col gap-4">
41
- {snapshot?.model && (
42
- <ModelBadge
43
- name={snapshot.model.name}
44
- providerName={snapshot.model.providerName}
45
- provider={snapshot.model.provider}
46
- inputRate={snapshot.model.inputRate}
47
- outputRate={snapshot.model.outputRate}
48
- />
49
- )}
50
- <PerfChart perf={perf} />
51
- <PerfCards perf={perf} />
52
- <div className="text-xs text-muted-foreground">
53
- {perf.sampleCount} samples · updated {perf.updatedAt}
54
- </div>
55
- {NEW_UI() && <RagDashboard />}
56
- </div>
57
- );
16
+ return <MetricsCards />;
58
17
  }
@@ -10,7 +10,8 @@
10
10
  * no external network calls.
11
11
  */
12
12
  import type React from "react";
13
- import { useState, useMemo } from "react";
13
+ import { useState, useMemo, useCallback } from "react";
14
+ import type { SettingsResponse } from "@contracts";
14
15
  import GameTab from "./GameTab";
15
16
  import AchievementsTab from "./AchievementsTab";
16
17
  import ConfigTab from "./ConfigTab";
@@ -18,8 +19,26 @@ import EmbedderSetup from "./SetupTab/EmbedderSetup";
18
19
  import ThresholdsPanel from "./SetupTab/ThresholdsPanel";
19
20
  import CortexSetup from "./SetupTab/CortexSetup";
20
21
  import { Toggle } from "../components/ui/toggle";
22
+ import { useApi } from "../hooks/useApi";
23
+ import { fetchSettings } from "../api/client";
21
24
  import { useSetupCortexPoll, isCortexSubTabVisible } from "./useSetupCortexPoll";
22
25
 
26
+ const DASH_0C_KEY = "MEGACOMPACT_DASH_0C";
27
+
28
+ /** Resolve the DASH-0c consolidation flag from the server settings state.
29
+ * Absent/not-yet-loaded => false (flag-off posture), so flag-off users keep the
30
+ * Config sub-tab; it is hidden only once settings confirm the flag is ON (the
31
+ * config editor then lives solely on the Admin surface). */
32
+ function dash0cEnabled(settings: SettingsResponse | null): boolean {
33
+ if (!settings) return false;
34
+ for (const cat of settings.categories) {
35
+ for (const s of cat.settings) {
36
+ if (s.key === DASH_0C_KEY && s.type === "boolean") return s.value === true;
37
+ }
38
+ }
39
+ return false;
40
+ }
41
+
23
42
  type SetupSubTab =
24
43
  | "embedder"
25
44
  | "thresholds"
@@ -43,11 +62,21 @@ export default function SetupTab(): React.ReactElement {
43
62
  const [subTab, setSubTab] = useState<SetupSubTab>("embedder");
44
63
  const [cortex] = useSetupCortexPoll();
45
64
 
65
+ /* DASH-0c: flag-ON hides the config sub-tab member (the config editor is then
66
+ * reachable only via the Admin surface). Flag-OFF renders config as today. */
67
+ const { data: settingsData } = useApi<SettingsResponse>(
68
+ useCallback(() => fetchSettings(), []),
69
+ { pollInterval: 0, maxRetries: 0 },
70
+ );
71
+ const dash0cOn = dash0cEnabled(settingsData);
72
+
46
73
  const subTabs = useMemo(() => {
47
- const tabs = [...BASE_SUB_TABS];
74
+ const tabs = dash0cOn
75
+ ? BASE_SUB_TABS.filter((t) => t.id !== "config")
76
+ : [...BASE_SUB_TABS];
48
77
  if (isCortexSubTabVisible(cortex.data)) tabs.push(CORTEX_TAB);
49
78
  return tabs;
50
- }, [cortex.data]);
79
+ }, [cortex.data, dash0cOn]);
51
80
 
52
81
  return (
53
82
  <div className="mx-auto flex max-w-3xl flex-col gap-4 p-4">
@@ -68,7 +97,7 @@ export default function SetupTab(): React.ReactElement {
68
97
 
69
98
  {subTab === "embedder" && <EmbedderSetup />}
70
99
  {subTab === "thresholds" && <ThresholdsPanel />}
71
- {subTab === "config" && <ConfigTab />}
100
+ {subTab === "config" && !dash0cOn && <ConfigTab />}
72
101
  {subTab === "game" && <GameTab />}
73
102
  {subTab === "achievements" && <AchievementsTab />}
74
103
  {subTab === "cortex" && <CortexSetup />}