From f6bc266e1d40d4a7066ce7af21e370b28d543744 Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Thu, 21 Apr 2022 21:16:31 +0100 Subject: [PATCH] feat: improve remove group events --- .../dockview/dockviewComponent.spec.ts | 206 +++++++++++++++++- .../src/dockview/dockviewComponent.ts | 31 +-- .../dockview/src/react/dockview/dockview.tsx | 9 + 3 files changed, 229 insertions(+), 17 deletions(-) diff --git a/packages/dockview/src/__tests__/dockview/dockviewComponent.spec.ts b/packages/dockview/src/__tests__/dockview/dockviewComponent.spec.ts index e4bb7ca5b..2e1789f73 100644 --- a/packages/dockview/src/__tests__/dockview/dockviewComponent.spec.ts +++ b/packages/dockview/src/__tests__/dockview/dockviewComponent.spec.ts @@ -1,7 +1,11 @@ -import { DockviewComponent } from '../../dockview/dockviewComponent'; +import { + DockviewComponent, + IDockviewComponent, +} from '../../dockview/dockviewComponent'; import { GroupPanelPartInitParameters, IContentRenderer, + ITabRenderer, } from '../../groupview/types'; import { PanelUpdateEvent } from '../../panel/types'; import { Orientation } from '../../splitview/core/splitview'; @@ -12,6 +16,20 @@ import { GroupChangeEvent, GroupChangeKind, } from '../../gridview/baseComponentGridview'; +import { CompositeDisposable } from '../../lifecycle'; +import { + GroupPanelUpdateEvent, + GroupviewPanelState, + IGroupPanel, + IGroupPanelInitParameters, +} from '../../groupview/groupPanel'; +import { IGroupPanelView } from '../../dockview/defaultGroupPanelView'; +import { + DockviewPanelApi, + DockviewPanelApiImpl, +} from '../../api/groupPanelApi'; +import { DefaultTab } from '../../dockview/components/tab/defaultTab'; + class PanelContentPartTest implements IContentRenderer { element: HTMLElement = document.createElement('div'); @@ -48,12 +66,106 @@ class PanelContentPartTest implements IContentRenderer { } } +class TestGroupPanelView implements IGroupPanelView { + readonly tab: ITabRenderer = new DefaultTab(); + + constructor(public readonly content: IContentRenderer) { + // + } + + update(event: GroupPanelUpdateEvent): void { + // + } + + layout(width: number, height: number): void { + // + } + + init(params: GroupPanelPartInitParameters): void { + // + } + + updateParentGroup(group: GroupviewPanel, isPanelVisible: boolean): void { + // + } + + toJSON(): {} { + return {}; + } + + dispose(): void { + // + } +} + +class TestGroupPanel implements IGroupPanel { + private _group: GroupviewPanel | undefined; + + readonly view: IGroupPanelView; + readonly suppressClosable: boolean = false; + readonly api: DockviewPanelApi; + + constructor( + public readonly id: string, + public readonly title: string, + accessor: IDockviewComponent + ) { + this.api = new DockviewPanelApiImpl(this, this._group); + this._group = new GroupviewPanel(accessor, id, {}); + this.view = new TestGroupPanelView( + new PanelContentPartTest(id, 'component') + ); + } + + get group(): GroupviewPanel | undefined { + return this._group; + } + + updateParentGroup(group: GroupviewPanel, isGroupActive: boolean): void { + this._group = group; + } + + init(params: IGroupPanelInitParameters): void { + // + } + + layout(width: number, height: number): void { + // + } + + focus(): void { + // + } + + toJSON(): GroupviewPanelState { + return { + id: this.id, + title: this.title, + }; + } + + update(event: GroupPanelUpdateEvent): void { + // + } + + dispose(): void { + // + } +} + describe('dockviewComponent', () => { + let root: HTMLElement; let container: HTMLElement; let dockview: DockviewComponent; beforeEach(() => { + root = document.createElement('div'); // dockview container must have parent element container = document.createElement('div'); + + root.appendChild(container); + root.className = 'root'; + container.className = 'container'; + dockview = new DockviewComponent(container, { components: { default: PanelContentPartTest, @@ -155,7 +267,7 @@ describe('dockviewComponent', () => { dockview.removeGroup(panel2.group); - expect(dockview.size).toBe(1); + expect(dockview.size).toBe(0); expect(dockview.totalPanels).toBe(0); }); @@ -294,7 +406,7 @@ describe('dockviewComponent', () => { await panel2.api.close(); - expect(dockview.size).toBe(1); + expect(dockview.size).toBe(0); expect(dockview.totalPanels).toBe(0); }); @@ -838,4 +950,92 @@ describe('dockviewComponent', () => { expect(dockview.getGroupPanel('panel1')).toBeUndefined(); expect(dockview.getGroupPanel('panel2')).toBeUndefined(); }); + + test('#1', () => { + dockview.layout(500, 500); + dockview.deserializer = { + fromJSON: (panelData: GroupviewPanelState): IGroupPanel => { + return new TestGroupPanel( + panelData.id, + panelData.title, + dockview + ); + }, + }; + + const panel1 = dockview.addPanel({ + id: 'panel1', + component: 'default', + }); + + const panel2 = dockview.addPanel({ + id: 'panel2', + component: 'default', + }); + + const panel3 = dockview.addPanel({ + id: 'panel3', + component: 'default', + position: { referencePanel: 'panel2', direction: 'below' }, + }); + + const removedGroups: GroupviewPanel[] = []; + const removedPanels: IGroupPanel[] = []; + + const disposable = new CompositeDisposable( + dockview.onDidRemoveGroup((group) => { + removedGroups.push(group); + }), + dockview.onDidRemovePanel((panel) => { + removedPanels.push(panel); + }) + ); + + dockview.fromJSON({ + grid: { + height: 500, + width: 500, + orientation: Orientation.HORIZONTAL, + root: { + type: 'branch', + data: [ + { + type: 'leaf', + data: { + views: ['view_1', 'view_2'], + id: 'group_1', + }, + }, + { + type: 'leaf', + data: { views: ['view_3'], id: 'group_2' }, + }, + ], + }, + }, + panels: { + view_1: { + id: 'view_1', + title: 'view_1_title', + view: {}, + }, + view_2: { + id: 'view_2', + title: 'view_2_title', + view: {}, + }, + view_3: { + id: 'view_3', + title: 'view_3_title', + view: {}, + }, + }, + options: {}, + }); + + expect(removedGroups.length).toBe(2); + expect(removedPanels.length).toBe(3); + + disposable.dispose(); + }); }); diff --git a/packages/dockview/src/dockview/dockviewComponent.ts b/packages/dockview/src/dockview/dockviewComponent.ts index 310cc5f11..8d0c84e91 100644 --- a/packages/dockview/src/dockview/dockviewComponent.ts +++ b/packages/dockview/src/dockview/dockviewComponent.ts @@ -71,6 +71,7 @@ export type DockviewComponentUpdateOptions = Pick< | 'tabComponents' | 'frameworkTabComponents' | 'showDndOverlay' + | 'watermarkFrameworkComponent' >; export interface DockviewDropEvent extends GroupviewDropEvent { @@ -335,11 +336,14 @@ export class DockviewComponent } fromJSON(data: SerializedDockview): void { + const groups = Array.from(this._groups.values()).map((_) => _.value); + + for (const group of groups) { + // remove the group will automatically remove the panels + this.removeGroup(group, true); + } + this.gridview.clear(); - this.panels.forEach((panel) => { - panel.dispose(); - }); - this._groups.clear(); if (!this.deserializer) { throw new Error('invalid deserializer'); @@ -438,7 +442,10 @@ export class DockviewComponent return panel; } - removePanel(panel: IGroupPanel): void { + removePanel( + panel: IGroupPanel, + options: { removeEmptyGroup: boolean } = { removeEmptyGroup: true } + ): void { const group = panel.group; if (!group) { @@ -449,7 +456,7 @@ export class DockviewComponent group.model.removePanel(panel); - if (group.model.size === 0) { + if (group.model.size === 0 && options.removeEmptyGroup) { this.removeGroup(group); } } @@ -504,18 +511,14 @@ export class DockviewComponent } } - removeGroup(group: GroupviewPanel): void { + removeGroup(group: GroupviewPanel, skipActive = false): void { const panels = [...group.model.panels]; // reassign since group panels will mutate - panels.forEach((panel) => { - this.removePanel(panel); - }); - if (this._groups.size === 1) { - this._activeGroup = group; - return; + for (const panel of panels) { + this.removePanel(panel, { removeEmptyGroup: false }); } - super.removeGroup(group); + super.doRemoveGroup(group, { skipActive }); } moveGroupOrPanel( diff --git a/packages/dockview/src/react/dockview/dockview.tsx b/packages/dockview/src/react/dockview/dockview.tsx index 71cc9d8cc..76dee4f85 100644 --- a/packages/dockview/src/react/dockview/dockview.tsx +++ b/packages/dockview/src/react/dockview/dockview.tsx @@ -167,6 +167,15 @@ export const DockviewReact = React.forwardRef( }); }, [props.components]); + React.useEffect(() => { + if (!dockviewRef.current) { + return; + } + dockviewRef.current.updateOptions({ + watermarkFrameworkComponent: props.watermarkComponent, + }); + }, [props.watermarkComponent]); + React.useEffect(() => { if (!dockviewRef.current) { return;