Skip to content

Commit

Permalink
(#85) Publish VSCode extension 0.1.2 on microsoft marketplace
Browse files Browse the repository at this point in the history
  • Loading branch information
mario4tier committed May 2, 2024
1 parent 81a77c9 commit 278edce
Show file tree
Hide file tree
Showing 25 changed files with 294 additions and 257 deletions.
9 changes: 8 additions & 1 deletion typescript/vscode-extension/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,19 @@
"plugin:react/jsx-runtime"
],
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unsafe-member-access": "off",
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-parameter": "off",
"@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/no-unsafe-return": "off",
"@typescript-eslint/naming-convention": "warn",
"@typescript-eslint/semi": "warn",
"no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
"curly": "warn",
"eqeqeq": "warn",
"no-throw-literal": "warn",
"semi": "off"
"semi": "off"
},
"ignorePatterns": [
"out",
Expand Down
3 changes: 3 additions & 0 deletions typescript/vscode-extension/.vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

# Ignore test files
.vscode-test/**

# Ignore build artifacts
out/**
!out/extension.js

# Ignore source code
src/**
Expand Down
5 changes: 1 addition & 4 deletions typescript/vscode-extension/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how

## [Unreleased]

## 0.0.4
## 0.1.2
- Warn about requiring suibase to be installed.
- Clean-up sidebar buttons.

## 0.0.1
- Initial release
14 changes: 7 additions & 7 deletions typescript/vscode-extension/dist/extension.js

Large diffs are not rendered by default.

9 changes: 2 additions & 7 deletions typescript/vscode-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
},
"license": "Apache-2.0",
"icon": "media/logo_128.png",
"version": "0.0.3",
"version": "0.1.2",
"repository": {
"type": "git",
"url": "https://github.com/ChainMovers/suibase.git"
Expand All @@ -23,7 +23,7 @@
],
"pricing": "Free",
"activationEvents": [],
"main": "./dist/extension.js",
"main": "./out/extension.js",
"contributes": {
"commands": [
{
Expand All @@ -48,11 +48,6 @@
"command": "suibase.console",
"when": "view == explorerView",
"group": "navigation@1"
},
{
"command": "suibase.refresh",
"when": "view == explorerView",
"group": "navigation@2"
}
]
},
Expand Down
53 changes: 37 additions & 16 deletions typescript/vscode-extension/src/BackendSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ export class BackendSync {

private mWorkdir: string; // Last known active workdir. One of "localnet", "mainnet", "testnet", "devnet".
private mWorkdirTrackings: BackendWorkdirTracking[] = []; // One instance per workdir, align with WORKDIRS_KEYS.
private mForceRefreshOnNextReconnect: boolean; // Force some refresh when there was a lost of backend connection.

// Singleton
private constructor() {
this.mWorkdir = "";
this.mForceRefreshOnNextReconnect = false;

// Create one instance of BackendWorkdirTracking for each element in WORKDIRS_KEYS.
for (let workdirIdx = 0; workdirIdx < WORKDIRS_KEYS.length; workdirIdx++) {
for (const {} of WORKDIRS_KEYS) {
this.mWorkdirTrackings.push(new BackendWorkdirTracking());
}
}
Expand Down Expand Up @@ -80,12 +82,12 @@ export class BackendSync {
if (message.workdirIdx >= 0 && message.workdirIdx < WORKDIRS_KEYS.length) {
workdir = WORKDIRS_KEYS[message.workdirIdx];
}
this.fetchWorkdirCommand(workdir, message.command);
void this.fetchWorkdirCommand(workdir, message.command);
} else if (message.name === "RequestWorkdirStatus") {
this.replyWorkdirStatus(message as RequestWorkdirStatus);
void this.replyWorkdirStatus(message as RequestWorkdirStatus);
}
} catch (error) {
console.error(`Error in handleViewMessage: ${error}`);
console.error(`Error in handleViewMessage: ${JSON.stringify(error)}`);
}
}

Expand All @@ -108,7 +110,7 @@ export class BackendSync {

private async asyncLoop(forceRefresh: boolean): Promise<void> {
await this.loopMutex.runExclusive(async () => {
this.update(forceRefresh);
await this.update(forceRefresh);

if (forceRefresh === false) {
// Schedule another call in one second.
Expand Down Expand Up @@ -145,13 +147,13 @@ export class BackendSync {
body: JSON.stringify(body),
});
if (!response.ok) {
throw new Error(`${method} ${params} not ok`);
throw new Error(`${method} ${JSON.stringify(params)} not ok`);
}
let json: T = (await response.json()) as T;
const json: T = (await response.json()) as T;
BackendSync.validateHeader(json, method);
return json;
} catch (error) {
let errorMsg = `Error in fetchBackend ${method} ${params}: ${error}`;
const errorMsg = `Error in fetchBackend ${method} ${JSON.stringify(params)}: ${JSON.stringify(error)}`;
console.error(errorMsg);
throw error;
}
Expand Down Expand Up @@ -196,15 +198,31 @@ export class BackendSync {
}
}

private diagnoseBackendError(workdirIdx: number) {
// This is a helper function to diagnose the backend error.
// It will send a message to the views to display the error message.
// For now, always broadcast a message to all views that the backend is not responding.
this.mForceRefreshOnNextReconnect = true;
const msg = new UpdateVersions(WEBVIEW_BACKEND, workdirIdx, undefined);
msg.setSetupIssue("Suibase not responding. Is it installed?");
BaseWebview.broadcastMessage(msg);
}

private async updateUsingBackend(forceRefresh: boolean) {
// Do getVersions for every possible workdir.
//
// TODO Optimize to do this to retrieve all only when dashboard is visible, otherwise just do the active?

// Iterate the WORKDIRS_KEYS
for (let workdirIdx = 0; workdirIdx < WORKDIRS_KEYS.length; workdirIdx++) {
let workdir = WORKDIRS_KEYS[workdirIdx];
const data = await this.fetchGetVersions(workdir);
const workdir = WORKDIRS_KEYS[workdirIdx];
let data = undefined;
try {
data = await this.fetchGetVersions(workdir);
} catch (error) {
this.diagnoseBackendError(workdirIdx);
return;
}
if (data) {
try {
// This is an example of data:
Expand All @@ -223,11 +241,14 @@ export class BackendSync {

// Broadcast UpdateVersions message to all the views when change detected or requested.
// The views will then decide if they need to synchronize further with the extension.
if (hasChanged || forceRefresh) {
if (hasChanged || forceRefresh || this.mForceRefreshOnNextReconnect) {
this.mForceRefreshOnNextReconnect = false;
BaseWebview.broadcastMessage(new UpdateVersions(WEBVIEW_BACKEND, workdirIdx, data.result));
}
} catch (error) {
const errorMsg = `Error in updateUsingBackend: ${error}. Data: ${JSON.stringify(data)}`;
const errorMsg = `Error in updateUsingBackend: ${JSON.stringify(error)}. Data: ${JSON.stringify(
data
)}`;
console.error(errorMsg);
throw new Error(errorMsg);
}
Expand All @@ -238,12 +259,12 @@ export class BackendSync {
private async replyWorkdirStatus(message: RequestWorkdirStatus) {
const sender = message.sender; // Will reply to sender only.
const workdirIdx = message.workdirIdx;
const methodUuid= message.methodUuid;
const methodUuid = message.methodUuid;
const dataUuid = message.dataUuid;

let data = null;
try {
let workdir = WORKDIRS_KEYS[workdirIdx];
const workdir = WORKDIRS_KEYS[workdirIdx];
const workdirTracking = this.mWorkdirTrackings[workdirIdx];
const tracking = workdirTracking.workdirStatus;
data = tracking.getJson(); // Start with what is already in-memory (fetch only as needed)
Expand All @@ -262,9 +283,9 @@ export class BackendSync {
// {"label":"Multi-link RPC","status":"OK","statusInfo":null,"helpInfo":null,"pid":null}]},"id":2}
//
// Update the SuibaseJson instance for the workdir.
BaseWebview.postMessageTo(sender,new UpdateWorkdirStatus(WEBVIEW_BACKEND, workdirIdx, data));
BaseWebview.postMessageTo(sender, new UpdateWorkdirStatus(WEBVIEW_BACKEND, workdirIdx, data));
} catch (error) {
const errorMsg = `Error in replyWorkdirStatus: ${error}. Data: ${JSON.stringify(data)}`;
const errorMsg = `Error in replyWorkdirStatus: ${JSON.stringify(error)}. Data: ${JSON.stringify(data)}`;
console.error(errorMsg);
//throw new Error(errorMsg);
}
Expand Down
22 changes: 6 additions & 16 deletions typescript/vscode-extension/src/SuibaseCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// a UI interaction (e.g. pressing a "refresh" button).
//
import * as vscode from "vscode";
import { SuibaseExec } from "./SuibaseExec";

import { DashboardPanel } from "./panels/DashboardPanel";
import { ConsolePanel } from "./panels/ConsolePanel";
Expand All @@ -13,7 +12,9 @@ export class SuibaseCommands {
private static instance?: SuibaseCommands;
private static context?: vscode.ExtensionContext;

// eslint-disable-next-line @typescript-eslint/no-empty-function
private constructor() {} // Called from activate() only.
// eslint-disable-next-line @typescript-eslint/no-empty-function
private dispose() {} // Called from deactivate() only.

public static activate(context: vscode.ExtensionContext) {
Expand All @@ -26,19 +27,19 @@ export class SuibaseCommands {
SuibaseCommands.instance = new SuibaseCommands();

{
let disposable = vscode.commands.registerCommand(WEBVIEW_DASHBOARD, () => {
const disposable = vscode.commands.registerCommand(WEBVIEW_DASHBOARD, () => {
SuibaseCommands.getInstance()?.settings();
});
context.subscriptions.push(disposable);
}

{
let disposable = vscode.commands.registerCommand(WEBVIEW_CONSOLE, () => {
const disposable = vscode.commands.registerCommand(WEBVIEW_CONSOLE, () => {
SuibaseCommands.getInstance()?.console();
});
context.subscriptions.push(disposable);
}

/*
{
let disposable = vscode.commands.registerCommand("suibase.refresh", () => {
SuibaseCommands.getInstance()?.refresh();
Expand All @@ -50,6 +51,7 @@ export class SuibaseCommands {
setInterval(() => {
vscode.commands.executeCommand("suibase.refresh");
}, 3000); // 3 seconds
*/
}

