From eb4e4aacc0f1222993e64a05d947807314692eb1 Mon Sep 17 00:00:00 2001 From: Stephanie Roy Date: Tue, 7 Mar 2023 17:28:45 -0500 Subject: [PATCH 1/2] Add command to reset state --- extension/package.json | 5 +++++ extension/src/commands/external.ts | 4 +++- extension/src/extension.ts | 23 +++++++++++++++++++++++ extension/src/telemetry/constants.ts | 2 ++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/extension/package.json b/extension/package.json index 39bbd28e6f..1ab883d9b3 100644 --- a/extension/package.json +++ b/extension/package.json @@ -558,6 +558,11 @@ "command": "dvc.views.plotsPathsTree.refreshPlots", "category": "DVC", "icon": "$(refresh)" + }, + { + "title": "Reset Persisted State and Reload Window", + "command": "dvc.resetState", + "category": "DVC" } ], "configuration": { diff --git a/extension/src/commands/external.ts b/extension/src/commands/external.ts index 5443d9c59a..22155248e7 100644 --- a/extension/src/commands/external.ts +++ b/extension/src/commands/external.ts @@ -101,5 +101,7 @@ export enum RegisteredCommands { ADD_STUDIO_ACCESS_TOKEN = 'dvc.addStudioAccessToken', UPDATE_STUDIO_ACCESS_TOKEN = 'dvc.updateStudioAccessToken', REMOVE_STUDIO_ACCESS_TOKEN = 'dvc.removeStudioAccessToken', - EXPERIMENT_VIEW_SHARE_TO_STUDIO = 'dvc.views.experiments.shareExperimentToStudio' + EXPERIMENT_VIEW_SHARE_TO_STUDIO = 'dvc.views.experiments.shareExperimentToStudio', + + RESET_STATE = 'dvc.resetState' } diff --git a/extension/src/extension.ts b/extension/src/extension.ts index 9c1fd8e3fd..80abc0d726 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -56,6 +56,7 @@ import { LanguageClient } from './languageClient' import { collectRunningExperimentPids } from './experiments/processExecution/collect' import { registerPatchCommand } from './patch' import { DvcViewer } from './cli/dvc/viewer' +import { PersistenceKey } from './persistence/constants' export class Extension extends Disposable { protected readonly internalCommands: InternalCommands @@ -72,6 +73,7 @@ export class Extension extends Disposable { private readonly dvcViewer: DvcViewer private readonly gitExecutor: GitExecutor private readonly gitReader: GitReader + private readonly context: ExtensionContext private updatesPaused: EventEmitter = this.dispose.track( new EventEmitter() @@ -80,6 +82,7 @@ export class Extension extends Disposable { constructor(context: ExtensionContext) { super() + this.context = context const stopWatch = new StopWatch() this.dispose.track(getTelemetryReporter()) @@ -291,6 +294,11 @@ export class Extension extends Disposable { this.dispose.track(recommendRedHatExtensionOnce()) this.dispose.track(new LanguageClient()) + + this.internalCommands.registerExternalCommand( + RegisteredCommands.RESET_STATE, + () => this.resetState() + ) } public async initialize() { @@ -329,6 +337,21 @@ export class Extension extends Disposable { private getRoots() { return this.setup.getRoots() } + + private async resetState() { + const dvcRoots = this.getRoots() + + for (const dvcRoot of dvcRoots) { + for (const persistenceKey of Object.values(PersistenceKey)) { + await this.context.workspaceState.update( + persistenceKey + dvcRoot, + undefined + ) + } + } + + await commands.executeCommand('workbench.action.reloadWindow') + } } let extension: undefined | Extension diff --git a/extension/src/telemetry/constants.ts b/extension/src/telemetry/constants.ts index c6a0a3cb4e..5bde86f186 100644 --- a/extension/src/telemetry/constants.ts +++ b/extension/src/telemetry/constants.ts @@ -289,4 +289,6 @@ export interface IEventNamePropertyMapping { [EventName.ADD_STUDIO_ACCESS_TOKEN]: undefined [EventName.UPDATE_STUDIO_ACCESS_TOKEN]: undefined [EventName.REMOVE_STUDIO_ACCESS_TOKEN]: undefined + + [EventName.RESET_STATE]: undefined } From 225934748c2361b9a556663eea3726e9cfcd6bde Mon Sep 17 00:00:00 2001 From: Stephanie Roy Date: Fri, 10 Mar 2023 13:57:09 -0500 Subject: [PATCH 2/2] Add tests --- extension/src/extension.ts | 26 ++------------ extension/src/persistence/register.ts | 13 +++++++ extension/src/persistence/util.test.ts | 49 ++++++++++++++++++++++++++ extension/src/persistence/util.ts | 9 +++++ extension/src/test/util/index.ts | 8 ++--- 5 files changed, 78 insertions(+), 27 deletions(-) create mode 100644 extension/src/persistence/register.ts create mode 100644 extension/src/persistence/util.test.ts create mode 100644 extension/src/persistence/util.ts diff --git a/extension/src/extension.ts b/extension/src/extension.ts index 80abc0d726..ad29e06aaa 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -56,7 +56,7 @@ import { LanguageClient } from './languageClient' import { collectRunningExperimentPids } from './experiments/processExecution/collect' import { registerPatchCommand } from './patch' import { DvcViewer } from './cli/dvc/viewer' -import { PersistenceKey } from './persistence/constants' +import { registerPersistenceCommands } from './persistence/register' export class Extension extends Disposable { protected readonly internalCommands: InternalCommands @@ -73,7 +73,6 @@ export class Extension extends Disposable { private readonly dvcViewer: DvcViewer private readonly gitExecutor: GitExecutor private readonly gitReader: GitReader - private readonly context: ExtensionContext private updatesPaused: EventEmitter = this.dispose.track( new EventEmitter() @@ -82,7 +81,6 @@ export class Extension extends Disposable { constructor(context: ExtensionContext) { super() - this.context = context const stopWatch = new StopWatch() this.dispose.track(getTelemetryReporter()) @@ -290,15 +288,12 @@ export class Extension extends Disposable { ).contributes.walkthroughs[0].id ) + registerPersistenceCommands(context.workspaceState, this.internalCommands) + void showWalkthroughOnFirstUse(env.isNewAppInstall) this.dispose.track(recommendRedHatExtensionOnce()) this.dispose.track(new LanguageClient()) - - this.internalCommands.registerExternalCommand( - RegisteredCommands.RESET_STATE, - () => this.resetState() - ) } public async initialize() { @@ -337,21 +332,6 @@ export class Extension extends Disposable { private getRoots() { return this.setup.getRoots() } - - private async resetState() { - const dvcRoots = this.getRoots() - - for (const dvcRoot of dvcRoots) { - for (const persistenceKey of Object.values(PersistenceKey)) { - await this.context.workspaceState.update( - persistenceKey + dvcRoot, - undefined - ) - } - } - - await commands.executeCommand('workbench.action.reloadWindow') - } } let extension: undefined | Extension diff --git a/extension/src/persistence/register.ts b/extension/src/persistence/register.ts new file mode 100644 index 0000000000..bde9a7d601 --- /dev/null +++ b/extension/src/persistence/register.ts @@ -0,0 +1,13 @@ +import { Memento } from 'vscode' +import { resetPersistedState } from './util' +import { RegisteredCommands } from '../commands/external' +import { InternalCommands } from '../commands/internal' + +export const registerPersistenceCommands = ( + workspaceState: Memento, + internalCommands: InternalCommands +) => { + internalCommands.registerExternalCommand(RegisteredCommands.RESET_STATE, () => + resetPersistedState(workspaceState) + ) +} diff --git a/extension/src/persistence/util.test.ts b/extension/src/persistence/util.test.ts new file mode 100644 index 0000000000..ca92150bd8 --- /dev/null +++ b/extension/src/persistence/util.test.ts @@ -0,0 +1,49 @@ +import { commands } from 'vscode' +import { PersistenceKey } from './constants' +import { resetPersistedState } from './util' +import { buildMockMemento } from '../test/util' +import { + DEFAULT_HEIGHT, + DEFAULT_SECTION_NB_ITEMS_PER_ROW +} from '../plots/webview/contract' + +jest.mock('vscode') + +const mockedCommands = jest.mocked(commands) +mockedCommands.executeCommand = jest.fn() + +describe('Persistence util', () => { + beforeEach(() => { + jest.resetAllMocks() + }) + + describe('resetPersistedState', () => { + it('should reload the window', async () => { + const workspaceState = buildMockMemento() + + await resetPersistedState(workspaceState) + + expect(mockedCommands.executeCommand).toHaveBeenCalledWith( + 'workbench.action.reloadWindow' + ) + }) + + it('should reset all values from all dvc roots', async () => { + const persistedState = { + [PersistenceKey.PLOT_HEIGHT + 'root1']: DEFAULT_HEIGHT, + [PersistenceKey.PLOT_NB_ITEMS_PER_ROW + 'root2']: + DEFAULT_SECTION_NB_ITEMS_PER_ROW + } + const workspaceState = buildMockMemento(persistedState) + + await resetPersistedState(workspaceState) + + expect( + workspaceState.get(PersistenceKey.PLOT_HEIGHT + 'root1') + ).toBeUndefined() + expect( + workspaceState.get(PersistenceKey.PLOT_NB_ITEMS_PER_ROW + 'root2') + ).toBeUndefined() + }) + }) +}) diff --git a/extension/src/persistence/util.ts b/extension/src/persistence/util.ts new file mode 100644 index 0000000000..089d07ecc6 --- /dev/null +++ b/extension/src/persistence/util.ts @@ -0,0 +1,9 @@ +import { commands, Memento } from 'vscode' + +export const resetPersistedState = async (workspaceState: Memento) => { + for (const persistenceKey of workspaceState.keys()) { + await workspaceState.update(persistenceKey, undefined) + } + + await commands.executeCommand('workbench.action.reloadWindow') +} diff --git a/extension/src/test/util/index.ts b/extension/src/test/util/index.ts index 5354b58a04..a39062a077 100644 --- a/extension/src/test/util/index.ts +++ b/extension/src/test/util/index.ts @@ -16,8 +16,8 @@ export const buildMockMemento = ( ({ get: (key: string, defaultValue: unknown) => values[key] || defaultValue, keys: () => Object.keys(values), - update: (key: string, value: unknown) => - new Promise(() => { - values[key] = value - }) + update: (key: string, value: unknown) => { + values[key] = value + void Promise.resolve() + } } as unknown as Memento)