@atolis-hq/wake 0.2.80 → 0.2.82
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.
|
@@ -61,7 +61,10 @@ export const indexHtml = `<!DOCTYPE html>
|
|
|
61
61
|
main { padding: 1rem; }
|
|
62
62
|
.columns { display: grid; grid-template-columns: repeat(6, minmax(180px, 1fr)); gap: 0.6rem; overflow-x: auto; }
|
|
63
63
|
.col { background: #1a1d23; border-radius: 10px; padding: 0.5rem; min-height: 200px; }
|
|
64
|
-
.col
|
|
64
|
+
.col-header { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin: 0.2rem 0.4rem 0.5rem; }
|
|
65
|
+
.col h2 { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em; color: #9aa2ad; margin: 0; }
|
|
66
|
+
.col-toggle { display: none; width: 1.65rem; height: 1.65rem; flex: 0 0 auto; align-items: center; justify-content: center; background: transparent; border: 1px solid #3a4150; border-radius: 6px; color: #cbd5e1; cursor: pointer; font-size: 1rem; line-height: 1; }
|
|
67
|
+
.col-toggle:hover { border-color: var(--accent); color: var(--accent-light); }
|
|
65
68
|
.card { background: #22262e; border: 1px solid #2c313a; border-radius: 8px; padding: 0.5rem; margin-bottom: 0.5rem; cursor: pointer; font-size: 0.8rem; transition: border-color 0.12s ease; }
|
|
66
69
|
.card:hover { border-color: var(--accent); }
|
|
67
70
|
.card .title { font-weight: 600; margin-bottom: 0.25rem; }
|
|
@@ -103,6 +106,20 @@ export const indexHtml = `<!DOCTYPE html>
|
|
|
103
106
|
.modal-tabs .nav-button.active { color: var(--accent-light); border-bottom-color: var(--accent); }
|
|
104
107
|
.modal-body { flex: 1; min-height: 0; overflow-y: auto; padding: 1rem; }
|
|
105
108
|
.modal-body h3:first-child { margin-top: 0; }
|
|
109
|
+
.event-list { display: flex; flex-direction: column; gap: 0.45rem; }
|
|
110
|
+
.event-card { background: #20242c; border: 1px solid #2c313a; border-radius: 6px; overflow: hidden; }
|
|
111
|
+
.event-card:hover { border-color: #3a4150; }
|
|
112
|
+
.event-summary { display: grid; grid-template-columns: minmax(11rem, 14rem) minmax(10rem, 1fr) minmax(8rem, 18rem) 2.4rem; gap: 0.65rem; align-items: center; width: 100%; min-height: 2.25rem; background: transparent; border: 0; color: inherit; padding: 0.45rem 0.65rem; text-align: left; cursor: pointer; font: inherit; }
|
|
113
|
+
.event-summary:hover { background: rgba(255, 255, 255, 0.03); }
|
|
114
|
+
.event-time, .event-type, .event-id, .event-direction { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
115
|
+
.event-time, .event-id { color: #9aa2ad; font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 0.72rem; }
|
|
116
|
+
.event-type { font-weight: 650; font-size: 0.8rem; }
|
|
117
|
+
.event-direction { justify-self: end; width: 1.7rem; height: 1.7rem; display: inline-flex; align-items: center; justify-content: center; border-radius: 999px; background: #151922; border: 1px solid #334155; color: var(--accent-light); font-size: 0.9rem; }
|
|
118
|
+
.event-json { display: none; position: relative; border-top: 1px solid #2c313a; background: #14171d; }
|
|
119
|
+
.event-card.expanded .event-json { display: block; }
|
|
120
|
+
.event-copy { position: absolute; top: 0.55rem; right: 0.55rem; z-index: 1; background: rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.18); color: #fff; border-radius: 6px; padding: 0.16rem 0.48rem; cursor: pointer; font-size: 0.72rem; }
|
|
121
|
+
.event-copy:hover { border-color: var(--accent-light); background: rgba(45, 212, 191, 0.16); }
|
|
122
|
+
.event-json pre { margin: 0; padding-top: 2.35rem; border-radius: 0; background: transparent; }
|
|
106
123
|
.transcript-session { margin: 0.75rem 0; color: #9aa2ad; font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 0.75rem; text-align: center; }
|
|
107
124
|
.transcript-entry { background: #101216; border: 1px solid #2c313a; border-radius: 6px; margin-bottom: 0.75rem; overflow: hidden; }
|
|
108
125
|
.transcript-head { color: #9aa2ad; background: #171a20; border-bottom: 1px solid #2c313a; padding: 0.45rem 0.6rem; font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 0.72rem; }
|
|
@@ -112,8 +129,12 @@ export const indexHtml = `<!DOCTYPE html>
|
|
|
112
129
|
.modal { width: 100%; height: 100%; max-height: none; border-radius: 0; border-left: 0; border-right: 0; }
|
|
113
130
|
.columns { display: flex; flex-direction: column; overflow-x: unset; }
|
|
114
131
|
.col { min-height: unset; }
|
|
132
|
+
.col-toggle { display: inline-flex; }
|
|
133
|
+
.col.is-collapsed .col-cards { display: none; }
|
|
115
134
|
.col-empty { padding: 0.25rem 0.5rem; }
|
|
116
|
-
.col-empty
|
|
135
|
+
.col-empty .col-header { margin: 0.1rem 0.4rem; }
|
|
136
|
+
.event-summary { grid-template-columns: minmax(8.5rem, 10rem) minmax(8rem, 1fr) 2.2rem; gap: 0.5rem; }
|
|
137
|
+
.event-id { display: none; }
|
|
117
138
|
}
|
|
118
139
|
.tiles { display: flex; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 1rem; }
|
|
119
140
|
.tile { background: #1a1d23; border-radius: 10px; padding: 0.6rem 0.9rem; min-width: 120px; }
|
|
@@ -194,6 +215,7 @@ const COND_CARD = {
|
|
|
194
215
|
'needs-human': 'card-needs-human',
|
|
195
216
|
error: 'card-error',
|
|
196
217
|
};
|
|
218
|
+
const BOARD_COLLAPSE_STORAGE_KEY = 'wake:board:collapsed-columns';
|
|
197
219
|
let currentView = 'board';
|
|
198
220
|
let analyticsWindow = '1d';
|
|
199
221
|
let analyticsMetric = 'runs-over-time';
|
|
@@ -264,6 +286,35 @@ function isActiveRequest(requestId) {
|
|
|
264
286
|
return activeViewRequest && activeViewRequest.id === requestId;
|
|
265
287
|
}
|
|
266
288
|
|
|
289
|
+
function readCollapsedColumns() {
|
|
290
|
+
try {
|
|
291
|
+
const raw = window.localStorage.getItem(BOARD_COLLAPSE_STORAGE_KEY);
|
|
292
|
+
if (!raw) return new Set();
|
|
293
|
+
const values = JSON.parse(raw);
|
|
294
|
+
if (!Array.isArray(values)) return new Set();
|
|
295
|
+
return new Set(values.filter((value) => CONDITIONS.includes(value)));
|
|
296
|
+
} catch {
|
|
297
|
+
return new Set();
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function writeCollapsedColumns(collapsed) {
|
|
302
|
+
try {
|
|
303
|
+
window.localStorage.setItem(BOARD_COLLAPSE_STORAGE_KEY, JSON.stringify([...collapsed]));
|
|
304
|
+
} catch {
|
|
305
|
+
// Ignore storage failures; the toggle should still work for this render.
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function setColumnCollapsed(column, button, collapsed) {
|
|
310
|
+
const label = collapsed ? 'Expand column' : 'Collapse column';
|
|
311
|
+
column.classList.toggle('is-collapsed', collapsed);
|
|
312
|
+
button.textContent = collapsed ? '+' : '-';
|
|
313
|
+
button.setAttribute('aria-label', label);
|
|
314
|
+
button.setAttribute('aria-expanded', String(!collapsed));
|
|
315
|
+
button.setAttribute('title', label);
|
|
316
|
+
}
|
|
317
|
+
|
|
267
318
|
function loadingNode(label) {
|
|
268
319
|
return el('p', { class: 'meta', text: 'Loading ' + label + '...' });
|
|
269
320
|
}
|
|
@@ -329,6 +380,7 @@ async function renderBoard(context) {
|
|
|
329
380
|
const board = await getJson('/board', context.signal);
|
|
330
381
|
if (!isActiveRequest(context.requestId)) return;
|
|
331
382
|
const main = document.getElementById('main');
|
|
383
|
+
const collapsedColumns = readCollapsedColumns();
|
|
332
384
|
const columns = el('div', { class: 'columns' }, CONDITIONS.map((cond) => {
|
|
333
385
|
const items = board.filter((c) => c.condition === cond);
|
|
334
386
|
if (cond === 'finished') items.sort((a, b) => a.timeInStageMs - b.timeInStageMs);
|
|
@@ -342,10 +394,27 @@ async function renderBoard(context) {
|
|
|
342
394
|
...renderCardSummaryNodes(item),
|
|
343
395
|
]);
|
|
344
396
|
});
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
397
|
+
const isCollapsed = collapsedColumns.has(cond);
|
|
398
|
+
const toggle = el('button', {
|
|
399
|
+
class: 'col-toggle',
|
|
400
|
+
type: 'button',
|
|
401
|
+
onclick: () => {
|
|
402
|
+
const nextCollapsed = !collapsedColumns.has(cond);
|
|
403
|
+
if (nextCollapsed) collapsedColumns.add(cond);
|
|
404
|
+
else collapsedColumns.delete(cond);
|
|
405
|
+
writeCollapsedColumns(collapsedColumns);
|
|
406
|
+
setColumnCollapsed(column, toggle, nextCollapsed);
|
|
407
|
+
},
|
|
408
|
+
});
|
|
409
|
+
const column = el('div', { class: 'col' + (items.length === 0 ? ' col-empty' : '') }, [
|
|
410
|
+
el('div', { class: 'col-header' }, [
|
|
411
|
+
el('h2', { text: cond + ' (' + items.length + ')' }),
|
|
412
|
+
toggle,
|
|
413
|
+
]),
|
|
414
|
+
el('div', { class: 'col-cards' }, cards),
|
|
348
415
|
]);
|
|
416
|
+
setColumnCollapsed(column, toggle, isCollapsed);
|
|
417
|
+
return column;
|
|
349
418
|
}));
|
|
350
419
|
main.replaceChildren(columns);
|
|
351
420
|
}
|
|
@@ -442,7 +511,7 @@ async function openItemModal(repo, number, boardItem) {
|
|
|
442
511
|
const detail = await ensureDetail();
|
|
443
512
|
if (!detail) return el('p', { text: 'Not found' });
|
|
444
513
|
if (tab === 'events') {
|
|
445
|
-
return
|
|
514
|
+
return renderItemEvents(detail.events || []);
|
|
446
515
|
}
|
|
447
516
|
if (tab === 'transcripts') {
|
|
448
517
|
const transcripts = await getJson('/work-items/' + encodeURIComponent(detail.item.workItemKey) + '/transcripts');
|
|
@@ -454,6 +523,81 @@ async function openItemModal(repo, number, boardItem) {
|
|
|
454
523
|
await switchItemTab('details');
|
|
455
524
|
}
|
|
456
525
|
|
|
526
|
+
function eventTimestamp(event) {
|
|
527
|
+
return event.ingestedAt || event.occurredAt || '';
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
function eventDirectionSymbol(direction) {
|
|
531
|
+
if (direction === 'inbound') return '\\u2193';
|
|
532
|
+
if (direction === 'outbound') return '\\u2191';
|
|
533
|
+
return '\\u2194';
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function sortedEventsNewestFirst(events) {
|
|
537
|
+
return [...events].sort((left, right) => eventTimestamp(right).localeCompare(eventTimestamp(left)));
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
async function copyText(text, button) {
|
|
541
|
+
const original = button.textContent;
|
|
542
|
+
try {
|
|
543
|
+
if (navigator.clipboard && window.isSecureContext) {
|
|
544
|
+
await navigator.clipboard.writeText(text);
|
|
545
|
+
} else {
|
|
546
|
+
const input = document.createElement('textarea');
|
|
547
|
+
input.value = text;
|
|
548
|
+
input.setAttribute('readonly', 'readonly');
|
|
549
|
+
input.style.position = 'fixed';
|
|
550
|
+
input.style.top = '-1000px';
|
|
551
|
+
document.body.appendChild(input);
|
|
552
|
+
input.select();
|
|
553
|
+
document.execCommand('copy');
|
|
554
|
+
input.remove();
|
|
555
|
+
}
|
|
556
|
+
button.textContent = 'Copied';
|
|
557
|
+
} catch (err) {
|
|
558
|
+
button.textContent = 'Copy failed';
|
|
559
|
+
} finally {
|
|
560
|
+
setTimeout(() => {
|
|
561
|
+
button.textContent = original;
|
|
562
|
+
}, 1100);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
function renderItemEvents(events) {
|
|
567
|
+
if (events.length === 0) {
|
|
568
|
+
return el('p', { class: 'meta', text: 'No events available for this item.' });
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const root = el('div', { class: 'event-list' });
|
|
572
|
+
for (const event of sortedEventsNewestFirst(events)) {
|
|
573
|
+
const json = JSON.stringify(event, null, 2);
|
|
574
|
+
const card = el('article', { class: 'event-card' });
|
|
575
|
+
const summary = el('button', { type: 'button', class: 'event-summary' }, [
|
|
576
|
+
el('span', { class: 'event-time', text: eventTimestamp(event) }),
|
|
577
|
+
el('span', { class: 'event-type', text: event.sourceEventType || 'unknown event' }),
|
|
578
|
+
el('span', { class: 'event-id', text: event.eventId || '' }),
|
|
579
|
+
el('span', { class: 'event-direction', title: event.direction || 'unknown', text: eventDirectionSymbol(event.direction) }),
|
|
580
|
+
]);
|
|
581
|
+
summary.addEventListener('click', () => {
|
|
582
|
+
card.classList.toggle('expanded');
|
|
583
|
+
summary.setAttribute('aria-expanded', String(card.classList.contains('expanded')));
|
|
584
|
+
});
|
|
585
|
+
const copyButton = el('button', { type: 'button', class: 'event-copy', text: 'Copy' });
|
|
586
|
+
copyButton.addEventListener('click', (clickEvent) => {
|
|
587
|
+
clickEvent.stopPropagation();
|
|
588
|
+
copyText(json, copyButton);
|
|
589
|
+
});
|
|
590
|
+
const jsonArea = el('div', { class: 'event-json' }, [
|
|
591
|
+
copyButton,
|
|
592
|
+
el('pre', { text: json }),
|
|
593
|
+
]);
|
|
594
|
+
card.appendChild(summary);
|
|
595
|
+
card.appendChild(jsonArea);
|
|
596
|
+
root.appendChild(card);
|
|
597
|
+
}
|
|
598
|
+
return root;
|
|
599
|
+
}
|
|
600
|
+
|
|
457
601
|
function renderItemDetails(detail, boardItem) {
|
|
458
602
|
const body = el('div');
|
|
459
603
|
const repo = detail.item.issue.repo;
|
package/dist/src/version.js
CHANGED