public static deactivate() {
Expand All @@ -72,18 +74,6 @@ export class SuibaseCommands {
return SuibaseCommands.instance;
}

public refresh(workdir?: string) {
//const str = "SuibaseCommands.refresh() called";
//console.log(str);
// TODO Debouncing to avoid excessive global refresh.
// Do a JSON-RPC call to the suibase server API.
//
// If workdir is not specified, update them all.
// This is a best-effort request and reactions to the
// eventual response are handled somewhere else...
//SuibaseExec.getInstance()?.getLinks();
}

public settings() {
if (!SuibaseCommands.context) {
return;
Expand Down
8 changes: 4 additions & 4 deletions typescript/vscode-extension/src/SuibaseExec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class SuibaseExec {

// Store the response in the cache
//let self = SuibaseExec.getInstance();
this.cache["response"] = response.result;
this.cache.response = response.result;
console.log(response.result);
});
}
Expand Down Expand Up @@ -115,7 +115,7 @@ export class SuibaseExec {
for (let i = 0; i < lines.length && !suibaseRunning; i++) {
const line = lines[i];
const columns = line.split(" ");
if (columns[0].indexOf("suibase") === 0) {
if (columns[0].startsWith("suibase")) {
suibaseRunning = true;
}
}
Expand All @@ -125,7 +125,7 @@ export class SuibaseExec {

if (!suibaseRunning) {
// Start suibase daemon
const result = await execShell("~/suibase/scripts/common/run-daemon.sh suibase &");
await execShell("~/suibase/scripts/common/run-daemon.sh suibase &");

// TODO Implement retry and error handling of run-daemon.sh for faster startup.

Expand All @@ -147,7 +147,7 @@ export class SuibaseExec {
// The caller get the response (or last known state) with
// a lookup for the data in the cache.
//
let sb = SuibaseExec.getInstance();
const sb = SuibaseExec.getInstance();
if (!sb) {
return;
}
Expand Down
27 changes: 20 additions & 7 deletions typescript/vscode-extension/src/bases/BaseWebview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class BaseWebview implements vscode.WebviewViewProvider {

// Keep track of all BaseWebview instances. They
// can be accessed by "name" for some message handling.
private static instances: { [key: string]: BaseWebview } = {};
private static instances: Record<string, BaseWebview> = {};

// Allow BackendSync to peek at every message for all views.
private static backendSyncMessageCallback: (message: any) => void;
Expand Down Expand Up @@ -106,7 +106,9 @@ export class BaseWebview implements vscode.WebviewViewProvider {

public resolveWebviewView(
webviewView: vscode.WebviewView,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_context: vscode.WebviewViewResolveContext,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_token: vscode.CancellationToken
) {
this.webview = webviewView.webview;
Expand Down Expand Up @@ -228,17 +230,27 @@ export class BaseWebview implements vscode.WebviewViewProvider {
* rendered within the webview panel
*/
private _getWebviewContent() {
let webview = this.getWebview();
const webview = this.getWebview();
if (!webview) {
// Should never happen, but just in case... show an error so the user can see (and report).
return "Error: Missing webview instance";
}

// The CSS file from the Svelte build output
const stylesUri = getUri(webview, this.extensionUri, ["webview-ui", "build", "assets", "index.css"]);
const stylesUri = getUri(webview, this.extensionUri, [
"webview-ui",
"build",
"assets",
"index.css",
]).toString();

// The JS file from the Svelte build output
const scriptUri = getUri(webview, this.extensionUri, ["webview-ui", "build", "assets", "index.js"]);
const scriptUri = getUri(webview, this.extensionUri, [
"webview-ui",
"build",
"assets",
"index.js",
]).toString();

// The icon library being used.
const iconsUri = getUri(webview, this.extensionUri, [
Expand All @@ -247,7 +259,7 @@ export class BaseWebview implements vscode.WebviewViewProvider {
"@vscode/codicons",
"dist",
"codicon.css",
]);
]).toString();

const nonce = getNonce();

Expand Down Expand Up @@ -279,6 +291,7 @@ export class BaseWebview implements vscode.WebviewViewProvider {
`;
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
protected handleMessage(_message: any): void {
// This is a placeholder for the derived class to implement.
// The derived class should override this method to handle messages
Expand All @@ -293,9 +306,9 @@ export class BaseWebview implements vscode.WebviewViewProvider {
}

if (this.panel) {
this.panel.webview.postMessage(message);
void this.panel.webview.postMessage(message);
} else if (this.webview) {
this.webview.postMessage(message);
void this.webview.postMessage(message);
}
}

Expand Down
Loading

0 comments on commit 278edce

Please sign in to comment.