pi-mega-compact 0.20.60 → 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.
- package/dist/config/vector-cortex-dash-0d.js +26 -0
- package/dist/config/vector-cortex.js +2 -0
- package/dist/config.js +1 -1
- package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +1 -0
- package/dist/src/config/vector-cortex-dash-0d.js +26 -0
- package/dist/src/config/vector-cortex.js +2 -0
- package/dist/src/config.js +1 -1
- package/extensions/dashboard-client/dist/assets/AdminTab-DEjVnlwe.js +2 -0
- package/extensions/dashboard-client/dist/assets/AdminTab-DEjVnlwe.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{AreaChart-B5Is2_EN.js → AreaChart-B1PoTqKJ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AreaChart-B5Is2_EN.js.map → AreaChart-B1PoTqKJ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{BarChart-Bj2oT871.js → BarChart-DaoONT_V.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{BarChart-Bj2oT871.js.map → BarChart-DaoONT_V.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{CacheTab-DuhLeKHW.js → CacheTab-rD5sjlkW.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-DuhLeKHW.js.map → CacheTab-rD5sjlkW.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/ConfigTab-BQkufK7t.js +2 -0
- package/extensions/dashboard-client/dist/assets/ConfigTab-BQkufK7t.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{EventsTab-BG6L8uWh.js → EventsTab-DGlQzJaT.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-BG6L8uWh.js.map → EventsTab-DGlQzJaT.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HealthTab-CZmGCUJh.js → HealthTab-DW7kt4qm.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HealthTab-CZmGCUJh.js.map → HealthTab-DW7kt4qm.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-CGiZ0OQ6.js +2 -0
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-CoZ1mSjU.js.map → MaintenanceTab-CGiZ0OQ6.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-BwyrxjuW.js +2 -0
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-BwVaWniY.js.map → MemoryMapTab-BwyrxjuW.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsCards-BCJoHe_n.js → MetricsCards-IZaCOOXU.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsCards-BCJoHe_n.js.map → MetricsCards-IZaCOOXU.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/MetricsTab-wCxVpHlC.js +2 -0
- package/extensions/dashboard-client/dist/assets/{MetricsTab-UQSqUGXe.js.map → MetricsTab-wCxVpHlC.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-qi12IYvs.js → OverviewTab-DsH08Wr0.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-qi12IYvs.js.map → OverviewTab-DsH08Wr0.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-CcHZPzOO.js → ReposTab-Dpb7sXWB.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-CcHZPzOO.js.map → ReposTab-Dpb7sXWB.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/SessionsTab-DFMo7tKA.js +2 -0
- package/extensions/dashboard-client/dist/assets/SessionsTab-DFMo7tKA.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-D2IEBt1u.js +3 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-D2IEBt1u.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-DhfdRM3_.js → TimeSavedCard-BGPvmVFG.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-DhfdRM3_.js.map → TimeSavedCard-BGPvmVFG.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/TurnMemoryView-BZo09Jri.js +5 -0
- package/extensions/dashboard-client/dist/assets/TurnMemoryView-BZo09Jri.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/TurnsTab-CosKNvMp.js +2 -0
- package/extensions/dashboard-client/dist/assets/TurnsTab-CosKNvMp.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{VcStatusBadge-XGMW6u62.js → VcStatusBadge-UEZLL6Zj.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{VcStatusBadge-XGMW6u62.js.map → VcStatusBadge-UEZLL6Zj.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{VectorCortexTab-BACHKLjU.js → VectorCortexTab-fDAgD2pN.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{VectorCortexTab-BACHKLjU.js.map → VectorCortexTab-fDAgD2pN.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{WikiTab-CGQWHuRq.js → WikiTab-7TIe2MkS.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{WikiTab-CGQWHuRq.js.map → WikiTab-7TIe2MkS.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/button-C9qrZYdn.js +2 -0
- package/extensions/dashboard-client/dist/assets/{button-SyOWCGkp.js.map → button-C9qrZYdn.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{card-69DCTMel.js → card-DxZRNC4E.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{card-69DCTMel.js.map → card-DxZRNC4E.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/client-extra-Dj7wJs6Z.js +2 -0
- package/extensions/dashboard-client/dist/assets/{client-extra-CgeDg1Md.js.map → client-extra-Dj7wJs6Z.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-BwTtrqm5.js → generateCategoricalChart-Dj-DYUgL.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-BwTtrqm5.js.map → generateCategoricalChart-Dj-DYUgL.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-BZcYzeCr.js → index-Bq2n15a4.js} +31 -31
- package/extensions/dashboard-client/dist/assets/index-Bq2n15a4.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/switch-1sEgLPHu.js +2 -0
- package/extensions/dashboard-client/dist/assets/{switch-DhQfmSFD.js.map → switch-1sEgLPHu.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/toggle-jMzQoJ2C.js +2 -0
- package/extensions/dashboard-client/dist/assets/{toggle-B3gNAVog.js.map → toggle-jMzQoJ2C.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-BkkjZ4bO.js → useSSE-Dxy616R1.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-BkkjZ4bO.js.map → useSSE-Dxy616R1.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/App.tsx +150 -17
- package/extensions/dashboard-client/src/tabs/TurnsTab.tsx +9 -366
- package/extensions/dashboard-client/src/tabs/dashHashRouter.ts +76 -0
- package/extensions/dashboard-client/src/tabs/registry.ts +9 -1
- package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +6 -0
- package/package.json +1 -1
- package/src/config/vector-cortex-dash-0d.ts +28 -0
- package/src/config/vector-cortex.ts +2 -0
- package/src/config.ts +1 -0
- package/extensions/dashboard-client/dist/assets/HydeDetailPanel-B-P1jTtk.js +0 -5
- package/extensions/dashboard-client/dist/assets/HydeDetailPanel-B-P1jTtk.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-CoZ1mSjU.js +0 -2
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-BwVaWniY.js +0 -2
- package/extensions/dashboard-client/dist/assets/MetricsTab-UQSqUGXe.js +0 -2
- package/extensions/dashboard-client/dist/assets/SessionsTab-nzd1408Z.js +0 -2
- package/extensions/dashboard-client/dist/assets/SessionsTab-nzd1408Z.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/SetupTab-DPrG3s9V.js +0 -3
- package/extensions/dashboard-client/dist/assets/SetupTab-DPrG3s9V.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/TurnsTab-oalBNLVr.js +0 -2
- package/extensions/dashboard-client/dist/assets/TurnsTab-oalBNLVr.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/button-SyOWCGkp.js +0 -2
- package/extensions/dashboard-client/dist/assets/client-extra-CgeDg1Md.js +0 -2
- package/extensions/dashboard-client/dist/assets/index-BZcYzeCr.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/switch-DhQfmSFD.js +0 -2
- package/extensions/dashboard-client/dist/assets/toggle-B3gNAVog.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.
|
|
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
|
-
|
|
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
|
-
<
|
|
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
|
-
<
|
|
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<
|
|
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={
|
|
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={
|
|
160
|
-
setActiveTab={setActiveTab}
|
|
292
|
+
activeTab={legacyTab}
|
|
293
|
+
setActiveTab={(id: TabId) => setActiveTab(id)}
|
|
161
294
|
snapshot={snapshot}
|
|
162
295
|
loading={loading}
|
|
163
296
|
error={error}
|
|
@@ -1,374 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* dashboard-client/src/tabs/TurnsTab.tsx — Turn-by-turn memory
|
|
2
|
+
* dashboard-client/src/tabs/TurnsTab.tsx — Turn-by-turn memory surface (S52).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* - Pending rewind intents (S52A) + Fork action (S50C primitive).
|
|
11
|
-
*
|
|
12
|
-
* Read-mostly via /api/turns; fork/intent/prune via POST. No absolute URLs
|
|
13
|
-
* (PREVENT-PI-004: loopback-only, same-origin static bundle).
|
|
4
|
+
* DASH-0d consolidation: the sessions surface owns the turns body as a drill-
|
|
5
|
+
* down (`SessionsTab/TurnMemoryView.tsx`, re-homed VERBATIM in DASH-0b). This
|
|
6
|
+
* standalone top-level file is reduced to a thin shell re-exporting
|
|
7
|
+
* `TurnMemoryView`, so the flag-off pre-rollup 13-tab surface set still
|
|
8
|
+
* resolves `TurnsTab` (deep-link + lazy-import anchor) with no duplicated
|
|
9
|
+
* render body. The canonical home is `SessionsTab/TurnMemoryView.tsx`.
|
|
14
10
|
*/
|
|
15
11
|
|
|
16
12
|
import type React from "react";
|
|
17
|
-
import {
|
|
18
|
-
import { useApi } from "../hooks/useApi";
|
|
19
|
-
import {
|
|
20
|
-
fetchTurns,
|
|
21
|
-
fetchConversationTurns,
|
|
22
|
-
fetchTurnIntents,
|
|
23
|
-
postFork,
|
|
24
|
-
postTurnIntent,
|
|
25
|
-
} from "../api/client";
|
|
26
|
-
import type {
|
|
27
|
-
TurnsResponse,
|
|
28
|
-
ConversationTurnsResponse,
|
|
29
|
-
RewindIntentsResponse,
|
|
30
|
-
TurnRow,
|
|
31
|
-
ConversationSummary,
|
|
32
|
-
} from "@contracts";
|
|
33
|
-
import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card";
|
|
34
|
-
import { Badge } from "../components/ui/badge";
|
|
35
|
-
import { Button } from "../components/ui/button";
|
|
36
|
-
import { HydeDetailPanel } from "../components/HydeDetailPanel";
|
|
37
|
-
|
|
38
|
-
function fmtTs(ms: number): string {
|
|
39
|
-
if (!ms) return "—";
|
|
40
|
-
return new Date(ms).toLocaleString();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function bandVariant(band: TurnRow["pressureBand"]): "success" | "warning" | "danger" | "default" {
|
|
44
|
-
if (band === "green") return "success";
|
|
45
|
-
if (band === "yellow") return "warning";
|
|
46
|
-
if (band === "red") return "danger";
|
|
47
|
-
return "default";
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function sourceLabel(s: TurnRow["recall"][number]["source"]): string {
|
|
51
|
-
if (s === "checkpoint") return "ckpt";
|
|
52
|
-
if (s === "cluster_summary") return "raptor";
|
|
53
|
-
return "mem";
|
|
54
|
-
}
|
|
13
|
+
import { TurnMemoryView } from "./SessionsTab/TurnMemoryView";
|
|
55
14
|
|
|
56
15
|
export default function TurnsTab(): React.ReactElement {
|
|
57
|
-
|
|
58
|
-
data: turns,
|
|
59
|
-
loading,
|
|
60
|
-
error,
|
|
61
|
-
} = useApi<TurnsResponse>(
|
|
62
|
-
useCallback(() => fetchTurns(), []),
|
|
63
|
-
{
|
|
64
|
-
pollInterval: 10_000,
|
|
65
|
-
},
|
|
66
|
-
);
|
|
67
|
-
const { data: intents } = useApi<RewindIntentsResponse>(
|
|
68
|
-
useCallback(() => fetchTurnIntents(), []),
|
|
69
|
-
{ pollInterval: 5_000 },
|
|
70
|
-
);
|
|
71
|
-
const [expanded, setExpanded] = useState<string | null>(null);
|
|
72
|
-
const [detail, setDetail] = useState<ConversationTurnsResponse | null>(null);
|
|
73
|
-
const [detailLoading, setDetailLoading] = useState(false);
|
|
74
|
-
const [busy, setBusy] = useState<string | null>(null);
|
|
75
|
-
const [notice, setNotice] = useState<string | null>(null);
|
|
76
|
-
|
|
77
|
-
const expand = useCallback(
|
|
78
|
-
async (conversationId: string) => {
|
|
79
|
-
if (expanded === conversationId) {
|
|
80
|
-
setExpanded(null);
|
|
81
|
-
setDetail(null);
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
setExpanded(conversationId);
|
|
85
|
-
setDetailLoading(true);
|
|
86
|
-
setDetail(null);
|
|
87
|
-
try {
|
|
88
|
-
const d = await fetchConversationTurns(conversationId);
|
|
89
|
-
setDetail(d);
|
|
90
|
-
} finally {
|
|
91
|
-
setDetailLoading(false);
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
[expanded],
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
const onFork = useCallback(
|
|
98
|
-
async (conversationId: string, turnIndex: number) => {
|
|
99
|
-
setBusy(`fork:${conversationId}:${turnIndex}`);
|
|
100
|
-
setNotice(null);
|
|
101
|
-
try {
|
|
102
|
-
const out = await postFork(conversationId, turnIndex);
|
|
103
|
-
setNotice(
|
|
104
|
-
`Forked → ${out.childConversationId} (${out.recalledCount} recalled)`,
|
|
105
|
-
);
|
|
106
|
-
} catch (e) {
|
|
107
|
-
setNotice(`Fork failed: ${(e as Error).message}`);
|
|
108
|
-
} finally {
|
|
109
|
-
setBusy(null);
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
[],
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
const onRewind = useCallback(
|
|
116
|
-
async (conversationId: string, turnIndex: number) => {
|
|
117
|
-
setBusy(`rewind:${conversationId}:${turnIndex}`);
|
|
118
|
-
setNotice(null);
|
|
119
|
-
try {
|
|
120
|
-
await postTurnIntent(conversationId, turnIndex);
|
|
121
|
-
setNotice(`Rewind intent queued for turn ${turnIndex}`);
|
|
122
|
-
} catch (e) {
|
|
123
|
-
setNotice(`Rewind failed: ${(e as Error).message}`);
|
|
124
|
-
} finally {
|
|
125
|
-
setBusy(null);
|
|
126
|
-
}
|
|
127
|
-
},
|
|
128
|
-
[],
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
if (error && !turns) {
|
|
132
|
-
return <div className="tab-stub">Error loading turns: {error.message}</div>;
|
|
133
|
-
}
|
|
134
|
-
if (loading && !turns) {
|
|
135
|
-
return <div className="tab-stub">Loading turns…</div>;
|
|
136
|
-
}
|
|
137
|
-
if (!turns || turns.conversations.length === 0) {
|
|
138
|
-
return (
|
|
139
|
-
<div className="tab-stub">
|
|
140
|
-
<h3>Turn-by-turn memory</h3>
|
|
141
|
-
<p>
|
|
142
|
-
No turns recorded yet. Per-turn tracking starts when{" "}
|
|
143
|
-
<code>MEGACOMPACT_TURNS_DB=1</code> and the session runs through a
|
|
144
|
-
compaction. Each turn records its context metrics + the checkpoints
|
|
145
|
-
recalled into it.
|
|
146
|
-
</p>
|
|
147
|
-
</div>
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return (
|
|
152
|
-
<div className="flex flex-col gap-4">
|
|
153
|
-
<h3 className="font-heading text-lg font-semibold">
|
|
154
|
-
Turn-by-turn memory tracking + recall
|
|
155
|
-
</h3>
|
|
156
|
-
{notice && <Badge variant="warning">{notice}</Badge>}
|
|
157
|
-
|
|
158
|
-
{intents && intents.intents.length > 0 && (
|
|
159
|
-
<Card>
|
|
160
|
-
<CardHeader>
|
|
161
|
-
<CardTitle>
|
|
162
|
-
Pending rewind intents ({intents.intents.length})
|
|
163
|
-
</CardTitle>
|
|
164
|
-
</CardHeader>
|
|
165
|
-
<CardContent>
|
|
166
|
-
<ul className="list-disc space-y-1 pl-5">
|
|
167
|
-
{intents.intents.map((i) => (
|
|
168
|
-
<li key={i.id}>
|
|
169
|
-
{fmtTs(i.createdAt)} — rewind{" "}
|
|
170
|
-
<code>{i.conversationId}</code> to turn {i.targetTurnIndex}
|
|
171
|
-
</li>
|
|
172
|
-
))}
|
|
173
|
-
</ul>
|
|
174
|
-
</CardContent>
|
|
175
|
-
</Card>
|
|
176
|
-
)}
|
|
177
|
-
|
|
178
|
-
<Card>
|
|
179
|
-
<CardHeader>
|
|
180
|
-
<CardTitle>
|
|
181
|
-
Conversations ({turns.conversations.length})
|
|
182
|
-
</CardTitle>
|
|
183
|
-
</CardHeader>
|
|
184
|
-
<CardContent>
|
|
185
|
-
<table className="w-full border-collapse text-sm">
|
|
186
|
-
<thead>
|
|
187
|
-
<tr>
|
|
188
|
-
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Conversation</th>
|
|
189
|
-
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Turns</th>
|
|
190
|
-
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Recall</th>
|
|
191
|
-
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Epochs</th>
|
|
192
|
-
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Avg ctx%</th>
|
|
193
|
-
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Last turn</th>
|
|
194
|
-
<th className="border-b border-border px-3 py-2"></th>
|
|
195
|
-
</tr>
|
|
196
|
-
</thead>
|
|
197
|
-
<tbody>
|
|
198
|
-
{turns.conversations.map((c: ConversationSummary) => (
|
|
199
|
-
<ConversationRow
|
|
200
|
-
key={c.conversationId}
|
|
201
|
-
c={c}
|
|
202
|
-
active={turns.activeConversationId === c.conversationId}
|
|
203
|
-
expanded={expanded === c.conversationId}
|
|
204
|
-
onExpand={() => expand(c.conversationId)}
|
|
205
|
-
/>
|
|
206
|
-
))}
|
|
207
|
-
</tbody>
|
|
208
|
-
</table>
|
|
209
|
-
</CardContent>
|
|
210
|
-
</Card>
|
|
211
|
-
|
|
212
|
-
{expanded && (
|
|
213
|
-
<Card>
|
|
214
|
-
<CardHeader>
|
|
215
|
-
<CardTitle>
|
|
216
|
-
Turns in <code>{expanded}</code>
|
|
217
|
-
</CardTitle>
|
|
218
|
-
</CardHeader>
|
|
219
|
-
<CardContent>
|
|
220
|
-
{detailLoading ? (
|
|
221
|
-
<div className="text-sm text-muted-foreground">Loading turns…</div>
|
|
222
|
-
) : detail ? (
|
|
223
|
-
<TurnDetail
|
|
224
|
-
detail={detail}
|
|
225
|
-
busy={busy}
|
|
226
|
-
onFork={onFork}
|
|
227
|
-
onRewind={onRewind}
|
|
228
|
-
/>
|
|
229
|
-
) : (
|
|
230
|
-
<div className="text-sm text-muted-foreground">No detail.</div>
|
|
231
|
-
)}
|
|
232
|
-
</CardContent>
|
|
233
|
-
</Card>
|
|
234
|
-
)}
|
|
235
|
-
</div>
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function ConversationRow({
|
|
240
|
-
c,
|
|
241
|
-
active,
|
|
242
|
-
expanded,
|
|
243
|
-
onExpand,
|
|
244
|
-
}: {
|
|
245
|
-
c: ConversationSummary;
|
|
246
|
-
active: boolean;
|
|
247
|
-
expanded: boolean;
|
|
248
|
-
onExpand: () => void;
|
|
249
|
-
}): React.ReactElement {
|
|
250
|
-
return (
|
|
251
|
-
<>
|
|
252
|
-
<tr
|
|
253
|
-
className={`border-b border-border/50 hover:bg-bg-elevated/40 ${
|
|
254
|
-
active ? "bg-primary/10" : ""
|
|
255
|
-
}`}
|
|
256
|
-
onClick={onExpand}
|
|
257
|
-
style={{ cursor: "pointer" }}
|
|
258
|
-
>
|
|
259
|
-
<td className="px-3 py-2">
|
|
260
|
-
{expanded ? "▾" : "▸"} <code>{c.conversationId}</code>
|
|
261
|
-
{active && <Badge variant="accent" className="ml-2">active</Badge>}
|
|
262
|
-
</td>
|
|
263
|
-
<td className="px-3 py-2 text-right">{c.turnCount}</td>
|
|
264
|
-
<td className="px-3 py-2 text-right">{c.totalRecall}</td>
|
|
265
|
-
<td className="px-3 py-2 text-right">{c.epochCount}</td>
|
|
266
|
-
<td className="px-3 py-2 text-right">{c.avgCtxPercent.toFixed(0)}%</td>
|
|
267
|
-
<td className="px-3 py-2">{fmtTs(c.lastTurnAt)}</td>
|
|
268
|
-
<td className="px-3 py-2" />
|
|
269
|
-
</tr>
|
|
270
|
-
</>
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
function TurnDetail({
|
|
275
|
-
detail,
|
|
276
|
-
busy,
|
|
277
|
-
onFork,
|
|
278
|
-
onRewind,
|
|
279
|
-
}: {
|
|
280
|
-
detail: ConversationTurnsResponse;
|
|
281
|
-
busy: string | null;
|
|
282
|
-
onFork: (conversationId: string, turnIndex: number) => void;
|
|
283
|
-
onRewind: (conversationId: string, turnIndex: number) => void;
|
|
284
|
-
}): React.ReactElement {
|
|
285
|
-
return (
|
|
286
|
-
<table className="w-full border-collapse text-sm">
|
|
287
|
-
<thead>
|
|
288
|
-
<tr>
|
|
289
|
-
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">#</th>
|
|
290
|
-
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Role</th>
|
|
291
|
-
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Ctx</th>
|
|
292
|
-
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Band</th>
|
|
293
|
-
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Epoch</th>
|
|
294
|
-
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Recalled checkpoints (memory recall)</th>
|
|
295
|
-
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">HyDE</th>
|
|
296
|
-
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Ended</th>
|
|
297
|
-
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Actions</th>
|
|
298
|
-
</tr>
|
|
299
|
-
</thead>
|
|
300
|
-
<tbody>
|
|
301
|
-
{detail.turns.map((t) => (
|
|
302
|
-
<tr
|
|
303
|
-
key={`${t.conversationId}:${t.turnIndex}`}
|
|
304
|
-
className="border-b border-border/50 hover:bg-bg-elevated/40"
|
|
305
|
-
>
|
|
306
|
-
<td className="px-3 py-2 text-right">{t.turnIndex}</td>
|
|
307
|
-
<td className="px-3 py-2">{t.role}</td>
|
|
308
|
-
<td className="px-3 py-2">
|
|
309
|
-
{t.ctxTokens ?? "—"}
|
|
310
|
-
{t.ctxPercent != null && (
|
|
311
|
-
<span className="text-muted-foreground">
|
|
312
|
-
{" "}
|
|
313
|
-
· {t.ctxPercent.toFixed(0)}%
|
|
314
|
-
</span>
|
|
315
|
-
)}
|
|
316
|
-
</td>
|
|
317
|
-
<td className="px-3 py-2">
|
|
318
|
-
<Badge variant={bandVariant(t.pressureBand)}>
|
|
319
|
-
{t.pressureBand ?? "—"}
|
|
320
|
-
</Badge>
|
|
321
|
-
</td>
|
|
322
|
-
<td className="px-3 py-2">{t.epochId ? <code>{t.epochId.slice(0, 8)}</code> : "—"}</td>
|
|
323
|
-
<td className="px-3 py-2">
|
|
324
|
-
{t.recall.length === 0 ? (
|
|
325
|
-
<span className="text-muted-foreground">—</span>
|
|
326
|
-
) : (
|
|
327
|
-
<ul className="space-y-1">
|
|
328
|
-
{t.recall.map((r) => (
|
|
329
|
-
<li key={r.checkpointId}>
|
|
330
|
-
<code>{r.checkpointId.slice(0, 12)}</code>{" "}
|
|
331
|
-
<span className="text-muted-foreground">
|
|
332
|
-
{sourceLabel(r.source)} · {r.score.toFixed(2)}
|
|
333
|
-
{r.raptorLevel != null ? ` · L${r.raptorLevel}` : ""}
|
|
334
|
-
</span>
|
|
335
|
-
</li>
|
|
336
|
-
))}
|
|
337
|
-
</ul>
|
|
338
|
-
)}
|
|
339
|
-
</td>
|
|
340
|
-
<td className="px-3 py-2 align-top">
|
|
341
|
-
<HydeDetailPanel
|
|
342
|
-
conversationId={t.conversationId}
|
|
343
|
-
turnIndex={t.turnIndex}
|
|
344
|
-
/>
|
|
345
|
-
</td>
|
|
346
|
-
<td className="px-3 py-2">{fmtTs(t.endedAt)}</td>
|
|
347
|
-
<td className="px-3 py-2">
|
|
348
|
-
<div className="flex gap-2">
|
|
349
|
-
<Button
|
|
350
|
-
type="button"
|
|
351
|
-
variant="outline"
|
|
352
|
-
size="sm"
|
|
353
|
-
disabled={busy !== null}
|
|
354
|
-
onClick={() => onFork(t.conversationId, t.turnIndex)}
|
|
355
|
-
>
|
|
356
|
-
fork
|
|
357
|
-
</Button>
|
|
358
|
-
<Button
|
|
359
|
-
type="button"
|
|
360
|
-
variant="outline"
|
|
361
|
-
size="sm"
|
|
362
|
-
disabled={busy !== null}
|
|
363
|
-
onClick={() => onRewind(t.conversationId, t.turnIndex)}
|
|
364
|
-
>
|
|
365
|
-
rewind
|
|
366
|
-
</Button>
|
|
367
|
-
</div>
|
|
368
|
-
</td>
|
|
369
|
-
</tr>
|
|
370
|
-
))}
|
|
371
|
-
</tbody>
|
|
372
|
-
</table>
|
|
373
|
-
);
|
|
16
|
+
return <TurnMemoryView />;
|
|
374
17
|
}
|