[PM-6382] Migrate disableContextMenuItem to Autofill Settings state (#8246)
* add enableContextMenu to autofillSettings and migrate disableContextMenuItem * replace usages of disableContextMenuItem with autofill settings service global enableContextMenu
This commit is contained in:
parent
4cd8b07ea3
commit
f90de62adc
|
@ -1,6 +1,8 @@
|
||||||
import { mock, MockProxy } from "jest-mock-extended";
|
import { mock, MockProxy } from "jest-mock-extended";
|
||||||
|
import { of } from "rxjs";
|
||||||
|
|
||||||
import { NOOP_COMMAND_SUFFIX } from "@bitwarden/common/autofill/constants";
|
import { NOOP_COMMAND_SUFFIX } from "@bitwarden/common/autofill/constants";
|
||||||
|
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
|
@ -13,6 +15,7 @@ import { MainContextMenuHandler } from "./main-context-menu-handler";
|
||||||
|
|
||||||
describe("context-menu", () => {
|
describe("context-menu", () => {
|
||||||
let stateService: MockProxy<BrowserStateService>;
|
let stateService: MockProxy<BrowserStateService>;
|
||||||
|
let autofillSettingsService: MockProxy<AutofillSettingsServiceAbstraction>;
|
||||||
let i18nService: MockProxy<I18nService>;
|
let i18nService: MockProxy<I18nService>;
|
||||||
let logService: MockProxy<LogService>;
|
let logService: MockProxy<LogService>;
|
||||||
|
|
||||||
|
@ -26,6 +29,7 @@ describe("context-menu", () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
stateService = mock();
|
stateService = mock();
|
||||||
|
autofillSettingsService = mock();
|
||||||
i18nService = mock();
|
i18nService = mock();
|
||||||
logService = mock();
|
logService = mock();
|
||||||
|
|
||||||
|
@ -41,14 +45,20 @@ describe("context-menu", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
i18nService.t.mockImplementation((key) => key);
|
i18nService.t.mockImplementation((key) => key);
|
||||||
sut = new MainContextMenuHandler(stateService, i18nService, logService);
|
sut = new MainContextMenuHandler(
|
||||||
|
stateService,
|
||||||
|
autofillSettingsService,
|
||||||
|
i18nService,
|
||||||
|
logService,
|
||||||
|
);
|
||||||
|
autofillSettingsService.enableContextMenu$ = of(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => jest.resetAllMocks());
|
afterEach(() => jest.resetAllMocks());
|
||||||
|
|
||||||
describe("init", () => {
|
describe("init", () => {
|
||||||
it("has menu disabled", async () => {
|
it("has menu disabled", async () => {
|
||||||
stateService.getDisableContextMenuItem.mockResolvedValue(true);
|
autofillSettingsService.enableContextMenu$ = of(false);
|
||||||
|
|
||||||
const createdMenu = await sut.init();
|
const createdMenu = await sut.init();
|
||||||
expect(createdMenu).toBeFalsy();
|
expect(createdMenu).toBeFalsy();
|
||||||
|
@ -56,8 +66,6 @@ describe("context-menu", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("has menu enabled, but does not have premium", async () => {
|
it("has menu enabled, but does not have premium", async () => {
|
||||||
stateService.getDisableContextMenuItem.mockResolvedValue(false);
|
|
||||||
|
|
||||||
stateService.getCanAccessPremium.mockResolvedValue(false);
|
stateService.getCanAccessPremium.mockResolvedValue(false);
|
||||||
|
|
||||||
const createdMenu = await sut.init();
|
const createdMenu = await sut.init();
|
||||||
|
@ -66,8 +74,6 @@ describe("context-menu", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("has menu enabled and has premium", async () => {
|
it("has menu enabled and has premium", async () => {
|
||||||
stateService.getDisableContextMenuItem.mockResolvedValue(false);
|
|
||||||
|
|
||||||
stateService.getCanAccessPremium.mockResolvedValue(true);
|
stateService.getCanAccessPremium.mockResolvedValue(true);
|
||||||
|
|
||||||
const createdMenu = await sut.init();
|
const createdMenu = await sut.init();
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AUTOFILL_CARD_ID,
|
AUTOFILL_CARD_ID,
|
||||||
AUTOFILL_ID,
|
AUTOFILL_ID,
|
||||||
|
@ -14,6 +16,7 @@ import {
|
||||||
ROOT_ID,
|
ROOT_ID,
|
||||||
SEPARATOR_ID,
|
SEPARATOR_ID,
|
||||||
} from "@bitwarden/common/autofill/constants";
|
} from "@bitwarden/common/autofill/constants";
|
||||||
|
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
|
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
|
||||||
|
@ -22,6 +25,7 @@ import { GlobalState } from "@bitwarden/common/platform/models/domain/global-sta
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
|
|
||||||
|
import { autofillSettingsServiceFactory } from "../../autofill/background/service_factories/autofill-settings-service.factory";
|
||||||
import { Account } from "../../models/account";
|
import { Account } from "../../models/account";
|
||||||
import { CachedServices } from "../../platform/background/service-factories/factory-options";
|
import { CachedServices } from "../../platform/background/service-factories/factory-options";
|
||||||
import {
|
import {
|
||||||
|
@ -156,6 +160,7 @@ export class MainContextMenuHandler {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private stateService: BrowserStateService,
|
private stateService: BrowserStateService,
|
||||||
|
private autofillSettingsService: AutofillSettingsServiceAbstraction,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
) {}
|
) {}
|
||||||
|
@ -183,6 +188,7 @@ export class MainContextMenuHandler {
|
||||||
|
|
||||||
return new MainContextMenuHandler(
|
return new MainContextMenuHandler(
|
||||||
await stateServiceFactory(cachedServices, serviceOptions),
|
await stateServiceFactory(cachedServices, serviceOptions),
|
||||||
|
await autofillSettingsServiceFactory(cachedServices, serviceOptions),
|
||||||
await i18nServiceFactory(cachedServices, serviceOptions),
|
await i18nServiceFactory(cachedServices, serviceOptions),
|
||||||
await logServiceFactory(cachedServices, serviceOptions),
|
await logServiceFactory(cachedServices, serviceOptions),
|
||||||
);
|
);
|
||||||
|
@ -193,8 +199,8 @@ export class MainContextMenuHandler {
|
||||||
* @returns a boolean showing whether or not items were created
|
* @returns a boolean showing whether or not items were created
|
||||||
*/
|
*/
|
||||||
async init(): Promise<boolean> {
|
async init(): Promise<boolean> {
|
||||||
const menuDisabled = await this.stateService.getDisableContextMenuItem();
|
const menuEnabled = await firstValueFrom(this.autofillSettingsService.enableContextMenu$);
|
||||||
if (menuDisabled) {
|
if (!menuEnabled) {
|
||||||
await MainContextMenuHandler.removeAll();
|
await MainContextMenuHandler.removeAll();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -950,6 +950,7 @@ export default class MainBackground {
|
||||||
if (!this.popupOnlyContext) {
|
if (!this.popupOnlyContext) {
|
||||||
this.mainContextMenuHandler = new MainContextMenuHandler(
|
this.mainContextMenuHandler = new MainContextMenuHandler(
|
||||||
this.stateService,
|
this.stateService,
|
||||||
|
this.autofillSettingsService,
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.logService,
|
this.logService,
|
||||||
);
|
);
|
||||||
|
|
|
@ -105,7 +105,9 @@ export class OptionsComponent implements OnInit {
|
||||||
this.userNotificationSettingsService.enableChangedPasswordPrompt$,
|
this.userNotificationSettingsService.enableChangedPasswordPrompt$,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.enableContextMenuItem = !(await this.stateService.getDisableContextMenuItem());
|
this.enableContextMenuItem = await firstValueFrom(
|
||||||
|
this.autofillSettingsService.enableContextMenu$,
|
||||||
|
);
|
||||||
|
|
||||||
this.showCardsCurrentTab = !(await this.stateService.getDontShowCardsCurrentTab());
|
this.showCardsCurrentTab = !(await this.stateService.getDontShowCardsCurrentTab());
|
||||||
this.showIdentitiesCurrentTab = !(await this.stateService.getDontShowIdentitiesCurrentTab());
|
this.showIdentitiesCurrentTab = !(await this.stateService.getDontShowIdentitiesCurrentTab());
|
||||||
|
@ -143,7 +145,7 @@ export class OptionsComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateContextMenuItem() {
|
async updateContextMenuItem() {
|
||||||
await this.stateService.setDisableContextMenuItem(!this.enableContextMenuItem);
|
await this.autofillSettingsService.setEnableContextMenu(this.enableContextMenuItem);
|
||||||
this.messagingService.send("bgUpdateContextMenu");
|
this.messagingService.send("bgUpdateContextMenu");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,10 @@ const INLINE_MENU_VISIBILITY = new KeyDefinition(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const ENABLE_CONTEXT_MENU = new KeyDefinition(AUTOFILL_SETTINGS_DISK, "enableContextMenu", {
|
||||||
|
deserializer: (value: boolean) => value ?? true,
|
||||||
|
});
|
||||||
|
|
||||||
const CLEAR_CLIPBOARD_DELAY = new KeyDefinition(
|
const CLEAR_CLIPBOARD_DELAY = new KeyDefinition(
|
||||||
AUTOFILL_SETTINGS_DISK_LOCAL,
|
AUTOFILL_SETTINGS_DISK_LOCAL,
|
||||||
"clearClipboardDelay",
|
"clearClipboardDelay",
|
||||||
|
@ -75,6 +79,8 @@ export abstract class AutofillSettingsServiceAbstraction {
|
||||||
setAutoCopyTotp: (newValue: boolean) => Promise<void>;
|
setAutoCopyTotp: (newValue: boolean) => Promise<void>;
|
||||||
inlineMenuVisibility$: Observable<InlineMenuVisibilitySetting>;
|
inlineMenuVisibility$: Observable<InlineMenuVisibilitySetting>;
|
||||||
setInlineMenuVisibility: (newValue: InlineMenuVisibilitySetting) => Promise<void>;
|
setInlineMenuVisibility: (newValue: InlineMenuVisibilitySetting) => Promise<void>;
|
||||||
|
enableContextMenu$: Observable<boolean>;
|
||||||
|
setEnableContextMenu: (newValue: boolean) => Promise<void>;
|
||||||
clearClipboardDelay$: Observable<ClearClipboardDelaySetting>;
|
clearClipboardDelay$: Observable<ClearClipboardDelaySetting>;
|
||||||
setClearClipboardDelay: (newValue: ClearClipboardDelaySetting) => Promise<void>;
|
setClearClipboardDelay: (newValue: ClearClipboardDelaySetting) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
@ -100,6 +106,9 @@ export class AutofillSettingsService implements AutofillSettingsServiceAbstracti
|
||||||
private inlineMenuVisibilityState: GlobalState<InlineMenuVisibilitySetting>;
|
private inlineMenuVisibilityState: GlobalState<InlineMenuVisibilitySetting>;
|
||||||
readonly inlineMenuVisibility$: Observable<InlineMenuVisibilitySetting>;
|
readonly inlineMenuVisibility$: Observable<InlineMenuVisibilitySetting>;
|
||||||
|
|
||||||
|
private enableContextMenuState: GlobalState<boolean>;
|
||||||
|
readonly enableContextMenu$: Observable<boolean>;
|
||||||
|
|
||||||
private clearClipboardDelayState: ActiveUserState<ClearClipboardDelaySetting>;
|
private clearClipboardDelayState: ActiveUserState<ClearClipboardDelaySetting>;
|
||||||
readonly clearClipboardDelay$: Observable<ClearClipboardDelaySetting>;
|
readonly clearClipboardDelay$: Observable<ClearClipboardDelaySetting>;
|
||||||
|
|
||||||
|
@ -142,6 +151,9 @@ export class AutofillSettingsService implements AutofillSettingsServiceAbstracti
|
||||||
map((x) => x ?? AutofillOverlayVisibility.Off),
|
map((x) => x ?? AutofillOverlayVisibility.Off),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.enableContextMenuState = this.stateProvider.getGlobal(ENABLE_CONTEXT_MENU);
|
||||||
|
this.enableContextMenu$ = this.enableContextMenuState.state$.pipe(map((x) => x ?? true));
|
||||||
|
|
||||||
this.clearClipboardDelayState = this.stateProvider.getActive(CLEAR_CLIPBOARD_DELAY);
|
this.clearClipboardDelayState = this.stateProvider.getActive(CLEAR_CLIPBOARD_DELAY);
|
||||||
this.clearClipboardDelay$ = this.clearClipboardDelayState.state$.pipe(
|
this.clearClipboardDelay$ = this.clearClipboardDelayState.state$.pipe(
|
||||||
map((x) => x ?? ClearClipboardDelay.Never),
|
map((x) => x ?? ClearClipboardDelay.Never),
|
||||||
|
@ -172,6 +184,10 @@ export class AutofillSettingsService implements AutofillSettingsServiceAbstracti
|
||||||
await this.inlineMenuVisibilityState.update(() => newValue);
|
await this.inlineMenuVisibilityState.update(() => newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setEnableContextMenu(newValue: boolean): Promise<void> {
|
||||||
|
await this.enableContextMenuState.update(() => newValue);
|
||||||
|
}
|
||||||
|
|
||||||
async setClearClipboardDelay(newValue: ClearClipboardDelaySetting): Promise<void> {
|
async setClearClipboardDelay(newValue: ClearClipboardDelaySetting): Promise<void> {
|
||||||
await this.clearClipboardDelayState.update(() => newValue);
|
await this.clearClipboardDelayState.update(() => newValue);
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,8 +189,6 @@ export abstract class StateService<T extends Account = Account> {
|
||||||
setDecryptedSends: (value: SendView[], options?: StorageOptions) => Promise<void>;
|
setDecryptedSends: (value: SendView[], options?: StorageOptions) => Promise<void>;
|
||||||
getDefaultUriMatch: (options?: StorageOptions) => Promise<UriMatchType>;
|
getDefaultUriMatch: (options?: StorageOptions) => Promise<UriMatchType>;
|
||||||
setDefaultUriMatch: (value: UriMatchType, options?: StorageOptions) => Promise<void>;
|
setDefaultUriMatch: (value: UriMatchType, options?: StorageOptions) => Promise<void>;
|
||||||
getDisableContextMenuItem: (options?: StorageOptions) => Promise<boolean>;
|
|
||||||
setDisableContextMenuItem: (value: boolean, options?: StorageOptions) => Promise<void>;
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Do not call this, use SettingsService
|
* @deprecated Do not call this, use SettingsService
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -26,6 +26,5 @@ export class GlobalState {
|
||||||
enableBrowserIntegrationFingerprint?: boolean;
|
enableBrowserIntegrationFingerprint?: boolean;
|
||||||
enableDuckDuckGoBrowserIntegration?: boolean;
|
enableDuckDuckGoBrowserIntegration?: boolean;
|
||||||
neverDomains?: { [id: string]: unknown };
|
neverDomains?: { [id: string]: unknown };
|
||||||
disableContextMenuItem?: boolean;
|
|
||||||
deepLinkRedirectUrl?: string;
|
deepLinkRedirectUrl?: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -832,24 +832,6 @@ export class StateService<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDisableContextMenuItem(options?: StorageOptions): Promise<boolean> {
|
|
||||||
return (
|
|
||||||
(await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions())))
|
|
||||||
?.disableContextMenuItem ?? false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async setDisableContextMenuItem(value: boolean, options?: StorageOptions): Promise<void> {
|
|
||||||
const globals = await this.getGlobals(
|
|
||||||
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
|
||||||
);
|
|
||||||
globals.disableContextMenuItem = value;
|
|
||||||
await this.saveGlobals(
|
|
||||||
globals,
|
|
||||||
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getDisableFavicon(options?: StorageOptions): Promise<boolean> {
|
async getDisableFavicon(options?: StorageOptions): Promise<boolean> {
|
||||||
return (
|
return (
|
||||||
(
|
(
|
||||||
|
|
|
@ -26,6 +26,7 @@ import { MoveBiometricUnlockToStateProviders } from "./migrations/28-move-biomet
|
||||||
import { UserNotificationSettingsKeyMigrator } from "./migrations/29-move-user-notification-settings-to-state-provider";
|
import { UserNotificationSettingsKeyMigrator } from "./migrations/29-move-user-notification-settings-to-state-provider";
|
||||||
import { FixPremiumMigrator } from "./migrations/3-fix-premium";
|
import { FixPremiumMigrator } from "./migrations/3-fix-premium";
|
||||||
import { PolicyMigrator } from "./migrations/30-move-policy-state-to-state-provider";
|
import { PolicyMigrator } from "./migrations/30-move-policy-state-to-state-provider";
|
||||||
|
import { EnableContextMenuMigrator } from "./migrations/31-move-enable-context-menu-to-autofill-settings-state-provider";
|
||||||
import { RemoveEverBeenUnlockedMigrator } from "./migrations/4-remove-ever-been-unlocked";
|
import { RemoveEverBeenUnlockedMigrator } from "./migrations/4-remove-ever-been-unlocked";
|
||||||
import { AddKeyTypeToOrgKeysMigrator } from "./migrations/5-add-key-type-to-org-keys";
|
import { AddKeyTypeToOrgKeysMigrator } from "./migrations/5-add-key-type-to-org-keys";
|
||||||
import { RemoveLegacyEtmKeyMigrator } from "./migrations/6-remove-legacy-etm-key";
|
import { RemoveLegacyEtmKeyMigrator } from "./migrations/6-remove-legacy-etm-key";
|
||||||
|
@ -35,7 +36,7 @@ import { MoveBrowserSettingsToGlobal } from "./migrations/9-move-browser-setting
|
||||||
import { MinVersionMigrator } from "./migrations/min-version";
|
import { MinVersionMigrator } from "./migrations/min-version";
|
||||||
|
|
||||||
export const MIN_VERSION = 2;
|
export const MIN_VERSION = 2;
|
||||||
export const CURRENT_VERSION = 30;
|
export const CURRENT_VERSION = 31;
|
||||||
export type MinVersion = typeof MIN_VERSION;
|
export type MinVersion = typeof MIN_VERSION;
|
||||||
|
|
||||||
export function createMigrationBuilder() {
|
export function createMigrationBuilder() {
|
||||||
|
@ -68,7 +69,8 @@ export function createMigrationBuilder() {
|
||||||
.with(BadgeSettingsMigrator, 26, 27)
|
.with(BadgeSettingsMigrator, 26, 27)
|
||||||
.with(MoveBiometricUnlockToStateProviders, 27, 28)
|
.with(MoveBiometricUnlockToStateProviders, 27, 28)
|
||||||
.with(UserNotificationSettingsKeyMigrator, 28, 29)
|
.with(UserNotificationSettingsKeyMigrator, 28, 29)
|
||||||
.with(PolicyMigrator, 29, CURRENT_VERSION);
|
.with(PolicyMigrator, 29, 30)
|
||||||
|
.with(EnableContextMenuMigrator, 30, CURRENT_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function currentVersion(
|
export async function currentVersion(
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
import { any, MockProxy } from "jest-mock-extended";
|
||||||
|
|
||||||
|
import { KeyDefinitionLike, MigrationHelper } from "../migration-helper";
|
||||||
|
import { mockMigrationHelper } from "../migration-helper.spec";
|
||||||
|
|
||||||
|
import { EnableContextMenuMigrator } from "./31-move-enable-context-menu-to-autofill-settings-state-provider";
|
||||||
|
|
||||||
|
function exampleJSON() {
|
||||||
|
return {
|
||||||
|
global: {
|
||||||
|
disableContextMenuItem: true,
|
||||||
|
otherStuff: "otherStuff1",
|
||||||
|
},
|
||||||
|
otherStuff: "otherStuff2",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function rollbackJSON() {
|
||||||
|
return {
|
||||||
|
global_autofillSettings_enableContextMenu: false,
|
||||||
|
global: {
|
||||||
|
otherStuff: "otherStuff1",
|
||||||
|
},
|
||||||
|
otherStuff: "otherStuff2",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const enableContextMenuKeyDefinition: KeyDefinitionLike = {
|
||||||
|
stateDefinition: {
|
||||||
|
name: "autofillSettings",
|
||||||
|
},
|
||||||
|
key: "enableContextMenu",
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("EnableContextMenuMigrator", () => {
|
||||||
|
let helper: MockProxy<MigrationHelper>;
|
||||||
|
let sut: EnableContextMenuMigrator;
|
||||||
|
|
||||||
|
describe("migrate", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
helper = mockMigrationHelper(exampleJSON(), 30);
|
||||||
|
sut = new EnableContextMenuMigrator(30, 31);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should remove global disableContextMenuItem setting", async () => {
|
||||||
|
await sut.migrate(helper);
|
||||||
|
|
||||||
|
expect(helper.set).toHaveBeenCalledTimes(1);
|
||||||
|
expect(helper.set).toHaveBeenCalledWith("global", {
|
||||||
|
otherStuff: "otherStuff1",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set enableContextMenu globally", async () => {
|
||||||
|
await sut.migrate(helper);
|
||||||
|
|
||||||
|
expect(helper.setToGlobal).toHaveBeenCalledTimes(1);
|
||||||
|
expect(helper.setToGlobal).toHaveBeenCalledWith(enableContextMenuKeyDefinition, false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("rollback", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
helper = mockMigrationHelper(rollbackJSON(), 31);
|
||||||
|
sut = new EnableContextMenuMigrator(30, 31);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should null out new enableContextMenu global value", async () => {
|
||||||
|
await sut.rollback(helper);
|
||||||
|
|
||||||
|
expect(helper.setToGlobal).toHaveBeenCalledTimes(1);
|
||||||
|
expect(helper.setToGlobal).toHaveBeenCalledWith(enableContextMenuKeyDefinition, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should add disableContextMenuItem global value back", async () => {
|
||||||
|
await sut.rollback(helper);
|
||||||
|
|
||||||
|
expect(helper.set).toHaveBeenCalledTimes(1);
|
||||||
|
expect(helper.set).toHaveBeenCalledWith("global", {
|
||||||
|
disableContextMenuItem: true,
|
||||||
|
otherStuff: "otherStuff1",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not try to restore values to missing accounts", async () => {
|
||||||
|
await sut.rollback(helper);
|
||||||
|
|
||||||
|
expect(helper.set).not.toHaveBeenCalledWith("user-3", any());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { KeyDefinitionLike, MigrationHelper } from "../migration-helper";
|
||||||
|
import { Migrator } from "../migrator";
|
||||||
|
|
||||||
|
type ExpectedGlobalState = {
|
||||||
|
disableContextMenuItem?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const enableContextMenuKeyDefinition: KeyDefinitionLike = {
|
||||||
|
stateDefinition: {
|
||||||
|
name: "autofillSettings",
|
||||||
|
},
|
||||||
|
key: "enableContextMenu",
|
||||||
|
};
|
||||||
|
|
||||||
|
export class EnableContextMenuMigrator extends Migrator<30, 31> {
|
||||||
|
async migrate(helper: MigrationHelper): Promise<void> {
|
||||||
|
const globalState = await helper.get<ExpectedGlobalState>("global");
|
||||||
|
|
||||||
|
// disableContextMenuItem -> enableContextMenu
|
||||||
|
if (globalState?.disableContextMenuItem != null) {
|
||||||
|
await helper.setToGlobal(enableContextMenuKeyDefinition, !globalState.disableContextMenuItem);
|
||||||
|
|
||||||
|
// delete `disableContextMenuItem` from state global
|
||||||
|
delete globalState.disableContextMenuItem;
|
||||||
|
|
||||||
|
await helper.set<ExpectedGlobalState>("global", globalState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async rollback(helper: MigrationHelper): Promise<void> {
|
||||||
|
const globalState = (await helper.get<ExpectedGlobalState>("global")) || {};
|
||||||
|
|
||||||
|
const enableContextMenu: boolean = await helper.getFromGlobal(enableContextMenuKeyDefinition);
|
||||||
|
|
||||||
|
// enableContextMenu -> disableContextMenuItem
|
||||||
|
if (enableContextMenu != null) {
|
||||||
|
await helper.set<ExpectedGlobalState>("global", {
|
||||||
|
...globalState,
|
||||||
|
disableContextMenuItem: !enableContextMenu,
|
||||||
|
});
|
||||||
|
|
||||||
|
// remove the global state provider framework key for `enableContextMenu`
|
||||||
|
await helper.setToGlobal(enableContextMenuKeyDefinition, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue