clean up events
This commit is contained in:
parent
da6123dfa1
commit
900ab0d01c
|
@ -9,6 +9,7 @@ import { ExtHostContext, IExtHostEditorTabsShape, IExtHostContext, MainContext,
|
|||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { EditorResourceAccessor, IUntypedEditorInput, SideBySideEditor } from 'vs/workbench/common/editor';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import { isGroupEditorCloseEvent, isGroupEditorMoveEvent, isGroupEditorOpenEvent } from 'vs/workbench/common/editor/editorGroupModel';
|
||||
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
|
||||
import { columnToEditorGroup, EditorGroupColumn, editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
|
||||
|
@ -105,7 +106,7 @@ export class MainThreadEditorTabs {
|
|||
}
|
||||
|
||||
private _onDidTabOpen(event: IEditorsChangeEvent): void {
|
||||
if (event.kind !== GroupChangeKind.EDITOR_OPEN || !event.editor || event.editorIndex === undefined) {
|
||||
if (!isGroupEditorOpenEvent(event)) {
|
||||
return;
|
||||
}
|
||||
if (!this._tabModel.has(event.groupId)) {
|
||||
|
@ -124,7 +125,7 @@ export class MainThreadEditorTabs {
|
|||
}
|
||||
|
||||
private _onDidTabClose(event: IEditorsChangeEvent): void {
|
||||
if (event.kind !== GroupChangeKind.EDITOR_CLOSE || event.editorIndex === undefined) {
|
||||
if (!isGroupEditorCloseEvent(event)) {
|
||||
return;
|
||||
}
|
||||
this._tabModel.get(event.groupId)?.splice(event.editorIndex, 1);
|
||||
|
@ -137,7 +138,7 @@ export class MainThreadEditorTabs {
|
|||
}
|
||||
|
||||
private _onDidTabMove(event: IEditorsChangeEvent): void {
|
||||
if (event.kind !== GroupChangeKind.EDITOR_MOVE || event.editorIndex === undefined || event.oldEditorIndex === undefined) {
|
||||
if (!isGroupEditorMoveEvent(event)) {
|
||||
return;
|
||||
}
|
||||
const movedTab = this._tabModel.get(event.groupId)?.splice(event.oldEditorIndex, 1);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/editorgroupview';
|
||||
import { EditorGroupModel, GroupChangeKind, IEditorOpenOptions, IGroupChangeEvent, ISerializedEditorGroupModel, isSerializedEditorGroupModel } from 'vs/workbench/common/editor/editorGroupModel';
|
||||
import { EditorGroupModel, GroupChangeKind, IEditorOpenOptions, IGroupChangeEvent, IGroupEditorCloseEvent, IGroupEditorMoveEvent, IGroupEditorOpenEvent, ISerializedEditorGroupModel, isGroupEditorCloseEvent, isGroupEditorMoveEvent, isGroupEditorOpenEvent, isSerializedEditorGroupModel } from 'vs/workbench/common/editor/editorGroupModel';
|
||||
import { GroupIdentifier, CloseDirection, IEditorCloseEvent, ActiveEditorDirtyContext, IEditorPane, EditorGroupEditorsCountContext, SaveReason, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditorPane, ActiveEditorStickyContext, ActiveEditorPinnedContext, EditorResourceAccessor, EditorInputCapabilities, IUntypedEditorInput, DEFAULT_EDITOR_ASSOCIATION, ActiveEditorGroupLockedContext, SideBySideEditor, EditorCloseContext, IEditorWillMoveEvent, IEditorWillOpenEvent } from 'vs/workbench/common/editor';
|
||||
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
|
||||
|
@ -559,18 +559,18 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
this.onDidChangeEditorSticky(e.editor);
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_MOVE:
|
||||
if (e.oldEditorIndex !== undefined && e.editorIndex !== undefined) {
|
||||
if (isGroupEditorMoveEvent(e)) {
|
||||
this.onDidMoveEditor(e.editor, e.oldEditorIndex, e.editorIndex);
|
||||
}
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_OPEN:
|
||||
if (e.editorIndex !== undefined) {
|
||||
if (isGroupEditorOpenEvent(e)) {
|
||||
this.onDidOpenEditor(e.editor, e.editorIndex);
|
||||
}
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_CLOSE:
|
||||
if (e.editorIndex !== undefined && e.closeContext !== undefined && e.closedSticky !== undefined) {
|
||||
this.handleOnDidCloseEditor(e.editor, e.editorIndex, e.closeContext, e.closedSticky);
|
||||
if (isGroupEditorCloseEvent(e)) {
|
||||
this.handleOnDidCloseEditor(e.editor, e.editorIndex, e.context, e.sticky);
|
||||
}
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_WILL_DISPOSE:
|
||||
|
@ -601,7 +601,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
}
|
||||
|
||||
private onDidMoveEditor(editor: EditorInput, oldEditorIndex: number, editorIndex: number): void {
|
||||
this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_MOVE, editor, oldEditorIndex, editorIndex });
|
||||
const event: IGroupEditorMoveEvent = { kind: GroupChangeKind.EDITOR_MOVE, editor, oldEditorIndex, editorIndex };
|
||||
this._onDidGroupChange.fire(event);
|
||||
}
|
||||
|
||||
private onDidOpenEditor(editor: EditorInput, editorIndex: number): void {
|
||||
|
@ -619,7 +620,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
this.updateContainer();
|
||||
|
||||
// Event
|
||||
this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_OPEN, editor, editorIndex });
|
||||
const event: IGroupEditorOpenEvent = { kind: GroupChangeKind.EDITOR_OPEN, editor, editorIndex };
|
||||
this._onDidGroupChange.fire(event);
|
||||
}
|
||||
|
||||
private handleOnDidCloseEditor(editor: EditorInput, editorIndex: number, context: EditorCloseContext, sticky: boolean): void {
|
||||
|
@ -659,7 +661,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
|
||||
// Event
|
||||
this._onDidCloseEditor.fire({ groupId: this.id, editor, context, index: editorIndex, sticky });
|
||||
this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_CLOSE, editor, editorIndex });
|
||||
const event: IGroupEditorCloseEvent = { kind: GroupChangeKind.EDITOR_CLOSE, editor, editorIndex, context, sticky };
|
||||
this._onDidGroupChange.fire(event);
|
||||
}
|
||||
|
||||
private canDispose(editor: EditorInput): boolean {
|
||||
|
@ -1487,7 +1490,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
// Update model
|
||||
let index: number | undefined = undefined;
|
||||
if (editorToClose) {
|
||||
index = this.model.closeEditor(editorToClose, internalOptions?.context)?.index;
|
||||
index = this.model.closeEditor(editorToClose, internalOptions?.context)?.editorIndex;
|
||||
}
|
||||
|
||||
// Open next active if there are more to show
|
||||
|
@ -1557,7 +1560,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
private doCloseInactiveEditor(editor: EditorInput, internalOptions?: IInternalEditorCloseOptions): number | undefined {
|
||||
|
||||
// Update model
|
||||
return this.model.closeEditor(editor, internalOptions?.context)?.index;
|
||||
return this.model.closeEditor(editor, internalOptions?.context)?.editorIndex;
|
||||
}
|
||||
|
||||
private async handleDirtyClosing(editors: EditorInput[]): Promise<boolean /* veto */> {
|
||||
|
|
|
@ -102,55 +102,85 @@ export interface IGroupChangeEvent {
|
|||
* access to the editor the event is about.
|
||||
*/
|
||||
readonly editor?: EditorInput;
|
||||
|
||||
/**
|
||||
* Only applies when an editor opens, closes
|
||||
* or is moved. Identifies the index of the
|
||||
* editor in the group.
|
||||
*/
|
||||
readonly editorIndex?: number;
|
||||
|
||||
/**
|
||||
* For `EDITOR_MOVE` only: Signifies the index the
|
||||
* editor is moving from. `editorIndex` will contain
|
||||
* the index the editor is moving to.
|
||||
*/
|
||||
readonly oldEditorIndex?: number;
|
||||
|
||||
/**
|
||||
* For `EDITOR_CLOSE` only: Signifies
|
||||
* the context in which the editor is being closed.
|
||||
* This allows for understanding if a replace or reopen is occuring
|
||||
*/
|
||||
readonly closeContext?: EditorCloseContext;
|
||||
|
||||
/**
|
||||
* For `EDITOR_CLOSE` only: Signifies
|
||||
* whether or not the closed editor was sticky.
|
||||
* This is necessary becasue state is lost after closing.
|
||||
*/
|
||||
readonly closedSticky?: boolean;
|
||||
}
|
||||
|
||||
export interface IGroupEditorMoveEvent extends IGroupChangeEvent {
|
||||
readonly kind: GroupChangeKind.EDITOR_MOVE;
|
||||
export interface IGroupEditorChangeEvent extends IGroupChangeEvent {
|
||||
readonly editor: EditorInput;
|
||||
}
|
||||
|
||||
export interface IGroupEditorOpenEvent extends IGroupEditorChangeEvent {
|
||||
|
||||
readonly kind: GroupChangeKind.EDITOR_OPEN;
|
||||
|
||||
/**
|
||||
* Identifies the index of the editor in the group.
|
||||
*/
|
||||
readonly editorIndex: number;
|
||||
}
|
||||
|
||||
export function isGroupEditorOpenEvent(e: IGroupChangeEvent): e is IGroupEditorOpenEvent {
|
||||
const candidate = e as IGroupEditorOpenEvent;
|
||||
|
||||
return candidate.kind === GroupChangeKind.EDITOR_OPEN && candidate.editorIndex !== undefined;
|
||||
}
|
||||
|
||||
export interface IGroupEditorMoveEvent extends IGroupEditorChangeEvent {
|
||||
|
||||
readonly kind: GroupChangeKind.EDITOR_MOVE;
|
||||
|
||||
/**
|
||||
* Identifies the index of the editor in the group.
|
||||
*/
|
||||
readonly editorIndex: number;
|
||||
|
||||
/**
|
||||
* Signifies the index the editor is moving from.
|
||||
* `editorIndex` will contain the index the editor
|
||||
* is moving to.
|
||||
*/
|
||||
readonly oldEditorIndex: number;
|
||||
}
|
||||
|
||||
export interface IGroupEditorCloseEvent extends IGroupChangeEvent {
|
||||
export function isGroupEditorMoveEvent(e: IGroupChangeEvent): e is IGroupEditorMoveEvent {
|
||||
const candidate = e as IGroupEditorMoveEvent;
|
||||
|
||||
return candidate.kind === GroupChangeKind.EDITOR_MOVE && candidate.editorIndex !== undefined && candidate.oldEditorIndex !== undefined;
|
||||
}
|
||||
|
||||
export interface IGroupEditorCloseEvent extends IGroupEditorChangeEvent {
|
||||
|
||||
readonly kind: GroupChangeKind.EDITOR_CLOSE;
|
||||
readonly editor: EditorInput;
|
||||
|
||||
/**
|
||||
* Identifies the index of the editor in the group.
|
||||
*/
|
||||
readonly editorIndex: number;
|
||||
readonly closeContext: EditorCloseContext;
|
||||
readonly closedSticky: boolean;
|
||||
|
||||
/**
|
||||
* Signifies the context in which the editor
|
||||
* is being closed. This allows for understanding
|
||||
* if a replace or reopen is occuring
|
||||
*/
|
||||
readonly context: EditorCloseContext;
|
||||
|
||||
/**
|
||||
* Signifies whether or not the closed editor was
|
||||
* sticky. This is necessary becasue state is lost
|
||||
* after closing.
|
||||
*/
|
||||
readonly sticky: boolean;
|
||||
}
|
||||
|
||||
export function isGroupEditorCloseEvent(e: IGroupChangeEvent): e is IGroupEditorCloseEvent {
|
||||
const candidate = e as IGroupEditorCloseEvent;
|
||||
|
||||
return candidate.kind === GroupChangeKind.EDITOR_CLOSE && candidate.editorIndex !== undefined && candidate.context !== undefined && candidate.sticky !== undefined;
|
||||
}
|
||||
|
||||
interface IEditorCloseResult {
|
||||
readonly editor: EditorInput;
|
||||
readonly context: EditorCloseContext;
|
||||
readonly index: number;
|
||||
readonly editorIndex: number;
|
||||
readonly sticky: boolean;
|
||||
}
|
||||
|
||||
|
@ -340,11 +370,12 @@ export class EditorGroupModel extends Disposable {
|
|||
this.registerEditorListeners(newEditor);
|
||||
|
||||
// Event
|
||||
this._onDidModelChange.fire({
|
||||
const event: IGroupEditorOpenEvent = {
|
||||
kind: GroupChangeKind.EDITOR_OPEN,
|
||||
editor: newEditor,
|
||||
editorIndex: targetIndex
|
||||
});
|
||||
};
|
||||
this._onDidModelChange.fire(event);
|
||||
|
||||
// Handle active
|
||||
if (makeActive) {
|
||||
|
@ -443,13 +474,11 @@ export class EditorGroupModel extends Disposable {
|
|||
this.splice(replaceIndex, false, replaceWith);
|
||||
|
||||
if (closeResult) {
|
||||
this._onDidModelChange.fire({
|
||||
const event: IGroupEditorCloseEvent = {
|
||||
kind: GroupChangeKind.EDITOR_CLOSE,
|
||||
editor: closeResult.editor,
|
||||
editorIndex: closeResult.index,
|
||||
closeContext: closeResult.context,
|
||||
closedSticky: closeResult.sticky
|
||||
});
|
||||
...closeResult
|
||||
};
|
||||
this._onDidModelChange.fire(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -457,13 +486,11 @@ export class EditorGroupModel extends Disposable {
|
|||
const closeResult = this.doCloseEditor(candidate, context, openNext);
|
||||
|
||||
if (closeResult) {
|
||||
this._onDidModelChange.fire({
|
||||
const event: IGroupEditorCloseEvent = {
|
||||
kind: GroupChangeKind.EDITOR_CLOSE,
|
||||
editor: closeResult.editor,
|
||||
editorIndex: closeResult.index,
|
||||
closeContext: closeResult.context,
|
||||
closedSticky: closeResult.sticky
|
||||
});
|
||||
...closeResult
|
||||
};
|
||||
this._onDidModelChange.fire(event);
|
||||
|
||||
return closeResult;
|
||||
}
|
||||
|
@ -514,7 +541,7 @@ export class EditorGroupModel extends Disposable {
|
|||
this.splice(index, true);
|
||||
|
||||
// Event
|
||||
return { editor, sticky, index, context };
|
||||
return { editor, sticky, editorIndex: index, context };
|
||||
}
|
||||
|
||||
moveEditor(candidate: EditorInput, toIndex: number): EditorInput | undefined {
|
||||
|
@ -548,12 +575,13 @@ export class EditorGroupModel extends Disposable {
|
|||
this.editors.splice(toIndex, 0, editor);
|
||||
|
||||
// Event
|
||||
this._onDidModelChange.fire({
|
||||
const event: IGroupEditorMoveEvent = {
|
||||
kind: GroupChangeKind.EDITOR_MOVE,
|
||||
editor,
|
||||
oldEditorIndex: index,
|
||||
editorIndex: toIndex,
|
||||
});
|
||||
};
|
||||
this._onDidModelChange.fire(event);
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import { ConfirmResult } from 'vs/platform/dialogs/common/dialogs';
|
|||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
|
||||
import { GroupChangeKind, IGroupChangeEvent } from 'vs/workbench/common/editor/editorGroupModel';
|
||||
import { GroupChangeKind, IGroupChangeEvent, IGroupEditorMoveEvent, IGroupEditorOpenEvent } from 'vs/workbench/common/editor/editorGroupModel';
|
||||
|
||||
suite('EditorGroupsService', () => {
|
||||
|
||||
|
@ -455,8 +455,8 @@ suite('EditorGroupsService', () => {
|
|||
assert.strictEqual(group.count, 2);
|
||||
assert.strictEqual(editorCapabilitiesCounter, 0);
|
||||
assert.strictEqual(editorDidOpenCounter, 2);
|
||||
assert.strictEqual(editorOpenEvents[0].editorIndex, 0);
|
||||
assert.strictEqual(editorOpenEvents[1].editorIndex, 1);
|
||||
assert.strictEqual((editorOpenEvents[0] as IGroupEditorOpenEvent).editorIndex, 0);
|
||||
assert.strictEqual((editorOpenEvents[1] as IGroupEditorOpenEvent).editorIndex, 1);
|
||||
assert.strictEqual(editorOpenEvents[0].editor, input);
|
||||
assert.strictEqual(editorOpenEvents[1].editor, inputInactive);
|
||||
assert.strictEqual(activeEditorChangeCounter, 1);
|
||||
|
@ -496,7 +496,7 @@ suite('EditorGroupsService', () => {
|
|||
|
||||
assert.strictEqual(activeEditorChangeCounter, 3);
|
||||
assert.strictEqual(editorCloseCounter, 1);
|
||||
assert.strictEqual(editorCloseEvents[0].editorIndex, 1);
|
||||
assert.strictEqual((editorCloseEvents[0] as IGroupEditorOpenEvent).editorIndex, 1);
|
||||
assert.strictEqual(editorCloseEvents[0].editor, inputInactive);
|
||||
assert.strictEqual(editorCloseCounter1, 1);
|
||||
assert.strictEqual(editorWillCloseCounter, 1);
|
||||
|
@ -953,16 +953,16 @@ suite('EditorGroupsService', () => {
|
|||
assert.strictEqual(group.getEditorByIndex(1), inputInactive);
|
||||
group.moveEditor(inputInactive, group, { index: 0 });
|
||||
assert.strictEqual(moveEvents.length, 1);
|
||||
assert.strictEqual(moveEvents[0].editorIndex, 0);
|
||||
assert.strictEqual(moveEvents[0].oldEditorIndex, 1);
|
||||
assert.strictEqual((moveEvents[0] as IGroupEditorOpenEvent).editorIndex, 0);
|
||||
assert.strictEqual((moveEvents[0] as IGroupEditorMoveEvent).oldEditorIndex, 1);
|
||||
assert.strictEqual(moveEvents[0].editor, inputInactive);
|
||||
assert.strictEqual(group.getEditorByIndex(0), inputInactive);
|
||||
assert.strictEqual(group.getEditorByIndex(1), input);
|
||||
|
||||
group.moveEditors([{ editor: inputInactive, options: { index: 1 } }], group);
|
||||
assert.strictEqual(moveEvents.length, 2);
|
||||
assert.strictEqual(moveEvents[1].editorIndex, 1);
|
||||
assert.strictEqual(moveEvents[1].oldEditorIndex, 0);
|
||||
assert.strictEqual((moveEvents[1] as IGroupEditorOpenEvent).editorIndex, 1);
|
||||
assert.strictEqual((moveEvents[1] as IGroupEditorMoveEvent).oldEditorIndex, 0);
|
||||
assert.strictEqual(moveEvents[1].editor, inputInactive);
|
||||
assert.strictEqual(group.getEditorByIndex(0), input);
|
||||
assert.strictEqual(group.getEditorByIndex(1), inputInactive);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { EditorGroupModel, GroupChangeKind, ISerializedEditorGroupModel } from 'vs/workbench/common/editor/editorGroupModel';
|
||||
import { EditorGroupModel, GroupChangeKind, ISerializedEditorGroupModel, isGroupEditorCloseEvent, isGroupEditorMoveEvent, isGroupEditorOpenEvent } from 'vs/workbench/common/editor/editorGroupModel';
|
||||
import { EditorExtensions, IEditorFactoryRegistry, IFileEditorInput, IEditorSerializer, CloseDirection, EditorsOrder, IResourceDiffEditorInput, IResourceSideBySideEditorInput, SideBySideEditor, EditorCloseContext, IEditorCloseEvent, IEditorOpenEvent, IEditorMoveEvent } from 'vs/workbench/common/editor';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { TestLifecycleService, workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
|
@ -115,13 +115,13 @@ suite('EditorGroupModel', () => {
|
|||
}
|
||||
switch (e.kind) {
|
||||
case GroupChangeKind.EDITOR_OPEN:
|
||||
if (e.editorIndex !== undefined) {
|
||||
if (isGroupEditorOpenEvent(e)) {
|
||||
groupEvents.opened.push({ editor: e.editor, index: e.editorIndex, groupId: group.id });
|
||||
}
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_CLOSE:
|
||||
if (e.editorIndex !== undefined && e.closeContext !== undefined && e.closedSticky !== undefined) {
|
||||
groupEvents.closed.push({ editor: e.editor, index: e.editorIndex, groupId: group.id, context: e.closeContext, sticky: e.closedSticky });
|
||||
if (isGroupEditorCloseEvent(e)) {
|
||||
groupEvents.closed.push({ editor: e.editor, index: e.editorIndex, groupId: group.id, context: e.context, sticky: e.sticky });
|
||||
}
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_ACTIVE:
|
||||
|
@ -134,7 +134,7 @@ suite('EditorGroupModel', () => {
|
|||
group.isSticky(e.editor) ? groupEvents.sticky.push(e.editor) : groupEvents.unsticky.push(e.editor);
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_MOVE:
|
||||
if (e.oldEditorIndex !== undefined && e.editorIndex !== undefined) {
|
||||
if (isGroupEditorMoveEvent(e)) {
|
||||
groupEvents.moved.push({ editor: e.editor, index: e.oldEditorIndex, newIndex: e.editorIndex, target: group.id, groupId: group.id });
|
||||
}
|
||||
break;
|
||||
|
@ -788,7 +788,7 @@ suite('EditorGroupModel', () => {
|
|||
let index = group.indexOf(input1);
|
||||
let event = group.closeEditor(input1, EditorCloseContext.UNPIN);
|
||||
assert.strictEqual(event?.editor, input1);
|
||||
assert.strictEqual(event?.index, index);
|
||||
assert.strictEqual(event?.editorIndex, index);
|
||||
assert.strictEqual(group.count, 0);
|
||||
assert.strictEqual(group.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE).length, 0);
|
||||
assert.strictEqual(group.activeEditor, null);
|
||||
|
|
Loading…
Reference in a new issue