diff --git a/src/behaviours/tray/clicking-tray-menu-item-originating-from-extension.test.ts b/src/behaviours/tray/clicking-tray-menu-item-originating-from-extension.test.ts index 006760f902..31556a4b7d 100644 --- a/src/behaviours/tray/clicking-tray-menu-item-originating-from-extension.test.ts +++ b/src/behaviours/tray/clicking-tray-menu-item-originating-from-extension.test.ts @@ -8,6 +8,7 @@ import type { ApplicationBuilder } from "../../renderer/components/test-utils/ge import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import loggerInjectable from "../../common/logger.injectable"; import type { Logger } from "../../common/logger"; +import getRandomIdInjectable from "../../common/utils/get-random-id.injectable"; describe("clicking tray menu item originating from extension", () => { let applicationBuilder: ApplicationBuilder; @@ -20,6 +21,7 @@ describe("clicking tray menu item originating from extension", () => { logErrorMock = jest.fn(); mainDi.override(loggerInjectable, () => ({ error: logErrorMock }) as unknown as Logger); + mainDi.override(getRandomIdInjectable, () => () => "some-random-id"); }); await applicationBuilder.render(); @@ -42,7 +44,7 @@ describe("clicking tray menu item originating from extension", () => { it("when item is clicked, triggers the click handler", () => { applicationBuilder.tray.click( - "some-label-tray-menu-item-for-extension-some-extension-id", + "some-random-id-tray-menu-item-for-extension-some-extension-id", ); expect(clickMock).toHaveBeenCalled(); @@ -55,13 +57,13 @@ describe("clicking tray menu item originating from extension", () => { }); applicationBuilder.tray.click( - "some-label-tray-menu-item-for-extension-some-extension-id", + "some-random-id-tray-menu-item-for-extension-some-extension-id", ); }); it("logs the error", () => { expect(logErrorMock).toHaveBeenCalledWith( - '[TRAY]: Clicking of tray item "some-label" from extension "some-extension-id" failed.', + '[TRAY]: Clicking of tray item "some-random-id" from extension "some-extension-id" failed.', expect.any(Error), ); }); @@ -72,13 +74,13 @@ describe("clicking tray menu item originating from extension", () => { clickMock.mockImplementation(() => Promise.reject("some-rejection")); applicationBuilder.tray.click( - "some-label-tray-menu-item-for-extension-some-extension-id", + "some-random-id-tray-menu-item-for-extension-some-extension-id", ); }); it("logs the error", () => { expect(logErrorMock).toHaveBeenCalledWith( - '[TRAY]: Clicking of tray item "some-label" from extension "some-extension-id" failed.', + '[TRAY]: Clicking of tray item "some-random-id" from extension "some-extension-id" failed.', "some-rejection", ); }); @@ -92,7 +94,7 @@ describe("clicking tray menu item originating from extension", () => { it("does not have the tray menu item from extension", () => { expect( applicationBuilder.tray.get( - "some-label-tray-menu-item-for-extension-some-extension-id", + "some-random-id-tray-menu-item-for-extension-some-extension-id", ), ).toBeNull(); }); @@ -103,7 +105,7 @@ describe("clicking tray menu item originating from extension", () => { expect( applicationBuilder.tray.get( - "some-label-tray-menu-item-for-extension-some-extension-id", + "some-random-id-tray-menu-item-for-extension-some-extension-id", ), ).not.toBeNull(); }); diff --git a/src/behaviours/tray/extension-adding-tray-items.test.tsx b/src/behaviours/tray/extension-adding-tray-items.test.tsx index 35e09e0f76..5d9004ba5e 100644 --- a/src/behaviours/tray/extension-adding-tray-items.test.tsx +++ b/src/behaviours/tray/extension-adding-tray-items.test.tsx @@ -13,6 +13,7 @@ describe("preferences: extension adding tray items", () => { let builder: ApplicationBuilder; let someObservableForVisibility: IObservableValue; let someObservableForEnabled: IObservableValue; + let someObservableLabel: IObservableValue; beforeEach(async () => { builder = getApplicationBuilder(); @@ -25,6 +26,7 @@ describe("preferences: extension adding tray items", () => { someObservableForVisibility = observable.box(false); someObservableForEnabled = observable.box(false); + someObservableLabel = observable.box("Some label"); const testExtension = getExtensionFake({ id: "some-extension-id", @@ -33,38 +35,51 @@ describe("preferences: extension adding tray items", () => { mainOptions: { trayMenus: [ { + id: "some-controlled-visibility", label: "some-controlled-visibility", click: () => {}, visible: computed(() => someObservableForVisibility.get()), }, { + id: "some-uncontrolled-visibility", label: "some-uncontrolled-visibility", click: () => {}, }, { + id: "some-controlled-enabled", label: "some-controlled-enabled", click: () => {}, enabled: computed(() => someObservableForEnabled.get()), }, { + id: "some-uncontrolled-enabled", label: "some-uncontrolled-enabled", click: () => {}, }, { + id: "some-statically-enabled", label: "some-statically-enabled", click: () => {}, enabled: true, }, { + id: "some-statically-disabled", label: "some-statically-disabled", click: () => {}, enabled: false, }, + + { + id: "some-item-with-controlled-label", + label: computed(() => someObservableLabel.get()), + click: () => {}, + enabled: true, + }, ], }, }); @@ -72,6 +87,37 @@ describe("preferences: extension adding tray items", () => { builder.extensions.enable(testExtension); }); + describe("given controlled label", () => { + it("has the label", () => { + const item = builder.tray.get( + "some-item-with-controlled-label-tray-menu-item-for-extension-some-extension", + ); + + expect(item?.label).toBe("Some label"); + }); + + it("when label changes, updates the label", () => { + runInAction(() => { + someObservableLabel.set("Some new label"); + }); + + const item = builder.tray.get( + "some-item-with-controlled-label-tray-menu-item-for-extension-some-extension", + ); + + expect(item?.label).toBe("Some new label"); + + }); + }); + + it("given item is statically disabled, item is disabled", () => { + const item = builder.tray.get( + "some-statically-disabled-tray-menu-item-for-extension-some-extension", + ); + + expect(item?.enabled).toBe(false); + }); + it("shows item which doesn't control the visibility", () => { expect( builder.tray.get( diff --git a/src/main/tray/tray-menu-item/tray-menu-item-registrator.injectable.ts b/src/main/tray/tray-menu-item/tray-menu-item-registrator.injectable.ts index 136f869b8f..f1ebe7885d 100644 --- a/src/main/tray/tray-menu-item/tray-menu-item-registrator.injectable.ts +++ b/src/main/tray/tray-menu-item/tray-menu-item-registrator.injectable.ts @@ -3,7 +3,6 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { pipeline } from "@ogre-tools/fp"; -import { kebabCase } from "lodash/fp"; import type { Injectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable"; import { computed } from "mobx"; @@ -16,7 +15,7 @@ import { withErrorSuppression } from "../../../common/utils/with-error-suppressi import type { WithErrorLoggingFor } from "../../../common/utils/with-error-logging/with-error-logging.injectable"; import withErrorLoggingInjectable from "../../../common/utils/with-error-logging/with-error-logging.injectable"; import getRandomIdInjectable from "../../../common/utils/get-random-id.injectable"; -import { isBoolean } from "../../../common/utils"; +import { isBoolean, isString } from "../../../common/utils"; const trayMenuItemRegistratorInjectable = getInjectable({ id: "tray-menu-item-registrator", @@ -38,7 +37,7 @@ export default trayMenuItemRegistratorInjectable; const toItemInjectablesFor = (extension: LensMainExtension, withErrorLoggingFor: WithErrorLoggingFor, getRandomId: () => string) => { const _toItemInjectables = (parentId: string | null) => (registration: TrayMenuRegistration): Injectable[] => { - const trayItemId = registration.id || kebabCase(registration.label || getRandomId()); + const trayItemId = registration.id || getRandomId(); const id = `${trayItemId}-tray-menu-item-for-extension-${extension.sanitizedExtensionId}`; const parentInjectable = getInjectable({ @@ -51,7 +50,18 @@ const toItemInjectablesFor = (extension: LensMainExtension, withErrorLoggingFor: separator: registration.type === "separator", - label: computed(() => registration.label || ""), + label: computed(() => { + if (!registration.label) { + return ""; + } + + if (isString(registration.label)) { + return registration.label; + } + + return registration.label.get(); + }), + tooltip: registration.toolTip, click: () => { diff --git a/src/main/tray/tray-menu-registration.ts b/src/main/tray/tray-menu-registration.ts index c192dd89fb..8b316b7b92 100644 --- a/src/main/tray/tray-menu-registration.ts +++ b/src/main/tray/tray-menu-registration.ts @@ -6,7 +6,7 @@ import type { IComputedValue } from "mobx"; export interface TrayMenuRegistration { - label?: string; + label?: string | IComputedValue; click?: (menuItem: TrayMenuRegistration) => void; id?: string; type?: "normal" | "separator" | "submenu";