From 512d6b67e9823f3a36b2c6e01fa436a2647f544b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Salom=C3=A9=20VOLTZ?= <80842312+salome-voltz@users.noreply.github.com> Date: Wed, 11 Sep 2024 10:49:20 +0200 Subject: [PATCH] fix(ggshield-view-provider): switch to WebviewView for customization (#2) * fix(ggshield-view-provider): switch to WebviewView for customization --- ...gitguardian-icon-primary700-background.svg | 8 ++ media/main.css | 33 +++++ package.json | 1 + src/extension.ts | 9 +- src/ggshield-view.ts | 70 ---------- .../gitguardian-webview-view.ts | 123 ++++++++++++++++++ src/status-bar-utils.ts | 14 +- 7 files changed, 181 insertions(+), 77 deletions(-) create mode 100644 images/gitguardian-icon-primary700-background.svg create mode 100644 media/main.css delete mode 100644 src/ggshield-view.ts create mode 100644 src/ggshield-webview/gitguardian-webview-view.ts diff --git a/images/gitguardian-icon-primary700-background.svg b/images/gitguardian-icon-primary700-background.svg new file mode 100644 index 0000000..471aa15 --- /dev/null +++ b/images/gitguardian-icon-primary700-background.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/media/main.css b/media/main.css new file mode 100644 index 0000000..f130ee4 --- /dev/null +++ b/media/main.css @@ -0,0 +1,33 @@ +body { + height: 100vh; +} + +body.vscode-light { + color: black; +} + +body.vscode-dark { + color: white; +} + +p { + font-size: 16px; +} + +.anonymous { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +button.large { + background-color: #2200fb; + color: white; + border: none; + padding: 10px 20px; + font-size: 16px; + cursor: pointer; + border-radius: 5px; + margin: 2em 0; +} \ No newline at end of file diff --git a/package.json b/package.json index ae38a58..481b4d1 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "views": { "gitguardian": [ { + "type": "webview", "id": "gitguardianView", "name": "gitguardian", "when": "gitguardian.isAuthenticated == false" diff --git a/src/extension.ts b/src/extension.ts index e31fef9..e784279 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -24,7 +24,7 @@ import { } from "vscode"; import { GGShieldResolver } from "./lib/ggshield-resolver"; import { isGitInstalled } from "./utils"; -import { GGShieldViewProvider } from "./ggshield-view"; +import { GitGuardianWebviewProvider } from "./ggshield-webview/gitguardian-webview-view"; import { StatusBarStatus, updateStatusBarItem } from "./status-bar-utils"; /** @@ -83,8 +83,11 @@ export function activate(context: ExtensionContext) { context, configuration ); - const ggshieldViewProvider = new GGShieldViewProvider(ggshieldResolver); - window.registerTreeDataProvider("gitguardianView", ggshieldViewProvider); + const ggshieldViewProvider = new GitGuardianWebviewProvider( + configuration, + context.extensionUri + ); + window.registerWebviewViewProvider("gitguardianView", ggshieldViewProvider); context.subscriptions.push(ggshieldViewProvider); statusBar = window.createStatusBarItem(StatusBarAlignment.Left, 0); diff --git a/src/ggshield-view.ts b/src/ggshield-view.ts deleted file mode 100644 index f097a0a..0000000 --- a/src/ggshield-view.ts +++ /dev/null @@ -1,70 +0,0 @@ -import * as vscode from "vscode"; -import { GGShieldResolver } from "./lib/ggshield-resolver"; -import { ggshieldAuthStatus } from "./lib/ggshield-api"; - -/** - * View provider for the GitGuardian view - * The view provides authentication status - * - If the user is not authenticated, it provides a login button - * - If the user is authenticated, the view is left empty for now - */ -export class GGShieldViewProvider - implements vscode.TreeDataProvider -{ - private _onDidChangeTreeData: vscode.EventEmitter< - vscode.TreeItem | undefined | void - > = new vscode.EventEmitter(); - readonly onDidChangeTreeData: vscode.Event = - this._onDidChangeTreeData.event; - private isAuthenticated: boolean = false; - - constructor(private ggshieldResolver: GGShieldResolver) { - // Initialize authentication state - this.checkAuthenticationStatus(); - } - - private async checkAuthenticationStatus() { - // Update authentication status - this.isAuthenticated = await ggshieldAuthStatus( - this.ggshieldResolver.configuration - ); - this._onDidChangeTreeData.fire(); // Notify the view to refresh - } - - getTreeItem(element: vscode.TreeItem): vscode.TreeItem { - return element; - } - - getChildren(element?: vscode.TreeItem): Thenable { - if (element) { - return Promise.resolve([]); - } - - // Provide root level items based on authentication status - if (this.isAuthenticated) { - return Promise.resolve([ - new vscode.TreeItem( - "ggshield is running", - vscode.TreeItemCollapsibleState.None - ), - ]); - } else { - return Promise.resolve([]); - } - } - - dispose(): void { - this._onDidChangeTreeData.dispose(); - } - - refresh(): void { - this.checkAuthenticationStatus() - .then(() => { - // After checking the authentication status, force a view update - this._onDidChangeTreeData.fire(undefined); - }) - .catch((error) => { - console.error("Error checking authentication status:", error); - }); - } -} diff --git a/src/ggshield-webview/gitguardian-webview-view.ts b/src/ggshield-webview/gitguardian-webview-view.ts new file mode 100644 index 0000000..cad5505 --- /dev/null +++ b/src/ggshield-webview/gitguardian-webview-view.ts @@ -0,0 +1,123 @@ +import * as vscode from "vscode"; +import { GGShieldConfiguration } from "../lib/ggshield-configuration"; +import { ggshieldAuthStatus } from "../lib/ggshield-api"; + +const documentationUri = vscode.Uri.parse( + "https://docs.gitguardian.com/ggshield-docs/getting-started" +); +const feedbackFormUri = vscode.Uri.parse( + "https://docs.google.com/forms/d/e/1FAIpQLSc_BemGrdQfxp6lg7KgeDoB32XZg8yMfapk2gbemu0mVfskDQ/viewform" +); + +export class GitGuardianWebviewProvider implements vscode.WebviewViewProvider { + public static readonly viewType = "gitguardian.gitguardianView"; + private _view?: vscode.WebviewView; + private isAuthenticated: boolean = false; + + constructor( + private ggshieldConfiguration: GGShieldConfiguration, + private readonly _extensionUri: vscode.Uri + ) { + this.checkAuthenticationStatus(); + } + + public async resolveWebviewView( + webviewView: vscode.WebviewView, + context: vscode.WebviewViewResolveContext, + _token: vscode.CancellationToken + ) { + this._view = webviewView; + + webviewView.webview.options = { + enableScripts: true, + localResourceRoots: [vscode.Uri.joinPath(this._extensionUri, "media"), vscode.Uri.joinPath(this._extensionUri, "images")], + }; + + this.updateWebViewContent(webviewView); + + webviewView.webview.onDidReceiveMessage(async (data) => { + if (data.type === "authenticate") { + vscode.commands.executeCommand("gitguardian.authenticate"); + } + }); + } + + private async checkAuthenticationStatus() { + this.isAuthenticated = await ggshieldAuthStatus(this.ggshieldConfiguration); + this.updateWebViewContent(this._view); + } + + private updateWebViewContent(webviewView?: vscode.WebviewView) { + if (webviewView) { + webviewView.webview.html = this.getHtmlForWebview(webviewView.webview); + } + } + + private getHtmlForWebview(webview: vscode.Webview): string { + const styleUri = webview.asWebviewUri( + vscode.Uri.joinPath(this._extensionUri, "media", "main.css") + ); + const logoUri = webview.asWebviewUri( + vscode.Uri.joinPath(this._extensionUri, "images", "gitguardian-icon-primary700-background.svg") + ); + + if (this.isAuthenticated) { + return ` + + + + + + + GitGuardian - Authenticated + + +

How it works

+

Each time you save a document, it will undergo automatic scanning, and any detected secrets will be highlighted as errors.

+

Open documentation

+ +

Feedback

+

This extension is in beta.

+

Please share any issues or suggestions using the following feedback form.

+ + `; + } else { + return ` + + + + + + + GitGuardian - Welcome + + +
+ GitGuardian Logo +

Welcome to GitGuardian

+

Protect your code from secrets leakage

+ +
+ + + `; + } + } + + public refresh() { + this.checkAuthenticationStatus(); + } + + dispose(): void { + if (this._view) { + this._view.webview.onDidReceiveMessage(() => { }); + this._view.webview.html = ""; + this._view = undefined; + } + } +} diff --git a/src/status-bar-utils.ts b/src/status-bar-utils.ts index 601e48d..49a0c45 100644 --- a/src/status-bar-utils.ts +++ b/src/status-bar-utils.ts @@ -21,33 +21,39 @@ export function getStatusBarConfig(status: StatusBarStatus): StatusBarConfig { return { text: "Gitguardian - Initializing...", color: "statusBar.foreground", + // TODO: onclick open output channel if the bar is frozen and I want to see what's going on }; case StatusBarStatus.unauthenticated: return { text: "Gitguardian - Please authenticate", color: "statusBarItem.warningBackground", + // TODO: onclick open sidebar }; case StatusBarStatus.ready: return { text: "Gitguardian is ready", color: "statusBar.foreground" }; case StatusBarStatus.scanning: return { - text: "Gitguardian - Scanning...", + text: "GitGuardian - scanning...", color: "statusBar.foreground", + // TODO: onclick open output channel if the bar is frozen and I want to see what's going on }; case StatusBarStatus.secretFound: return { - text: "Gitguardian - Secret found", + text: "GitGuardian - found secret", color: "statusBarItem.errorBackground", + // TODO: onclick open problems panel }; case StatusBarStatus.noSecretFound: return { - text: "Gitguardian - No secret found", + text: "GitGuardian - no secret found", color: "statusBar.foreground", + // TODO: onclick open sidebar }; case StatusBarStatus.error: return { - text: "Gitguardian - error", + text: "GitGuardian - error", color: "statusBarItem.errorBackground", + // TODO: onclick open output channel panel }; default: return { text: "", color: "statusBar.foreground" };