From bf11a482c2ab3a842e289a5b1da2f161c01b6621 Mon Sep 17 00:00:00 2001 From: Iku-turso Date: Wed, 9 Nov 2022 09:09:36 +0200 Subject: [PATCH] Preserve preference URLs (#6501) * Add line breaks for readability of a long warning message Co-authored-by: Janne Savolainen Signed-off-by: Iku-turso * Preserve URLs leading to extension preferences Co-authored-by: Janne Savolainen Signed-off-by: Iku-turso * Tweak variable name for readability Co-authored-by: Janne Savolainen Signed-off-by: Iku-turso Signed-off-by: Iku-turso --- .../urls-of-legacy-extensions.test.tsx.snap | 1695 +++++++++++++++++ ...-route-for-legacy-extensions.injectable.ts | 21 + .../current-preference-tab-id.injectable.ts | 29 +- .../preferences-composite.injectable.ts | 2 +- ...ponent-for-legacy-extensions.injectable.ts | 21 + .../urls-of-legacy-extensions.test.tsx | 330 ++++ 6 files changed, 2094 insertions(+), 4 deletions(-) create mode 100644 src/features/preferences/__snapshots__/urls-of-legacy-extensions.test.tsx.snap create mode 100644 src/features/preferences/common/preferences-route-for-legacy-extensions.injectable.ts create mode 100644 src/features/preferences/renderer/preferences-route-component-for-legacy-extensions.injectable.ts create mode 100644 src/features/preferences/urls-of-legacy-extensions.test.tsx diff --git a/src/features/preferences/__snapshots__/urls-of-legacy-extensions.test.tsx.snap b/src/features/preferences/__snapshots__/urls-of-legacy-extensions.test.tsx.snap new file mode 100644 index 0000000000..05e451bf27 --- /dev/null +++ b/src/features/preferences/__snapshots__/urls-of-legacy-extensions.test.tsx.snap @@ -0,0 +1,1695 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`preferences: URLs of legacy extensions given extension with both custom preference tabs and content for the default tab when navigating to specific custom preference tab using magic string URL renders 1`] = ` + +
+
+
+
+
+ + + home + + +
+
+
+ + + arrow_back + + +
+
+
+ + + arrow_forward + + +
+
+
+
+
+
+
+ +
+
+
+

+ Some title +

+
+
+
+ some-title + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + close + + +
+ +
+
+
+
+
+
+
+
+
+ + + arrow_left + + +
+
+ 0 +
+
+ + + arrow_right + + +
+
+
+
+
+
+
+
+
+ +`; + +exports[`preferences: URLs of legacy extensions given extension with both custom preference tabs and content for the default tab when navigating to unspecified custom preferences tab using magic string URL renders 1`] = ` + +
+
+
+
+
+ + + home + + +
+
+
+ + + arrow_back + + +
+
+
+ + + arrow_forward + + +
+
+
+
+
+
+
+ +
+
+
+

+ some-extension preferences +

+
+
+
+ some-title-in-default-tab + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + close + + +
+ +
+
+
+
+
+
+
+
+
+ + + arrow_left + + +
+
+ 0 +
+
+ + + arrow_right + + +
+
+
+
+
+
+
+
+
+ +`; + +exports[`preferences: URLs of legacy extensions given extension with custom preferences and a custom preference tab when navigating to specific custom preference tab using magic string URL renders 1`] = ` + +
+
+
+
+
+ + + home + + +
+
+
+ + + arrow_back + + +
+
+
+ + + arrow_forward + + +
+
+
+
+
+
+
+ +
+
+
+

+ Some title +

+
+
+
+ some-title + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + close + + +
+ +
+
+
+
+
+
+
+
+
+ + + arrow_left + + +
+
+ 0 +
+
+ + + arrow_right + + +
+
+
+
+
+
+
+
+
+ +`; + +exports[`preferences: URLs of legacy extensions given extension with custom preferences and a custom preference tab when navigating to unspecified custom preferences tab using magic string URL renders 1`] = ` + +
+
+
+
+
+ + + home + + +
+
+
+ + + arrow_back + + +
+
+
+ + + arrow_forward + + +
+
+
+
+
+
+
+ +
+
+
+

+ some-extension preferences +

+
+
+
+
+
+
+ + + close + + +
+ +
+
+
+
+
+
+
+
+
+ + + arrow_left + + +
+
+ 0 +
+
+ + + arrow_right + + +
+
+
+
+
+
+
+
+
+ +`; + +exports[`preferences: URLs of legacy extensions given extension with custom preferences but without a custom preference tab when navigating to the default preference tab using magic string URL renders 1`] = ` + +
+
+
+
+
+ + + home + + +
+
+
+ + + arrow_back + + +
+
+
+ + + arrow_forward + + +
+
+
+
+
+
+
+ +
+
+
+

+ some-extension preferences +

+
+
+
+ some-title + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + close + + +
+ +
+
+
+
+
+
+
+
+
+ + + arrow_left + + +
+
+ 0 +
+
+ + + arrow_right + + +
+
+
+
+
+
+
+
+
+ +`; diff --git a/src/features/preferences/common/preferences-route-for-legacy-extensions.injectable.ts b/src/features/preferences/common/preferences-route-for-legacy-extensions.injectable.ts new file mode 100644 index 0000000000..c1f81953a0 --- /dev/null +++ b/src/features/preferences/common/preferences-route-for-legacy-extensions.injectable.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { computed } from "mobx"; +import { frontEndRouteInjectionToken } from "../../../common/front-end-routing/front-end-route-injection-token"; + +const preferencesRouteForLegacyExtensionsInjectable = getInjectable({ + id: "preferences-route-for-legacy-extensions", + + instantiate: () => ({ + path: "/preferences/extension/:extensionId/:preferenceTabId?", + clusterFrame: false, + isEnabled: computed(() => true), + }), + + injectionToken: frontEndRouteInjectionToken, +}); + +export default preferencesRouteForLegacyExtensionsInjectable; diff --git a/src/features/preferences/renderer/preference-items/current-preference-tab-id.injectable.ts b/src/features/preferences/renderer/preference-items/current-preference-tab-id.injectable.ts index e5c3be9da6..cdac5905a4 100644 --- a/src/features/preferences/renderer/preference-items/current-preference-tab-id.injectable.ts +++ b/src/features/preferences/renderer/preference-items/current-preference-tab-id.injectable.ts @@ -6,21 +6,44 @@ import { getInjectable } from "@ogre-tools/injectable"; import { computed } from "mobx"; import preferencesRouteInjectable from "../../common/preferences-route.injectable"; import routePathParametersInjectable from "../../../../renderer/routes/route-path-parameters.injectable"; +import preferencesRouteForLegacyExtensionsInjectable from "../../common/preferences-route-for-legacy-extensions.injectable"; const currentPreferenceTabIdInjectable = getInjectable({ id: "current-preference-tab-id", instantiate: (di) => { const preferencesRoute = di.inject(preferencesRouteInjectable); + const preferencesRouteForLegacyExtensions = di.inject(preferencesRouteForLegacyExtensionsInjectable); - const routePathParameters = di.inject( + const nonLegacyRoutePathParameters = di.inject( routePathParametersInjectable, preferencesRoute, ); - return computed( - () => routePathParameters.get().preferenceTabId || "app", + const legacyRoutePathParameters = di.inject( + routePathParametersInjectable, + preferencesRouteForLegacyExtensions, ); + + return computed(() => { + const nonLegacyPreferenceTabId = nonLegacyRoutePathParameters.get().preferenceTabId; + + if (nonLegacyPreferenceTabId) { + return nonLegacyPreferenceTabId; + } + + const legacyParameters = legacyRoutePathParameters.get(); + + if (legacyParameters.extensionId) { + if (legacyParameters.preferenceTabId) { + return `extension-${legacyParameters.extensionId}-${legacyParameters.preferenceTabId}`; + } + + return legacyParameters.extensionId; + } + + return "app"; + }); }, }); diff --git a/src/features/preferences/renderer/preference-items/preferences-composite.injectable.ts b/src/features/preferences/renderer/preference-items/preferences-composite.injectable.ts index 45f64d6233..dd1ffd1ed8 100644 --- a/src/features/preferences/renderer/preference-items/preferences-composite.injectable.ts +++ b/src/features/preferences/renderer/preference-items/preferences-composite.injectable.ts @@ -31,7 +31,7 @@ const preferencesCompositeInjectable = getInjectable({ logError( `Tried to create preferences, but encountered references to unknown ids: "${ids.missingParentIds.join( '", "', - )}". Available ids are: "${ids.availableParentIds.join('", "')}"`, + )}".\n\nAvailable ids are:\n\n${ids.availableParentIds.join("\n")}`, ); }, diff --git a/src/features/preferences/renderer/preferences-route-component-for-legacy-extensions.injectable.ts b/src/features/preferences/renderer/preferences-route-component-for-legacy-extensions.injectable.ts new file mode 100644 index 0000000000..981c4b3c84 --- /dev/null +++ b/src/features/preferences/renderer/preferences-route-component-for-legacy-extensions.injectable.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { routeSpecificComponentInjectionToken } from "../../../renderer/routes/route-specific-component-injection-token"; +import preferencesRouteForLegacyExtensions from "../common/preferences-route-for-legacy-extensions.injectable"; +import { Preferences } from "./preferences"; + +const preferencesRouteComponentInjectable = getInjectable({ + id: "preferences-route-component-for-legacy-extensions", + + instantiate: (di) => ({ + route: di.inject(preferencesRouteForLegacyExtensions), + Component: Preferences, + }), + + injectionToken: routeSpecificComponentInjectionToken, +}); + +export default preferencesRouteComponentInjectable; diff --git a/src/features/preferences/urls-of-legacy-extensions.test.tsx b/src/features/preferences/urls-of-legacy-extensions.test.tsx new file mode 100644 index 0000000000..1eba04c683 --- /dev/null +++ b/src/features/preferences/urls-of-legacy-extensions.test.tsx @@ -0,0 +1,330 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import type { RenderResult } from "@testing-library/react"; +import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; +import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; +import type { Discover } from "../../renderer/components/test-utils/discovery-of-html-elements"; +import { discoverFor } from "../../renderer/components/test-utils/discovery-of-html-elements"; +import React from "react"; +import type { Navigate } from "../../renderer/navigation/navigate.injectable"; +import navigateInjectable from "../../renderer/navigation/navigate.injectable"; + +describe("preferences: URLs of legacy extensions", () => { + let builder: ApplicationBuilder; + + beforeEach(() => { + builder = getApplicationBuilder(); + }); + + describe("given extension with custom preferences and a custom preference tab", () => { + let rendered: RenderResult; + let discover: Discover; + let navigate: Navigate; + + beforeEach(async () => { + rendered = await builder.render(); + + discover = discoverFor(() => rendered); + + const testExtension = { + id: "some-extension-id", + name: "some-extension", + + rendererOptions: { + appPreferenceTabs: [ + { + title: "Some title", + id: "some-preference-tab-id", + orderNumber: 1, + }, + + { + title: "Some other title", + id: "some-other-preference-tab-id", + orderNumber: 2, + }, + ], + + appPreferences: [ + { + title: "some-title", + id: "some-preference-item-id", + showInPreferencesTab: "some-preference-tab-id", + + components: { + Hint: () =>
, + Input: () =>
, + }, + }, + + { + title: "some-other-title", + id: "some-other-preference-item-id", + showInPreferencesTab: "some-other-preference-tab-id", + + components: { + Hint: () =>
, + Input: () =>
, + }, + }, + ], + }, + }; + + builder.extensions.enable(testExtension); + + navigate = builder.applicationWindow.only.di.inject(navigateInjectable); + }); + + describe("when navigating to specific custom preference tab using magic string URL", () => { + beforeEach(() => { + navigate("/preferences/extension/some-extension/some-preference-tab-id"); + }); + + it("renders", () => { + expect(rendered.baseElement).toMatchSnapshot(); + }); + + it("shows the custom preference page for the custom preference tab", () => { + const { discovered } = discover.getSingleElement( + "preference-page", + "preference-item-for-extension-some-extension-additional-page-some-preference-tab-id", + ); + + expect(discovered).not.toBeNull(); + }); + + it("shows the custom preferences", () => { + const { discovered } = discover.getSingleElement( + "some-preference", + ); + + expect(discovered).not.toBeNull(); + }); + }); + + describe("when navigating to unspecified custom preferences tab using magic string URL", () => { + beforeEach(() => { + navigate("/preferences/extension/some-extension"); + }); + + it("renders", () => { + expect(rendered.baseElement).toMatchSnapshot(); + }); + + it("cannot find contents of the arbitrary custom preference tabs", () => { + const { discovered } = discover.querySingleElement( + "some-preference", + ); + + expect(discovered).toBeNull(); + }); + + it("shows the empty default preference page for the extension", () => { + const { discovered } = discover.getSingleElement( + "preference-page", + "preference-item-for-extension-some-extension-page", + ); + + expect(discovered).not.toBeNull(); + }); + }); + }); + + describe("given extension with custom preferences but without a custom preference tab", () => { + let rendered: RenderResult; + let discover: Discover; + let navigate: Navigate; + + beforeEach(async () => { + rendered = await builder.render(); + + discover = discoverFor(() => rendered); + + const testExtension = { + id: "some-extension-id", + name: "some-extension", + + rendererOptions: { + appPreferences: [ + { + title: "some-title", + id: "some-preference-item-id", + + components: { + Hint: () =>
, + Input: () =>
, + }, + }, + ], + }, + }; + + builder.extensions.enable(testExtension); + + navigate = builder.applicationWindow.only.di.inject(navigateInjectable); + }); + + describe("when navigating to the default preference tab using magic string URL", () => { + beforeEach(() => { + navigate("/preferences/extension/some-extension"); + }); + + it("renders", () => { + expect(rendered.baseElement).toMatchSnapshot(); + }); + + it("shows the preference page for the custom preferences", () => { + const { discovered } = discover.getSingleElement( + "preference-page", + "preference-item-for-extension-some-extension-page", + ); + + expect(discovered).not.toBeNull(); + }); + + it("shows the custom preferences", () => { + const { discovered } = discover.getSingleElement("some-preference"); + + expect(discovered).not.toBeNull(); + }); + }); + }); + + describe("given extension with both custom preference tabs and content for the default tab", () => { + let rendered: RenderResult; + let discover: Discover; + let navigate: Navigate; + + beforeEach(async () => { + rendered = await builder.render(); + + discover = discoverFor(() => rendered); + + const testExtension = { + id: "some-extension-id", + name: "some-extension", + + rendererOptions: { + appPreferenceTabs: [ + { + title: "Some title", + id: "some-preference-tab-id", + orderNumber: 1, + }, + + { + title: "Some other title", + id: "some-other-preference-tab-id", + orderNumber: 2, + }, + ], + + appPreferences: [ + { + title: "some-title", + id: "some-preference-item-id", + showInPreferencesTab: "some-preference-tab-id", + + components: { + Hint: () =>
, + Input: () =>
, + }, + }, + + { + title: "some-other-title", + id: "some-other-preference-item-id", + showInPreferencesTab: "some-other-preference-tab-id", + + components: { + Hint: () =>
, + Input: () =>
, + }, + }, + + { + title: "some-title-in-default-tab", + id: "some-preference-item-id-in-default-tab", + + components: { + Hint: () =>
, + Input: () =>
, + }, + }, + ], + }, + }; + + builder.extensions.enable(testExtension); + + navigate = builder.applicationWindow.only.di.inject(navigateInjectable); + }); + + describe("when navigating to specific custom preference tab using magic string URL", () => { + beforeEach(() => { + navigate("/preferences/extension/some-extension/some-preference-tab-id"); + }); + + it("renders", () => { + expect(rendered.baseElement).toMatchSnapshot(); + }); + + it("shows the custom preference page for the custom preference tab", () => { + const { discovered } = discover.getSingleElement( + "preference-page", + "preference-item-for-extension-some-extension-additional-page-some-preference-tab-id", + ); + + expect(discovered).not.toBeNull(); + }); + + it("shows the custom preferences", () => { + const { discovered } = discover.getSingleElement( + "some-preference", + ); + + expect(discovered).not.toBeNull(); + }); + }); + + describe("when navigating to unspecified custom preferences tab using magic string URL", () => { + beforeEach(() => { + navigate("/preferences/extension/some-extension"); + }); + + it("renders", () => { + expect(rendered.baseElement).toMatchSnapshot(); + }); + + it("cannot find contents of the arbitrary custom preference tabs", () => { + const { discovered } = discover.querySingleElement( + "some-preference", + "some-preference-in-custom-tab", + ); + + expect(discovered).toBeNull(); + }); + + it("shows the default preference page for the extension", () => { + const { discovered } = discover.getSingleElement( + "preference-page", + "preference-item-for-extension-some-extension-page", + ); + + expect(discovered).not.toBeNull(); + }); + + it("shows preferences of default preference page of the extension", () => { + const { discovered } = discover.getSingleElement( + "some-preference", + "some-preference-in-default-tab", + ); + + expect(discovered).not.toBeNull(); + }); + }); + }); +});