Skip to content

Commit

Permalink
Add SQL activity log (#117)
Browse files Browse the repository at this point in the history
* Add query activity log

* Revert the log to show newest first

* Remove copy notifications and add data storage

* Change emojies to svg icons

* Remove the latency emoji
  • Loading branch information
bobbyiliev authored Oct 27, 2023
1 parent 73f515f commit da3f5a4
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 3 deletions.
15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@
"name": "Explorer",
"icon": "",
"contextualTitle": "Explorer"
},
{
"id": "activityLog",
"name": "Activity Log",
"icon": "",
"contextualTitle": "Activity Log"
}
],
"materializePanelContainer": [
Expand Down Expand Up @@ -154,6 +160,15 @@
"light": "resources/clip_light.svg",
"dark": "resources/clip_dark.svg"
}
},
{
"command": "extension.copySQL",
"title": "Copy SQL",
"category": "materialize",
"icon": {
"light": "resources/clip_light.svg",
"dark": "resources/clip_dark.svg"
}
}
],
"keybindings": [
Expand Down
3 changes: 3 additions & 0 deletions resources/error_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions resources/success_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 24 additions & 2 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as vscode from 'vscode';
import { AuthProvider, ResultsProvider, DatabaseTreeProvider } from './providers';
import { AuthProvider, ResultsProvider, DatabaseTreeProvider, ActivityLogTreeProvider } from './providers';
import { Context, EventType } from './context';
import { randomUUID } from 'crypto';

Expand All @@ -10,6 +10,10 @@ export function activate(vsContext: vscode.ExtensionContext) {
console.log("[Extension]", "Activating Materialize extension.");
context = new Context();

// Register the activity log
const activityLogProvider = new ActivityLogTreeProvider(vsContext);
vscode.window.registerTreeDataProvider('activityLog', activityLogProvider);

// Register the database explorer
const databaseTreeProvider = new DatabaseTreeProvider(context);
vscode.window.createTreeView('explorer', { treeDataProvider: databaseTreeProvider });
Expand Down Expand Up @@ -76,12 +80,23 @@ export function activate(vsContext: vscode.ExtensionContext) {
} else {
context.emit("event", { type: EventType.queryResults, data: { ...results, elapsedTime, id } });
}
activityLogProvider.addLog({
status: "success",
latency: elapsedTime, // assuming elapsedTime holds the time taken for the query to execute
sql: query
});
} catch (error: any) {
console.log("[RunSQLCommand]", error.toString());
console.log("[RunSQLCommand]", JSON.stringify(error));
const endTime = Date.now();
const elapsedTime = endTime - startTime;

activityLogProvider.addLog({
status: "failure",
latency: elapsedTime, // assuming elapsedTime holds the time taken before the error was caught
sql: query
});

context.emit("event", { type: EventType.queryResults, data: { id, rows: [], fields: [], error: {
message: error.toString(),
position: error.position,
Expand All @@ -106,10 +121,17 @@ export function activate(vsContext: vscode.ExtensionContext) {

vsContext.subscriptions.push(runDisposable);
vsContext.subscriptions.push(copyDisposable);

let copySQLDisposable = vscode.commands.registerCommand('extension.copySQL', (sql: string) => {
vscode.env.clipboard.writeText(sql);
});

vsContext.subscriptions.push(copySQLDisposable);

return context;
}

export function deactivate() {
console.log("[Extension]", "Deactivating Materialize extension.");
context.stop();
}
}
72 changes: 72 additions & 0 deletions src/providers/activity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import * as vscode from 'vscode';
import * as path from 'path';

export default class ActivityLogTreeProvider implements vscode.TreeDataProvider<ActivityLogNode> {

private _onDidChangeTreeData: vscode.EventEmitter<ActivityLogNode | undefined | null | void> = new vscode.EventEmitter<ActivityLogNode | undefined | null | void>();
readonly onDidChangeTreeData: vscode.Event<ActivityLogNode | undefined | null | void> = this._onDidChangeTreeData.event;

private logs: ActivityLog[] = [];

constructor(private context: vscode.ExtensionContext) {
this.logs = this.context.globalState.get('activityLogs') || [];
}

addLog(log: ActivityLog) {
this.logs.push(log);

// Remove the oldest log if we have more than 100
if (this.logs.length > 100) {
this.logs.shift();
}

this.context.globalState.update('activityLogs', this.logs);
this._onDidChangeTreeData.fire();
}

getTreeItem(element: ActivityLogNode): vscode.TreeItem {
return element;
}

getChildren(element?: ActivityLogNode): Thenable<ActivityLogNode[]> {
if (!element) {
// Revert the logs to show the newest ones at the top
return Promise.resolve(this.logs.slice().reverse().map(log => new ActivityLogNode(log)));
}
return Promise.resolve([]);
}
}

interface ActivityLog {
status: "success" | "failure";
latency: number;
sql: string;
}

class ActivityLogItem extends vscode.TreeItem {
constructor(public readonly log: ActivityLog) {
// Shorten the displayed query if it's too long
const shortSQL = log.sql.length > 50 ? log.sql.substring(0, 50) + "..." : log.sql;

super(shortSQL, vscode.TreeItemCollapsibleState.None);

// Set iconPath based on the status
const iconName = log.status === "success" ? "success_icon.svg" : "error_icon.svg";
this.iconPath = vscode.Uri.file(path.join(__dirname, '..', 'resources', iconName));

// Set the description to the query latency
this.description = `${log.latency}ms`;

this.tooltip = `${log.sql} | Latency: ${log.latency}ms`;
this.contextValue = 'activityLogItem';

// Copy SQL command to clipboard
this.command = {
command: 'extension.copySQL',
title: 'Copy SQL',
arguments: [log.sql]
};
}
}

class ActivityLogNode extends ActivityLogItem {}
4 changes: 3 additions & 1 deletion src/providers/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import AuthProvider from "./auth";
import ResultsProvider from "./results";
import DatabaseTreeProvider from "./schema";
import ActivityLogTreeProvider from "./activity";

export {
AuthProvider,
ResultsProvider,
DatabaseTreeProvider,
};
ActivityLogTreeProvider,
};

0 comments on commit da3f5a4

Please sign in to comment.