codex-devtools 0.1.10 → 0.2.0
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/bin/codex-devtools.cjs +1 -0
- package/dist-electron/main/chunks/{CodexServiceContext-CRkTP14W.cjs → CodexServiceContext-BYe2UXME.cjs} +788 -56
- package/dist-electron/main/index.cjs +46 -2
- package/dist-electron/main/standalone.cjs +76 -15
- package/dist-electron/preload/index.cjs +2 -0
- package/out/renderer/assets/{index-C1DUQHyp.js → index-C-iGxog-.js} +467 -23
- package/out/renderer/assets/{index-BTmVA30y.css → index-D3FYKy1U.css} +230 -16
- package/out/renderer/index.html +2 -2
- package/package.json +1 -1
|
@@ -7055,6 +7055,14 @@ class HttpApiClient {
|
|
|
7055
7055
|
async getSessionChunks(sessionId) {
|
|
7056
7056
|
return this.get(`/sessions/${encodeURIComponent(sessionId)}/chunks`);
|
|
7057
7057
|
}
|
|
7058
|
+
async getStats(scope = { type: "all" }) {
|
|
7059
|
+
if (scope.type === "project") {
|
|
7060
|
+
return this.get(
|
|
7061
|
+
`/stats?scope=project&cwd=${encodeURIComponent(scope.cwd)}`
|
|
7062
|
+
);
|
|
7063
|
+
}
|
|
7064
|
+
return this.get("/stats?scope=all");
|
|
7065
|
+
}
|
|
7058
7066
|
async searchSessions(query) {
|
|
7059
7067
|
return this.get(`/search?q=${encodeURIComponent(query)}`);
|
|
7060
7068
|
}
|
|
@@ -7142,6 +7150,7 @@ function resolveApi() {
|
|
|
7142
7150
|
}
|
|
7143
7151
|
return cachedHttpApi;
|
|
7144
7152
|
}
|
|
7153
|
+
const isElectronMode = () => getWindowApi() !== null;
|
|
7145
7154
|
const api = new Proxy({}, {
|
|
7146
7155
|
get(_target, prop, receiver) {
|
|
7147
7156
|
const impl = resolveApi();
|
|
@@ -7484,6 +7493,7 @@ function isCodexBootstrapMessage(content) {
|
|
|
7484
7493
|
}
|
|
7485
7494
|
const logger = createLogger("Store:sessionSlice");
|
|
7486
7495
|
const PREVIEW_PREFETCH_LIMIT = 25;
|
|
7496
|
+
const DEFAULT_PREFETCH_PREVIEWS = isElectronMode();
|
|
7487
7497
|
function normalizeFilePath(value) {
|
|
7488
7498
|
return value.trim().replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
7489
7499
|
}
|
|
@@ -7527,7 +7537,7 @@ const createSessionSlice = (client2) => (set, get) => ({
|
|
|
7527
7537
|
set({ sessions: [], activeSessionId: null });
|
|
7528
7538
|
return;
|
|
7529
7539
|
}
|
|
7530
|
-
const shouldPrefetchPreviews = (_a = options == null ? void 0 : options.prefetchPreviews) != null ? _a :
|
|
7540
|
+
const shouldPrefetchPreviews = (_a = options == null ? void 0 : options.prefetchPreviews) != null ? _a : DEFAULT_PREFETCH_PREVIEWS;
|
|
7531
7541
|
const isBackgroundRefresh = (_b = options == null ? void 0 : options.background) != null ? _b : false;
|
|
7532
7542
|
if (!isBackgroundRefresh) {
|
|
7533
7543
|
set({ sessionsLoading: true, sessionsError: null });
|
|
@@ -7640,8 +7650,57 @@ const createSessionSlice = (client2) => (set, get) => ({
|
|
|
7640
7650
|
});
|
|
7641
7651
|
}
|
|
7642
7652
|
});
|
|
7653
|
+
function normalizeScope$1(scope) {
|
|
7654
|
+
var _a;
|
|
7655
|
+
if (!scope || scope.type === "all") {
|
|
7656
|
+
return { type: "all" };
|
|
7657
|
+
}
|
|
7658
|
+
const cwd = (_a = scope.cwd) == null ? void 0 : _a.trim();
|
|
7659
|
+
if (!cwd) {
|
|
7660
|
+
return { type: "all" };
|
|
7661
|
+
}
|
|
7662
|
+
return {
|
|
7663
|
+
type: "project",
|
|
7664
|
+
cwd
|
|
7665
|
+
};
|
|
7666
|
+
}
|
|
7667
|
+
const createStatsSlice = (client2) => (set, get) => ({
|
|
7668
|
+
statsData: null,
|
|
7669
|
+
statsScope: { type: "all" },
|
|
7670
|
+
statsLoading: false,
|
|
7671
|
+
statsError: null,
|
|
7672
|
+
fetchStats: async (scope, options) => {
|
|
7673
|
+
var _a;
|
|
7674
|
+
const resolvedScope = normalizeScope$1(scope != null ? scope : get().statsScope);
|
|
7675
|
+
const background = (_a = options == null ? void 0 : options.background) != null ? _a : false;
|
|
7676
|
+
if (!background) {
|
|
7677
|
+
set({ statsLoading: true, statsError: null });
|
|
7678
|
+
}
|
|
7679
|
+
try {
|
|
7680
|
+
const statsData = await client2.getStats(resolvedScope);
|
|
7681
|
+
set((state) => ({
|
|
7682
|
+
statsData,
|
|
7683
|
+
statsScope: resolvedScope,
|
|
7684
|
+
statsLoading: background ? state.statsLoading : false,
|
|
7685
|
+
statsError: null
|
|
7686
|
+
}));
|
|
7687
|
+
} catch (error) {
|
|
7688
|
+
set((state) => ({
|
|
7689
|
+
statsScope: resolvedScope,
|
|
7690
|
+
statsLoading: background ? state.statsLoading : false,
|
|
7691
|
+
statsError: error instanceof Error ? error.message : "Failed to fetch stats"
|
|
7692
|
+
}));
|
|
7693
|
+
}
|
|
7694
|
+
},
|
|
7695
|
+
setStatsScope: async (scope) => {
|
|
7696
|
+
const resolvedScope = normalizeScope$1(scope);
|
|
7697
|
+
set({ statsScope: resolvedScope });
|
|
7698
|
+
await get().fetchStats(resolvedScope);
|
|
7699
|
+
}
|
|
7700
|
+
});
|
|
7643
7701
|
const DASHBOARD_TAB_ID$2 = "dashboard";
|
|
7644
7702
|
const SETTINGS_TAB_ID$2 = "settings";
|
|
7703
|
+
const STATS_TAB_ID$3 = "stats";
|
|
7645
7704
|
function createSessionTabId(sessionId) {
|
|
7646
7705
|
return `session:${sessionId}`;
|
|
7647
7706
|
}
|
|
@@ -7672,6 +7731,10 @@ const createTabSlice = (_client) => (set, get) => ({
|
|
|
7672
7731
|
openDashboardTab: () => {
|
|
7673
7732
|
set({ activeTabId: DASHBOARD_TAB_ID$2, activeSessionId: null });
|
|
7674
7733
|
},
|
|
7734
|
+
openStatsTab: () => {
|
|
7735
|
+
set({ activeTabId: STATS_TAB_ID$3, activeSessionId: null });
|
|
7736
|
+
void get().fetchStats(get().statsScope);
|
|
7737
|
+
},
|
|
7675
7738
|
openSettingsTab: () => {
|
|
7676
7739
|
set({ activeTabId: SETTINGS_TAB_ID$2, activeSessionId: null });
|
|
7677
7740
|
},
|
|
@@ -7688,6 +7751,9 @@ const createTabSlice = (_client) => (set, get) => ({
|
|
|
7688
7751
|
if (tab.type === "session" && tab.sessionId) {
|
|
7689
7752
|
void get().fetchChunks(tab.sessionId);
|
|
7690
7753
|
}
|
|
7754
|
+
if (tab.type === "stats") {
|
|
7755
|
+
void get().fetchStats(get().statsScope);
|
|
7756
|
+
}
|
|
7691
7757
|
},
|
|
7692
7758
|
closeTab: (tabId) => {
|
|
7693
7759
|
set((state) => {
|
|
@@ -7726,6 +7792,7 @@ const createUISlice = (_client) => (set) => ({
|
|
|
7726
7792
|
const createAppStore = (client2 = api) => create()((...args) => ({
|
|
7727
7793
|
...createProjectSlice(client2)(...args),
|
|
7728
7794
|
...createSessionSlice(client2)(...args),
|
|
7795
|
+
...createStatsSlice(client2)(...args),
|
|
7729
7796
|
...createConversationSlice(client2)(...args),
|
|
7730
7797
|
...createConfigSlice(client2)(...args),
|
|
7731
7798
|
...createTabSlice()(...args),
|
|
@@ -7734,7 +7801,8 @@ const createAppStore = (client2 = api) => create()((...args) => ({
|
|
|
7734
7801
|
}));
|
|
7735
7802
|
const useAppStore = createAppStore();
|
|
7736
7803
|
const REFRESH_DEBOUNCE_MS = 120;
|
|
7737
|
-
const FALLBACK_POLL_INTERVAL_MS =
|
|
7804
|
+
const FALLBACK_POLL_INTERVAL_MS = 5e3;
|
|
7805
|
+
const STATS_TAB_ID$2 = "stats";
|
|
7738
7806
|
function initializeEventListeners(store = useAppStore, client2 = api) {
|
|
7739
7807
|
let refreshTimer = null;
|
|
7740
7808
|
let pollTimer = null;
|
|
@@ -7758,6 +7826,9 @@ function initializeEventListeners(store = useAppStore, client2 = api) {
|
|
|
7758
7826
|
if (state.activeSessionId) {
|
|
7759
7827
|
void state.fetchChunks(state.activeSessionId);
|
|
7760
7828
|
}
|
|
7829
|
+
if (state.activeTabId === STATS_TAB_ID$2) {
|
|
7830
|
+
void state.fetchStats(state.statsScope, { background: true });
|
|
7831
|
+
}
|
|
7761
7832
|
}, REFRESH_DEBOUNCE_MS);
|
|
7762
7833
|
});
|
|
7763
7834
|
const runFallbackRefresh = () => {
|
|
@@ -7780,7 +7851,8 @@ function initializeEventListeners(store = useAppStore, client2 = api) {
|
|
|
7780
7851
|
prefetchPreviews: false,
|
|
7781
7852
|
background: true
|
|
7782
7853
|
}) : Promise.resolve(),
|
|
7783
|
-
state.activeSessionId ? state.fetchChunks(state.activeSessionId) : Promise.resolve()
|
|
7854
|
+
state.activeSessionId ? state.fetchChunks(state.activeSessionId) : Promise.resolve(),
|
|
7855
|
+
state.activeTabId === STATS_TAB_ID$2 ? state.fetchStats(state.statsScope, { background: true }) : Promise.resolve()
|
|
7784
7856
|
]).finally(() => {
|
|
7785
7857
|
polling = false;
|
|
7786
7858
|
});
|
|
@@ -9351,6 +9423,256 @@ const DashboardView = () => {
|
|
|
9351
9423
|
] })
|
|
9352
9424
|
] });
|
|
9353
9425
|
};
|
|
9426
|
+
function formatDuration$1(durationMs) {
|
|
9427
|
+
if (!Number.isFinite(durationMs) || durationMs <= 0) {
|
|
9428
|
+
return "0m";
|
|
9429
|
+
}
|
|
9430
|
+
const totalMinutes = Math.round(durationMs / 6e4);
|
|
9431
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
9432
|
+
const minutes = totalMinutes % 60;
|
|
9433
|
+
if (hours <= 0) {
|
|
9434
|
+
return `${minutes}m`;
|
|
9435
|
+
}
|
|
9436
|
+
if (minutes === 0) {
|
|
9437
|
+
return `${hours}h`;
|
|
9438
|
+
}
|
|
9439
|
+
return `${hours}h ${minutes}m`;
|
|
9440
|
+
}
|
|
9441
|
+
function normalizeScope(scope) {
|
|
9442
|
+
if (scope.type === "project" && scope.cwd.trim().length > 0) {
|
|
9443
|
+
return { type: "project", cwd: scope.cwd.trim() };
|
|
9444
|
+
}
|
|
9445
|
+
return { type: "all" };
|
|
9446
|
+
}
|
|
9447
|
+
const StatsView = () => {
|
|
9448
|
+
const {
|
|
9449
|
+
projects,
|
|
9450
|
+
statsData,
|
|
9451
|
+
statsScope,
|
|
9452
|
+
statsLoading,
|
|
9453
|
+
statsError,
|
|
9454
|
+
fetchStats,
|
|
9455
|
+
setStatsScope
|
|
9456
|
+
} = useAppStore((state) => ({
|
|
9457
|
+
projects: state.projects,
|
|
9458
|
+
statsData: state.statsData,
|
|
9459
|
+
statsScope: state.statsScope,
|
|
9460
|
+
statsLoading: state.statsLoading,
|
|
9461
|
+
statsError: state.statsError,
|
|
9462
|
+
fetchStats: state.fetchStats,
|
|
9463
|
+
setStatsScope: state.setStatsScope
|
|
9464
|
+
}));
|
|
9465
|
+
reactExports.useEffect(() => {
|
|
9466
|
+
if (!statsData && !statsLoading) {
|
|
9467
|
+
void fetchStats(statsScope);
|
|
9468
|
+
}
|
|
9469
|
+
}, [statsData, statsLoading, fetchStats, statsScope]);
|
|
9470
|
+
const dailyMaxOutput = reactExports.useMemo(
|
|
9471
|
+
() => {
|
|
9472
|
+
var _a;
|
|
9473
|
+
return Math.max(...(_a = statsData == null ? void 0 : statsData.daily.map((point) => point.outputTokens)) != null ? _a : [1]);
|
|
9474
|
+
},
|
|
9475
|
+
[statsData]
|
|
9476
|
+
);
|
|
9477
|
+
const hourlyMaxEvents = reactExports.useMemo(
|
|
9478
|
+
() => {
|
|
9479
|
+
var _a;
|
|
9480
|
+
return Math.max(...(_a = statsData == null ? void 0 : statsData.hourly.map((point) => point.eventCount)) != null ? _a : [1]);
|
|
9481
|
+
},
|
|
9482
|
+
[statsData]
|
|
9483
|
+
);
|
|
9484
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "stats-shell", children: [
|
|
9485
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("header", { className: "stats-header", children: [
|
|
9486
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { children: "Stats" }),
|
|
9487
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "Token volume, activity patterns, model usage, and reasoning effort." })
|
|
9488
|
+
] }),
|
|
9489
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "stats-controls", children: [
|
|
9490
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "sidebar-label", htmlFor: "stats-scope", children: "Scope" }),
|
|
9491
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
9492
|
+
"select",
|
|
9493
|
+
{
|
|
9494
|
+
id: "stats-scope",
|
|
9495
|
+
className: "app-select",
|
|
9496
|
+
value: statsScope.type,
|
|
9497
|
+
onChange: (event) => {
|
|
9498
|
+
var _a, _b;
|
|
9499
|
+
if (event.target.value === "project") {
|
|
9500
|
+
const defaultProject = (_b = (_a = projects[0]) == null ? void 0 : _a.cwd) != null ? _b : "";
|
|
9501
|
+
void setStatsScope({ type: "project", cwd: defaultProject });
|
|
9502
|
+
return;
|
|
9503
|
+
}
|
|
9504
|
+
void setStatsScope({ type: "all" });
|
|
9505
|
+
},
|
|
9506
|
+
children: [
|
|
9507
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "all", children: "All projects" }),
|
|
9508
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "project", children: "Single project" })
|
|
9509
|
+
]
|
|
9510
|
+
}
|
|
9511
|
+
),
|
|
9512
|
+
statsScope.type === "project" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
9513
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "sidebar-label", htmlFor: "stats-project", children: "Project" }),
|
|
9514
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
9515
|
+
"select",
|
|
9516
|
+
{
|
|
9517
|
+
id: "stats-project",
|
|
9518
|
+
className: "app-select",
|
|
9519
|
+
value: statsScope.cwd,
|
|
9520
|
+
onChange: (event) => {
|
|
9521
|
+
void setStatsScope({ type: "project", cwd: event.target.value });
|
|
9522
|
+
},
|
|
9523
|
+
children: [
|
|
9524
|
+
projects.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: "No projects available" }) : null,
|
|
9525
|
+
projects.map((project) => /* @__PURE__ */ jsxRuntimeExports.jsxs("option", { value: project.cwd, children: [
|
|
9526
|
+
project.name,
|
|
9527
|
+
" - ",
|
|
9528
|
+
project.cwd
|
|
9529
|
+
] }, project.cwd))
|
|
9530
|
+
]
|
|
9531
|
+
}
|
|
9532
|
+
)
|
|
9533
|
+
] }) : null,
|
|
9534
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
9535
|
+
"button",
|
|
9536
|
+
{
|
|
9537
|
+
type: "button",
|
|
9538
|
+
className: "tabbar-action",
|
|
9539
|
+
onClick: () => {
|
|
9540
|
+
void fetchStats(normalizeScope(statsScope));
|
|
9541
|
+
},
|
|
9542
|
+
children: "Refresh"
|
|
9543
|
+
}
|
|
9544
|
+
)
|
|
9545
|
+
] }),
|
|
9546
|
+
statsError ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "stats-error", children: statsError }) : null,
|
|
9547
|
+
!statsData ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "empty-view", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "empty-title", children: statsLoading ? "Loading stats..." : "No stats available yet" }) }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
9548
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "stats-kpi-grid", children: [
|
|
9549
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("article", { className: "stat-card", children: [
|
|
9550
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "stat-label", children: "Total tokens" }),
|
|
9551
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "stat-value", children: statsData.totals.totalTokens.toLocaleString() })
|
|
9552
|
+
] }),
|
|
9553
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("article", { className: "stat-card", children: [
|
|
9554
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "stat-label", children: "Generated tokens" }),
|
|
9555
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "stat-value", children: statsData.totals.outputTokens.toLocaleString() })
|
|
9556
|
+
] }),
|
|
9557
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("article", { className: "stat-card", children: [
|
|
9558
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "stat-label", children: "Active time" }),
|
|
9559
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "stat-value", children: formatDuration$1(statsData.totals.durationMs) })
|
|
9560
|
+
] }),
|
|
9561
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("article", { className: "stat-card", children: [
|
|
9562
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "stat-label", children: "Sessions" }),
|
|
9563
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("strong", { className: "stat-value", children: [
|
|
9564
|
+
statsData.totals.sessions.toLocaleString(),
|
|
9565
|
+
statsData.totals.archivedSessions > 0 ? ` (${statsData.totals.archivedSessions.toLocaleString()} archived)` : ""
|
|
9566
|
+
] })
|
|
9567
|
+
] })
|
|
9568
|
+
] }),
|
|
9569
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "stats-section", children: [
|
|
9570
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "stats-section-header", children: [
|
|
9571
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { children: "Generated tokens by day" }),
|
|
9572
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "stats-section-subtle", children: "Output tokens" })
|
|
9573
|
+
] }),
|
|
9574
|
+
statsData.daily.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "empty-copy", children: "No daily token data yet." }) : /* @__PURE__ */ jsxRuntimeExports.jsx("ul", { className: "stats-day-list", children: statsData.daily.map((point) => {
|
|
9575
|
+
const widthPercent = dailyMaxOutput > 0 ? Math.max(6, point.outputTokens / dailyMaxOutput * 100) : 6;
|
|
9576
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { className: "stats-day-row", children: [
|
|
9577
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "stats-day-label", children: point.date }),
|
|
9578
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "stats-day-bar-wrap", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "stats-day-bar", style: { width: `${widthPercent}%` } }) }),
|
|
9579
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "stats-day-value", children: point.outputTokens.toLocaleString() })
|
|
9580
|
+
] }, point.date);
|
|
9581
|
+
}) })
|
|
9582
|
+
] }),
|
|
9583
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "stats-grid-2", children: [
|
|
9584
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("article", { className: "stats-section", children: [
|
|
9585
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "stats-section-header", children: [
|
|
9586
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { children: "Most active days" }),
|
|
9587
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "stats-section-subtle", children: "By event count" })
|
|
9588
|
+
] }),
|
|
9589
|
+
statsData.topDays.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "empty-copy", children: "No activity data yet." }) : /* @__PURE__ */ jsxRuntimeExports.jsx("ul", { className: "stats-top-list", children: statsData.topDays.map((day) => /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { className: "stats-top-item", children: [
|
|
9590
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: day.date }),
|
|
9591
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
9592
|
+
day.eventCount.toLocaleString(),
|
|
9593
|
+
" events"
|
|
9594
|
+
] })
|
|
9595
|
+
] }, day.date)) })
|
|
9596
|
+
] }),
|
|
9597
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("article", { className: "stats-section", children: [
|
|
9598
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "stats-section-header", children: [
|
|
9599
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { children: "Most active hours" }),
|
|
9600
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "stats-section-subtle", children: "By event count" })
|
|
9601
|
+
] }),
|
|
9602
|
+
statsData.topHours.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "empty-copy", children: "No activity data yet." }) : /* @__PURE__ */ jsxRuntimeExports.jsx("ul", { className: "stats-top-list", children: statsData.topHours.map((hour) => /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { className: "stats-top-item", children: [
|
|
9603
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
9604
|
+
String(hour.hour).padStart(2, "0"),
|
|
9605
|
+
":00"
|
|
9606
|
+
] }),
|
|
9607
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
9608
|
+
hour.eventCount.toLocaleString(),
|
|
9609
|
+
" events"
|
|
9610
|
+
] })
|
|
9611
|
+
] }, hour.hour)) })
|
|
9612
|
+
] })
|
|
9613
|
+
] }),
|
|
9614
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "stats-section", children: [
|
|
9615
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "stats-section-header", children: [
|
|
9616
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { children: "Hourly activity heatmap" }),
|
|
9617
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "stats-section-subtle", children: "Event count + token volume + session presence" })
|
|
9618
|
+
] }),
|
|
9619
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "stats-heatmap-grid", children: statsData.hourly.map((point) => {
|
|
9620
|
+
const intensity = point.eventCount <= 0 ? 0 : point.eventCount / hourlyMaxEvents;
|
|
9621
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
9622
|
+
"div",
|
|
9623
|
+
{
|
|
9624
|
+
className: "stats-heat-cell",
|
|
9625
|
+
style: {
|
|
9626
|
+
backgroundColor: intensity === 0 ? "rgba(59, 130, 246, 0.08)" : `rgba(59, 130, 246, ${0.16 + intensity * 0.66})`
|
|
9627
|
+
},
|
|
9628
|
+
title: `${String(point.hour).padStart(2, "0")}:00 • ${point.eventCount.toLocaleString()} events • ${point.totalTokens.toLocaleString()} tokens • ${point.sessionCount.toLocaleString()} sessions`,
|
|
9629
|
+
children: [
|
|
9630
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: String(point.hour).padStart(2, "0") }),
|
|
9631
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: point.eventCount.toLocaleString() })
|
|
9632
|
+
]
|
|
9633
|
+
},
|
|
9634
|
+
point.hour
|
|
9635
|
+
);
|
|
9636
|
+
}) })
|
|
9637
|
+
] }),
|
|
9638
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "stats-grid-2", children: [
|
|
9639
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("article", { className: "stats-section", children: [
|
|
9640
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "stats-section-header", children: [
|
|
9641
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { children: "Models and reasoning effort" }),
|
|
9642
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "stats-section-subtle", children: "Token distribution" })
|
|
9643
|
+
] }),
|
|
9644
|
+
statsData.models.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "empty-copy", children: "No model usage data yet." }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "stats-table-wrap", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("table", { className: "stats-table", children: [
|
|
9645
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("thead", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { children: [
|
|
9646
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("th", { children: "Model" }),
|
|
9647
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("th", { children: "Effort" }),
|
|
9648
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("th", { children: "Tokens" }),
|
|
9649
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("th", { children: "Sessions" })
|
|
9650
|
+
] }) }),
|
|
9651
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("tbody", { children: statsData.models.map((model) => /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { children: [
|
|
9652
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { children: model.model }),
|
|
9653
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { children: model.reasoningEffort }),
|
|
9654
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { children: model.totalTokens.toLocaleString() }),
|
|
9655
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("td", { children: model.sessionCount.toLocaleString() })
|
|
9656
|
+
] }, `${model.model}::${model.reasoningEffort}`)) })
|
|
9657
|
+
] }) })
|
|
9658
|
+
] }),
|
|
9659
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("article", { className: "stats-section", children: [
|
|
9660
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "stats-section-header", children: [
|
|
9661
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { children: "Reasoning effort mix" }),
|
|
9662
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "stats-section-subtle", children: "Across all models" })
|
|
9663
|
+
] }),
|
|
9664
|
+
statsData.reasoningEfforts.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "empty-copy", children: "No reasoning effort data yet." }) : /* @__PURE__ */ jsxRuntimeExports.jsx("ul", { className: "stats-top-list", children: statsData.reasoningEfforts.map((effort) => /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { className: "stats-top-item", children: [
|
|
9665
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: effort.reasoningEffort }),
|
|
9666
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
9667
|
+
effort.totalTokens.toLocaleString(),
|
|
9668
|
+
" tokens"
|
|
9669
|
+
] })
|
|
9670
|
+
] }, effort.reasoningEffort)) })
|
|
9671
|
+
] })
|
|
9672
|
+
] })
|
|
9673
|
+
] })
|
|
9674
|
+
] });
|
|
9675
|
+
};
|
|
9354
9676
|
const SettingsView = () => {
|
|
9355
9677
|
const { appConfig, configLoading, fetchConfig, updateConfig } = useAppStore((state) => ({
|
|
9356
9678
|
appConfig: state.appConfig,
|
|
@@ -11318,6 +11640,16 @@ function getPreludeHint(kind) {
|
|
|
11318
11640
|
return "System prelude";
|
|
11319
11641
|
}
|
|
11320
11642
|
}
|
|
11643
|
+
function buildSessionTokenStats() {
|
|
11644
|
+
return {
|
|
11645
|
+
totalTokens: 0,
|
|
11646
|
+
inputTokens: 0,
|
|
11647
|
+
outputTokens: 0
|
|
11648
|
+
};
|
|
11649
|
+
}
|
|
11650
|
+
function buildSystemPreludeKey(timestamp, rowIndex) {
|
|
11651
|
+
return `${timestamp}-${rowIndex}`;
|
|
11652
|
+
}
|
|
11321
11653
|
const ChatHistory = ({ sessionId }) => {
|
|
11322
11654
|
const { chunks, chunksLoading, chunksSessionId, sessions } = useAppStore((state) => ({
|
|
11323
11655
|
chunks: state.chunks,
|
|
@@ -11332,7 +11664,40 @@ const ChatHistory = ({ sessionId }) => {
|
|
|
11332
11664
|
estimateSize: () => 168,
|
|
11333
11665
|
overscan: 6
|
|
11334
11666
|
});
|
|
11667
|
+
const [expandedPreludeKeys, setExpandedPreludeKeys] = reactExports.useState(
|
|
11668
|
+
() => /* @__PURE__ */ new Set()
|
|
11669
|
+
);
|
|
11335
11670
|
const virtualRows = rowVirtualizer.getVirtualItems();
|
|
11671
|
+
const remeasureVisibleRows = reactExports.useCallback(() => {
|
|
11672
|
+
rowVirtualizer.measure();
|
|
11673
|
+
const parent = parentRef.current;
|
|
11674
|
+
if (!parent) {
|
|
11675
|
+
return;
|
|
11676
|
+
}
|
|
11677
|
+
for (const row of rowVirtualizer.getVirtualItems()) {
|
|
11678
|
+
const element = parent.querySelector(`[data-index="${row.index}"]`);
|
|
11679
|
+
if (!element) {
|
|
11680
|
+
continue;
|
|
11681
|
+
}
|
|
11682
|
+
rowVirtualizer.measureElement(element);
|
|
11683
|
+
}
|
|
11684
|
+
}, [rowVirtualizer]);
|
|
11685
|
+
const toggleSystemPrelude = reactExports.useCallback((preludeKey) => {
|
|
11686
|
+
setExpandedPreludeKeys((current) => {
|
|
11687
|
+
const next = new Set(current);
|
|
11688
|
+
if (next.has(preludeKey)) {
|
|
11689
|
+
next.delete(preludeKey);
|
|
11690
|
+
} else {
|
|
11691
|
+
next.add(preludeKey);
|
|
11692
|
+
}
|
|
11693
|
+
return next;
|
|
11694
|
+
});
|
|
11695
|
+
remeasureVisibleRows();
|
|
11696
|
+
notifyChatLayoutInvalidated();
|
|
11697
|
+
}, [remeasureVisibleRows]);
|
|
11698
|
+
reactExports.useEffect(() => {
|
|
11699
|
+
setExpandedPreludeKeys(/* @__PURE__ */ new Set());
|
|
11700
|
+
}, [sessionId]);
|
|
11336
11701
|
reactExports.useEffect(() => {
|
|
11337
11702
|
const container = parentRef.current;
|
|
11338
11703
|
if (!container) {
|
|
@@ -11348,15 +11713,37 @@ const ChatHistory = ({ sessionId }) => {
|
|
|
11348
11713
|
return;
|
|
11349
11714
|
}
|
|
11350
11715
|
const handleLayoutInvalidation = () => {
|
|
11351
|
-
|
|
11716
|
+
remeasureVisibleRows();
|
|
11717
|
+
requestAnimationFrame(() => {
|
|
11718
|
+
remeasureVisibleRows();
|
|
11719
|
+
});
|
|
11352
11720
|
};
|
|
11353
11721
|
window.addEventListener(CHAT_LAYOUT_INVALIDATED_EVENT, handleLayoutInvalidation);
|
|
11354
11722
|
return () => {
|
|
11355
11723
|
window.removeEventListener(CHAT_LAYOUT_INVALIDATED_EVENT, handleLayoutInvalidation);
|
|
11356
11724
|
};
|
|
11357
|
-
}, [
|
|
11725
|
+
}, [remeasureVisibleRows]);
|
|
11726
|
+
reactExports.useEffect(() => {
|
|
11727
|
+
remeasureVisibleRows();
|
|
11728
|
+
const raf = requestAnimationFrame(() => {
|
|
11729
|
+
remeasureVisibleRows();
|
|
11730
|
+
});
|
|
11731
|
+
return () => cancelAnimationFrame(raf);
|
|
11732
|
+
}, [chunks, expandedPreludeKeys, remeasureVisibleRows]);
|
|
11358
11733
|
const hasChunks = chunks.length > 0;
|
|
11359
11734
|
const isLoading = chunksLoading && chunksSessionId === sessionId;
|
|
11735
|
+
const sessionTokenStats = reactExports.useMemo(() => {
|
|
11736
|
+
return chunks.reduce((totals, chunk) => {
|
|
11737
|
+
var _a, _b, _c;
|
|
11738
|
+
if (chunk.type !== "ai") {
|
|
11739
|
+
return totals;
|
|
11740
|
+
}
|
|
11741
|
+
totals.totalTokens += (_a = chunk.metrics.totalTokens) != null ? _a : 0;
|
|
11742
|
+
totals.inputTokens += (_b = chunk.metrics.inputTokens) != null ? _b : 0;
|
|
11743
|
+
totals.outputTokens += (_c = chunk.metrics.outputTokens) != null ? _c : 0;
|
|
11744
|
+
return totals;
|
|
11745
|
+
}, buildSessionTokenStats());
|
|
11746
|
+
}, [chunks]);
|
|
11360
11747
|
const initialModelUsage = reactExports.useMemo(() => {
|
|
11361
11748
|
if (!sessionId) {
|
|
11362
11749
|
return null;
|
|
@@ -11384,14 +11771,27 @@ const ChatHistory = ({ sessionId }) => {
|
|
|
11384
11771
|
] });
|
|
11385
11772
|
}
|
|
11386
11773
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
11387
|
-
|
|
11388
|
-
"
|
|
11389
|
-
|
|
11390
|
-
|
|
11391
|
-
|
|
11392
|
-
|
|
11393
|
-
|
|
11394
|
-
|
|
11774
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "chat-session-token-sticky", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "chat-session-token-strip", "aria-label": "Session token totals and initial model", children: [
|
|
11775
|
+
initialModelUsage ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "chat-session-token-pair", children: [
|
|
11776
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "chat-session-token-key", children: "Model:" }),
|
|
11777
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "chat-session-token-value", children: [
|
|
11778
|
+
initialModelUsage.model,
|
|
11779
|
+
initialModelUsage.reasoningEffort !== "unknown" ? ` (${initialModelUsage.reasoningEffort})` : ""
|
|
11780
|
+
] })
|
|
11781
|
+
] }) : null,
|
|
11782
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "chat-session-token-pair", children: [
|
|
11783
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "chat-session-token-key", children: "In:" }),
|
|
11784
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "chat-session-token-value", children: sessionTokenStats.inputTokens.toLocaleString() })
|
|
11785
|
+
] }),
|
|
11786
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "chat-session-token-pair", children: [
|
|
11787
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "chat-session-token-key", children: "Out:" }),
|
|
11788
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "chat-session-token-value", children: sessionTokenStats.outputTokens.toLocaleString() })
|
|
11789
|
+
] }),
|
|
11790
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "chat-session-token-pair", children: [
|
|
11791
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "chat-session-token-key", children: "Total:" }),
|
|
11792
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "chat-session-token-value", children: sessionTokenStats.totalTokens.toLocaleString() })
|
|
11793
|
+
] })
|
|
11794
|
+
] }) }),
|
|
11395
11795
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
11396
11796
|
"div",
|
|
11397
11797
|
{
|
|
@@ -11406,6 +11806,8 @@ const ChatHistory = ({ sessionId }) => {
|
|
|
11406
11806
|
return null;
|
|
11407
11807
|
}
|
|
11408
11808
|
const systemPreludeKind = chunk.type === "system" ? classifyCodexBootstrapMessage(chunk.content) : null;
|
|
11809
|
+
const systemPreludeKey = chunk.type === "system" && systemPreludeKind && systemPreludeKind !== "collaboration_mode" ? buildSystemPreludeKey(chunk.timestamp, virtualRow.index) : null;
|
|
11810
|
+
const isSystemPreludeExpanded = systemPreludeKey !== null && expandedPreludeKeys.has(systemPreludeKey);
|
|
11409
11811
|
const key = `${chunk.type}-${chunk.timestamp}-${virtualRow.index}`;
|
|
11410
11812
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
11411
11813
|
"div",
|
|
@@ -11427,16 +11829,28 @@ const ChatHistory = ({ sessionId }) => {
|
|
|
11427
11829
|
"Collaboration mode: ",
|
|
11428
11830
|
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: extractCollaborationModeLabel(chunk.content) })
|
|
11429
11831
|
] }) }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
11430
|
-
"
|
|
11832
|
+
"section",
|
|
11431
11833
|
{
|
|
11432
|
-
className: `chat-system-prelude ${systemPreludeKind}`,
|
|
11433
|
-
onToggle: notifyChatLayoutInvalidated,
|
|
11834
|
+
className: `chat-system-prelude ${systemPreludeKind}${isSystemPreludeExpanded ? " open" : ""}`,
|
|
11434
11835
|
children: [
|
|
11435
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
11436
|
-
|
|
11437
|
-
|
|
11438
|
-
|
|
11439
|
-
|
|
11836
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
11837
|
+
"button",
|
|
11838
|
+
{
|
|
11839
|
+
type: "button",
|
|
11840
|
+
className: "chat-system-prelude-summary",
|
|
11841
|
+
"aria-expanded": isSystemPreludeExpanded,
|
|
11842
|
+
onClick: () => {
|
|
11843
|
+
if (systemPreludeKey) {
|
|
11844
|
+
toggleSystemPrelude(systemPreludeKey);
|
|
11845
|
+
}
|
|
11846
|
+
},
|
|
11847
|
+
children: [
|
|
11848
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: getPreludeLabel(systemPreludeKind) }),
|
|
11849
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "chat-system-prelude-summary-hint", children: getPreludeHint(systemPreludeKind) })
|
|
11850
|
+
]
|
|
11851
|
+
}
|
|
11852
|
+
),
|
|
11853
|
+
isSystemPreludeExpanded ? /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "chat-system-prelude-content", children: chunk.content }) : null
|
|
11440
11854
|
]
|
|
11441
11855
|
}
|
|
11442
11856
|
) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "chat-system-message", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: chunk.content }) }) : null,
|
|
@@ -11469,7 +11883,20 @@ const ChatHistory = ({ sessionId }) => {
|
|
|
11469
11883
|
}
|
|
11470
11884
|
)
|
|
11471
11885
|
] });
|
|
11472
|
-
}, [
|
|
11886
|
+
}, [
|
|
11887
|
+
chunks,
|
|
11888
|
+
hasChunks,
|
|
11889
|
+
initialModelUsage,
|
|
11890
|
+
isLoading,
|
|
11891
|
+
rowVirtualizer,
|
|
11892
|
+
sessionTokenStats.inputTokens,
|
|
11893
|
+
sessionTokenStats.outputTokens,
|
|
11894
|
+
sessionTokenStats.totalTokens,
|
|
11895
|
+
expandedPreludeKeys,
|
|
11896
|
+
remeasureVisibleRows,
|
|
11897
|
+
toggleSystemPrelude,
|
|
11898
|
+
virtualRows
|
|
11899
|
+
]);
|
|
11473
11900
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "chat-shell", ref: parentRef, children: content });
|
|
11474
11901
|
};
|
|
11475
11902
|
const SessionTabContent = ({ tab }) => {
|
|
@@ -11693,6 +12120,7 @@ const Sidebar = () => {
|
|
|
11693
12120
|
] });
|
|
11694
12121
|
};
|
|
11695
12122
|
const DASHBOARD_TAB_ID$1 = "dashboard";
|
|
12123
|
+
const STATS_TAB_ID$1 = "stats";
|
|
11696
12124
|
const SETTINGS_TAB_ID$1 = "settings";
|
|
11697
12125
|
const TabBar = () => {
|
|
11698
12126
|
const {
|
|
@@ -11701,6 +12129,7 @@ const TabBar = () => {
|
|
|
11701
12129
|
setActiveTab,
|
|
11702
12130
|
closeTab,
|
|
11703
12131
|
openDashboardTab,
|
|
12132
|
+
openStatsTab,
|
|
11704
12133
|
openSettingsTab,
|
|
11705
12134
|
toggleSidebarCollapsed,
|
|
11706
12135
|
sidebarCollapsed
|
|
@@ -11710,6 +12139,7 @@ const TabBar = () => {
|
|
|
11710
12139
|
setActiveTab: state.setActiveTab,
|
|
11711
12140
|
closeTab: state.closeTab,
|
|
11712
12141
|
openDashboardTab: state.openDashboardTab,
|
|
12142
|
+
openStatsTab: state.openStatsTab,
|
|
11713
12143
|
openSettingsTab: state.openSettingsTab,
|
|
11714
12144
|
toggleSidebarCollapsed: state.toggleSidebarCollapsed,
|
|
11715
12145
|
sidebarCollapsed: state.sidebarCollapsed
|
|
@@ -11741,6 +12171,17 @@ const TabBar = () => {
|
|
|
11741
12171
|
children: "Dashboard"
|
|
11742
12172
|
}
|
|
11743
12173
|
),
|
|
12174
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
12175
|
+
"button",
|
|
12176
|
+
{
|
|
12177
|
+
className: `tabbar-action ${activeTabId === STATS_TAB_ID$1 ? "active" : ""}`,
|
|
12178
|
+
onClick: openStatsTab,
|
|
12179
|
+
type: "button",
|
|
12180
|
+
role: "tab",
|
|
12181
|
+
"aria-selected": activeTabId === STATS_TAB_ID$1,
|
|
12182
|
+
children: "Stats"
|
|
12183
|
+
}
|
|
12184
|
+
),
|
|
11744
12185
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
11745
12186
|
"button",
|
|
11746
12187
|
{
|
|
@@ -11784,6 +12225,7 @@ const TabBar = () => {
|
|
|
11784
12225
|
};
|
|
11785
12226
|
const DASHBOARD_TAB_ID = "dashboard";
|
|
11786
12227
|
const SETTINGS_TAB_ID = "settings";
|
|
12228
|
+
const STATS_TAB_ID = "stats";
|
|
11787
12229
|
const TabbedLayout = () => {
|
|
11788
12230
|
const { openTabs, activeTabId, sidebarCollapsed } = useAppStore((state) => ({
|
|
11789
12231
|
openTabs: state.openTabs,
|
|
@@ -11795,13 +12237,15 @@ const TabbedLayout = () => {
|
|
|
11795
12237
|
return (activeTab == null ? void 0 : activeTab.type) === "session" ? activeTab : null;
|
|
11796
12238
|
}, [openTabs, activeTabId]);
|
|
11797
12239
|
const settingsActive = activeTabId === SETTINGS_TAB_ID;
|
|
11798
|
-
const
|
|
12240
|
+
const statsActive = activeTabId === STATS_TAB_ID;
|
|
12241
|
+
const dashboardActive = activeTabId === DASHBOARD_TAB_ID || !settingsActive && !statsActive && !activeSessionTab;
|
|
11799
12242
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "layout-shell", children: [
|
|
11800
12243
|
!sidebarCollapsed ? /* @__PURE__ */ jsxRuntimeExports.jsx(Sidebar, {}) : null,
|
|
11801
12244
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "content-shell", children: [
|
|
11802
12245
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TabBar, {}),
|
|
11803
12246
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "content-body", children: [
|
|
11804
12247
|
activeSessionTab ? /* @__PURE__ */ jsxRuntimeExports.jsx(SessionTabContent, { tab: activeSessionTab }) : null,
|
|
12248
|
+
statsActive ? /* @__PURE__ */ jsxRuntimeExports.jsx(StatsView, {}) : null,
|
|
11805
12249
|
dashboardActive ? /* @__PURE__ */ jsxRuntimeExports.jsx(DashboardView, {}) : null,
|
|
11806
12250
|
settingsActive ? /* @__PURE__ */ jsxRuntimeExports.jsx(SettingsView, {}) : null
|
|
11807
12251
|
] })
|