added a shortcut to open the loging app
This commit is contained in:
1 parent
5614ad049d
commit
f57e23d76a
7 files changed
+31
-5
No files matched your search
@@ -17,7 +17,7 @@ By default, it reads the existing AppDaemon text logs from the workspace:
|
||||
- `logs/error.log`
|
||||
- `logs/virtualsensors.log`
|
||||
|
||||
The explorer groups lines by the app name in the standard AppDaemon log format. It provides INFO/WARNING/ERROR counts, expandable app histories, relative timestamps, sorting by latest activity or app name, text/time/level filters, live updates, and raw-log navigation. Duplicate error lines found in multiple files are merged. The log reader handles file rotation, truncation, multiline exceptions, UTF-8, and legacy Windows-1252 bytes.
|
||||
The explorer groups lines by the app name in the standard AppDaemon log format. It provides INFO/WARNING/ERROR counts, expandable app histories, links to app definitions, relative timestamps, sorting by latest activity or app name, text/time/level filters, live updates, and raw-log navigation. Duplicate error lines found in multiple files are merged. The log reader handles file rotation, truncation, multiline exceptions, UTF-8, and legacy Windows-1252 bytes.
|
||||
|
||||
**AD Logs** turns red when the loaded logs contain an ERROR or CRITICAL entry. **Clear logs** empties the configured log files and clears the current explorer history.
|
||||
|
||||
|
||||
@@ -13,3 +13,4 @@
|
||||
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}
|
||||
.rows{max-height:min(45vh,420px);overflow-y:auto;scrollbar-gutter:stable;overflow-anchor:none}
|
||||
.app-label{flex-direction:row;align-items:center;gap:6px}.app-label .name{min-width:0}.app-link{color:var(--accent);font-size:13px;line-height:1;text-decoration:none;white-space:nowrap}.app-link:hover{text-decoration:underline}.app-link:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
|
||||
@@ -161,6 +161,15 @@
|
||||
const last = lastLogs.get(app);
|
||||
let preview;
|
||||
label.append(node('span', app, 'name'));
|
||||
const appLink = node('a', '↗', 'app-link');
|
||||
appLink.href = '#';
|
||||
appLink.title = `Open ${app} definition`;
|
||||
appLink.setAttribute('aria-label', `Open ${app} definition`);
|
||||
appLink.onclick = event => {
|
||||
event.preventDefault(); event.stopPropagation();
|
||||
vscode.postMessage({ type: 'app', app });
|
||||
};
|
||||
label.append(appLink);
|
||||
if (last) {
|
||||
const line = node('span', undefined, `last-log log-message level-${normalLevel(last)}`);
|
||||
const age = node('span', shortTimeSince(last.time), 'last-age');
|
||||
|
||||
@@ -444,10 +444,12 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
editor.revealRange(new vscode.Range(pos, pos), vscode.TextEditorRevealType.InCenter);
|
||||
}),
|
||||
|
||||
vscode.commands.registerCommand('appdaemon.goToApp', async () => {
|
||||
const apps = await findAllApps();
|
||||
vscode.commands.registerCommand('appdaemon.goToApp', async (requestedName?: string) => {
|
||||
const apps = (await findAllApps()).filter(app => !requestedName || app.appName === requestedName);
|
||||
if (apps.length === 0) {
|
||||
vscode.window.showWarningMessage('AppDaemon: No app definitions found in workspace');
|
||||
vscode.window.showWarningMessage(requestedName
|
||||
? `AppDaemon: No definition found for ${requestedName}`
|
||||
: 'AppDaemon: No app definitions found in workspace');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -459,7 +461,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
app
|
||||
}));
|
||||
|
||||
const picked = await vscode.window.showQuickPick(items, {
|
||||
const picked = apps.length === 1 && requestedName ? items[0] : await vscode.window.showQuickPick(items, {
|
||||
placeHolder: 'Go to AppDaemon app…',
|
||||
matchOnDescription: true,
|
||||
matchOnDetail: false
|
||||
|
||||
@@ -58,6 +58,9 @@ export class LogExplorer implements vscode.Disposable {
|
||||
this.messageListener?.dispose();
|
||||
this.messageListener = webview.onDidReceiveMessage(async message => {
|
||||
if (message.type === 'ready') { this.publish(); }
|
||||
if (message.type === 'app' && typeof message.app === 'string') {
|
||||
await vscode.commands.executeCommand('appdaemon.goToApp', message.app);
|
||||
}
|
||||
if (message.type === 'open' && typeof message.id === 'string') {
|
||||
const entry = this.entries.get(message.id);
|
||||
if (!entry?.file) { return; }
|
||||
|
||||
@@ -51,6 +51,17 @@ test('selects individual logs and entire initialization groups',()=>{
|
||||
const input=d.getElementById('search'),paste=new dom.window.KeyboardEvent('keydown',{key:'v',ctrlKey:true,bubbles:true,cancelable:true});input.dispatchEvent(paste);assert.equal(paste.defaultPrevented,false);
|
||||
assert.deepEqual(errors,[]);dom.window.close();
|
||||
});
|
||||
|
||||
test('app link opens its YAML definition without expanding the log group',async()=>{
|
||||
const {dom,d,sent}=setup();
|
||||
const app=d.querySelector('[data-app="alpha"]'),link=app.querySelector('.app-link');
|
||||
assert.equal(link.getAttribute('aria-label'),'Open alpha definition');
|
||||
link.click();
|
||||
await new Promise(resolve=>setTimeout(resolve,0));
|
||||
assert.equal(sent.at(-1).type,'app');assert.equal(sent.at(-1).app,'alpha');
|
||||
assert.equal(app.open,false);
|
||||
dom.window.close();
|
||||
});
|
||||
test('retains selected text during live updates and leaves Ctrl+C to the browser',async()=>{
|
||||
const {dom,d,entries,errors,send}=setup();const alpha=d.querySelector('[data-app="alpha"]');alpha.open=true;alpha.dispatchEvent(new dom.window.Event('toggle'));
|
||||
const text=alpha.querySelector('.row-message'),range=d.createRange();range.selectNodeContents(text);dom.window.getSelection().addRange(range);
|
||||
|
||||
Binary file not shown.
Reference in new issue
Block a user