From a6b0250b867494993ddedec66b7c22334818e5eb Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Mon, 2 May 2022 17:47:49 +0100 Subject: [PATCH] feat: adjust to make group non-optional --- .../dockview/dockviewComponent.spec.ts | 2 +- .../dockview/dockviewGroupPanel.spec.ts | 25 ++++++++--- packages/dockview/src/api/groupPanelApi.ts | 12 ++--- .../dockview/src/dockview/deserializer.ts | 45 ++++++++++--------- .../src/dockview/dockviewComponent.ts | 35 ++++++++------- .../src/dockview/dockviewGroupPanel.ts | 10 +++-- packages/dockview/src/groupview/groupPanel.ts | 2 +- packages/dockview/src/groupview/groupview.ts | 16 +++++-- .../dockview/src/groupview/groupviewPanel.ts | 6 ++- packages/dockview/src/react/deserializer.ts | 9 +++- 10 files changed, 99 insertions(+), 63 deletions(-) diff --git a/packages/dockview/src/__tests__/dockview/dockviewComponent.spec.ts b/packages/dockview/src/__tests__/dockview/dockviewComponent.spec.ts index 665a38b7d..3bc90aefa 100644 --- a/packages/dockview/src/__tests__/dockview/dockviewComponent.spec.ts +++ b/packages/dockview/src/__tests__/dockview/dockviewComponent.spec.ts @@ -619,7 +619,7 @@ describe('dockviewComponent', () => { data: { views: ['panel2', 'panel3'], id: 'group-2', - activeView: 'panel2', + activeView: 'panel3', }, size: 500, }, diff --git a/packages/dockview/src/__tests__/dockview/dockviewGroupPanel.spec.ts b/packages/dockview/src/__tests__/dockview/dockviewGroupPanel.spec.ts index f3bb9d402..657274e33 100644 --- a/packages/dockview/src/__tests__/dockview/dockviewGroupPanel.spec.ts +++ b/packages/dockview/src/__tests__/dockview/dockviewGroupPanel.spec.ts @@ -1,19 +1,26 @@ -import { DockviewComponent } from '../..'; +import { DockviewComponent } from '../../dockview/dockviewComponent'; import { DockviewApi } from '../../api/component.api'; import { IGroupPanelView } from '../../dockview/defaultGroupPanelView'; import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel'; +import { GroupviewPanel } from '../../groupview/groupviewPanel'; describe('dockviewGroupPanel', () => { test('update title', () => { const dockviewApiMock = jest.fn(() => { - return {} as any; + return { + onDidActiveChange: jest.fn(), + } as any; }); const accessorMock = jest.fn(() => { return {} as any; }); + const groupMock = jest.fn(() => { + return {} as any; + }); const api = new dockviewApiMock(); const accessor = new accessorMock(); - const cut = new DockviewGroupPanel('fake-id', accessor, api); + const group = new groupMock(); + const cut = new DockviewGroupPanel('fake-id', accessor, api, group); let latestTitle: string | undefined = undefined; @@ -41,10 +48,14 @@ describe('dockviewGroupPanel', () => { const accessorMock = jest.fn(() => { return {} as any; }); + const groupMock = jest.fn(() => { + return {} as any; + }); const api = new dockviewApiMock(); const accessor = new accessorMock(); + const group = new groupMock(); - const cut = new DockviewGroupPanel('fake-id', accessor, api); + const cut = new DockviewGroupPanel('fake-id', accessor, api, group); let latestSuppressClosable: boolean | undefined = undefined; @@ -77,10 +88,14 @@ describe('dockviewGroupPanel', () => { const accessorMock = jest.fn(() => { return {} as any; }); + const groupMock = jest.fn(() => { + return {} as any; + }); const api = new dockviewApiMock(); const accessor = new accessorMock(); + const group = new groupMock(); - const cut = new DockviewGroupPanel('fake-id', accessor, api); + const cut = new DockviewGroupPanel('fake-id', accessor, api, group); const viewMock = jest.fn(() => { return { diff --git a/packages/dockview/src/api/groupPanelApi.ts b/packages/dockview/src/api/groupPanelApi.ts index 4bface8ef..78e72d291 100644 --- a/packages/dockview/src/api/groupPanelApi.ts +++ b/packages/dockview/src/api/groupPanelApi.ts @@ -17,7 +17,7 @@ export interface SuppressClosableEvent { * because it belongs to a groupview */ export interface DockviewPanelApi extends Omit { - readonly group: GroupviewPanel | undefined; + readonly group: GroupviewPanel; readonly isGroupActive: boolean; readonly title: string; readonly suppressClosable: boolean; @@ -29,7 +29,7 @@ export class DockviewPanelApiImpl extends GridviewPanelApiImpl implements DockviewPanelApi { - private _group: GroupviewPanel | undefined; + private _group: GroupviewPanel; readonly _onDidTitleChange = new Emitter(); readonly onDidTitleChange = this._onDidTitleChange.event; @@ -60,7 +60,7 @@ export class DockviewPanelApiImpl return !!this.group?.isActive; } - set group(value: GroupviewPanel | undefined) { + set group(value: GroupviewPanel) { const isOldGroupActive = this.isGroupActive; this._group = value; @@ -78,13 +78,13 @@ export class DockviewPanelApiImpl } } - get group(): GroupviewPanel | undefined { + get group(): GroupviewPanel { return this._group; } - constructor(private panel: IGroupPanel, group: GroupviewPanel | undefined) { + constructor(private panel: IGroupPanel, group: GroupviewPanel) { super(panel.id); - this.group = group; + this._group = group; this.addDisposables( this.disposable, diff --git a/packages/dockview/src/dockview/deserializer.ts b/packages/dockview/src/dockview/deserializer.ts index cfd05883c..2a14fc295 100644 --- a/packages/dockview/src/dockview/deserializer.ts +++ b/packages/dockview/src/dockview/deserializer.ts @@ -5,17 +5,21 @@ import { } from '../gridview/gridview'; import { GroupviewPanelState, IGroupPanel } from '../groupview/groupPanel'; import { GroupPanelViewState } from '../groupview/groupview'; +import { GroupviewPanel } from '../groupview/groupviewPanel'; import { DockviewComponent } from './dockviewComponent'; export interface IPanelDeserializer { - fromJSON(panelData: GroupviewPanelState): IGroupPanel; + fromJSON( + panelData: GroupviewPanelState, + group: GroupviewPanel + ): IGroupPanel; } export class DefaultDeserializer implements IViewDeserializer { constructor( private readonly layout: DockviewComponent, private panelDeserializer: { - createPanel: (id: string) => IGroupPanel; + createPanel: (id: string, group: GroupviewPanel) => IGroupPanel; } ) {} @@ -24,29 +28,26 @@ export class DefaultDeserializer implements IViewDeserializer { const children = data.views; const active = data.activeView; - const panels: IGroupPanel[] = []; - - for (const child of children) { - const panel = this.panelDeserializer.createPanel(child); - - panels.push(panel); - } - - return this.layout.createGroup({ - panels, - activePanel: panels.find((p) => p.id === active), + const group = this.layout.createGroup({ id: data.id, locked: !!data.locked, headerHidden: !!data.headerHidden, }); + + for (const child of children) { + const panel = this.panelDeserializer.createPanel(child, group); + + const isActive = typeof active === 'string' && active === panel.id; + + group.model.openPanel(panel, { + skipSetActive: !isActive, + }); + } + + if (!group.activePanel && group.panels.length > 0) { + group.model.openPanel(group.panels[group.panels.length - 1]); + } + + return group; } } - -/** - * isGroup - * - * - * panel.group.locked = true - * panel.group.header.hiddden = true - * - */ diff --git a/packages/dockview/src/dockview/dockviewComponent.ts b/packages/dockview/src/dockview/dockviewComponent.ts index ffdc66d85..b88fd6cc5 100644 --- a/packages/dockview/src/dockview/dockviewComponent.ts +++ b/packages/dockview/src/dockview/dockviewComponent.ts @@ -263,9 +263,6 @@ export class DockviewComponent } setActivePanel(panel: IGroupPanel): void { - if (!panel.group) { - throw new Error(`Panel ${panel.id} has no associated group`); - } this.doSetGroupActive(panel.group); panel.group.model.openPanel(panel); } @@ -367,9 +364,9 @@ export class DockviewComponent this.gridview.deserialize( grid, new DefaultDeserializer(this, { - createPanel: (id) => { + createPanel: (id, group) => { const panelData = panels[id]; - return this.deserializer!.fromJSON(panelData); + return this.deserializer!.fromJSON(panelData, group); }, }) ); @@ -411,8 +408,6 @@ export class DockviewComponent throw new Error(`panel with id ${options.id} already exists`); } - const panel = this.createPanel(options); - let referenceGroup: GroupviewPanel | undefined; if (options.position?.referencePanel) { @@ -431,9 +426,12 @@ export class DockviewComponent referenceGroup = this.activeGroup; } + let panel: IGroupPanel + if (referenceGroup) { const target = toTarget(options.position?.direction || 'within'); if (target === Position.Center) { + panel = this.createPanel(options, referenceGroup) referenceGroup.model.openPanel(panel); } else { const location = getGridLocation(referenceGroup.element); @@ -442,10 +440,14 @@ export class DockviewComponent location, target ); - this.addPanelToNewGroup(panel, relativeLocation); + const group = this.createGroupAtLocation(relativeLocation); + panel = this.createPanel(options, group) + group.model.openPanel(panel); } } else { - this.addPanelToNewGroup(panel); + const group = this.createGroupAtLocation(); + panel = this.createPanel(options, group); + group.model.openPanel(panel); } return panel; @@ -622,7 +624,8 @@ export class DockviewComponent target ); - this.addPanelToNewGroup(groupItem, dropLocation); + const group = this.createGroupAtLocation( dropLocation); + group.model.openPanel(groupItem); } } } @@ -710,13 +713,13 @@ export class DockviewComponent return view; } - private createPanel(options: AddPanelOptions): IGroupPanel { + private createPanel(options: AddPanelOptions, group: GroupviewPanel): IGroupPanel { const view = new DefaultGroupPanelView({ content: this.createContentComponent(options.id, options.component), tab: this.createTabComponent(options.id, options.tabComponent), }); - const panel = new DockviewGroupPanel(options.id, this, this._api); + const panel = new DockviewGroupPanel(options.id, this, this._api, group); panel.init({ view, title: options.title || options.id, @@ -754,14 +757,12 @@ export class DockviewComponent ); } - private addPanelToNewGroup( - panel: IGroupPanel, + private createGroupAtLocation( location: number[] = [0] - ): void { + ): GroupviewPanel { const group = this.createGroup(); this.doAddGroup(group, location); - - group.model.openPanel(panel); + return group } private findGroup(panel: IGroupPanel): GroupviewPanel | undefined { diff --git a/packages/dockview/src/dockview/dockviewGroupPanel.ts b/packages/dockview/src/dockview/dockviewGroupPanel.ts index 35049f5d2..b4f9d0572 100644 --- a/packages/dockview/src/dockview/dockviewGroupPanel.ts +++ b/packages/dockview/src/dockview/dockviewGroupPanel.ts @@ -19,7 +19,7 @@ export class DockviewGroupPanel private readonly mutableDisposable = new MutableDisposable(); readonly api: DockviewPanelApiImpl; - private _group: GroupviewPanel | undefined; + private _group: GroupviewPanel; private _params?: Parameters; private _view?: IGroupPanelView; @@ -39,7 +39,7 @@ export class DockviewGroupPanel return this._suppressClosable; } - get group(): GroupviewPanel | undefined { + get group(): GroupviewPanel { return this._group; } @@ -50,11 +50,13 @@ export class DockviewGroupPanel constructor( public readonly id: string, accessor: DockviewComponent, - private readonly containerApi: DockviewApi + private readonly containerApi: DockviewApi, + group: GroupviewPanel ) { super(); this._suppressClosable = false; this._title = ''; + this._group = group; this.api = new DockviewPanelApiImpl(this, this._group); @@ -169,7 +171,7 @@ export class DockviewGroupPanel // the obtain the correct dimensions of the content panel we must deduct the tab height this.api._onDidPanelDimensionChange.fire({ width, - height: height - (this.group?.model.header.height || 0), + height: height - (this.group.model.header.height || 0), }); this.view?.layout(width, height); diff --git a/packages/dockview/src/groupview/groupPanel.ts b/packages/dockview/src/groupview/groupPanel.ts index 1b0ab7391..48050c742 100644 --- a/packages/dockview/src/groupview/groupPanel.ts +++ b/packages/dockview/src/groupview/groupPanel.ts @@ -24,7 +24,7 @@ export type GroupPanelUpdateEvent = PanelUpdateEvent<{ export interface IGroupPanel extends IDisposable, IPanel { readonly view?: IGroupPanelView; - readonly group?: GroupviewPanel; + readonly group: GroupviewPanel; readonly api: DockviewPanelApi; readonly title: string; readonly suppressClosable: boolean; diff --git a/packages/dockview/src/groupview/groupview.ts b/packages/dockview/src/groupview/groupview.ts index 057a01459..dfa85e9c4 100644 --- a/packages/dockview/src/groupview/groupview.ts +++ b/packages/dockview/src/groupview/groupview.ts @@ -394,7 +394,11 @@ export class Groupview extends CompositeDisposable implements IGroupview { public openPanel( panel: IGroupPanel, - options: { index?: number; skipFocus?: boolean } = {} + options: { + index?: number; + skipFocus?: boolean; + skipSetActive?: boolean; + } = {} ) { if ( typeof options.index !== 'number' || @@ -403,18 +407,22 @@ export class Groupview extends CompositeDisposable implements IGroupview { options.index = this.panels.length; } + const skipSetActive = !!options.skipSetActive; + // ensure the group is updated before we fire any events panel.updateParentGroup(this.parent, true); - if (this._activePanel === panel) { + if (!skipSetActive && this._activePanel === panel) { this.accessor.doSetGroupActive(this.parent); return; } this.doAddPanel(panel, options.index); - this.doSetActivePanel(panel); - this.accessor.doSetGroupActive(this.parent, !!options.skipFocus); + if (!skipSetActive) { + this.doSetActivePanel(panel); + this.accessor.doSetGroupActive(this.parent, !!options.skipFocus); + } this.updateContainer(); } diff --git a/packages/dockview/src/groupview/groupviewPanel.ts b/packages/dockview/src/groupview/groupviewPanel.ts index ae4ef9c16..7d2216520 100644 --- a/packages/dockview/src/groupview/groupviewPanel.ts +++ b/packages/dockview/src/groupview/groupviewPanel.ts @@ -4,7 +4,7 @@ import { GridviewPanelApi, GridviewPanelApiImpl, } from '../api/gridviewPanelApi'; -import { Groupview, GroupOptions, IGroupview } from './groupview'; +import { Groupview, GroupOptions, IHeader } from './groupview'; import { GridviewPanel, IGridviewPanel } from '../gridview/gridviewPanel'; import { IGroupPanel } from './groupPanel'; @@ -65,6 +65,10 @@ export class GroupviewPanel extends GridviewPanel implements IGroupviewPanel { this._model.locked = value; } + get header(): IHeader { + return this._model.header; + } + constructor( accessor: IDockviewComponent, id: string, diff --git a/packages/dockview/src/react/deserializer.ts b/packages/dockview/src/react/deserializer.ts index 904f25891..c51f9672e 100644 --- a/packages/dockview/src/react/deserializer.ts +++ b/packages/dockview/src/react/deserializer.ts @@ -6,11 +6,15 @@ import { createComponent } from '../panel/componentFactory'; import { DockviewApi } from '../api/component.api'; import { DefaultTab } from '../dockview/components/tab/defaultTab'; import { DefaultGroupPanelView } from '../dockview/defaultGroupPanelView'; +import { GroupviewPanel } from '../groupview/groupviewPanel'; export class ReactPanelDeserialzier implements IPanelDeserializer { constructor(private readonly layout: DockviewComponent) {} - public fromJSON(panelData: GroupviewPanelState): IGroupPanel { + public fromJSON( + panelData: GroupviewPanelState, + group: GroupviewPanel + ): IGroupPanel { const panelId = panelData.id; const params = panelData.params; const title = panelData.title; @@ -39,7 +43,8 @@ export class ReactPanelDeserialzier implements IPanelDeserializer { const panel = new DockviewGroupPanel( panelId, this.layout, - new DockviewApi(this.layout) + new DockviewApi(this.layout), + group ); panel.init({