Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not store webview if there is no corresponding serializer #8680

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 38 additions & 9 deletions packages/core/src/browser/shell/shell-layout-restorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ import { ApplicationShell, applicationShellLayoutVersion, ApplicationShellLayout
export interface StatefulWidget {

/**
* Called on unload to store the inner state.
* Called on unload to store the inner state. Returns 'undefined' if the widget cannot be stored.
*/
storeState(): object;
storeState(): object | undefined;

/**
* Called when the widget got created by the storage service
Expand Down Expand Up @@ -205,14 +205,18 @@ export class ShellLayoutRestorer implements CommandContribution {
private convertToDescription(widget: Widget): WidgetDescription | undefined {
const desc = this.widgetManager.getDescription(widget);
if (desc) {
let innerState = undefined;
if (StatefulWidget.is(widget)) {
innerState = widget.storeState();
const innerState = widget.storeState();
return innerState ? {
constructionOptions: desc,
innerWidgetState: this.deflate(innerState)
} : undefined;
} else {
return {
constructionOptions: desc,
innerWidgetState: undefined
};
}
return {
constructionOptions: desc,
innerWidgetState: innerState && this.deflate(innerState)
};
}
}

Expand Down Expand Up @@ -265,7 +269,7 @@ export class ShellLayoutRestorer implements CommandContribution {
protected parse<T>(layoutData: string, parseContext: ShellLayoutRestorer.ParseContext): T {
return JSON.parse(layoutData, (property: string, value) => {
if (this.isWidgetsProperty(property)) {
const widgets: (Widget | undefined)[] = [];
const widgets = parseContext.filteredArray();
const descs = (value as WidgetDescription[]);
for (let i = 0; i < descs.length; i++) {
parseContext.push(async context => {
Expand Down Expand Up @@ -347,9 +351,22 @@ export class ShellLayoutRestorer implements CommandContribution {
}

}

export namespace ShellLayoutRestorer {

export class ParseContext {
protected readonly toInflate: Inflate[] = [];
protected readonly toFilter: Widgets[] = [];

/**
* Returns an array, which will be filtered from undefined elements
* after resolving promises, that create widgets.
*/
filteredArray(): Widgets {
const array: Widgets = [];
this.toFilter.push(array);
return array;
}

push(toInflate: Inflate): void {
this.toInflate.push(toInflate);
Expand All @@ -361,8 +378,20 @@ export namespace ShellLayoutRestorer {
pending.push(this.toInflate.pop()!(context));
}
await Promise.all(pending);

if (this.toFilter.length) {
this.toFilter.forEach(array => {
for (let i = 0; i < array.length; i++) {
if (array[i] === undefined) {
array.splice(i--, 1);
}
}
});
}
}
}

export type Widgets = (Widget | undefined)[];
export type Inflate = (context: InflateContext) => Promise<void>;
export interface InflateContext extends ApplicationShellLayoutMigrationContext {
readonly migrations: ApplicationShellLayoutMigration[];
Expand Down
11 changes: 7 additions & 4 deletions packages/plugin-ext/src/hosted/browser/hosted-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,19 +197,22 @@ export class HostedPluginSupport {
this.taskProviderRegistry.onWillProvideTaskProvider(event => this.ensureTaskActivation(event));
this.taskResolverRegistry.onWillProvideTaskResolver(event => this.ensureTaskActivation(event));
this.fileService.onWillActivateFileSystemProvider(event => this.ensureFileSystemActivation(event));

this.widgets.onDidCreateWidget(({ factoryId, widget }) => {
if (factoryId === WebviewWidget.FACTORY_ID && widget instanceof WebviewWidget) {
const storeState = widget.storeState.bind(widget);
const restoreState = widget.restoreState.bind(widget);

widget.storeState = () => {
if (this.webviewRevivers.has(widget.viewType)) {
return storeState();
}
return {};
return undefined;
};
widget.restoreState = oldState => {
if (oldState.viewType) {
restoreState(oldState);

widget.restoreState = state => {
if (state.viewType) {
restoreState(state);
this.preserveWebview(widget);
} else {
widget.dispose();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,10 @@ export class PluginViewRegistry implements FrontendApplicationContribution {
const widgets = this.widgetManager.getWidgets(PLUGIN_VIEW_DATA_FACTORY_ID);
for (const widget of widgets) {
if (StatefulWidget.is(widget)) {
this.viewDataState.set(widget.id, widget.storeState());
const state = widget.storeState();
if (state) {
this.viewDataState.set(widget.id, state);
}
}
widget.dispose();
}
Expand Down Expand Up @@ -565,7 +568,10 @@ export class PluginViewRegistry implements FrontendApplicationContribution {
protected storeViewDataStateOnDispose(viewId: string, widget: Widget & StatefulWidget): void {
const dispose = widget.dispose.bind(widget);
widget.dispose = () => {
this.viewDataState.set(viewId, widget.storeState());
const state = widget.storeState();
if (state) {
this.viewDataState.set(viewId, state);
}
dispose();
};
}
Expand Down
10 changes: 5 additions & 5 deletions packages/plugin-ext/src/main/browser/webviews-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export class WebviewsMainImpl implements WebviewsMain, Disposable {

private readonly proxy: WebviewsExt;
protected readonly shell: ApplicationShell;
protected readonly widgets: WidgetManager;
protected readonly widgetManager: WidgetManager;
protected readonly pluginService: HostedPluginSupport;
protected readonly viewColumnService: ViewColumnService;
private readonly toDispose = new DisposableCollection();
Expand All @@ -43,7 +43,7 @@ export class WebviewsMainImpl implements WebviewsMain, Disposable {
this.proxy = rpc.getProxy(MAIN_RPC_CONTEXT.WEBVIEWS_EXT);
this.shell = container.get(ApplicationShell);
this.viewColumnService = container.get(ViewColumnService);
this.widgets = container.get(WidgetManager);
this.widgetManager = container.get(WidgetManager);
this.pluginService = container.get(HostedPluginSupport);
this.toDispose.push(this.shell.onDidChangeActiveWidget(() => this.updateViewStates()));
this.toDispose.push(this.shell.onDidChangeCurrentWidget(() => this.updateViewStates()));
Expand All @@ -61,7 +61,7 @@ export class WebviewsMainImpl implements WebviewsMain, Disposable {
showOptions: WebviewPanelShowOptions,
options: WebviewPanelOptions & WebviewOptions
): Promise<void> {
const view = await this.widgets.getOrCreateWidget<WebviewWidget>(WebviewWidget.FACTORY_ID, <WebviewWidgetIdentifier>{ id: panelId });
const view = await this.widgetManager.getOrCreateWidget<WebviewWidget>(WebviewWidget.FACTORY_ID, <WebviewWidgetIdentifier>{ id: panelId });
this.hookWebview(view);
view.viewType = viewType;
view.title.label = title;
Expand Down Expand Up @@ -217,7 +217,7 @@ export class WebviewsMainImpl implements WebviewsMain, Disposable {
}

protected readonly updateViewStates = debounce(() => {
for (const widget of this.widgets.getWidgets(WebviewWidget.FACTORY_ID)) {
for (const widget of this.widgetManager.getWidgets(WebviewWidget.FACTORY_ID)) {
if (widget instanceof WebviewWidget) {
this.updateViewState(widget);
}
Expand Down Expand Up @@ -251,7 +251,7 @@ export class WebviewsMainImpl implements WebviewsMain, Disposable {
}

private async tryGetWebview(id: string): Promise<WebviewWidget | undefined> {
return this.widgets.getWidget<WebviewWidget>(WebviewWidget.FACTORY_ID, <WebviewWidgetIdentifier>{ id });
return this.widgetManager.getWidget<WebviewWidget>(WebviewWidget.FACTORY_ID, <WebviewWidgetIdentifier>{ id });
}

}