@code-rag/api-server 0.1.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/LICENSE +21 -0
- package/README.md +26 -0
- package/dist/dashboard/data-collector.d.ts +61 -0
- package/dist/dashboard/data-collector.js +244 -0
- package/dist/dashboard/data-collector.js.map +1 -0
- package/dist/dashboard/data-collector.test.d.ts +1 -0
- package/dist/dashboard/data-collector.test.js +334 -0
- package/dist/dashboard/data-collector.test.js.map +1 -0
- package/dist/dashboard/index.d.ts +10 -0
- package/dist/dashboard/index.js +6 -0
- package/dist/dashboard/index.js.map +1 -0
- package/dist/dashboard/routes.d.ts +18 -0
- package/dist/dashboard/routes.js +150 -0
- package/dist/dashboard/routes.js.map +1 -0
- package/dist/dashboard/templates.d.ts +47 -0
- package/dist/dashboard/templates.js +591 -0
- package/dist/dashboard/templates.js.map +1 -0
- package/dist/dashboard/templates.test.d.ts +1 -0
- package/dist/dashboard/templates.test.js +408 -0
- package/dist/dashboard/templates.test.js.map +1 -0
- package/dist/dashboard/types.d.ts +119 -0
- package/dist/dashboard/types.js +4 -0
- package/dist/dashboard/types.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/auth.d.ts +37 -0
- package/dist/middleware/auth.js +92 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/rate-limit.d.ts +26 -0
- package/dist/middleware/rate-limit.js +79 -0
- package/dist/middleware/rate-limit.js.map +1 -0
- package/dist/openapi.d.ts +14 -0
- package/dist/openapi.js +363 -0
- package/dist/openapi.js.map +1 -0
- package/dist/routes/context.d.ts +15 -0
- package/dist/routes/context.js +84 -0
- package/dist/routes/context.js.map +1 -0
- package/dist/routes/history.d.ts +56 -0
- package/dist/routes/history.js +308 -0
- package/dist/routes/history.js.map +1 -0
- package/dist/routes/index-trigger.d.ts +21 -0
- package/dist/routes/index-trigger.js +47 -0
- package/dist/routes/index-trigger.js.map +1 -0
- package/dist/routes/search.d.ts +24 -0
- package/dist/routes/search.js +85 -0
- package/dist/routes/search.js.map +1 -0
- package/dist/routes/status.d.ts +14 -0
- package/dist/routes/status.js +37 -0
- package/dist/routes/status.js.map +1 -0
- package/dist/routes/team.d.ts +62 -0
- package/dist/routes/team.js +129 -0
- package/dist/routes/team.js.map +1 -0
- package/dist/routes/viewer.d.ts +78 -0
- package/dist/routes/viewer.js +387 -0
- package/dist/routes/viewer.js.map +1 -0
- package/dist/routes/viewer.test.d.ts +1 -0
- package/dist/routes/viewer.test.js +509 -0
- package/dist/routes/viewer.test.js.map +1 -0
- package/dist/server.d.ts +45 -0
- package/dist/server.js +227 -0
- package/dist/server.js.map +1 -0
- package/dist/server.test.d.ts +1 -0
- package/dist/server.test.js +620 -0
- package/dist/server.test.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { ok, err } from 'neverthrow';
|
|
3
|
+
import { StoreError } from '@coderag/core';
|
|
4
|
+
import { DashboardDataCollector } from './data-collector.js';
|
|
5
|
+
// --- Helpers ---
|
|
6
|
+
function mockStore(overrides = {}) {
|
|
7
|
+
return {
|
|
8
|
+
count: vi.fn().mockResolvedValue(ok(42)),
|
|
9
|
+
...overrides,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function mockConfig(overrides = {}) {
|
|
13
|
+
return {
|
|
14
|
+
version: '1',
|
|
15
|
+
project: { name: 'test-project', languages: ['typescript', 'python'] },
|
|
16
|
+
ingestion: { maxTokensPerChunk: 512, exclude: [] },
|
|
17
|
+
embedding: { provider: 'ollama', model: 'nomic-embed-text', dimensions: 768, autoStart: true, autoStop: false, docker: { image: 'ollama/ollama', gpu: 'auto' } },
|
|
18
|
+
llm: { provider: 'ollama', model: 'qwen2.5-coder:7b' },
|
|
19
|
+
search: { topK: 10, vectorWeight: 0.7, bm25Weight: 0.3 },
|
|
20
|
+
storage: { path: '.coderag' },
|
|
21
|
+
...overrides,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function createDeps(overrides = {}) {
|
|
25
|
+
const store = mockStore();
|
|
26
|
+
const config = mockConfig();
|
|
27
|
+
return {
|
|
28
|
+
getStore: () => store,
|
|
29
|
+
getConfig: () => config,
|
|
30
|
+
apiKeys: [],
|
|
31
|
+
...overrides,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// --- getIndexOverview Tests ---
|
|
35
|
+
describe('DashboardDataCollector', () => {
|
|
36
|
+
describe('getIndexOverview', () => {
|
|
37
|
+
it('should return index overview with chunk count from store', async () => {
|
|
38
|
+
const deps = createDeps();
|
|
39
|
+
const collector = new DashboardDataCollector(deps);
|
|
40
|
+
const overview = await collector.getIndexOverview();
|
|
41
|
+
expect(overview.chunkCount).toBe(42);
|
|
42
|
+
expect(overview.health).toBe('healthy');
|
|
43
|
+
});
|
|
44
|
+
it('should estimate file count from chunk count', async () => {
|
|
45
|
+
const deps = createDeps();
|
|
46
|
+
const collector = new DashboardDataCollector(deps);
|
|
47
|
+
const overview = await collector.getIndexOverview();
|
|
48
|
+
// 42 chunks / 5 ≈ 9 files
|
|
49
|
+
expect(overview.fileCount).toBe(9);
|
|
50
|
+
});
|
|
51
|
+
it('should return languages from config', async () => {
|
|
52
|
+
const deps = createDeps();
|
|
53
|
+
const collector = new DashboardDataCollector(deps);
|
|
54
|
+
const overview = await collector.getIndexOverview();
|
|
55
|
+
expect(overview.languages).toEqual(['typescript', 'python']);
|
|
56
|
+
});
|
|
57
|
+
it('should return not_initialized when store is null', async () => {
|
|
58
|
+
const deps = createDeps({ getStore: () => null });
|
|
59
|
+
const collector = new DashboardDataCollector(deps);
|
|
60
|
+
const overview = await collector.getIndexOverview();
|
|
61
|
+
expect(overview.health).toBe('not_initialized');
|
|
62
|
+
expect(overview.chunkCount).toBe(0);
|
|
63
|
+
expect(overview.fileCount).toBe(0);
|
|
64
|
+
});
|
|
65
|
+
it('should return degraded when store count fails', async () => {
|
|
66
|
+
const store = mockStore({
|
|
67
|
+
count: vi.fn().mockResolvedValue(err(new StoreError('Connection lost'))),
|
|
68
|
+
});
|
|
69
|
+
const deps = createDeps({ getStore: () => store });
|
|
70
|
+
const collector = new DashboardDataCollector(deps);
|
|
71
|
+
const overview = await collector.getIndexOverview();
|
|
72
|
+
expect(overview.health).toBe('degraded');
|
|
73
|
+
expect(overview.chunkCount).toBe(0);
|
|
74
|
+
});
|
|
75
|
+
it('should return degraded when store is empty', async () => {
|
|
76
|
+
const store = mockStore({
|
|
77
|
+
count: vi.fn().mockResolvedValue(ok(0)),
|
|
78
|
+
});
|
|
79
|
+
const deps = createDeps({ getStore: () => store });
|
|
80
|
+
const collector = new DashboardDataCollector(deps);
|
|
81
|
+
const overview = await collector.getIndexOverview();
|
|
82
|
+
expect(overview.health).toBe('degraded');
|
|
83
|
+
});
|
|
84
|
+
it('should estimate storage bytes from chunk count', async () => {
|
|
85
|
+
const deps = createDeps();
|
|
86
|
+
const collector = new DashboardDataCollector(deps);
|
|
87
|
+
const overview = await collector.getIndexOverview();
|
|
88
|
+
// 42 chunks * 4096 bytes
|
|
89
|
+
expect(overview.storageBytes).toBe(42 * 4096);
|
|
90
|
+
});
|
|
91
|
+
it('should return lastIndexed timestamp when set', async () => {
|
|
92
|
+
const deps = createDeps();
|
|
93
|
+
const collector = new DashboardDataCollector(deps);
|
|
94
|
+
collector.setLastIndexed('2026-02-22T10:00:00Z');
|
|
95
|
+
const overview = await collector.getIndexOverview();
|
|
96
|
+
expect(overview.lastIndexed).toBe('2026-02-22T10:00:00Z');
|
|
97
|
+
});
|
|
98
|
+
it('should return null lastIndexed when never indexed', async () => {
|
|
99
|
+
const deps = createDeps();
|
|
100
|
+
const collector = new DashboardDataCollector(deps);
|
|
101
|
+
const overview = await collector.getIndexOverview();
|
|
102
|
+
expect(overview.lastIndexed).toBeNull();
|
|
103
|
+
});
|
|
104
|
+
it('should return empty languages when config has none', async () => {
|
|
105
|
+
const config = mockConfig({ project: { name: 'test', languages: [] } });
|
|
106
|
+
const deps = createDeps({ getConfig: () => config });
|
|
107
|
+
const collector = new DashboardDataCollector(deps);
|
|
108
|
+
const overview = await collector.getIndexOverview();
|
|
109
|
+
expect(overview.languages).toEqual([]);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
// --- recordSearch & getSearchAnalytics Tests ---
|
|
113
|
+
describe('recordSearch / getSearchAnalytics', () => {
|
|
114
|
+
it('should record searches and return total count', () => {
|
|
115
|
+
const collector = new DashboardDataCollector(createDeps());
|
|
116
|
+
collector.recordSearch('hello world', 50, true);
|
|
117
|
+
collector.recordSearch('function parser', 30, true);
|
|
118
|
+
const analytics = collector.getSearchAnalytics(30);
|
|
119
|
+
expect(analytics.totalQueries).toBe(2);
|
|
120
|
+
});
|
|
121
|
+
it('should calculate average response time', () => {
|
|
122
|
+
const collector = new DashboardDataCollector(createDeps());
|
|
123
|
+
collector.recordSearch('query1', 100, true);
|
|
124
|
+
collector.recordSearch('query2', 200, true);
|
|
125
|
+
collector.recordSearch('query3', 300, true);
|
|
126
|
+
const analytics = collector.getSearchAnalytics(30);
|
|
127
|
+
expect(analytics.avgResponseTimeMs).toBe(200);
|
|
128
|
+
});
|
|
129
|
+
it('should calculate error rate', () => {
|
|
130
|
+
const collector = new DashboardDataCollector(createDeps());
|
|
131
|
+
collector.recordSearch('good1', 50, true);
|
|
132
|
+
collector.recordSearch('good2', 50, true);
|
|
133
|
+
collector.recordSearch('bad1', 50, false);
|
|
134
|
+
collector.recordSearch('bad2', 50, false);
|
|
135
|
+
const analytics = collector.getSearchAnalytics(30);
|
|
136
|
+
expect(analytics.errorRate).toBe(0.5);
|
|
137
|
+
});
|
|
138
|
+
it('should return top queries sorted by count', () => {
|
|
139
|
+
const collector = new DashboardDataCollector(createDeps());
|
|
140
|
+
collector.recordSearch('common query', 50, true);
|
|
141
|
+
collector.recordSearch('common query', 50, true);
|
|
142
|
+
collector.recordSearch('common query', 50, true);
|
|
143
|
+
collector.recordSearch('rare query', 50, true);
|
|
144
|
+
const analytics = collector.getSearchAnalytics(30);
|
|
145
|
+
expect(analytics.topQueries[0].query).toBe('common query');
|
|
146
|
+
expect(analytics.topQueries[0].count).toBe(3);
|
|
147
|
+
expect(analytics.topQueries[1].query).toBe('rare query');
|
|
148
|
+
expect(analytics.topQueries[1].count).toBe(1);
|
|
149
|
+
});
|
|
150
|
+
it('should normalize top queries to lowercase', () => {
|
|
151
|
+
const collector = new DashboardDataCollector(createDeps());
|
|
152
|
+
collector.recordSearch('Hello World', 50, true);
|
|
153
|
+
collector.recordSearch('hello world', 50, true);
|
|
154
|
+
const analytics = collector.getSearchAnalytics(30);
|
|
155
|
+
expect(analytics.topQueries).toHaveLength(1);
|
|
156
|
+
expect(analytics.topQueries[0].count).toBe(2);
|
|
157
|
+
});
|
|
158
|
+
it('should group queries by day', () => {
|
|
159
|
+
const collector = new DashboardDataCollector(createDeps());
|
|
160
|
+
collector.recordSearch('q1', 50, true);
|
|
161
|
+
collector.recordSearch('q2', 50, true);
|
|
162
|
+
const analytics = collector.getSearchAnalytics(30);
|
|
163
|
+
expect(analytics.queriesPerDay.length).toBeGreaterThanOrEqual(1);
|
|
164
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
165
|
+
const todayEntry = analytics.queriesPerDay.find((d) => d.date === today);
|
|
166
|
+
expect(todayEntry?.count).toBe(2);
|
|
167
|
+
});
|
|
168
|
+
it('should return empty analytics when no searches recorded', () => {
|
|
169
|
+
const collector = new DashboardDataCollector(createDeps());
|
|
170
|
+
const analytics = collector.getSearchAnalytics(30);
|
|
171
|
+
expect(analytics.totalQueries).toBe(0);
|
|
172
|
+
expect(analytics.queriesPerDay).toEqual([]);
|
|
173
|
+
expect(analytics.topQueries).toEqual([]);
|
|
174
|
+
expect(analytics.avgResponseTimeMs).toBe(0);
|
|
175
|
+
expect(analytics.errorRate).toBe(0);
|
|
176
|
+
});
|
|
177
|
+
it('should filter searches by date range', () => {
|
|
178
|
+
const collector = new DashboardDataCollector(createDeps());
|
|
179
|
+
collector.recordSearch('recent', 50, true);
|
|
180
|
+
// Requesting 0 days means cutoff = now, so entries at now are included
|
|
181
|
+
const analytics = collector.getSearchAnalytics(0);
|
|
182
|
+
expect(analytics.totalQueries).toBe(1);
|
|
183
|
+
// All queries within 30 days should be returned
|
|
184
|
+
const analytics30 = collector.getSearchAnalytics(30);
|
|
185
|
+
expect(analytics30.totalQueries).toBe(1);
|
|
186
|
+
});
|
|
187
|
+
it('should limit top queries to configured limit', () => {
|
|
188
|
+
const collector = new DashboardDataCollector(createDeps(), { topQueriesLimit: 2 });
|
|
189
|
+
collector.recordSearch('a', 50, true);
|
|
190
|
+
collector.recordSearch('b', 50, true);
|
|
191
|
+
collector.recordSearch('c', 50, true);
|
|
192
|
+
const analytics = collector.getSearchAnalytics(30);
|
|
193
|
+
expect(analytics.topQueries.length).toBeLessThanOrEqual(2);
|
|
194
|
+
});
|
|
195
|
+
it('should evict old search records when exceeding max limit', () => {
|
|
196
|
+
const collector = new DashboardDataCollector(createDeps(), { maxSearchRecords: 3 });
|
|
197
|
+
collector.recordSearch('q1', 50, true);
|
|
198
|
+
collector.recordSearch('q2', 50, true);
|
|
199
|
+
collector.recordSearch('q3', 50, true);
|
|
200
|
+
collector.recordSearch('q4', 50, true);
|
|
201
|
+
expect(collector.getSearchRecordCount()).toBe(3);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
// --- recordRequest & getUsageStats Tests ---
|
|
205
|
+
describe('recordRequest / getUsageStats', () => {
|
|
206
|
+
it('should count API calls today', () => {
|
|
207
|
+
const collector = new DashboardDataCollector(createDeps());
|
|
208
|
+
collector.recordRequest('GET', '/api/v1/status', null);
|
|
209
|
+
collector.recordRequest('POST', '/api/v1/search', null);
|
|
210
|
+
const stats = collector.getUsageStats();
|
|
211
|
+
expect(stats.apiCallsToday).toBe(2);
|
|
212
|
+
});
|
|
213
|
+
it('should count API calls for week and month', () => {
|
|
214
|
+
const collector = new DashboardDataCollector(createDeps());
|
|
215
|
+
collector.recordRequest('GET', '/health', null);
|
|
216
|
+
const stats = collector.getUsageStats();
|
|
217
|
+
expect(stats.apiCallsWeek).toBeGreaterThanOrEqual(1);
|
|
218
|
+
expect(stats.apiCallsMonth).toBeGreaterThanOrEqual(1);
|
|
219
|
+
});
|
|
220
|
+
it('should return zero stats when no requests recorded', () => {
|
|
221
|
+
const collector = new DashboardDataCollector(createDeps());
|
|
222
|
+
const stats = collector.getUsageStats();
|
|
223
|
+
expect(stats.apiCallsToday).toBe(0);
|
|
224
|
+
expect(stats.apiCallsWeek).toBe(0);
|
|
225
|
+
expect(stats.apiCallsMonth).toBe(0);
|
|
226
|
+
});
|
|
227
|
+
it('should evict old request records when exceeding max limit', () => {
|
|
228
|
+
const collector = new DashboardDataCollector(createDeps(), { maxRequestRecords: 3 });
|
|
229
|
+
collector.recordRequest('GET', '/a', null);
|
|
230
|
+
collector.recordRequest('GET', '/b', null);
|
|
231
|
+
collector.recordRequest('GET', '/c', null);
|
|
232
|
+
collector.recordRequest('GET', '/d', null);
|
|
233
|
+
expect(collector.getRequestRecordCount()).toBe(3);
|
|
234
|
+
});
|
|
235
|
+
it('should include cost estimate string', () => {
|
|
236
|
+
const collector = new DashboardDataCollector(createDeps());
|
|
237
|
+
collector.recordRequest('GET', '/api/v1/status', null);
|
|
238
|
+
const stats = collector.getUsageStats();
|
|
239
|
+
expect(typeof stats.costEstimate).toBe('string');
|
|
240
|
+
expect(stats.costEstimate.length).toBeGreaterThan(0);
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
// --- getUsers Tests ---
|
|
244
|
+
describe('getUsers', () => {
|
|
245
|
+
it('should return users from API keys', () => {
|
|
246
|
+
const apiKeys = [
|
|
247
|
+
{ key: 'admin-key-12345', admin: true },
|
|
248
|
+
{ key: 'user-key-67890', admin: false },
|
|
249
|
+
];
|
|
250
|
+
const collector = new DashboardDataCollector(createDeps({ apiKeys }));
|
|
251
|
+
const users = collector.getUsers();
|
|
252
|
+
expect(users).toHaveLength(2);
|
|
253
|
+
expect(users[0].role).toBe('admin');
|
|
254
|
+
expect(users[1].role).toBe('user');
|
|
255
|
+
});
|
|
256
|
+
it('should truncate user IDs to first 8 characters', () => {
|
|
257
|
+
const apiKeys = [
|
|
258
|
+
{ key: 'very-long-api-key-string', admin: false },
|
|
259
|
+
];
|
|
260
|
+
const collector = new DashboardDataCollector(createDeps({ apiKeys }));
|
|
261
|
+
const users = collector.getUsers();
|
|
262
|
+
expect(users[0].userId).toBe('very-lon...');
|
|
263
|
+
});
|
|
264
|
+
it('should not truncate short keys', () => {
|
|
265
|
+
const apiKeys = [
|
|
266
|
+
{ key: 'short', admin: false },
|
|
267
|
+
];
|
|
268
|
+
const collector = new DashboardDataCollector(createDeps({ apiKeys }));
|
|
269
|
+
const users = collector.getUsers();
|
|
270
|
+
expect(users[0].userId).toBe('short');
|
|
271
|
+
});
|
|
272
|
+
it('should track user activity from searches', () => {
|
|
273
|
+
const apiKeys = [
|
|
274
|
+
{ key: 'test-key', admin: false },
|
|
275
|
+
];
|
|
276
|
+
const collector = new DashboardDataCollector(createDeps({ apiKeys }));
|
|
277
|
+
collector.recordSearch('hello', 50, true, 'test-key');
|
|
278
|
+
collector.recordSearch('world', 30, true, 'test-key');
|
|
279
|
+
const users = collector.getUsers();
|
|
280
|
+
expect(users[0].queryCount).toBe(2);
|
|
281
|
+
expect(users[0].lastActive).not.toBeNull();
|
|
282
|
+
});
|
|
283
|
+
it('should return zero query count for inactive users', () => {
|
|
284
|
+
const apiKeys = [
|
|
285
|
+
{ key: 'inactive-user-key', admin: false },
|
|
286
|
+
];
|
|
287
|
+
const collector = new DashboardDataCollector(createDeps({ apiKeys }));
|
|
288
|
+
const users = collector.getUsers();
|
|
289
|
+
expect(users[0].queryCount).toBe(0);
|
|
290
|
+
expect(users[0].lastActive).toBeNull();
|
|
291
|
+
});
|
|
292
|
+
it('should return empty array when no API keys configured', () => {
|
|
293
|
+
const collector = new DashboardDataCollector(createDeps({ apiKeys: [] }));
|
|
294
|
+
const users = collector.getUsers();
|
|
295
|
+
expect(users).toEqual([]);
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
// --- getConfig Tests ---
|
|
299
|
+
describe('getConfig', () => {
|
|
300
|
+
it('should return default configuration', () => {
|
|
301
|
+
const collector = new DashboardDataCollector(createDeps());
|
|
302
|
+
const config = collector.getConfig();
|
|
303
|
+
expect(config.maxSearchRecords).toBe(10_000);
|
|
304
|
+
expect(config.maxRequestRecords).toBe(50_000);
|
|
305
|
+
expect(config.topQueriesLimit).toBe(20);
|
|
306
|
+
});
|
|
307
|
+
it('should return custom configuration when provided', () => {
|
|
308
|
+
const collector = new DashboardDataCollector(createDeps(), {
|
|
309
|
+
maxSearchRecords: 500,
|
|
310
|
+
topQueriesLimit: 5,
|
|
311
|
+
});
|
|
312
|
+
const config = collector.getConfig();
|
|
313
|
+
expect(config.maxSearchRecords).toBe(500);
|
|
314
|
+
expect(config.topQueriesLimit).toBe(5);
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
// --- setLastIndexed Tests ---
|
|
318
|
+
describe('setLastIndexed', () => {
|
|
319
|
+
it('should update lastIndexed timestamp', async () => {
|
|
320
|
+
const collector = new DashboardDataCollector(createDeps());
|
|
321
|
+
collector.setLastIndexed('2026-01-15T12:00:00Z');
|
|
322
|
+
const overview = await collector.getIndexOverview();
|
|
323
|
+
expect(overview.lastIndexed).toBe('2026-01-15T12:00:00Z');
|
|
324
|
+
});
|
|
325
|
+
it('should overwrite previous lastIndexed', async () => {
|
|
326
|
+
const collector = new DashboardDataCollector(createDeps());
|
|
327
|
+
collector.setLastIndexed('2026-01-01T00:00:00Z');
|
|
328
|
+
collector.setLastIndexed('2026-02-01T00:00:00Z');
|
|
329
|
+
const overview = await collector.getIndexOverview();
|
|
330
|
+
expect(overview.lastIndexed).toBe('2026-02-01T00:00:00Z');
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
//# sourceMappingURL=data-collector.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-collector.test.js","sourceRoot":"","sources":["../../src/dashboard/data-collector.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,OAAO,EAAE,sBAAsB,EAAmC,MAAM,qBAAqB,CAAC;AAE9F,kBAAkB;AAElB,SAAS,SAAS,CAAC,YAAmC,EAAE;IACtD,OAAO;QACL,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACxC,GAAG,SAAS;KACc,CAAC;AAC/B,CAAC;AAED,SAAS,UAAU,CAAC,YAAoC,EAAE;IACxD,OAAO;QACL,OAAO,EAAE,GAAG;QACZ,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,CAAC,YAAY,EAAE,QAAQ,CAAC,EAAE;QACtE,SAAS,EAAE,EAAE,iBAAiB,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE;QAClD,SAAS,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE;QAChK,GAAG,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,kBAAkB,EAAE;QACtD,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;QACxD,OAAO,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;QAC7B,GAAG,SAAS;KACI,CAAC;AACrB,CAAC;AAED,SAAS,UAAU,CAAC,YAAiD,EAAE;IACrE,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;IAC1B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO;QACL,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK;QACrB,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM;QACvB,OAAO,EAAE,EAAE;QACX,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,iCAAiC;AAEjC,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;YACxE,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,IAAI,CAAC,CAAC;YAEnD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;YAEpD,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACrC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YAC3D,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,IAAI,CAAC,CAAC;YAEnD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;YAEpD,0BAA0B;YAC1B,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;YACnD,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,IAAI,CAAC,CAAC;YAEnD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;YAEpD,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;YAChE,MAAM,IAAI,GAAG,UAAU,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;YAClD,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,IAAI,CAAC,CAAC;YAEnD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;YAEpD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAChD,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;YAC7D,MAAM,KAAK,GAAG,SAAS,CAAC;gBACtB,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC;aACzE,CAAC,CAAC;YACH,MAAM,IAAI,GAAG,UAAU,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;YACnD,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,IAAI,CAAC,CAAC;YAEnD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;YAEpD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACzC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;YAC1D,MAAM,KAAK,GAAG,SAAS,CAAC;gBACtB,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;aACxC,CAAC,CAAC;YACH,MAAM,IAAI,GAAG,UAAU,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;YACnD,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,IAAI,CAAC,CAAC;YAEnD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;YAEpD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;YAC9D,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,IAAI,CAAC,CAAC;YAEnD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;YAEpD,yBAAyB;YACzB,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;YAC5D,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,IAAI,CAAC,CAAC;YACnD,SAAS,CAAC,cAAc,CAAC,sBAAsB,CAAC,CAAC;YAEjD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;YAEpD,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;YACjE,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,IAAI,CAAC,CAAC;YAEnD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;YAEpD,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;YAClE,MAAM,MAAM,GAAG,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,EAA4B,CAAC,CAAC;YAClG,MAAM,IAAI,GAAG,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;YACrD,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,IAAI,CAAC,CAAC;YAEnD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;YAEpD,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,kDAAkD;IAElD,QAAQ,CAAC,mCAAmC,EAAE,GAAG,EAAE;QACjD,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;YACvD,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,CAAC,CAAC;YAE3D,SAAS,CAAC,YAAY,CAAC,aAAa,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YAChD,SAAS,CAAC,YAAY,CAAC,iBAAiB,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YAEpD,MAAM,SAAS,GAAG,SAAS,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;YAEnD,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YAChD,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,CAAC,CAAC;YAE3D,SAAS,CAAC,YAAY,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YAC5C,SAAS,CAAC,YAAY,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YAC5C,SAAS,CAAC,YAAY,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YAE5C,MAAM,SAAS,GAAG,SAAS,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;YAEnD,MAAM,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;YACrC,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,CAAC,CAAC;YAE3D,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YAC1C,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YAC1C,SAAS,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;YAC1C,SAAS,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;YAE1C,MAAM,SAAS,GAAG,SAAS,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;YAEnD,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,CAAC,CAAC;YAE3D,SAAS,CAAC,YAAY,CAAC,cAAc,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YACjD,SAAS,CAAC,YAAY,CAAC,cAAc,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YACjD,SAAS,CAAC,YAAY,CAAC,cAAc,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YACjD,SAAS,CAAC,YAAY,CAAC,YAAY,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YAE/C,MAAM,SAAS,GAAG,SAAS,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;YAEnD,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAC5D,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC/C,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC1D,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,CAAC,CAAC;YAE3D,SAAS,CAAC,YAAY,CAAC,aAAa,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YAChD,SAAS,CAAC,YAAY,CAAC,aAAa,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YAEhD,MAAM,SAAS,GAAG,SAAS,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;YAEnD,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC7C,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;YACrC,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,CAAC,CAAC;YAE3D,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YACvC,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YAEvC,MAAM,SAAS,GAAG,SAAS,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;YAEnD,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;YACjE,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpD,MAAM,UAAU,GAAG,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC;YACzE,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;YACjE,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,CAAC,CAAC;YAE3D,MAAM,SAAS,GAAG,SAAS,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;YAEnD,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACvC,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC5C,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACzC,MAAM,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,CAAC,CAAC;YAE3D,SAAS,CAAC,YAAY,CAAC,QAAQ,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YAE3C,uEAAuE;YACvE,MAAM,SAAS,GAAG,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;YAClD,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAEvC,gDAAgD;YAChD,MAAM,WAAW,GAAG,SAAS,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;YACrD,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACtD,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,EAAE,EAAE,eAAe,EAAE,CAAC,EAAE,CAAC,CAAC;YAEnF,SAAS,CAAC,YAAY,CAAC,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YACtC,SAAS,CAAC,YAAY,CAAC,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YACtC,SAAS,CAAC,YAAY,CAAC,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YAEtC,MAAM,SAAS,GAAG,SAAS,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;YAEnD,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;QAC7D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;YAClE,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,EAAE,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC,CAAC;YAEpF,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YACvC,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YACvC,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YACvC,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;YAEvC,MAAM,CAAC,SAAS,CAAC,oBAAoB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,8CAA8C;IAE9C,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;QAC7C,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;YACtC,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,CAAC,CAAC;YAE3D,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC;YACvD,SAAS,CAAC,aAAa,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC;YAExD,MAAM,KAAK,GAAG,SAAS,CAAC,aAAa,EAAE,CAAC;YAExC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,CAAC,CAAC;YAE3D,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;YAEhD,MAAM,KAAK,GAAG,SAAS,CAAC,aAAa,EAAE,CAAC;YAExC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;YACrD,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC5D,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,CAAC,CAAC;YAE3D,MAAM,KAAK,GAAG,SAAS,CAAC,aAAa,EAAE,CAAC;YAExC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACnC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;YACnE,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,EAAE,EAAE,iBAAiB,EAAE,CAAC,EAAE,CAAC,CAAC;YAErF,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YAC3C,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YAC3C,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YAC3C,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YAE3C,MAAM,CAAC,SAAS,CAAC,qBAAqB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,CAAC,CAAC;YAE3D,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC;YAEvD,MAAM,KAAK,GAAG,SAAS,CAAC,aAAa,EAAE,CAAC;YAExC,MAAM,CAAC,OAAO,KAAK,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACjD,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,yBAAyB;IAEzB,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;QACxB,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;YAC3C,MAAM,OAAO,GAAkB;gBAC7B,EAAE,GAAG,EAAE,iBAAiB,EAAE,KAAK,EAAE,IAAI,EAAE;gBACvC,EAAE,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,KAAK,EAAE;aACxC,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;YAEtE,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC;YAEnC,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC9B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACrC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;YACxD,MAAM,OAAO,GAAkB;gBAC7B,EAAE,GAAG,EAAE,0BAA0B,EAAE,KAAK,EAAE,KAAK,EAAE;aAClD,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;YAEtE,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC;YAEnC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;YACxC,MAAM,OAAO,GAAkB;gBAC7B,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE;aAC/B,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;YAEtE,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC;YAEnC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;YAClD,MAAM,OAAO,GAAkB;gBAC7B,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE;aAClC,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;YAEtE,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;YACtD,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;YAEtD,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC;YAEnC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACrC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;YAC3D,MAAM,OAAO,GAAkB;gBAC7B,EAAE,GAAG,EAAE,mBAAmB,EAAE,KAAK,EAAE,KAAK,EAAE;aAC3C,CAAC;YACF,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;YAEtE,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC;YAEnC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACrC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;YAC/D,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;YAE1E,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC;YAEnC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,0BAA0B;IAE1B,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,CAAC,CAAC;YAE3D,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,EAAE,CAAC;YAErC,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC7C,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC9C,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,EAAE;gBACzD,gBAAgB,EAAE,GAAG;gBACrB,eAAe,EAAE,CAAC;aACnB,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,EAAE,CAAC;YAErC,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC1C,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,+BAA+B;IAE/B,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;YACnD,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,CAAC,CAAC;YAE3D,SAAS,CAAC,cAAc,CAAC,sBAAsB,CAAC,CAAC;YAEjD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;YACpD,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;YACrD,MAAM,SAAS,GAAG,IAAI,sBAAsB,CAAC,UAAU,EAAE,CAAC,CAAC;YAE3D,SAAS,CAAC,cAAc,CAAC,sBAAsB,CAAC,CAAC;YACjD,SAAS,CAAC,cAAc,CAAC,sBAAsB,CAAC,CAAC;YAEjD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;YACpD,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard module barrel exports.
|
|
3
|
+
*/
|
|
4
|
+
export { DashboardDataCollector } from './data-collector.js';
|
|
5
|
+
export type { DashboardDataCollectorDeps } from './data-collector.js';
|
|
6
|
+
export { createDashboardRouter } from './routes.js';
|
|
7
|
+
export type { DashboardRouteDeps } from './routes.js';
|
|
8
|
+
export { renderDashboardPage, esc } from './templates.js';
|
|
9
|
+
export type { OverviewPageData, AnalyticsPageData, UsersPageData, SettingsPageData, PageData, } from './templates.js';
|
|
10
|
+
export type { IndexOverview, SearchAnalytics, UserInfo, UsageStats, DashboardConfig, DashboardPage, FlashMessage, DailyQueryCount, TopQuery, SearchRecord, RequestRecord, } from './types.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dashboard/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAG7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGpD,OAAO,EAAE,mBAAmB,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard Express routes — admin-only, server-rendered HTML.
|
|
3
|
+
*/
|
|
4
|
+
import { Router } from 'express';
|
|
5
|
+
import { type ApiKeyEntry } from '../middleware/auth.js';
|
|
6
|
+
import type { DashboardDataCollector } from './data-collector.js';
|
|
7
|
+
import type { IndexTriggerCallback } from '../routes/index-trigger.js';
|
|
8
|
+
import type { CodeRAGConfig } from '@code-rag/core';
|
|
9
|
+
export interface DashboardRouteDeps {
|
|
10
|
+
readonly dataCollector: DashboardDataCollector;
|
|
11
|
+
readonly onIndex: IndexTriggerCallback | null;
|
|
12
|
+
readonly getConfig: () => CodeRAGConfig | null;
|
|
13
|
+
readonly apiKeys: ReadonlyArray<ApiKeyEntry>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Create the dashboard router with all admin pages and actions.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createDashboardRouter(deps: DashboardRouteDeps): Router;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard Express routes — admin-only, server-rendered HTML.
|
|
3
|
+
*/
|
|
4
|
+
import { Router } from 'express';
|
|
5
|
+
import { createAuthMiddleware, requireAdmin } from '../middleware/auth.js';
|
|
6
|
+
import { renderDashboardPage } from './templates.js';
|
|
7
|
+
/**
|
|
8
|
+
* Create the dashboard router with all admin pages and actions.
|
|
9
|
+
*/
|
|
10
|
+
export function createDashboardRouter(deps) {
|
|
11
|
+
const router = Router();
|
|
12
|
+
// Apply auth middleware and requireAdmin to all dashboard routes
|
|
13
|
+
router.use(createAuthMiddleware(deps.apiKeys));
|
|
14
|
+
router.use(requireAdmin);
|
|
15
|
+
// Parse URL-encoded form bodies for POST actions
|
|
16
|
+
router.use((req, _res, next) => {
|
|
17
|
+
if (req.headers['content-type']?.includes('application/x-www-form-urlencoded')) {
|
|
18
|
+
let body = '';
|
|
19
|
+
req.on('data', (chunk) => {
|
|
20
|
+
body += chunk.toString();
|
|
21
|
+
});
|
|
22
|
+
req.on('end', () => {
|
|
23
|
+
// Simple URL-encoded parsing for flash messages
|
|
24
|
+
const params = new URLSearchParams(body);
|
|
25
|
+
req.formBody = Object.fromEntries(params.entries());
|
|
26
|
+
next();
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
next();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
// GET /dashboard → redirect to /dashboard/overview
|
|
34
|
+
router.get('/', (_req, res) => {
|
|
35
|
+
res.redirect(302, '/dashboard/overview');
|
|
36
|
+
});
|
|
37
|
+
// GET /dashboard/overview
|
|
38
|
+
router.get('/overview', async (req, res) => {
|
|
39
|
+
try {
|
|
40
|
+
const overview = await deps.dataCollector.getIndexOverview();
|
|
41
|
+
const usageStats = deps.dataCollector.getUsageStats();
|
|
42
|
+
// Read flash from query string (simple approach, no sessions)
|
|
43
|
+
const flash = parseFlash(req);
|
|
44
|
+
const html = renderDashboardPage({
|
|
45
|
+
page: 'overview',
|
|
46
|
+
data: { overview, usageStats, flash },
|
|
47
|
+
});
|
|
48
|
+
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
49
|
+
res.send(html);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
53
|
+
res.status(500).send(`<h1>Internal Server Error</h1><p>${escHtml(message)}</p>`);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
// GET /dashboard/analytics
|
|
57
|
+
router.get('/analytics', (_req, res) => {
|
|
58
|
+
try {
|
|
59
|
+
const analytics = deps.dataCollector.getSearchAnalytics(30);
|
|
60
|
+
const html = renderDashboardPage({
|
|
61
|
+
page: 'analytics',
|
|
62
|
+
data: { analytics },
|
|
63
|
+
});
|
|
64
|
+
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
65
|
+
res.send(html);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
69
|
+
res.status(500).send(`<h1>Internal Server Error</h1><p>${escHtml(message)}</p>`);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
// GET /dashboard/users
|
|
73
|
+
router.get('/users', (_req, res) => {
|
|
74
|
+
try {
|
|
75
|
+
const users = deps.dataCollector.getUsers();
|
|
76
|
+
const html = renderDashboardPage({
|
|
77
|
+
page: 'users',
|
|
78
|
+
data: { users },
|
|
79
|
+
});
|
|
80
|
+
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
81
|
+
res.send(html);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
85
|
+
res.status(500).send(`<h1>Internal Server Error</h1><p>${escHtml(message)}</p>`);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
// GET /dashboard/settings
|
|
89
|
+
router.get('/settings', (_req, res) => {
|
|
90
|
+
try {
|
|
91
|
+
const config = deps.dataCollector.getConfig();
|
|
92
|
+
const coderagConfig = deps.getConfig();
|
|
93
|
+
const projectConfig = coderagConfig
|
|
94
|
+
? {
|
|
95
|
+
name: coderagConfig.project.name,
|
|
96
|
+
embeddingModel: coderagConfig.embedding.model,
|
|
97
|
+
storagePath: coderagConfig.storage.path,
|
|
98
|
+
}
|
|
99
|
+
: null;
|
|
100
|
+
const html = renderDashboardPage({
|
|
101
|
+
page: 'settings',
|
|
102
|
+
data: { config, projectConfig },
|
|
103
|
+
});
|
|
104
|
+
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
105
|
+
res.send(html);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
109
|
+
res.status(500).send(`<h1>Internal Server Error</h1><p>${escHtml(message)}</p>`);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
// POST /dashboard/actions/reindex
|
|
113
|
+
router.post('/actions/reindex', async (_req, res) => {
|
|
114
|
+
if (!deps.onIndex) {
|
|
115
|
+
res.redirect(302, '/dashboard/overview?flash=error&msg=Indexing+service+not+configured');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
const result = await deps.onIndex({ force: true });
|
|
120
|
+
deps.dataCollector.setLastIndexed(new Date().toISOString());
|
|
121
|
+
const msg = encodeURIComponent(`Re-indexing completed: ${result.indexed_files} files in ${result.duration_ms}ms`);
|
|
122
|
+
res.redirect(302, `/dashboard/overview?flash=success&msg=${msg}`);
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
126
|
+
const msg = encodeURIComponent(`Re-indexing failed: ${message}`);
|
|
127
|
+
res.redirect(302, `/dashboard/overview?flash=error&msg=${msg}`);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
return router;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Parse a flash message from query parameters.
|
|
134
|
+
*/
|
|
135
|
+
function parseFlash(req) {
|
|
136
|
+
const flashType = req.query['flash'];
|
|
137
|
+
const flashMsg = req.query['msg'];
|
|
138
|
+
if (typeof flashType === 'string' &&
|
|
139
|
+
typeof flashMsg === 'string' &&
|
|
140
|
+
(flashType === 'success' || flashType === 'error' || flashType === 'info')) {
|
|
141
|
+
return { type: flashType, text: flashMsg };
|
|
142
|
+
}
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Simple HTML escape for error messages.
|
|
147
|
+
*/
|
|
148
|
+
function escHtml(s) {
|
|
149
|
+
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
150
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/dashboard/routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-rendered HTML templates for the CodeRAG admin dashboard.
|
|
3
|
+
*
|
|
4
|
+
* All HTML/CSS is inline — no external assets or client-side JS frameworks.
|
|
5
|
+
* Works without JavaScript in the browser (progressive enhancement).
|
|
6
|
+
*/
|
|
7
|
+
import type { FlashMessage, IndexOverview, SearchAnalytics, UserInfo, UsageStats, DashboardConfig } from './types.js';
|
|
8
|
+
export interface OverviewPageData {
|
|
9
|
+
readonly overview: IndexOverview;
|
|
10
|
+
readonly usageStats: UsageStats;
|
|
11
|
+
readonly flash?: FlashMessage;
|
|
12
|
+
}
|
|
13
|
+
export interface AnalyticsPageData {
|
|
14
|
+
readonly analytics: SearchAnalytics;
|
|
15
|
+
}
|
|
16
|
+
export interface UsersPageData {
|
|
17
|
+
readonly users: ReadonlyArray<UserInfo>;
|
|
18
|
+
}
|
|
19
|
+
export interface SettingsPageData {
|
|
20
|
+
readonly config: DashboardConfig;
|
|
21
|
+
readonly projectConfig: {
|
|
22
|
+
readonly name: string;
|
|
23
|
+
readonly embeddingModel: string;
|
|
24
|
+
readonly storagePath: string;
|
|
25
|
+
} | null;
|
|
26
|
+
}
|
|
27
|
+
export type PageData = {
|
|
28
|
+
page: 'overview';
|
|
29
|
+
data: OverviewPageData;
|
|
30
|
+
} | {
|
|
31
|
+
page: 'analytics';
|
|
32
|
+
data: AnalyticsPageData;
|
|
33
|
+
} | {
|
|
34
|
+
page: 'users';
|
|
35
|
+
data: UsersPageData;
|
|
36
|
+
} | {
|
|
37
|
+
page: 'settings';
|
|
38
|
+
data: SettingsPageData;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Render a complete dashboard HTML page.
|
|
42
|
+
*/
|
|
43
|
+
export declare function renderDashboardPage(pageData: PageData): string;
|
|
44
|
+
/**
|
|
45
|
+
* Escape HTML special characters to prevent XSS.
|
|
46
|
+
*/
|
|
47
|
+
export declare function esc(s: string): string;
|