added last log preview
This commit is contained in:
1 parent
cfb5334666
commit
6c345ccf81
4 files changed
+36
-7
No files matched your search
@@ -8,3 +8,7 @@
|
||||
.block-title{font-weight:600;margin-bottom:6px;color:var(--fg);overflow-wrap:anywhere}
|
||||
|
||||
#error-count{font-weight:700;font-size:14px}#error-count.has-errors{color:var(--vscode-editorError-foreground,#ffacac);border-color:currentColor;background:var(--vscode-inputValidation-errorBackground,#5b3039)}
|
||||
|
||||
.last-log{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||
summary{display:grid;grid-template-columns:auto minmax(0,1fr) repeat(3,max-content);align-items:center;column-gap:10px;row-gap:5px}
|
||||
summary .last-log{grid-column:1/-1;min-width:0}
|
||||
@@ -56,6 +56,19 @@
|
||||
const years = Math.floor(days / 365);
|
||||
return `${years} year${years === 1 ? '' : 's'} ago`;
|
||||
}
|
||||
function shortTimeSince(time) {
|
||||
const seconds = Math.max(0, Math.floor((Date.now() - Number(time)) / 1000));
|
||||
if (seconds < 60) return `${seconds} sec ago`;
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
if (minutes < 60) return `${minutes} min ago`;
|
||||
const hours = Math.floor(minutes / 60);
|
||||
if (hours < 24) return `${hours} hr ago`;
|
||||
const days = Math.floor(hours / 24);
|
||||
if (days < 30) return `${days} d ago`;
|
||||
const months = Math.floor(days / 30);
|
||||
if (days < 365) return `${months} mo ago`;
|
||||
return `${Math.floor(days / 365)} yr ago`;
|
||||
}
|
||||
function copy(text) { if (text) vscode.postMessage({ type: 'copy', text }); }
|
||||
function logMessages(items, cls) {
|
||||
const container = node('div', undefined, cls);
|
||||
@@ -133,7 +146,7 @@
|
||||
if (!groups.size) container.append(node('div', 'No logs match these filters. Try a wider time range or clear the search.', 'empty'));
|
||||
const lastLogs = new Map();
|
||||
entries.filter(e => e.kind === 'log' || e.kind.startsWith('initialization_')).forEach(e => {
|
||||
if (!lastLogs.has(e.app) || e.time > lastLogs.get(e.app).time) lastLogs.set(e.app, e);
|
||||
if (!lastLogs.has(e.app) || e.time >= lastLogs.get(e.app).time) lastLogs.set(e.app, e);
|
||||
});
|
||||
const timeOf = (app, logs) => (lastLogs.get(app) || logs[logs.length - 1]).time;
|
||||
$('error-count').setAttribute('aria-pressed', String($('level').value === 'ERROR'));
|
||||
@@ -146,15 +159,21 @@
|
||||
if (recentApps.has(app)) detail.classList.add('new-log-app');
|
||||
const summary = node('summary'), label = node('div', undefined, 'app-label');
|
||||
const last = lastLogs.get(app);
|
||||
let preview;
|
||||
label.append(node('span', app, 'name'));
|
||||
if (last) {
|
||||
const age = node('span', `Last log: ${timeSince(last.time)}`, 'last-log last-age');
|
||||
const line = node('span', undefined, `last-log log-message level-${normalLevel(last)}`);
|
||||
const age = node('span', shortTimeSince(last.time), 'last-age');
|
||||
age.dataset.time = String(last.time);
|
||||
age.title = `${formatTime(last, true)} · Exact: ${last.timestamp}`;
|
||||
label.append(age);
|
||||
} else label.append(node('span', 'No log in loaded history', 'last-log'));
|
||||
const message = cleanMessage(last);
|
||||
line.title = message;
|
||||
line.append(age, document.createTextNode(' : '), node('span', message.split(/\r?\n/, 1)[0].trim() || '—', 'last-message'));
|
||||
preview = line;
|
||||
} else preview = node('span', 'No log in loaded history', 'last-log');
|
||||
summary.append(label);
|
||||
['INFO', 'WARNING', 'ERROR'].forEach(level => summary.append(node('span', `${level} ${logs.filter(e => normalLevel(e) === level).length}`, `badge ${level}`)));
|
||||
summary.append(preview);
|
||||
detail.append(summary);
|
||||
function fill() {
|
||||
detail.querySelector('.rows')?.remove();
|
||||
@@ -332,7 +351,7 @@
|
||||
$('warnings').textContent = (message.warnings || []).join(' · '); renderApps(); renderDetail();
|
||||
}
|
||||
function refreshLastLogAges() {
|
||||
document.querySelectorAll('.last-age[data-time]').forEach(label => { label.textContent = `Last log: ${timeSince(label.dataset.time)}`; });
|
||||
document.querySelectorAll('.last-age[data-time]').forEach(label => { label.textContent = shortTimeSince(label.dataset.time); });
|
||||
document.querySelectorAll('.relative-time[data-time]').forEach(label => { label.textContent = timeSince(label.dataset.time); });
|
||||
}
|
||||
setInterval(refreshLastLogAges, 1000);
|
||||
|
||||
@@ -23,6 +23,10 @@ test('English interface, latest timestamps, sorting and separate initialization
|
||||
assert.equal(d.getElementById('copy').textContent,'Copy selected log');
|
||||
assert.deepEqual([...d.querySelectorAll('[data-app]')].map(e=>e.dataset.app),['beta','alpha']);
|
||||
assert.match(d.querySelector('[data-app="alpha"] .last-age').title,/10:00:10/);
|
||||
assert.match(d.querySelector('[data-app="alpha"] summary .last-log').textContent,/ : Température déjà disponible$/);
|
||||
const summary=d.querySelector('[data-app="alpha"] summary');
|
||||
assert.deepEqual([...summary.children].map(child=>child.className),['app-label','badge INFO','badge WARNING','badge ERROR','last-log']);
|
||||
assert.equal(summary.querySelector('.app-label .last-log'),null);
|
||||
d.getElementById('sort').value='oldest';d.getElementById('sort').dispatchEvent(new dom.window.Event('input'));
|
||||
assert.equal(d.querySelector('[data-app]').dataset.app,'alpha');
|
||||
const alpha=d.querySelector('[data-app="alpha"]');alpha.open=true;alpha.dispatchEvent(new dom.window.Event('toggle'));
|
||||
@@ -109,10 +113,12 @@ test('pulses an app when a new log arrives and refreshes its last-log age',async
|
||||
assert.ok(app.classList.contains('new-log-app'));
|
||||
app.open=true;app.dispatchEvent(new dom.window.Event('toggle'));
|
||||
assert.ok(app.querySelector('.recent-log'));
|
||||
assert.equal(app.querySelector('.last-age').textContent,'Last log: 1 second ago');
|
||||
assert.equal(app.querySelector('.last-age').textContent,'1 sec ago');
|
||||
assert.equal(app.querySelector('summary .last-log').textContent,'1 sec ago : Fresh log');
|
||||
dom.window.Date.now=()=>nextTime+65000;
|
||||
await new Promise(resolve=>setTimeout(resolve,1100));
|
||||
assert.equal(app.querySelector('.last-age').textContent,'Last log: 1 minute ago');
|
||||
assert.equal(app.querySelector('.last-age').textContent,'1 min ago');
|
||||
assert.equal(app.querySelector('summary .last-log').textContent,'1 min ago : Fresh log');
|
||||
dom.window.close();
|
||||
});
|
||||
|
||||
|
||||
Binary file not shown.
Reference in new issue
Block a user