Feat/478 webview api (#482)

This commit is contained in:
Alessio Occhipinti 2020-06-25 10:34:19 +02:00 committed by GitHub
parent 3c09e09b25
commit 04d220eda7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 408 additions and 577 deletions

View file

@ -5,8 +5,7 @@
], ],
"rules": { "rules": {
"@typescript-eslint/indent": ["error", 2, { "SwitchCase": 1 }], "@typescript-eslint/indent": ["error", 2, { "SwitchCase": 1 }],
"@typescript-eslint/member-naming": 0, "@typescript-eslint/member-naming": 0
"@typescript-eslint/interface-name-prefix": ["error", { "prefixWithI": "always" }]
}, },
"env": { "env": {
"browser": true "browser": true

View file

@ -170,17 +170,18 @@
"devDependencies": { "devDependencies": {
"@moxer/vscode-theme-generator": "1.19.0", "@moxer/vscode-theme-generator": "1.19.0",
"@types/browserify": "12.0.36", "@types/browserify": "12.0.36",
"@types/rimraf": "2.0.2", "@types/fs-extra": "8.1.0",
"@typescript-eslint/eslint-plugin": "2.12.0", "@types/rimraf": "3.0.0",
"@typescript-eslint/parser": "2.12.0", "@typescript-eslint/eslint-plugin": "3.3.0",
"browserify": "16.2.2", "@typescript-eslint/parser": "3.3.0",
"eslint": "6.7.2", "browserify": "16.5.1",
"eslint-config-xo-space": "0.22.0", "eslint": "7.2.0",
"eslint-config-xo-typescript": "0.23.0", "eslint-config-xo-space": "0.25.0",
"fs-extra": "8.1.0", "eslint-config-xo-typescript": "0.31.0",
"fs-extra": "9.0.1",
"ncp": "2.0.0", "ncp": "2.0.0",
"typescript": "3.7.4", "typescript": "3.9.5",
"vscode": "1.1.36" "vscode": "1.1.37"
}, },
"__metadata": { "__metadata": {
"id": "dffaf5a1-2219-434b-9d87-cb586fd59260", "id": "dffaf5a1-2219-434b-9d87-cb586fd59260",
@ -188,8 +189,7 @@
"publisherId": "e41388a1-a892-4c1e-940b-1e7c1bf43c97" "publisherId": "e41388a1-a892-4c1e-940b-1e7c1bf43c97"
}, },
"dependencies": { "dependencies": {
"@sanity/client": "0.147.3", "@sanity/client": "1.149.16",
"@types/fs-extra": "8.0.1",
"opencollective": "1.0.3" "opencollective": "1.0.3"
}, },
"collective": { "collective": {

View file

@ -24,10 +24,10 @@ const getThemeColorCustomizationsConfig = (accentColor?: string): Record<string,
const updateColorCustomizationsConfig = async (config: any): Promise<boolean> => { const updateColorCustomizationsConfig = async (config: any): Promise<boolean> => {
try { try {
workspace.getConfiguration().update('workbench.colorCustomizations', config, true); await workspace.getConfiguration().update('workbench.colorCustomizations', config, true);
return true; return true;
} catch (error) { } catch (error) {
window.showErrorMessage(error); await window.showErrorMessage(error);
} }
}; };

View file

@ -17,7 +17,7 @@ export interface IExtensionManager {
init: () => Promise<void>; init: () => Promise<void>;
getPackageJSON: () => Record<string, any>; getPackageJSON: () => Record<string, any>;
getConfig: () => MaterialThemeConfig; getConfig: () => MaterialThemeConfig;
getInstallationType: () => {}; getInstallationType: () => Record<string, unknown>;
updateConfig: (config: Partial<MaterialThemeConfig>) => Promise<void>; updateConfig: (config: Partial<MaterialThemeConfig>) => Promise<void>;
} }
@ -50,6 +50,32 @@ class ExtensionManager implements IExtensionManager {
await workspace.fs.writeFile(this.configFileUri, Buffer.from(JSON.stringify(newConfig), 'utf-8')); await workspace.fs.writeFile(this.configFileUri, Buffer.from(JSON.stringify(newConfig), 'utf-8'));
} }
async init(): Promise<void> {
try {
const packageJSON = this.getPackageJSON();
const userConfig = await this.getUserConfig();
this.installationType = {
update: userConfig && this.isVersionUpdate(userConfig),
firstInstall: !userConfig
};
const configBuffer = await workspace.fs.readFile(this.configFileUri);
const configContent = Buffer.from(configBuffer).toString('utf8');
this.configJSON = JSON.parse(configContent) as MaterialThemeConfig;
const userConfigUpdate = {...this.configJSON, changelog: {lastversion: packageJSON.version}};
await workspace.fs.writeFile(
this.userConfigFileUri,
Buffer.from(JSON.stringify(userConfigUpdate), 'utf-8')
);
} catch (error) {
this.configJSON = {accentsProperties: {}, accents: {}};
await window
.showErrorMessage(`Material Theme: there was an error while loading the configuration. Please retry or open an issue: ${String(error)}`);
}
}
private isVersionUpdate(userConfig: MaterialThemeConfig): boolean { private isVersionUpdate(userConfig: MaterialThemeConfig): boolean {
const splitVersion = (input: string): {major: number; minor: number; patch: number} => { const splitVersion = (input: string): {major: number; minor: number; patch: number} => {
const [major, minor, patch] = input.split('.').map(i => parseInt(i, 10)); const [major, minor, patch] = input.split('.').map(i => parseInt(i, 10));
@ -77,32 +103,6 @@ class ExtensionManager implements IExtensionManager {
return JSON.parse(configContent) as MaterialThemeConfig; return JSON.parse(configContent) as MaterialThemeConfig;
} catch {} } catch {}
} }
async init(): Promise<void> {
try {
const packageJSON = this.getPackageJSON();
const userConfig = await this.getUserConfig();
this.installationType = {
update: userConfig && this.isVersionUpdate(userConfig),
firstInstall: !userConfig
};
const configBuffer = await workspace.fs.readFile(this.configFileUri);
const configContent = Buffer.from(configBuffer).toString('utf8');
this.configJSON = JSON.parse(configContent) as MaterialThemeConfig;
const userConfigUpdate = {...this.configJSON, changelog: {lastversion: packageJSON.version}};
await workspace.fs.writeFile(
this.userConfigFileUri,
Buffer.from(JSON.stringify(userConfigUpdate), 'utf-8')
);
} catch (error) {
this.configJSON = {accentsProperties: {}, accents: {}};
window
.showErrorMessage(`Material Theme: there was an error while loading the configuration. Please retry or open an issue: ${String(error)}`);
}
}
} }
export const extensionManager = new ExtensionManager(); export const extensionManager = new ExtensionManager();

View file

@ -1,6 +1,6 @@
import {WebviewController} from './Webview'; import {WebviewController} from './Webview';
export class ReleaseNotesWebview extends WebviewController<{}> { export class ReleaseNotesWebview extends WebviewController<Record<string, unknown>> {
get filename(): string { get filename(): string {
return 'release-notes.html'; return 'release-notes.html';
} }
@ -17,7 +17,7 @@ export class ReleaseNotesWebview extends WebviewController<{}> {
* This will be called by the WebviewController when init the view * This will be called by the WebviewController when init the view
* passing as `window.bootstrap` to the view. * passing as `window.bootstrap` to the view.
*/ */
getBootstrap(): {} { getBootstrap(): Record<string, unknown> {
return {}; return {};
} }
} }

View file

@ -36,17 +36,10 @@ export abstract class WebviewController<TBootstrap> extends Disposable {
async show(): Promise<void> { async show(): Promise<void> {
const html = await this.getHtml(); const html = await this.getHtml();
const rootPath = Uri
.file(this.context.asAbsolutePath('./build'))
.with({scheme: 'vscode-resource'}).toString();
// Replace placeholders in html content for assets and adding configurations as `window.bootstrap`
const fullHtml = html
.replace(/{{root}}/g, rootPath)
.replace('\'{{bootstrap}}\'', JSON.stringify(this.getBootstrap()));
// If panel already opened just reveal // If panel already opened just reveal
if (this.panel !== undefined) { if (this.panel !== undefined) {
// Replace placeholders in html content for assets and adding configurations as `window.bootstrap`
const fullHtml = this.replaceInPanel(html);
this.panel.webview.html = fullHtml; this.panel.webview.html = fullHtml;
return this.panel.reveal(ViewColumn.Active); return this.panel.reveal(ViewColumn.Active);
} }
@ -71,6 +64,9 @@ export abstract class WebviewController<TBootstrap> extends Disposable {
this.panel.webview.onDidReceiveMessage(this.onMessageReceived, this) this.panel.webview.onDidReceiveMessage(this.onMessageReceived, this)
); );
// Replace placeholders in html content for assets and adding configurations as `window.bootstrap`
const fullHtml = this.replaceInPanel(html);
this.panel.webview.html = fullHtml; this.panel.webview.html = fullHtml;
} }
@ -90,6 +86,16 @@ export abstract class WebviewController<TBootstrap> extends Disposable {
} }
} }
private replaceInPanel(html: string): string {
// Replace placeholders in html content for assets and adding configurations as `window.bootstrap`
const fullHtml = html
.replace(/{{root}}/g, this.panel.webview.asWebviewUri(Uri.file(this.context.asAbsolutePath('./build'))).toString())
.replace(/{{cspSource}}/g, this.panel.webview.cspSource)
.replace('\'{{bootstrap}}\'', JSON.stringify(this.getBootstrap()));
return fullHtml;
}
private async getHtml(): Promise<string> { private async getHtml(): Promise<string> {
const doc = await Workspace const doc = await Workspace
.openTextDocument(this.context.asAbsolutePath(path.join('build/ui', this.filename))); .openTextDocument(this.context.asAbsolutePath(path.join('build/ui', this.filename)));
@ -127,7 +133,7 @@ export abstract class WebviewController<TBootstrap> extends Disposable {
this.panel = undefined; this.panel = undefined;
} }
private async onViewStateChanged(event: WebviewPanelOnDidChangeViewStateEvent): Promise<boolean | void> { private async onViewStateChanged(event: WebviewPanelOnDidChangeViewStateEvent): Promise<void> {
console.log('WebviewEditor.onViewStateChanged', event.webviewPanel.visible); console.log('WebviewEditor.onViewStateChanged', event.webviewPanel.visible);
if (!this.invalidateOnVisible || !event.webviewPanel.visible) { if (!this.invalidateOnVisible || !event.webviewPanel.visible) {

View file

@ -19,7 +19,7 @@ export interface IPostNormalized {
} }
export interface ISettingsChangedMessage { export interface ISettingsChangedMessage {
type: 'settingsChanged'; type: 'settingsChanged';
config: {}; config: Record<string, unknown>;
} }
export interface ISaveSettingsMessage { export interface ISaveSettingsMessage {
@ -36,18 +36,17 @@ export type Message = ISaveSettingsMessage | ISettingsChangedMessage;
export type Invalidates = 'all' | 'config' | undefined; export type Invalidates = 'all' | 'config' | undefined;
export interface IBootstrap { export interface IBootstrap {
config: {}; config: Record<string, unknown>;
} }
export interface ISettingsBootstrap extends IBootstrap { export interface ISettingsBootstrap extends IBootstrap {
scope: 'user' | 'workspace'; scope: 'user' | 'workspace';
scopes: Array<['user' | 'workspace', string]>; scopes: Array<['user' | 'workspace', string]>;
defaults: {}; defaults: Record<string, unknown>;
} }
declare global { declare global {
// eslint-disable-next-line @typescript-eslint/interface-name-prefix
interface Window { interface Window {
bootstrap: IBootstrap | ISettingsBootstrap | {}; bootstrap: IBootstrap | ISettingsBootstrap | Record<string, unknown>;
} }
} }

861
yarn.lock

File diff suppressed because it is too large Load diff