hzl-web 1.33.1 → 1.34.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/dist/server.d.ts.map +1 -1
- package/dist/server.js +105 -1
- package/dist/server.js.map +1 -1
- package/dist/server.test.js +249 -3
- package/dist/server.test.js.map +1 -1
- package/dist/ui/index.html +933 -123
- package/package.json +2 -2
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,WAAW,EACX,UAAU,EAIX,MAAM,UAAU,CAAC;AAGlB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAqHD,wBAAgB,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,YAAY,CAwYpE"}
|
package/dist/server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createServer } from 'http';
|
|
2
|
-
import { AmbiguousPrefixError, } from 'hzl-core';
|
|
2
|
+
import { EventType, AmbiguousPrefixError, } from 'hzl-core';
|
|
3
3
|
import { DASHBOARD_HTML } from './ui-embed.js';
|
|
4
4
|
// Date filter presets in days
|
|
5
5
|
const DATE_PRESETS = {
|
|
@@ -9,6 +9,9 @@ const DATE_PRESETS = {
|
|
|
9
9
|
'14d': 14,
|
|
10
10
|
'30d': 30,
|
|
11
11
|
};
|
|
12
|
+
const STREAM_POLL_MS = 2000;
|
|
13
|
+
const STREAM_KEEPALIVE_MS = 15000;
|
|
14
|
+
const STREAM_EVENT_TYPES = Object.values(EventType);
|
|
12
15
|
function parseUrl(url) {
|
|
13
16
|
const idx = url.indexOf('?');
|
|
14
17
|
if (idx === -1) {
|
|
@@ -33,8 +36,14 @@ function serverError(res, error) {
|
|
|
33
36
|
const message = error instanceof Error ? error.message : 'Internal Server Error';
|
|
34
37
|
json(res, { error: message }, 500);
|
|
35
38
|
}
|
|
39
|
+
function writeSseEvent(res, event, data) {
|
|
40
|
+
res.write(`event: ${event}\n`);
|
|
41
|
+
res.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
42
|
+
}
|
|
36
43
|
export function createWebServer(options) {
|
|
37
44
|
const { port, host = '0.0.0.0', allowFraming = false, taskService, eventStore } = options;
|
|
45
|
+
const sockets = new Set();
|
|
46
|
+
const activeStreamResponses = new Set();
|
|
38
47
|
// Route handlers
|
|
39
48
|
function handleTasks(params, res) {
|
|
40
49
|
const dueMonth = params.get('due_month');
|
|
@@ -175,6 +184,15 @@ export function createWebServer(options) {
|
|
|
175
184
|
// Get task titles for these events (batched query to avoid N+1)
|
|
176
185
|
const taskIds = [...new Set(rawEvents.map((e) => e.task_id).filter(Boolean))];
|
|
177
186
|
const titleMap = taskService.getTaskTitlesByIds(taskIds);
|
|
187
|
+
const taskMetadataMap = new Map();
|
|
188
|
+
for (const taskId of taskIds) {
|
|
189
|
+
const task = taskService.getTaskById(taskId);
|
|
190
|
+
taskMetadataMap.set(taskId, {
|
|
191
|
+
task_assignee: task?.assignee ?? null,
|
|
192
|
+
task_description: task?.description ?? null,
|
|
193
|
+
task_status: task?.status ?? null,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
178
196
|
const events = rawEvents.map((e) => ({
|
|
179
197
|
id: e.rowid,
|
|
180
198
|
event_id: e.event_id,
|
|
@@ -185,6 +203,9 @@ export function createWebServer(options) {
|
|
|
185
203
|
agent_id: e.agent_id ?? null,
|
|
186
204
|
timestamp: e.timestamp,
|
|
187
205
|
task_title: titleMap.get(e.task_id) ?? null,
|
|
206
|
+
task_assignee: taskMetadataMap.get(e.task_id)?.task_assignee ?? null,
|
|
207
|
+
task_description: taskMetadataMap.get(e.task_id)?.task_description ?? null,
|
|
208
|
+
task_status: taskMetadataMap.get(e.task_id)?.task_status ?? null,
|
|
188
209
|
}));
|
|
189
210
|
json(res, { events });
|
|
190
211
|
}
|
|
@@ -197,6 +218,63 @@ export function createWebServer(options) {
|
|
|
197
218
|
};
|
|
198
219
|
json(res, response);
|
|
199
220
|
}
|
|
221
|
+
function getLatestEventId() {
|
|
222
|
+
const latest = eventStore.getRecentEvents({
|
|
223
|
+
sinceId: 0,
|
|
224
|
+
limit: 1,
|
|
225
|
+
types: STREAM_EVENT_TYPES,
|
|
226
|
+
});
|
|
227
|
+
return latest[0]?.rowid ?? 0;
|
|
228
|
+
}
|
|
229
|
+
function handleStream(req, res) {
|
|
230
|
+
activeStreamResponses.add(res);
|
|
231
|
+
res.writeHead(200, {
|
|
232
|
+
'Content-Type': 'text/event-stream; charset=utf-8',
|
|
233
|
+
'Cache-Control': 'no-cache, no-transform',
|
|
234
|
+
Connection: 'keep-alive',
|
|
235
|
+
'X-Accel-Buffering': 'no',
|
|
236
|
+
});
|
|
237
|
+
if (typeof res.flushHeaders === 'function') {
|
|
238
|
+
res.flushHeaders();
|
|
239
|
+
}
|
|
240
|
+
res.write('retry: 2000\n\n');
|
|
241
|
+
let lastEventId = getLatestEventId();
|
|
242
|
+
const readyPayload = {
|
|
243
|
+
live: true,
|
|
244
|
+
latest_event_id: lastEventId,
|
|
245
|
+
};
|
|
246
|
+
writeSseEvent(res, 'ready', readyPayload);
|
|
247
|
+
const pollTimer = setInterval(() => {
|
|
248
|
+
if (req.destroyed || res.destroyed || res.writableEnded) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const latestId = getLatestEventId();
|
|
252
|
+
if (latestId > lastEventId) {
|
|
253
|
+
lastEventId = latestId;
|
|
254
|
+
const updatePayload = { latest_event_id: latestId };
|
|
255
|
+
writeSseEvent(res, 'update', updatePayload);
|
|
256
|
+
}
|
|
257
|
+
}, STREAM_POLL_MS);
|
|
258
|
+
const keepAliveTimer = setInterval(() => {
|
|
259
|
+
if (req.destroyed || res.destroyed || res.writableEnded) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
res.write(': keep-alive\n\n');
|
|
263
|
+
}, STREAM_KEEPALIVE_MS);
|
|
264
|
+
let closed = false;
|
|
265
|
+
const cleanup = () => {
|
|
266
|
+
if (closed)
|
|
267
|
+
return;
|
|
268
|
+
closed = true;
|
|
269
|
+
activeStreamResponses.delete(res);
|
|
270
|
+
clearInterval(pollTimer);
|
|
271
|
+
clearInterval(keepAliveTimer);
|
|
272
|
+
req.off('close', cleanup);
|
|
273
|
+
res.off('close', cleanup);
|
|
274
|
+
};
|
|
275
|
+
req.on('close', cleanup);
|
|
276
|
+
res.on('close', cleanup);
|
|
277
|
+
}
|
|
200
278
|
function handleRoot(res) {
|
|
201
279
|
const csp = allowFraming
|
|
202
280
|
? "default-src 'self'; script-src 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'unsafe-inline'; frame-ancestors *"
|
|
@@ -234,6 +312,10 @@ export function createWebServer(options) {
|
|
|
234
312
|
handleStats(res);
|
|
235
313
|
return;
|
|
236
314
|
}
|
|
315
|
+
if (pathname === '/api/events/stream' || pathname === '/api/stream') {
|
|
316
|
+
handleStream(req, res);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
237
319
|
// /api/tasks/:id routes
|
|
238
320
|
const taskMatch = pathname.match(/^\/api\/tasks\/([^/]+)$/);
|
|
239
321
|
if (taskMatch) {
|
|
@@ -262,15 +344,37 @@ export function createWebServer(options) {
|
|
|
262
344
|
}
|
|
263
345
|
}
|
|
264
346
|
const server = createServer(handleRequest);
|
|
347
|
+
server.on('connection', (socket) => {
|
|
348
|
+
sockets.add(socket);
|
|
349
|
+
socket.on('close', () => {
|
|
350
|
+
sockets.delete(socket);
|
|
351
|
+
});
|
|
352
|
+
});
|
|
265
353
|
server.listen(port, host);
|
|
266
354
|
return {
|
|
267
355
|
close: () => new Promise((resolve, reject) => {
|
|
356
|
+
for (const streamRes of activeStreamResponses) {
|
|
357
|
+
if (!streamRes.writableEnded && !streamRes.destroyed) {
|
|
358
|
+
streamRes.end();
|
|
359
|
+
}
|
|
360
|
+
}
|
|
268
361
|
server.close((err) => {
|
|
269
362
|
if (err)
|
|
270
363
|
reject(err);
|
|
271
364
|
else
|
|
272
365
|
resolve();
|
|
273
366
|
});
|
|
367
|
+
if (typeof server.closeIdleConnections === 'function') {
|
|
368
|
+
server.closeIdleConnections();
|
|
369
|
+
}
|
|
370
|
+
if (typeof server.closeAllConnections === 'function') {
|
|
371
|
+
server.closeAllConnections();
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
for (const socket of sockets) {
|
|
375
|
+
socket.destroy();
|
|
376
|
+
}
|
|
377
|
+
}
|
|
274
378
|
}),
|
|
275
379
|
port,
|
|
276
380
|
host,
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/server.test.js
CHANGED
|
@@ -46,6 +46,11 @@ describe('hzl-web server', () => {
|
|
|
46
46
|
const data = await res.json().catch(() => null);
|
|
47
47
|
return { status: res.status, data };
|
|
48
48
|
}
|
|
49
|
+
async function fetchText(path) {
|
|
50
|
+
const res = await globalThis.fetch(`${server.url}${path}`);
|
|
51
|
+
const body = await res.text();
|
|
52
|
+
return { status: res.status, body };
|
|
53
|
+
}
|
|
49
54
|
describe('server configuration', () => {
|
|
50
55
|
it('starts on specified port', async () => {
|
|
51
56
|
const s = createServer(4500);
|
|
@@ -79,6 +84,28 @@ describe('hzl-web server', () => {
|
|
|
79
84
|
// Prevent afterEach from closing again
|
|
80
85
|
server = undefined;
|
|
81
86
|
});
|
|
87
|
+
it('closes promptly even with an active SSE stream', async () => {
|
|
88
|
+
const s = createServer(4504);
|
|
89
|
+
const controller = new AbortController();
|
|
90
|
+
const response = await globalThis.fetch(`${s.url}/api/events/stream`, {
|
|
91
|
+
headers: { Accept: 'text/event-stream' },
|
|
92
|
+
signal: controller.signal,
|
|
93
|
+
});
|
|
94
|
+
expect(response.status).toBe(200);
|
|
95
|
+
const closePromise = s.close();
|
|
96
|
+
const closedQuickly = await Promise.race([
|
|
97
|
+
closePromise.then(() => true),
|
|
98
|
+
new Promise((resolve) => setTimeout(() => resolve(false), 500)),
|
|
99
|
+
]);
|
|
100
|
+
if (!closedQuickly) {
|
|
101
|
+
controller.abort();
|
|
102
|
+
await closePromise;
|
|
103
|
+
}
|
|
104
|
+
expect(closedQuickly).toBe(true);
|
|
105
|
+
controller.abort();
|
|
106
|
+
// Prevent afterEach from closing again
|
|
107
|
+
server = undefined;
|
|
108
|
+
});
|
|
82
109
|
});
|
|
83
110
|
describe('GET /api/tasks', () => {
|
|
84
111
|
it('returns empty task list initially', async () => {
|
|
@@ -107,6 +134,24 @@ describe('hzl-web server', () => {
|
|
|
107
134
|
project: 'test-project',
|
|
108
135
|
});
|
|
109
136
|
});
|
|
137
|
+
it('preserves assignee names with spaces and emojis', async () => {
|
|
138
|
+
taskService.createTask({
|
|
139
|
+
title: 'Space Name',
|
|
140
|
+
project: 'test-project',
|
|
141
|
+
assignee: 'Trevin C',
|
|
142
|
+
});
|
|
143
|
+
taskService.createTask({
|
|
144
|
+
title: 'Emoji Name',
|
|
145
|
+
project: 'test-project',
|
|
146
|
+
assignee: 'Clara 📝',
|
|
147
|
+
});
|
|
148
|
+
createServer(4518);
|
|
149
|
+
const { data } = await fetchJson('/api/tasks');
|
|
150
|
+
const tasks = data.tasks;
|
|
151
|
+
const assigneeByTitle = new Map(tasks.map((task) => [task.title, task.assignee]));
|
|
152
|
+
expect(assigneeByTitle.get('Space Name')).toBe('Trevin C');
|
|
153
|
+
expect(assigneeByTitle.get('Emoji Name')).toBe('Clara 📝');
|
|
154
|
+
});
|
|
110
155
|
it('filters by project', async () => {
|
|
111
156
|
projectService.createProject('other-project');
|
|
112
157
|
taskService.createTask({ title: 'Task 1', project: 'test-project' });
|
|
@@ -444,13 +489,22 @@ describe('hzl-web server', () => {
|
|
|
444
489
|
const { data } = await fetchJson('/api/events?since=99999');
|
|
445
490
|
expect(data.events).toHaveLength(0);
|
|
446
491
|
});
|
|
447
|
-
it('includes task
|
|
448
|
-
taskService.createTask({
|
|
492
|
+
it('includes task metadata fields in events', async () => {
|
|
493
|
+
const task = taskService.createTask({
|
|
494
|
+
title: 'Named Task',
|
|
495
|
+
project: 'test-project',
|
|
496
|
+
assignee: 'Clara 📝',
|
|
497
|
+
description: 'Task details for activity filtering',
|
|
498
|
+
});
|
|
499
|
+
taskService.setStatus(task.task_id, TaskStatus.Ready);
|
|
449
500
|
createServer(4552);
|
|
450
501
|
const { data } = await fetchJson('/api/events?since=0');
|
|
451
502
|
const events = data.events;
|
|
452
|
-
const createEvent = events.find((e) => e.type === 'task_created');
|
|
503
|
+
const createEvent = events.find((e) => e.task_id === task.task_id && e.type === 'task_created');
|
|
453
504
|
expect(createEvent?.task_title).toBe('Named Task');
|
|
505
|
+
expect(createEvent?.task_assignee).toBe('Clara 📝');
|
|
506
|
+
expect(createEvent?.task_description).toBe('Task details for activity filtering');
|
|
507
|
+
expect(createEvent?.task_status).toBe(TaskStatus.Ready);
|
|
454
508
|
});
|
|
455
509
|
});
|
|
456
510
|
describe('GET /api/tasks/:id/events', () => {
|
|
@@ -481,6 +535,50 @@ describe('hzl-web server', () => {
|
|
|
481
535
|
expect(data.events).toHaveLength(1);
|
|
482
536
|
});
|
|
483
537
|
});
|
|
538
|
+
describe('SSE + client wiring contracts', () => {
|
|
539
|
+
it('exposes an SSE route with event-stream content type', async () => {
|
|
540
|
+
server = createServer(4555);
|
|
541
|
+
const res = await globalThis.fetch(`${server.url}/api/events/stream`, {
|
|
542
|
+
headers: { Accept: 'text/event-stream' },
|
|
543
|
+
});
|
|
544
|
+
expect(res.status).toBe(200);
|
|
545
|
+
expect(res.headers.get('content-type') ?? '').toMatch(/text\/event-stream/i);
|
|
546
|
+
await res.body?.cancel();
|
|
547
|
+
});
|
|
548
|
+
it('includes EventSource usage and wiring in dashboard HTML', async () => {
|
|
549
|
+
server = createServer(4556);
|
|
550
|
+
const { body } = await fetchText('/');
|
|
551
|
+
const eventSourceInit = body.match(/(?:const|let|var)\s+([a-zA-Z_$][\w$]*)\s*=\s*new\s+EventSource\s*\([\s\S]*?\)/i);
|
|
552
|
+
expect(eventSourceInit).toBeTruthy();
|
|
553
|
+
expect(body).toMatch(/SSE_ENDPOINT\s*=\s*['"]\/api\/events\/stream['"]/i);
|
|
554
|
+
const eventSourceVar = eventSourceInit?.[1];
|
|
555
|
+
expect(eventSourceVar).toBeTruthy();
|
|
556
|
+
const eventSourceWiring = new RegExp(`${eventSourceVar}\\s*\\.\\s*(?:onopen|onmessage|onerror|addEventListener\\s*\\()`, 'i');
|
|
557
|
+
expect(body).toMatch(eventSourceWiring);
|
|
558
|
+
});
|
|
559
|
+
it('does not rely on setInterval(poll, ...) as the primary update loop', async () => {
|
|
560
|
+
server = createServer(4557);
|
|
561
|
+
const { body } = await fetchText('/');
|
|
562
|
+
expect(body).not.toMatch(/setInterval\s*\(\s*poll\s*,/i);
|
|
563
|
+
});
|
|
564
|
+
it('checks both visibility and focus before opening SSE connections', async () => {
|
|
565
|
+
server = createServer(4558);
|
|
566
|
+
const { body } = await fetchText('/');
|
|
567
|
+
const connectSetup = body.match(/function\s+connectEventStream\s*\([^)]*\)\s*\{[\s\S]*?if\s*\(\s*!\s*([a-zA-Z_$][\w$]*)\s*\(\s*\)\s*\)\s*\{[\s\S]{0,260}?pauseLiveUpdates\s*\(\s*\)[\s\S]{0,260}?return[\s\S]*?new\s+EventSource\s*\(/i);
|
|
568
|
+
expect(connectSetup).toBeTruthy();
|
|
569
|
+
const liveUpdateGate = connectSetup?.[1];
|
|
570
|
+
expect(liveUpdateGate).toBeTruthy();
|
|
571
|
+
const gateFunctionPattern = new RegExp(`function\\s+${liveUpdateGate}\\s*\\([^)]*\\)\\s*\\{[\\s\\S]*?(?:document\\.(?:hidden|visibilityState)[\\s\\S]*?document\\.hasFocus\\s*\\(\\s*\\)|document\\.hasFocus\\s*\\(\\s*\\)[\\s\\S]*?document\\.(?:hidden|visibilityState))`, 'i');
|
|
572
|
+
expect(body).toMatch(gateFunctionPattern);
|
|
573
|
+
});
|
|
574
|
+
it('wires blur/focus/visibilitychange handlers to pause and resume live updates', async () => {
|
|
575
|
+
server = createServer(4559);
|
|
576
|
+
const { body } = await fetchText('/');
|
|
577
|
+
expect(body).toMatch(/(?:window|document)\s*\.\s*addEventListener\s*\(\s*['"]blur['"]\s*,[\s\S]{0,240}?pauseLiveUpdates\s*\(/i);
|
|
578
|
+
expect(body).toMatch(/(?:window|document)\s*\.\s*addEventListener\s*\(\s*['"]focus['"]\s*,[\s\S]{0,240}?resumeLiveUpdates\s*\(/i);
|
|
579
|
+
expect(body).toMatch(/document\s*\.\s*addEventListener\s*\(\s*['"]visibilitychange['"]\s*,[\s\S]{0,500}?pauseLiveUpdates\s*\([\s\S]{0,500}?resumeLiveUpdates\s*\(/i);
|
|
580
|
+
});
|
|
581
|
+
});
|
|
484
582
|
describe('GET / (dashboard HTML)', () => {
|
|
485
583
|
it('serves HTML at root', async () => {
|
|
486
584
|
server = createServer(4560);
|
|
@@ -505,6 +603,154 @@ describe('hzl-web server', () => {
|
|
|
505
603
|
expect(res.headers.get('x-content-type-options')).toBe('nosniff');
|
|
506
604
|
expect(res.headers.get('referrer-policy')).toBe('no-referrer');
|
|
507
605
|
});
|
|
606
|
+
it('renders project metadata in the top-right header and assignee metadata in card footer', async () => {
|
|
607
|
+
server = createServer(4590);
|
|
608
|
+
const { body } = await fetchText('/');
|
|
609
|
+
const renderCardBlock = body.match(/function\s+renderCard\s*\([^)]*\)\s*\{[\s\S]*?return\s*`[\s\S]*?`;\s*}/i);
|
|
610
|
+
expect(renderCardBlock).toBeTruthy();
|
|
611
|
+
expect(renderCardBlock?.[0]).toMatch(/const\s+projectHtml\s*=\s*`[\s\S]*class=["']card-project["'][\s\S]*`;/i);
|
|
612
|
+
expect(renderCardBlock?.[0]).toMatch(/const\s+assigneeClass\s*=\s*hasAssignee\s*\?\s*['"][^'"]*\bcard-assignee\b[^'"]*['"]\s*:\s*['"][^'"]*\bcard-assignee\b[^'"]*['"]/i);
|
|
613
|
+
expect(renderCardBlock?.[0]).toMatch(/const\s+assigneeHtml\s*=\s*`[\s\S]*class=["']\$\{assigneeClass\}["'][\s\S]*`;/i);
|
|
614
|
+
expect(renderCardBlock?.[0]).toMatch(/<div[^>]*class=["']card-header-right["'][^>]*>[\s\S]*\$\{projectHtml\}[\s\S]*<\/div>/i);
|
|
615
|
+
expect(renderCardBlock?.[0]).toMatch(/<div[^>]*class=["']card-meta["'][^>]*>[\s\S]*\$\{assigneeHtml\}[\s\S]*<\/div>/i);
|
|
616
|
+
});
|
|
617
|
+
it('truncates card assignee labels to 10 characters plus ellipsis', async () => {
|
|
618
|
+
server = createServer(4598);
|
|
619
|
+
const { body } = await fetchText('/');
|
|
620
|
+
const renderCardBlock = body.match(/function\s+renderCard\s*\([^)]*\)\s*\{[\s\S]*?return\s*`[\s\S]*?`;\s*}/i);
|
|
621
|
+
expect(renderCardBlock).toBeTruthy();
|
|
622
|
+
expect(body).toMatch(/function\s+truncateCardLabel\s*\(value,\s*maxChars\s*=\s*10\)\s*\{/i);
|
|
623
|
+
expect(renderCardBlock?.[0]).toMatch(/const\s+assigneeCardText\s*=\s*truncateCardLabel\(assigneeText,\s*10\)/i);
|
|
624
|
+
expect(renderCardBlock?.[0]).toMatch(/title="\$\{escapeHtml\(assigneeText\)\}"[^>]*>\$\{escapeHtml\(assigneeCardText\)\}<\/span>/i);
|
|
625
|
+
});
|
|
626
|
+
it('binds modal assignee metadata with an Unassigned fallback value', async () => {
|
|
627
|
+
server = createServer(4591);
|
|
628
|
+
const { body } = await fetchText('/');
|
|
629
|
+
const openTaskModalBlock = body.match(/async\s+function\s+openTaskModal\s*\([^)]*\)\s*\{[\s\S]*?let\s+html\s*=\s*`[\s\S]*?`;/i);
|
|
630
|
+
expect(openTaskModalBlock).toBeTruthy();
|
|
631
|
+
expect(openTaskModalBlock?.[0]).toMatch(/const\s+assigneeValue\s*=\s*hasAssignee[\s\S]*<span[^>]*class=["']modal-meta-fallback["'][^>]*>\s*Unassigned\s*<\/span>/i);
|
|
632
|
+
expect(openTaskModalBlock?.[0]).toMatch(/<div[^>]*class=["']modal-meta-label["'][^>]*>\s*Assignee\s*<\/div>[\s\S]*?<div[^>]*class=["']modal-meta-value["'][^>]*>\s*\$\{assigneeValue\}\s*<\/div>/i);
|
|
633
|
+
});
|
|
634
|
+
it('binds modal task id display to task.task_id', async () => {
|
|
635
|
+
server = createServer(4592);
|
|
636
|
+
const { body } = await fetchText('/');
|
|
637
|
+
const hasTaskIdSourceBinding = /data\.task\.task_id/i.test(body);
|
|
638
|
+
const hasModalTaskIdDisplayBinding = /modalTaskIdValue\s*\.\s*textContent\s*=\s*(?:data\.task\.task_id|[a-zA-Z0-9_$]*taskId[a-zA-Z0-9_$]*)/i.test(body);
|
|
639
|
+
expect(hasTaskIdSourceBinding).toBe(true);
|
|
640
|
+
expect(hasModalTaskIdDisplayBinding).toBe(true);
|
|
641
|
+
});
|
|
642
|
+
it('includes a modal copy control for task id', async () => {
|
|
643
|
+
server = createServer(4593);
|
|
644
|
+
const { body } = await fetchText('/');
|
|
645
|
+
expect(body).toMatch(/<div[^>]*class=["']modal-task-id-row["'][^>]*>[\s\S]*id=["']modalTaskIdValue["'][\s\S]*<button[^>]*id=["']modalTaskIdCopy["'][^>]*>[\s\S]*\bcopy\b[\s\S]*<\/button>/i);
|
|
646
|
+
});
|
|
647
|
+
it('includes a copy handler that uses clipboard API and/or execCommand fallback', async () => {
|
|
648
|
+
server = createServer(4594);
|
|
649
|
+
const { body } = await fetchText('/');
|
|
650
|
+
const hasCopyHandlerFunction = /(?:async\s+)?function\s+[a-zA-Z0-9_$]*copy[a-zA-Z0-9_$]*\s*\(/i.test(body) ||
|
|
651
|
+
/(?:const|let)\s+[a-zA-Z0-9_$]*copy[a-zA-Z0-9_$]*\s*=\s*(?:async\s*)?\([^)]*\)\s*=>/i.test(body);
|
|
652
|
+
const hasClipboardOrExecCommand = /navigator\.clipboard\s*\.\s*writeText\s*\(|document\.execCommand\(\s*["']copy["']\s*\)/i.test(body);
|
|
653
|
+
expect(hasCopyHandlerFunction).toBe(true);
|
|
654
|
+
expect(hasClipboardOrExecCommand).toBe(true);
|
|
655
|
+
});
|
|
656
|
+
it('includes assignee filter select with id assigneeFilter', async () => {
|
|
657
|
+
server = createServer(4563);
|
|
658
|
+
const { body } = await fetchText('/');
|
|
659
|
+
expect(body).toMatch(/<select[^>]*id=["']assigneeFilter["'][^>]*>/i);
|
|
660
|
+
});
|
|
661
|
+
it('includes a default assignee option containing Any Agent', async () => {
|
|
662
|
+
server = createServer(4564);
|
|
663
|
+
const { body } = await fetchText('/');
|
|
664
|
+
const assigneeSelect = body.match(/<select[^>]*id=["']assigneeFilter["'][^>]*>([\s\S]*?)<\/select>/i);
|
|
665
|
+
expect(assigneeSelect).toBeTruthy();
|
|
666
|
+
expect(assigneeSelect?.[1]).toMatch(/<option[^>]*>[\s\S]*?Any Agent[\s\S]*?<\/option>/i);
|
|
667
|
+
});
|
|
668
|
+
it('includes script wiring for assignee filter change handling', async () => {
|
|
669
|
+
server = createServer(4565);
|
|
670
|
+
const { body } = await fetchText('/');
|
|
671
|
+
const hasAssigneeReference = /getElementById\(\s*['"]assigneeFilter['"]\s*\)/.test(body) ||
|
|
672
|
+
/querySelector\(\s*['"]#assigneeFilter['"]\s*\)/.test(body) ||
|
|
673
|
+
/assigneeFilter/.test(body);
|
|
674
|
+
const hasAssigneeChangeListener = /assigneeFilter\s*\.\s*addEventListener\(\s*['"]change['"]/.test(body) ||
|
|
675
|
+
/getElementById\(\s*['"]assigneeFilter['"]\s*\)\s*\.\s*addEventListener\(\s*['"]change['"]/.test(body) ||
|
|
676
|
+
/querySelector\(\s*['"]#assigneeFilter['"]\s*\)\s*\.\s*addEventListener\(\s*['"]change['"]/.test(body);
|
|
677
|
+
expect(hasAssigneeReference).toBe(true);
|
|
678
|
+
expect(hasAssigneeChangeListener).toBe(true);
|
|
679
|
+
});
|
|
680
|
+
it('preserves full assignee strings in board and activity filter wiring', async () => {
|
|
681
|
+
server = createServer(4600);
|
|
682
|
+
const { body } = await fetchText('/');
|
|
683
|
+
expect(body).toMatch(/function\s+getAssigneeValue\s*\(value\)\s*\{[\s\S]*value\.trim\(\)\.length\s*>\s*0[\s\S]*\?\s*value\s*:\s*['"]{2}/i);
|
|
684
|
+
expect(body).toMatch(/filtered\s*=\s*filtered\.filter\(\s*task\s*=>\s*getAssigneeValue\(task\.assignee\)\s*===\s*assigneeFilter\.value\s*\)/i);
|
|
685
|
+
expect(body).toMatch(/const\s+assignee\s*=\s*getAssigneeValue\(task\.assignee\);\s*if\s*\(!assignee\)\s*continue;[\s\S]*option\.value\s*=\s*assignee/i);
|
|
686
|
+
expect(body).toMatch(/const\s+taskAssignee\s*=\s*getAssigneeValue\(event\.task_assignee\);\s*if\s*\(taskAssignee\)\s*return\s+taskAssignee;[\s\S]*return\s+getAssigneeValue\(event\.data\?\.assignee\)/i);
|
|
687
|
+
});
|
|
688
|
+
it('includes activity assignee and keyword filter controls', async () => {
|
|
689
|
+
server = createServer(4566);
|
|
690
|
+
const { body } = await fetchText('/');
|
|
691
|
+
expect(body).toMatch(/<select[^>]*id=["']activityAssigneeFilter["'][^>]*>/i);
|
|
692
|
+
expect(body).toMatch(/<input[^>]*id=["']activityKeywordFilter["'][^>]*>/i);
|
|
693
|
+
});
|
|
694
|
+
it('applies activity keyword filtering only at 3+ characters', async () => {
|
|
695
|
+
server = createServer(4567);
|
|
696
|
+
const { body } = await fetchText('/');
|
|
697
|
+
expect(body).toMatch(/keyword\.length\s*>=\s*3/);
|
|
698
|
+
});
|
|
699
|
+
it('includes activity item markup with task id binding attribute', async () => {
|
|
700
|
+
server = createServer(4568);
|
|
701
|
+
const { body } = await fetchText('/');
|
|
702
|
+
expect(body).toMatch(/<div(?=[^>]*\bclass=["'][^"']*\bactivity-item\b[^"']*["'])(?=[^>]*\bdata-task-id\s*=\s*["'][^"']*event\.task_id[^"']*["'])[^>]*>/i);
|
|
703
|
+
});
|
|
704
|
+
it('includes activity list click delegation wired to openTaskModal', async () => {
|
|
705
|
+
server = createServer(4569);
|
|
706
|
+
const { body } = await fetchText('/');
|
|
707
|
+
expect(body).toMatch(/(?:activityList|getElementById\(\s*["']activityList["']\s*\)|querySelector\(\s*["']#activityList["']\s*\))\s*\.\s*addEventListener\(\s*["']click["']\s*,[\s\S]*?closest\(\s*["']\.activity-item["']\s*\)[\s\S]*?openTaskModal\b/i);
|
|
708
|
+
});
|
|
709
|
+
it('shows static Live text with green connection-dot live state when stream is healthy', async () => {
|
|
710
|
+
server = createServer(4598);
|
|
711
|
+
const { body } = await fetchText('/');
|
|
712
|
+
expect(body).toMatch(/\.connection-dot\.live\s*\{[\s\S]*--status-done/i);
|
|
713
|
+
expect(body).toMatch(/connectionText\.textContent\s*=\s*['"]Live['"]/);
|
|
714
|
+
expect(body).not.toMatch(/Live\s*\$\{ago\}s/);
|
|
715
|
+
});
|
|
716
|
+
it('uses hidden-by-default column scrollbars with scroll/touch reveal behavior', async () => {
|
|
717
|
+
server = createServer(4599);
|
|
718
|
+
const { body } = await fetchText('/');
|
|
719
|
+
expect(body).toMatch(/\.column-cards\s*\{[\s\S]*scrollbar-width:\s*none[\s\S]*-ms-overflow-style:\s*none/i);
|
|
720
|
+
expect(body).toMatch(/\.column-cards\.is-scrolling[\s\S]*::\-webkit-scrollbar/i);
|
|
721
|
+
expect(body).toMatch(/function\s+bindColumnScrollIndicators\s*\(/i);
|
|
722
|
+
expect(body).toMatch(/classList\.add\(\s*['"]is-scrolling['"]\s*\)/i);
|
|
723
|
+
});
|
|
724
|
+
it('renders an explicit activity actor/author element in task modal activity entries', async () => {
|
|
725
|
+
server = createServer(4595);
|
|
726
|
+
const { body } = await fetchText('/');
|
|
727
|
+
const activityMarkupBlock = body.match(/displayTaskActivity\.map\([\s\S]*?\)\.join\(\s*['"]{2}\s*\)/i);
|
|
728
|
+
expect(activityMarkupBlock).toBeTruthy();
|
|
729
|
+
expect(activityMarkupBlock?.[0]).toMatch(/class=["'][^"']*(?:activity|event)[^"']*(?:actor|author)[^"']*["']/i);
|
|
730
|
+
expect(activityMarkupBlock?.[0]).toMatch(/\$\{escapeHtml\(\s*actor\s*\)\}/i);
|
|
731
|
+
});
|
|
732
|
+
it('uses dedicated modal classes for checkpoint and activity author fields (not just .comment-author)', async () => {
|
|
733
|
+
server = createServer(4596);
|
|
734
|
+
const { body } = await fetchText('/');
|
|
735
|
+
const modalMarkupBlock = body.match(/async\s+function\s+openTaskModal\s*\([^)]*\)\s*\{[\s\S]*?modalBody\.innerHTML\s*=\s*html\s*;/i);
|
|
736
|
+
const checkpointMarkupBlock = modalMarkupBlock?.[0].match(/visibleCheckpoints\.map\([\s\S]*?\)\.join\(\s*['"]{2}\s*\)/i);
|
|
737
|
+
const activityMarkupBlock = modalMarkupBlock?.[0].match(/displayTaskActivity\.map\([\s\S]*?\)\.join\(\s*['"]{2}\s*\)/i);
|
|
738
|
+
expect(modalMarkupBlock).toBeTruthy();
|
|
739
|
+
expect(checkpointMarkupBlock).toBeTruthy();
|
|
740
|
+
expect(activityMarkupBlock).toBeTruthy();
|
|
741
|
+
expect(checkpointMarkupBlock?.[0]).toMatch(/class=["'][^"']*\b(?:modal-|task-)?(?:checkpoint|cp)-[^"']*["']/i);
|
|
742
|
+
expect(activityMarkupBlock?.[0]).toMatch(/class=["'][^"']*\b(?:modal-|task-)?(?:activity|event)-[^"']*["']/i);
|
|
743
|
+
expect(checkpointMarkupBlock?.[0]).not.toMatch(/\bcomment-author\b/i);
|
|
744
|
+
expect(activityMarkupBlock?.[0]).not.toMatch(/\bcomment-author\b/i);
|
|
745
|
+
});
|
|
746
|
+
it('styles modal checkpoint author/name with dedicated non-accent class rules', async () => {
|
|
747
|
+
server = createServer(4597);
|
|
748
|
+
const { body } = await fetchText('/');
|
|
749
|
+
const checkpointStyleRule = body.match(/\.(?:modal-|task-)?(?:checkpoint|cp)-[\w-]*(?:entry|item|author|name|title|meta)?[\w-]*\s*\{[\s\S]*?\}/i);
|
|
750
|
+
expect(checkpointStyleRule).toBeTruthy();
|
|
751
|
+
expect(checkpointStyleRule?.[0]).toMatch(/(?:color|border(?:-left|-color)?)\s*:/i);
|
|
752
|
+
expect(checkpointStyleRule?.[0]).not.toMatch(/--accent|--status-in-progress|orange/i);
|
|
753
|
+
});
|
|
508
754
|
});
|
|
509
755
|
describe('404 handling', () => {
|
|
510
756
|
it('returns 404 for unknown routes', async () => {
|