Merge pull request #548 from mathuo/504-bug-updating-panel-parameters-does-not-trigger-ondidlayoutchange

504 bug updating panel parameters does not trigger ondidlayoutchange
This commit is contained in:
mathuo 2024-03-11 21:15:53 +00:00 committed by GitHub
commit da6704b517
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 171 additions and 97 deletions

View File

@ -8,7 +8,7 @@ import { PanelUpdateEvent } from '../../panel/types';
import { Orientation } from '../../splitview/splitview';
import { CompositeDisposable } from '../../lifecycle';
import { Emitter } from '../../events';
import { IDockviewPanel } from '../../dockview/dockviewPanel';
import { DockviewPanel, IDockviewPanel } from '../../dockview/dockviewPanel';
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
import { fireEvent } from '@testing-library/dom';
import { getPanelData } from '../../dnd/dataTransfer';
@ -4598,6 +4598,64 @@ describe('dockviewComponent', () => {
});
});
describe('that emits onDidLayoutChange', () => {
let dockview: DockviewComponent;
let panel1: DockviewPanel;
beforeEach(() => {
jest.useFakeTimers();
dockview = new DockviewComponent({
parentElement: container,
components: {
default: PanelContentPartTest,
},
tabComponents: {
test_tab_id: PanelTabPartTest,
},
orientation: Orientation.HORIZONTAL,
});
panel1 = dockview.addPanel({
id: 'panel_1',
component: 'default',
});
});
afterEach(() => {
jest.runAllTimers();
jest.useRealTimers();
});
test('that emits onDidPanelTitleChange and onDidLayoutChange when the panel set a title', () => {
const didLayoutChangeHandler = jest.fn();
const { dispose: disposeDidLayoutChangeHandler } =
dockview.onDidLayoutChange(didLayoutChangeHandler);
panel1.setTitle('new title');
jest.runAllTimers();
expect(didLayoutChangeHandler).toHaveBeenCalledTimes(1);
disposeDidLayoutChangeHandler();
});
test('that emits onDidPanelParametersChange and onDidLayoutChange when the panel updates parameters', () => {
const didLayoutChangeHandler = jest.fn();
const { dispose: disposeDidLayoutChangeHandler } =
dockview.onDidLayoutChange(didLayoutChangeHandler);
panel1.api.updateParameters({ keyA: 'valueA' });
jest.runAllTimers();
expect(didLayoutChangeHandler).toHaveBeenCalledTimes(1);
disposeDidLayoutChangeHandler();
});
});
test('that setVisible toggles visiblity', () => {
const container = document.createElement('div');

View File

@ -9,19 +9,40 @@ import {
} from '../../dockview/types';
import { PanelUpdateEvent, Parameters } from '../../panel/types';
import {
DockviewGroupLocation,
DockviewGroupPanelModel,
GroupOptions,
} from '../../dockview/dockviewGroupPanelModel';
import { fireEvent } from '@testing-library/dom';
import { LocalSelectionTransfer, PanelTransfer } from '../../dnd/dataTransfer';
import { CompositeDisposable } from '../../lifecycle';
import { DockviewPanelApi } from '../../api/dockviewPanelApi';
import {
ActiveGroupEvent,
DockviewPanelApi,
GroupChangedEvent,
RendererChangedEvent,
} from '../../api/dockviewPanelApi';
import { IDockviewPanel } from '../../dockview/dockviewPanel';
import { IDockviewPanelModel } from '../../dockview/dockviewPanelModel';
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
import { WatermarkRendererInitParameters } from '../../dockview/types';
import { createOffsetDragOverEvent } from '../__test_utils__/utils';
import { OverlayRenderContainer } from '../../overlayRenderContainer';
import {
DockviewPanelRenderer,
OverlayRenderContainer,
} from '../../overlayRenderContainer';
import { DockviewGroupPanelFloatingChangeEvent } from '../../api/dockviewGroupPanelApi';
import { SizeEvent } from '../../api/gridviewPanelApi';
import {
PanelDimensionChangeEvent,
FocusEvent,
VisibilityEvent,
ActiveEvent,
WillFocusEvent,
} from '../../api/panelApi';
import { Position } from '../../dnd/droptarget';
import { Emitter, Event } from '../../events';
import { fromPartial } from '@total-typescript/shoehorn';
enum GroupChangeKind2 {
ADD_PANEL,
@ -240,12 +261,20 @@ describe('dockviewGroupPanelModel', () => {
let removePanelMock: jest.Mock;
let removeGroupMock: jest.Mock;
let panelApi: DockviewPanelApi;
beforeEach(() => {
removePanelMock = jest.fn();
removeGroupMock = jest.fn();
options = {};
panelApi = fromPartial<DockviewPanelApi>({
renderer: 'onlyWhenVisibile',
onDidTitleChange: new Emitter().event,
onDidParametersChange: new Emitter().event,
});
dockview = (<Partial<DockviewComponent>>{
options: { parentElement: document.createElement('div') },
createWatermarkComponent: () => new Watermark(),
@ -265,15 +294,9 @@ describe('dockviewGroupPanelModel', () => {
});
test('panel events are captured during de-serialization', () => {
const panel1 = new TestPanel('panel1', {
renderer: 'onlyWhenVisibile',
} as any);
const panel2 = new TestPanel('panel2', {
renderer: 'onlyWhenVisibile',
} as any);
const panel3 = new TestPanel('panel3', {
renderer: 'onlyWhenVisibile',
} as any);
const panel1 = new TestPanel('panel1', panelApi);
const panel2 = new TestPanel('panel2', panelApi);
const panel3 = new TestPanel('panel3', panelApi);
const groupview2 = new DockviewGroupPanel(dockview, 'groupview-2', {
panels: [panel1, panel2, panel3],
@ -357,15 +380,9 @@ describe('dockviewGroupPanelModel', () => {
})
);
const panel1 = new TestPanel('panel1', {
renderer: 'onlyWhenVisibile',
} as any);
const panel2 = new TestPanel('panel2', {
renderer: 'onlyWhenVisibile',
} as any);
const panel3 = new TestPanel('panel3', {
renderer: 'onlyWhenVisibile',
} as any);
const panel1 = new TestPanel('panel1', panelApi);
const panel2 = new TestPanel('panel2', panelApi);
const panel3 = new TestPanel('panel3', panelApi);
expect(events.length).toBe(0);
@ -443,15 +460,9 @@ describe('dockviewGroupPanelModel', () => {
});
test('moveToPrevious and moveToNext', () => {
const panel1 = new TestPanel('panel1', {
renderer: 'onlyWhenVisibile',
} as any);
const panel2 = new TestPanel('panel2', {
renderer: 'onlyWhenVisibile',
} as any);
const panel3 = new TestPanel('panel3', {
renderer: 'onlyWhenVisibile',
} as any);
const panel1 = new TestPanel('panel1', panelApi);
const panel2 = new TestPanel('panel2', panelApi);
const panel3 = new TestPanel('panel3', panelApi);
groupview.model.openPanel(panel1);
groupview.model.openPanel(panel2);
@ -495,15 +506,9 @@ describe('dockviewGroupPanelModel', () => {
});
test('closeAllPanels with panels', () => {
const panel1 = new TestPanel('panel1', {
renderer: 'onlyWhenVisibile',
} as any);
const panel2 = new TestPanel('panel2', {
renderer: 'onlyWhenVisibile',
} as any);
const panel3 = new TestPanel('panel3', {
renderer: 'onlyWhenVisibile',
} as any);
const panel1 = new TestPanel('panel1', panelApi);
const panel2 = new TestPanel('panel2', panelApi);
const panel3 = new TestPanel('panel3', panelApi);
groupview.model.openPanel(panel1);
groupview.model.openPanel(panel2);
@ -608,25 +613,19 @@ describe('dockviewGroupPanelModel', () => {
.getElementsByClassName('content-container')
.item(0)!.childNodes;
const panel1 = new TestPanel('id_1', {
renderer: 'onlyWhenVisibile',
} as any);
const panel1 = new TestPanel('id_1', panelApi);
cut.openPanel(panel1);
expect(contentContainer.length).toBe(1);
expect(contentContainer.item(0)).toBe(panel1.view.content.element);
const panel2 = new TestPanel('id_2', {
renderer: 'onlyWhenVisibile',
} as any);
const panel2 = new TestPanel('id_2', panelApi);
cut.openPanel(panel2);
expect(contentContainer.length).toBe(1);
expect(contentContainer.item(0)).toBe(panel2.view.content.element);
const panel3 = new TestPanel('id_2', {
renderer: 'onlyWhenVisibile',
} as any);
const panel3 = new TestPanel('id_2', panelApi);
cut.openPanel(panel3, { skipSetActive: true });
expect(contentContainer.length).toBe(1);
@ -834,11 +833,7 @@ describe('dockviewGroupPanelModel', () => {
new groupPanelMock() as DockviewGroupPanel
);
cut.openPanel(
new TestPanel('panel1', {
renderer: 'onlyWhenVisibile',
} as any)
);
cut.openPanel(new TestPanel('panel1', panelApi));
const element = container
.getElementsByClassName('content-container')
@ -908,16 +903,8 @@ describe('dockviewGroupPanelModel', () => {
new groupPanelMock() as DockviewGroupPanel
);
cut.openPanel(
new TestPanel('panel1', {
renderer: 'onlyWhenVisibile',
} as any)
);
cut.openPanel(
new TestPanel('panel2', {
renderer: 'onlyWhenVisibile',
} as any)
);
cut.openPanel(new TestPanel('panel1', panelApi));
cut.openPanel(new TestPanel('panel2', panelApi));
const element = container
.getElementsByClassName('content-container')
@ -987,16 +974,8 @@ describe('dockviewGroupPanelModel', () => {
new groupPanelMock() as DockviewGroupPanel
);
cut.openPanel(
new TestPanel('panel1', {
renderer: 'onlyWhenVisibile',
} as any)
);
cut.openPanel(
new TestPanel('panel2', {
renderer: 'onlyWhenVisibile',
} as any)
);
cut.openPanel(new TestPanel('panel1', panelApi));
cut.openPanel(new TestPanel('panel2', panelApi));
const element = container
.getElementsByClassName('content-container')
@ -1097,11 +1076,7 @@ describe('dockviewGroupPanelModel', () => {
container.getElementsByClassName('watermark-test-container').length
).toBe(1);
cut.openPanel(
new TestPanel('panel1', {
renderer: 'onlyWhenVisibile',
} as any)
);
cut.openPanel(new TestPanel('panel1', panelApi));
expect(
container.getElementsByClassName('watermark-test-container').length
@ -1111,11 +1086,7 @@ describe('dockviewGroupPanelModel', () => {
.length
).toBe(1);
cut.openPanel(
new TestPanel('panel2', {
renderer: 'onlyWhenVisibile',
} as any)
);
cut.openPanel(new TestPanel('panel2', panelApi));
expect(
container.getElementsByClassName('watermark-test-container').length
@ -1133,11 +1104,7 @@ describe('dockviewGroupPanelModel', () => {
container.getElementsByClassName('watermark-test-container').length
).toBe(1);
cut.openPanel(
new TestPanel('panel1', {
renderer: 'onlyWhenVisibile',
} as any)
);
cut.openPanel(new TestPanel('panel1', panelApi));
expect(
container.getElementsByClassName('watermark-test-container').length

View File

@ -37,6 +37,7 @@ export interface DockviewPanelApi
readonly title: string | undefined;
readonly onDidActiveGroupChange: Event<ActiveGroupEvent>;
readonly onDidGroupChange: Event<GroupChangedEvent>;
readonly onDidTitleChange: Event<TitleEvent>;
readonly onDidRendererChange: Event<RendererChangedEvent>;
readonly location: DockviewGroupLocation;
readonly onDidLocationChange: Event<DockviewGroupPanelFloatingChangeEvent>;

View File

@ -24,6 +24,7 @@ export interface PanelApi {
readonly onDidFocusChange: Event<FocusEvent>;
readonly onDidVisibilityChange: Event<VisibilityEvent>;
readonly onDidActiveChange: Event<ActiveEvent>;
readonly onDidParametersChange: Event<Parameters>;
setActive(): void;
setVisible(isVisible: boolean): void;
updateParameters(parameters: Parameters): void;
@ -53,6 +54,8 @@ export interface PanelApi {
readonly height: number;
readonly onWillFocus: Event<WillFocusEvent>;
getParameters<T extends Parameters = Parameters>(): T;
}
export class WillFocusEvent extends DockviewEvent {
@ -70,6 +73,7 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
private _isVisible = true;
private _width = 0;
private _height = 0;
private _parameters: Parameters = {};
private readonly panelUpdatesDisposable = new MutableDisposable();
@ -97,9 +101,9 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
readonly _onActiveChange = new Emitter<void>();
readonly onActiveChange: Event<void> = this._onActiveChange.event;
readonly _onUpdateParameters = new Emitter<Parameters>();
readonly onUpdateParameters: Event<Parameters> =
this._onUpdateParameters.event;
readonly _onDidParametersChange = new Emitter<Parameters>();
readonly onDidParametersChange: Event<Parameters> =
this._onDidParametersChange.event;
get isFocused(): boolean {
return this._isFocused;
@ -145,16 +149,20 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
this._onDidActiveChange,
this._onWillFocus,
this._onActiveChange,
this._onUpdateParameters,
this._onWillFocus,
this._onWillVisibilityChange,
this._onUpdateParameters
this._onDidParametersChange
);
}
getParameters<T extends Parameters = Parameters>(): T {
return this._parameters as T;
}
public initialize(panel: IPanel): void {
this.panelUpdatesDisposable.value = this._onUpdateParameters.event(
this.panelUpdatesDisposable.value = this._onDidParametersChange.event(
(parameters) => {
this._parameters = parameters;
panel.update({
params: parameters,
});
@ -171,6 +179,6 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
}
updateParameters(parameters: Parameters): void {
this._onUpdateParameters.fire(parameters);
this._onDidParametersChange.fire(parameters);
}
}

View File

@ -65,6 +65,7 @@ import {
OverlayRenderContainer,
} from '../overlayRenderContainer';
import { PopoutWindow } from '../popoutWindow';
import { TitleEvent } from '../api/dockviewPanelApi';
const DEFAULT_ROOT_OVERLAY_MODEL: DroptargetOverlayModel = {
activationSize: { type: 'pixels', value: 10 },
@ -2175,6 +2176,12 @@ export class DockviewComponent
if (this._onDidActivePanelChange.value !== event.panel) {
this._onDidActivePanelChange.fire(event.panel);
}
}),
Event.any(
view.model.onDidPanelTitleChange,
view.model.onDidPanelParametersChange
)(() => {
this._bufferOnDidLayoutChange.fire();
})
);

View File

@ -11,8 +11,13 @@ import {
IDockviewEvent,
} from '../events';
import { IViewSize } from '../gridview/gridview';
import { CompositeDisposable } from '../lifecycle';
import { IPanel, PanelInitParameters, PanelUpdateEvent } from '../panel/types';
import { CompositeDisposable, IDisposable } from '../lifecycle';
import {
IPanel,
PanelInitParameters,
PanelUpdateEvent,
Parameters,
} from '../panel/types';
import {
ContentContainer,
IContentContainer,
@ -28,6 +33,7 @@ import { DockviewGroupPanel } from './dockviewGroupPanel';
import { IDockviewPanel } from './dockviewPanel';
import { IHeaderActionsRenderer } from './options';
import { OverlayRenderContainer } from '../overlayRenderContainer';
import { TitleEvent } from '../api/dockviewPanelApi';
interface GroupMoveEvent {
groupId: string;
@ -245,6 +251,7 @@ export class DockviewGroupPanelModel
private _height = 0;
private _panels: IDockviewPanel[] = [];
private readonly _panelDisposables = new Map<string, IDisposable>();
private readonly _onMove = new Emitter<GroupMoveEvent>();
readonly onMove: Event<GroupMoveEvent> = this._onMove.event;
@ -271,6 +278,14 @@ export class DockviewGroupPanelModel
readonly onDidAddPanel: Event<DockviewGroupChangeEvent> =
this._onDidAddPanel.event;
private readonly _onDidPanelTitleChange = new Emitter<TitleEvent>();
readonly onDidPanelTitleChange: Event<TitleEvent> =
this._onDidPanelTitleChange.event;
private readonly _onDidPanelParametersChange = new Emitter<Parameters>();
readonly onDidPanelParametersChange: Event<Parameters> =
this._onDidPanelParametersChange.event;
private readonly _onDidRemovePanel =
new Emitter<DockviewGroupChangeEvent>();
readonly onDidRemovePanel: Event<DockviewGroupChangeEvent> =
@ -826,6 +841,12 @@ export class DockviewGroupPanelModel
);
}
const disposable = this._panelDisposables.get(panel.id);
if (disposable) {
disposable.dispose();
this._panelDisposables.delete(panel.id);
}
this._onDidRemovePanel.fire({ panel });
}
@ -856,6 +877,18 @@ export class DockviewGroupPanelModel
this.updateMru(panel);
this.panels.splice(index, 0, panel);
this._panelDisposables.set(
panel.id,
new CompositeDisposable(
panel.api.onDidTitleChange((event) =>
this._onDidPanelTitleChange.fire(event)
),
panel.api.onDidParametersChange((event) =>
this._onDidPanelParametersChange.fire(event)
)
)
);
this._onDidAddPanel.fire({ panel });
}