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

[vscode] Support ViewBadge and tree/web view badge property #72

Closed
wants to merge 1 commit into from
Closed
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
13 changes: 12 additions & 1 deletion packages/core/src/browser/view-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ export interface DescriptionWidget {

export interface BadgeWidget {
badge?: number;
badgeTooltip?: string;
onDidChangeBadge: CommonEvent<void>;
onDidChangeBadgeTooltip: CommonEvent<void>;
}

export namespace DescriptionWidget {
Expand All @@ -70,7 +72,7 @@ export namespace DescriptionWidget {

export namespace BadgeWidget {
export function is(arg: unknown): arg is BadgeWidget {
return isObject(arg) && 'onDidChangeBadge' in arg;
return isObject(arg) && ('onDidChangeBadge' in arg || 'onDidChangeBadgeTooltip' in arg);
}
}

Expand Down Expand Up @@ -927,6 +929,8 @@ export class ViewContainerPart extends BaseWidget {
readonly onDidChangeDescription = this.onDidChangeDescriptionEmitter.event;
protected readonly onDidChangeBadgeEmitter = new Emitter<void>();
readonly onDidChangeBadge = this.onDidChangeBadgeEmitter.event;
protected readonly onDidChangeBadgeTooltipEmitter = new Emitter<void>();
readonly onDidChangeBadgeTooltip = this.onDidChangeBadgeTooltipEmitter.event;

protected readonly toolbar: TabBarToolbar;

Expand Down Expand Up @@ -963,6 +967,7 @@ export class ViewContainerPart extends BaseWidget {

if (BadgeWidget.is(this.wrapped)) {
this.wrapped?.onDidChangeBadge(() => this.onDidChangeBadgeEmitter.fire(), undefined, this.toDispose);
this.wrapped?.onDidChangeBadgeTooltip(() => this.onDidChangeBadgeTooltipEmitter.fire(), undefined, this.toDispose);
}

const { header, body, disposable } = this.createContent();
Expand All @@ -982,6 +987,7 @@ export class ViewContainerPart extends BaseWidget {
this.onTitleChangedEmitter,
this.onDidChangeDescriptionEmitter,
this.onDidChangeBadgeEmitter,
this.onDidChangeBadgeTooltipEmitter,
this.registerContextMenu(),
this.onDidFocusEmitter,
// focus event does not bubble, capture it
Expand Down Expand Up @@ -1172,8 +1178,12 @@ export class ViewContainerPart extends BaseWidget {
const updateBadge = () => {
const visibleToolBarItems = this.toolbarRegistry.visibleItems(this.wrapped).length > 0;
const badge = BadgeWidget.is(this.wrapped) && this.wrapped.badge;
const badgeTooltip = BadgeWidget.is(this.wrapped) && this.wrapped.badgeTooltip;
if (typeof badge === 'number' && !visibleToolBarItems) {
badgeSpan.innerText = badge.toString();
if (typeof badgeTooltip === 'string') {
badgeSpan.title = badgeTooltip;
}
badgeContainer.style.display = badgeContainerDisplay;
} else {
badgeContainer.style.display = 'none';
Expand All @@ -1191,6 +1201,7 @@ export class ViewContainerPart extends BaseWidget {
this.onDidMove(updateTitle),
this.onDidChangeDescription(updateDescription),
this.onDidChangeBadge(updateBadge),
this.onDidChangeBadgeTooltip(updateBadge),
this.onCollapsed(updateDescription)
]);
header.appendChild(title);
Expand Down
3 changes: 3 additions & 0 deletions packages/plugin-ext/src/common/plugin-api-rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,7 @@ export interface TreeViewsMain {
$setMessage(treeViewId: string, message: string): void;
$setTitle(treeViewId: string, title: string): void;
$setDescription(treeViewId: string, description: string): void;
$setBadge(treeViewId: string, badge: theia.ViewBadge | undefined): void;
}
export class DataTransferFileDTO {
constructor(readonly name: string, readonly contentId: string, readonly uri?: UriComponents) { }
Expand Down Expand Up @@ -1709,6 +1710,7 @@ export interface WebviewsMain {
$reveal(handle: string, showOptions: theia.WebviewPanelShowOptions): void;
$setTitle(handle: string, value: string): void;
$setIconPath(handle: string, value: IconUrl | undefined): void;
$setBadge(handle: string, badge: theia.ViewBadge | undefined): void;
$setHtml(handle: string, value: string): void;
$setOptions(handle: string, options: theia.WebviewOptions): void;
$postMessage(handle: string, value: any): Thenable<boolean>;
Expand All @@ -1734,6 +1736,7 @@ export interface WebviewViewsMain extends Disposable {

$setWebviewViewTitle(handle: string, value: string | undefined): void;
$setWebviewViewDescription(handle: string, value: string | undefined): void;
$setBadge(handle: string, badge: theia.ViewBadge | undefined): void;

$show(handle: string, preserveFocus: boolean): void;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,14 @@ export class PluginViewRegistry implements FrontendApplicationContribution {
get description(): string | undefined { return _description; },
set description(value: string | undefined) { _description = value; },

get badge(): number | undefined { return webview.badge; },
set badge(badge: number | undefined) { webview.badge = badge; },

get badgeTooltip(): string | undefined { return webview.badgeTooltip; },
set badgeTooltip(badgeTooltip: string | undefined) { webview.badgeTooltip = badgeTooltip; },
onDidChangeBadge: webview.onDidChangeBadge,
onDidChangeBadgeTooltip: webview.onDidChangeBadgeTooltip,

dispose: webview.dispose,
show: webview.show
};
Expand Down
54 changes: 51 additions & 3 deletions packages/plugin-ext/src/main/browser/view/plugin-view-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { CommandRegistry } from '@theia/core/lib/common/command';
import { StatefulWidget } from '@theia/core/lib/browser/shell/shell-layout-restorer';
import { Message } from '@theia/core/shared/@phosphor/messaging';
import { TreeViewWidget } from './tree-view-widget';
import { DescriptionWidget } from '@theia/core/lib/browser/view-container';
import { BadgeWidget, DescriptionWidget } from '@theia/core/lib/browser/view-container';
import { DisposableCollection, Emitter, Event } from '@theia/core/lib/common';
import { ContextKeyService } from '@theia/core/lib/browser/context-key-service';

Expand All @@ -32,16 +32,20 @@ export class PluginViewWidgetIdentifier {
}

@injectable()
export class PluginViewWidget extends Panel implements StatefulWidget, DescriptionWidget {
export class PluginViewWidget extends Panel implements StatefulWidget, DescriptionWidget, BadgeWidget {

currentViewContainerId?: string;

protected _message?: string;
protected _description: string = '';
protected _badge?: number | undefined;
protected _badgeTooltip?: string | undefined;
protected _suppressUpdateViewVisibility = false;
protected updatingViewVisibility = false;
protected onDidChangeDescriptionEmitter = new Emitter<void>();
protected toDispose = new DisposableCollection(this.onDidChangeDescriptionEmitter);
protected onDidChangeBadgeEmitter = new Emitter<void>();
protected onDidChangeBadgeTooltipEmitter = new Emitter<void>();
protected toDispose = new DisposableCollection(this.onDidChangeDescriptionEmitter, this.onDidChangeBadgeEmitter, this.onDidChangeBadgeTooltipEmitter);

@inject(MenuModelRegistry)
protected readonly menus: MenuModelRegistry;
Expand Down Expand Up @@ -73,6 +77,14 @@ export class PluginViewWidget extends Panel implements StatefulWidget, Descripti
return this.onDidChangeDescriptionEmitter.event;
}

get onDidChangeBadge(): Event<void> {
return this.onDidChangeBadgeEmitter.event;
}

get onDidChangeBadgeTooltip(): Event<void> {
return this.onDidChangeBadgeTooltipEmitter.event;
}

protected override onActivateRequest(msg: Message): void {
super.onActivateRequest(msg);
const widget = this.widgets[0];
Expand Down Expand Up @@ -138,6 +150,38 @@ export class PluginViewWidget extends Panel implements StatefulWidget, Descripti
this.onDidChangeDescriptionEmitter.fire();
}

get badge(): number | undefined {
if (this._badge === undefined) {
for (const w of this.widgets) {
if (BadgeWidget.is(w)) {
return w.badge;
}
};
}
return this._badge;
}

set badge(badge: number | undefined) {
this._badge = badge;
this.onDidChangeBadgeEmitter.fire();
}

get badgeTooltip(): string | undefined {
if (this._badgeTooltip === undefined) {
for (const w of this.widgets) {
if (BadgeWidget.is(w)) {
return w.badgeTooltip;
}
};
}
return this._badgeTooltip;
}

set badgeTooltip(badgeTooltip: string | undefined) {
this._badgeTooltip = badgeTooltip;
this.onDidChangeBadgeTooltipEmitter.fire();
}

private updateWidgetMessage(): void {
const widget = this.widgets[0];
if (widget) {
Expand All @@ -149,6 +193,10 @@ export class PluginViewWidget extends Panel implements StatefulWidget, Descripti

override addWidget(widget: Widget): void {
super.addWidget(widget);
if (BadgeWidget.is(widget)) {
widget?.onDidChangeBadge(() => this.onDidChangeBadgeEmitter.fire());
widget?.onDidChangeBadgeTooltip(() => this.onDidChangeBadgeTooltipEmitter.fire());
}
this.updateWidgetMessage();
}

Expand Down
9 changes: 9 additions & 0 deletions packages/plugin-ext/src/main/browser/view/tree-views-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { TreeViewWidget, TreeViewNode, PluginTreeModel, TreeViewWidgetOptions }
import { PluginViewWidget } from './plugin-view-widget';
import { BinaryBuffer } from '@theia/core/lib/common/buffer';
import { DnDFileContentStore } from './dnd-file-content-store';
import { ViewBadge } from '@theia/plugin';

export class TreeViewsMainImpl implements TreeViewsMain, Disposable {

Expand Down Expand Up @@ -173,6 +174,14 @@ export class TreeViewsMainImpl implements TreeViewsMain, Disposable {
}
}

async $setBadge(treeViewId: string, badge: ViewBadge | undefined): Promise<void> {
const viewPanel = await this.viewRegistry.getView(treeViewId);
if (viewPanel) {
viewPanel.badge = badge?.value;
viewPanel.badgeTooltip = badge?.tooltip;
}
}

protected handleTreeEvents(treeViewId: string, treeViewWidget: TreeViewWidget): void {
this.toDispose.push(treeViewWidget.model.onExpansionChanged(event => {
this.proxy.$setExpanded(treeViewId, event.id, event.expanded);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { CancellationToken } from '@theia/core/lib/common/cancellation';
import { WebviewsMainImpl } from '../webviews-main';
import { Widget, WidgetManager } from '@theia/core/lib/browser';
import { PluginViewRegistry } from '../view/plugin-view-registry';
import { ViewBadge } from '@theia/plugin';

export class WebviewViewsMainImpl implements WebviewViewsMain, Disposable {

Expand Down Expand Up @@ -126,6 +127,14 @@ export class WebviewViewsMainImpl implements WebviewViewsMain, Disposable {
webviewView.description = value;
}

async $setBadge(handle: string, badge: ViewBadge | undefined): Promise<void> {
const webviewView = this.getWebviewView(handle);
if (webviewView) {
webviewView.badge = badge?.value;
webviewView.badgeTooltip = badge?.tooltip;
}
}

$show(handle: string, preserveFocus: boolean): void {
const webviewView = this.getWebviewView(handle);
webviewView.show(preserveFocus);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ import { WebviewWidget } from '../webview/webview';
export interface WebviewView {
title?: string;
description?: string;
badge?: number | undefined;
badgeTooltip?: string | undefined;
readonly webview: WebviewWidget;
readonly onDidChangeVisibility: Event<boolean>;
readonly onDidDispose: Event<void>;
readonly onDidChangeBadge: Event<void>;
readonly onDidChangeBadgeTooltip: Event<void>;

dispose(): void;
show(preserveFocus: boolean): void;
Expand Down
38 changes: 36 additions & 2 deletions packages/plugin-ext/src/main/browser/webview/webview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import { IconUrl } from '../../../common/plugin-protocol';
import { Deferred } from '@theia/core/lib/common/promise-util';
import { WebviewEnvironment } from './webview-environment';
import URI from '@theia/core/lib/common/uri';
import { Emitter } from '@theia/core/lib/common/event';
import { Emitter, Event } from '@theia/core/lib/common/event';
import { open, OpenerService } from '@theia/core/lib/browser/opener-service';
import { KeybindingRegistry } from '@theia/core/lib/browser/keybinding';
import { Schemes } from '../../../common/uri-components';
Expand All @@ -50,6 +50,7 @@ import { FileOperationError, FileOperationResult } from '@theia/filesystem/lib/c
import { BinaryBufferReadableStream } from '@theia/core/lib/common/buffer';
import { ViewColumn } from '../../../plugin/types-impl';
import { ExtractableWidget } from '@theia/core/lib/browser/widgets/extractable-widget';
import { BadgeWidget } from '@theia/core/lib/browser/view-container';

// Style from core
const TRANSPARENT_OVERLAY_STYLE = 'theia-transparent-overlay';
Expand Down Expand Up @@ -87,7 +88,7 @@ export class WebviewWidgetIdentifier {
export const WebviewWidgetExternalEndpoint = Symbol('WebviewWidgetExternalEndpoint');

@injectable()
export class WebviewWidget extends BaseWidget implements StatefulWidget, ExtractableWidget {
export class WebviewWidget extends BaseWidget implements StatefulWidget, ExtractableWidget, BadgeWidget {

private static readonly standardSupportedLinkSchemes = new Set([
Schemes.http,
Expand Down Expand Up @@ -178,6 +179,11 @@ export class WebviewWidget extends BaseWidget implements StatefulWidget, Extract
isExtractable: boolean = true;
secondaryWindow: Window | undefined = undefined;

protected _badge?: number | undefined;
protected _badgeTooltip?: string | undefined;
protected onDidChangeBadgeEmitter = new Emitter<void>();
protected onDidChangeBadgeTooltipEmitter = new Emitter<void>();

@postConstruct()
protected init(): void {
this.node.tabIndex = 0;
Expand All @@ -186,6 +192,8 @@ export class WebviewWidget extends BaseWidget implements StatefulWidget, Extract
this.addClass(WebviewWidget.Styles.WEBVIEW);

this.toDispose.push(this.onMessageEmitter);
this.toDispose.push(this.onDidChangeBadgeEmitter);
this.toDispose.push(this.onDidChangeBadgeTooltipEmitter);

this.transparentOverlay = document.createElement('div');
this.transparentOverlay.classList.add(TRANSPARENT_OVERLAY_STYLE);
Expand All @@ -204,6 +212,32 @@ export class WebviewWidget extends BaseWidget implements StatefulWidget, Extract
}));
}

get onDidChangeBadge(): Event<void> {
return this.onDidChangeBadgeEmitter.event;
}

get onDidChangeBadgeTooltip(): Event<void> {
return this.onDidChangeBadgeTooltipEmitter.event;
}

get badge(): number | undefined {
return this._badge;
}

set badge(badge: number | undefined) {
this._badge = badge;
this.onDidChangeBadgeEmitter.fire();
}

get badgeTooltip(): string | undefined {
return this._badgeTooltip;
}

set badgeTooltip(badgeTooltip: string | undefined) {
this._badgeTooltip = badgeTooltip;
this.onDidChangeBadgeTooltipEmitter.fire();
}

protected override onBeforeAttach(msg: Message): void {
super.onBeforeAttach(msg);
this.doShow();
Expand Down
10 changes: 9 additions & 1 deletion packages/plugin-ext/src/main/browser/webviews-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { URI } from '@theia/core/shared/vscode-uri';
import { interfaces } from '@theia/core/shared/inversify';
import { WebviewsMain, MAIN_RPC_CONTEXT, WebviewsExt, WebviewPanelViewState } from '../../common/plugin-api-rpc';
import { RPCProtocol } from '../../common/rpc-protocol';
import { WebviewOptions, WebviewPanelOptions, WebviewPanelShowOptions } from '@theia/plugin';
import { ViewBadge, WebviewOptions, WebviewPanelOptions, WebviewPanelShowOptions } from '@theia/plugin';
import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell';
import { WebviewWidget, WebviewWidgetIdentifier } from './webview/webview';
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
Expand Down Expand Up @@ -160,6 +160,14 @@ export class WebviewsMainImpl implements WebviewsMain, Disposable {
webview.title.label = value;
}

async $setBadge(handle: string, badge: ViewBadge | undefined): Promise<void> {
const webview = await this.getWebview(handle);
if (webview) {
webview.badge = badge?.value;
webview.badgeTooltip = badge?.tooltip;
}
}

async $setIconPath(handle: string, iconUrl: IconUrl | undefined): Promise<void> {
const webview = await this.getWebview(handle);
webview.setIconUrl(iconUrl);
Expand Down
Loading