From 67ac1692b260c0d18be74c878520375c2e324ad4 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 15 Sep 2022 17:20:58 -0400 Subject: [PATCH] Clean up versioning and packageJson uses (#6196) --- package.json | 3 +- src/common/__tests__/cluster-store.test.ts | 4 +- src/common/__tests__/hotbar-store.test.ts | 4 +- src/common/__tests__/user-store.test.ts | 13 +-- src/common/app-paths/app-paths.test.ts | 11 +-- .../default-update-channel.injectable.ts | 6 +- .../selected-update-channel.injectable.ts | 10 +- .../application-update/update-channels.ts | 4 +- src/common/base-store.ts | 4 +- src/common/catalog-entities/web-link.ts | 6 +- ...eporting.global-override-for-injectable.ts | 9 ++ .../initialize-sentry-reporting.injectable.ts | 65 +++++++++++++ ...e-config.global-override-for-injectable.ts | 8 -- .../welcome-route-config.injectable.ts | 8 +- src/common/initializable-state/create.test.ts | 77 +++++++++++++++ src/common/initializable-state/create.ts | 62 +++++++++++++ src/common/k8s/resource-stack.ts | 5 +- src/common/sentry.ts | 67 ------------- src/common/user-store/user-store.ts | 19 +--- src/common/utils/app-version.ts | 9 -- src/common/vars.ts | 12 --- .../vars}/app-name.injectable.ts | 4 +- .../vars/app-semantic-version.injectable.ts | 14 --- src/common/vars/app-version.injectable.ts | 13 --- .../vars/application-copyright.injectable.ts | 13 +++ .../application-description.injectable.ts | 13 +++ ...ormation.global-override-for-injectable.ts | 23 +++++ .../application-information.injectable.ts | 22 +++++ .../vars/build-semantic-version.injectable.ts | 30 ++++++ .../bundled-kubectl-version.injectable.ts | 13 +++ .../content-security-policy.injectable.ts | 13 +++ .../vars/extension-api-version.injectable.ts | 18 ++++ ...-package.global-override-for-injectable.ts | 9 ++ ...table.ts => is-snap-package.injectable.ts} | 9 +- .../vars}/product-name.injectable.ts | 5 +- src/common/vars/release-channel.injectable.ts | 10 +- src/common/vars/sentry-dsn-url.injectable.ts | 13 +++ .../store-migration-version.injectable.ts | 13 +++ .../__tests__/is-compatible-extension.test.ts | 34 +++---- src/extensions/common-api/app.ts | 63 +++++++++++-- src/extensions/common-api/index.ts | 4 +- src/extensions/common-api/user-preferences.ts | 15 +-- src/extensions/common-api/utils.ts | 36 +++++-- .../extension-discovery.injectable.ts | 29 +++--- .../extension-discovery.test.ts | 4 +- .../is-compatible-extension.injectable.ts | 4 +- .../is-compatible-extension.ts | 9 +- ...acters-in-page-registrations.test.tsx.snap | 2 +- .../navigate-to-extension-page.test.tsx.snap | 2 +- ...ation-using-application-menu.test.tsx.snap | 2 +- ...e-since-update-was-downloaded.test.ts.snap | 6 +- ...g-update-using-topbar-button.test.tsx.snap | 4 +- .../installing-update-using-tray.test.ts.snap | 12 +-- .../installing-update.test.ts.snap | 12 +-- ...eriodical-checking-of-updates.test.ts.snap | 2 +- ...selection-of-update-stability.test.ts.snap | 2 +- .../analytics-for-installing-update.test.ts | 4 +- .../downgrading-version-update.test.ts | 4 +- .../selection-of-update-stability.test.ts | 52 ++++------- .../keyboard-shortcuts.test.tsx.snap | 16 ++-- ...gation-using-application-menu.test.ts.snap | 2 +- ...gation-using-application-menu.test.ts.snap | 2 +- .../navigation-using-tray.test.ts.snap | 2 +- ...vigation-to-telemetry-preferences.test.tsx | 6 +- ...-originating-from-extensions.test.tsx.snap | 2 +- ...gation-using-application-menu.test.ts.snap | 4 +- .../app-paths/setup-app-paths.injectable.ts | 2 +- .../check-for-platform-updates.test.ts | 4 +- ...current-version-to-analytics.injectable.ts | 6 +- .../publish-is-configured.injectable.ts | 11 +-- .../build-version/setup-channel.injectable.ts | 23 +++++ ...ron-app.global-override-for-injectable.ts} | 6 +- .../setup-application-name.injectable.ts | 2 +- src/main/getDiForUnitTesting.ts | 9 -- .../kubectl/bundled-kubectl.injectable.ts | 5 +- src/main/kubectl/create-kubectl.injectable.ts | 4 + src/main/kubectl/kubectl.ts | 30 +----- src/main/kubectl/version-map.injectable.ts | 35 +++++++ src/main/lens-proxy/lens-proxy.injectable.ts | 26 ++---- src/main/lens-proxy/lens-proxy.ts | 16 ++-- .../menu/application-menu-items.injectable.ts | 6 +- src/main/menu/build-version.injectable.ts | 13 --- src/main/menu/menu.ts | 26 ------ src/main/menu/show-about.injectable.ts | 41 ++++++-- .../routes/static-file-route.injectable.ts | 93 +++++++++++-------- .../versions/get-version-route.injectable.ts | 22 +++-- src/main/shell-sync.ts | 40 -------- .../create-application-window.injectable.ts | 2 +- ...-on-main.global-override-for-injectable.ts | 9 ++ .../sentry/initialize-on-main.injectable.ts | 14 +++ .../runnables/sentry/setup.injectable.ts | 23 +++++ .../runnables/setup-lens-proxy.injectable.ts | 6 +- .../runnables/setup-sentry.injectable.ts | 24 ----- .../runnables/setup-shell.injectable.ts | 30 +++++- .../electron-tray/electron-tray.injectable.ts | 6 +- .../about-app-tray-item.injectable.ts | 11 +-- .../open-app-tray-item.injectable.ts | 12 +-- .../build-version/build-version.injectable.ts | 19 ++++ .../get-build-version.injectable.ts | 17 ++++ .../vars/build-version/init.injectable.ts | 21 +++++ .../default-update-channel/init.injectable.ts | 23 +++++ .../semantic-build-version/init.injectable.ts | 23 +++++ src/migrations/cluster-store/snap.ts | 5 +- .../weblinks-store/currentVersion.ts | 5 +- src/renderer/bootstrap.tsx | 6 +- ...-preferences-navigation-item.injectable.ts | 6 +- .../+preferences/sentry-dns-url.injectable.ts | 13 --- .../components/+preferences/telemetry.tsx | 4 +- src/renderer/components/+welcome/welcome.tsx | 11 ++- .../components/cluster-prometheus-setting.tsx | 20 +++- src/renderer/getDiForUnitTesting.tsx | 3 - src/renderer/utils/prevDefault.ts | 2 +- .../build-version/build-version.injectable.ts | 19 ++++ .../vars/build-version/init.injectable.ts | 21 +++++ .../default-update-channel/init.injectable.ts | 23 +++++ .../semantic-build-version/init.injectable.ts | 23 +++++ 116 files changed, 1154 insertions(+), 644 deletions(-) create mode 100644 src/common/error-reporting/initialize-sentry-reporting.global-override-for-injectable.ts create mode 100644 src/common/error-reporting/initialize-sentry-reporting.injectable.ts delete mode 100644 src/common/front-end-routing/routes/welcome/welcome-route-config.global-override-for-injectable.ts create mode 100644 src/common/initializable-state/create.test.ts create mode 100644 src/common/initializable-state/create.ts delete mode 100644 src/common/sentry.ts rename src/{main/app-paths/app-name => common/vars}/app-name.injectable.ts (83%) delete mode 100644 src/common/vars/app-semantic-version.injectable.ts delete mode 100644 src/common/vars/app-version.injectable.ts create mode 100644 src/common/vars/application-copyright.injectable.ts create mode 100644 src/common/vars/application-description.injectable.ts create mode 100644 src/common/vars/application-information.global-override-for-injectable.ts create mode 100644 src/common/vars/application-information.injectable.ts create mode 100644 src/common/vars/build-semantic-version.injectable.ts create mode 100644 src/common/vars/bundled-kubectl-version.injectable.ts create mode 100644 src/common/vars/content-security-policy.injectable.ts create mode 100644 src/common/vars/extension-api-version.injectable.ts create mode 100644 src/common/vars/is-snap-package.global-override-for-injectable.ts rename src/common/vars/{package-json.injectable.ts => is-snap-package.injectable.ts} (55%) rename src/{main/app-paths/app-name => common/vars}/product-name.injectable.ts (65%) create mode 100644 src/common/vars/sentry-dsn-url.injectable.ts create mode 100644 src/common/vars/store-migration-version.injectable.ts create mode 100644 src/main/build-version/setup-channel.injectable.ts rename src/main/{menu/build-version.global-override-for-injectable.ts => electron-app/electron-app.global-override-for-injectable.ts} (56%) create mode 100644 src/main/kubectl/version-map.injectable.ts delete mode 100644 src/main/menu/build-version.injectable.ts delete mode 100644 src/main/shell-sync.ts create mode 100644 src/main/start-main-application/runnables/sentry/initialize-on-main.global-override-for-injectable.ts create mode 100644 src/main/start-main-application/runnables/sentry/initialize-on-main.injectable.ts create mode 100644 src/main/start-main-application/runnables/sentry/setup.injectable.ts delete mode 100644 src/main/start-main-application/runnables/setup-sentry.injectable.ts create mode 100644 src/main/vars/build-version/build-version.injectable.ts create mode 100644 src/main/vars/build-version/get-build-version.injectable.ts create mode 100644 src/main/vars/build-version/init.injectable.ts create mode 100644 src/main/vars/default-update-channel/init.injectable.ts create mode 100644 src/main/vars/semantic-build-version/init.injectable.ts delete mode 100644 src/renderer/components/+preferences/sentry-dns-url.injectable.ts create mode 100644 src/renderer/vars/build-version/build-version.injectable.ts create mode 100644 src/renderer/vars/build-version/init.injectable.ts create mode 100644 src/renderer/vars/default-update-channel/init.injectable.ts create mode 100644 src/renderer/vars/semantic-build-version/init.injectable.ts diff --git a/package.json b/package.json index 03d6b34a08..2bc0d9ff26 100644 --- a/package.json +++ b/package.json @@ -208,7 +208,8 @@ "lens" ], "role": "Viewer" - } + }, + "publish": [] }, "resolutions": { "@astronautlabs/jsonpath/underscore": "^1.12.1" diff --git a/src/common/__tests__/cluster-store.test.ts b/src/common/__tests__/cluster-store.test.ts index b74659aea0..2253c7662f 100644 --- a/src/common/__tests__/cluster-store.test.ts +++ b/src/common/__tests__/cluster-store.test.ts @@ -18,13 +18,13 @@ import { createClusterInjectionToken } from "../cluster/create-cluster-injection import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable"; import { getDiForUnitTesting } from "../../main/getDiForUnitTesting"; import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable"; -import appVersionInjectable from "../vars/app-version.injectable"; import assert from "assert"; import directoryForTempInjectable from "../app-paths/directory-for-temp/directory-for-temp.injectable"; import kubectlBinaryNameInjectable from "../../main/kubectl/binary-name.injectable"; import kubectlDownloadingNormalizedArchInjectable from "../../main/kubectl/normalized-arch.injectable"; import normalizedPlatformInjectable from "../vars/normalized-platform.injectable"; import fsInjectable from "../fs/fs.injectable"; +import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable"; console = new Console(stdout, stderr); @@ -372,7 +372,7 @@ users: mockFs(mockOpts); - mainDi.override(appVersionInjectable, () => "3.6.0"); + mainDi.override(storeMigrationVersionInjectable, () => "3.6.0"); createCluster = mainDi.inject(createClusterInjectionToken); diff --git a/src/common/__tests__/hotbar-store.test.ts b/src/common/__tests__/hotbar-store.test.ts index d847ac76dc..0e1b3e27a2 100644 --- a/src/common/__tests__/hotbar-store.test.ts +++ b/src/common/__tests__/hotbar-store.test.ts @@ -8,7 +8,6 @@ import mockFs from "mock-fs"; import type { CatalogEntity, CatalogEntityData, CatalogEntityKindData } from "../catalog"; import { getDiForUnitTesting } from "../../main/getDiForUnitTesting"; import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable"; -import appVersionInjectable from "../vars/app-version.injectable"; import type { DiContainer } from "@ogre-tools/injectable"; import hotbarStoreInjectable from "../hotbars/store.injectable"; import type { HotbarStore } from "../hotbars/store"; @@ -19,6 +18,7 @@ import catalogCatalogEntityInjectable from "../catalog-entities/general-catalog- import loggerInjectable from "../logger.injectable"; import type { Logger } from "../logger"; import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable"; +import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable"; function getMockCatalogEntity(data: Partial & CatalogEntityKindData): CatalogEntity { return { @@ -348,7 +348,7 @@ describe("HotbarStore", () => { mockFs(configurationToBeMigrated); - di.override(appVersionInjectable, () => "5.0.0-beta.10"); + di.override(storeMigrationVersionInjectable, () => "5.0.0-beta.10"); hotbarStore = di.inject(hotbarStoreInjectable); diff --git a/src/common/__tests__/user-store.test.ts b/src/common/__tests__/user-store.test.ts index 23740c5457..e6fa7b4189 100644 --- a/src/common/__tests__/user-store.test.ts +++ b/src/common/__tests__/user-store.test.ts @@ -23,8 +23,6 @@ jest.mock("electron", () => ({ import type { UserStore } from "../user-store"; import { Console } from "console"; -import { SemVer } from "semver"; -import electron from "electron"; import { stdout, stderr } from "process"; import userStoreInjectable from "../user-store/user-store.injectable"; import type { DiContainer } from "@ogre-tools/injectable"; @@ -34,7 +32,7 @@ import { defaultThemeId } from "../vars"; import writeFileInjectable from "../fs/write-file.injectable"; import { getDiForUnitTesting } from "../../main/getDiForUnitTesting"; import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable"; -import appVersionInjectable from "../vars/app-version.injectable"; +import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable"; console = new Console(stdout, stderr); @@ -86,13 +84,6 @@ describe("user store tests", () => { userStore.resetTheme(); expect(userStore.colorTheme).toBe(defaultThemeId); }); - - it("correctly calculates if the last seen version is an old release", () => { - expect(userStore.isNewVersion).toBe(true); - - userStore.lastSeenAppVersion = (new SemVer(electron.app.getVersion())).inc("major").format(); - expect(userStore.isNewVersion).toBe(false); - }); }); describe("migrations", () => { @@ -125,7 +116,7 @@ describe("user store tests", () => { }, }); - di.override(appVersionInjectable, () => "10.0.0"); + di.override(storeMigrationVersionInjectable, () => "10.0.0"); userStore = di.inject(userStoreInjectable); }); diff --git a/src/common/app-paths/app-paths.test.ts b/src/common/app-paths/app-paths.test.ts index b5ec33059c..ff4bd88988 100644 --- a/src/common/app-paths/app-paths.test.ts +++ b/src/common/app-paths/app-paths.test.ts @@ -7,7 +7,6 @@ import { appPathsInjectionToken } from "./app-path-injection-token"; import getElectronAppPathInjectable from "../../main/app-paths/get-electron-app-path/get-electron-app-path.injectable"; import type { PathName } from "./app-path-names"; import setElectronAppPathInjectable from "../../main/app-paths/set-electron-app-path/set-electron-app-path.injectable"; -import appNameInjectable from "../../main/app-paths/app-name/app-name.injectable"; import directoryForIntegrationTestingInjectable from "../../main/app-paths/directory-for-integration-testing/directory-for-integration-testing.injectable"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; @@ -53,8 +52,6 @@ describe("app-paths", () => { defaultAppPathsStub[key] = path; }, ); - - mainDi.override(appNameInjectable, () => "some-app-name"); }); }); @@ -88,7 +85,7 @@ describe("app-paths", () => { recent: "some-recent", temp: "some-temp", videos: "some-videos", - userData: "some-app-data/some-app-name", + userData: "some-app-data/some-product-name", }); }); @@ -111,7 +108,7 @@ describe("app-paths", () => { recent: "some-recent", temp: "some-temp", videos: "some-videos", - userData: "some-app-data/some-app-name", + userData: "some-app-data/some-product-name", }); }); }); @@ -137,7 +134,7 @@ describe("app-paths", () => { expect({ appData, userData }).toEqual({ appData: "some-integration-testing-app-data", - userData: `some-integration-testing-app-data/some-app-name`, + userData: `some-integration-testing-app-data/some-product-name`, }); }); @@ -146,7 +143,7 @@ describe("app-paths", () => { expect({ appData, userData }).toEqual({ appData: "some-integration-testing-app-data", - userData: "some-integration-testing-app-data/some-app-name", + userData: "some-integration-testing-app-data/some-product-name", }); }); }); diff --git a/src/common/application-update/selected-update-channel/default-update-channel.injectable.ts b/src/common/application-update/selected-update-channel/default-update-channel.injectable.ts index 44d7ff364e..ff4fe32e4e 100644 --- a/src/common/application-update/selected-update-channel/default-update-channel.injectable.ts +++ b/src/common/application-update/selected-update-channel/default-update-channel.injectable.ts @@ -2,13 +2,13 @@ * 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 { createInitializableState } from "../../initializable-state/create"; import releaseChannelInjectable from "../../vars/release-channel.injectable"; import { updateChannels } from "../update-channels"; -const defaultUpdateChannelInjectable = getInjectable({ +const defaultUpdateChannelInjectable = createInitializableState({ id: "default-update-channel", - instantiate: (di) => updateChannels[di.inject(releaseChannelInjectable)], + init: (di) => updateChannels[di.inject(releaseChannelInjectable)], }); export default defaultUpdateChannelInjectable; diff --git a/src/common/application-update/selected-update-channel/selected-update-channel.injectable.ts b/src/common/application-update/selected-update-channel/selected-update-channel.injectable.ts index ceb47aee5e..8ca31e00aa 100644 --- a/src/common/application-update/selected-update-channel/selected-update-channel.injectable.ts +++ b/src/common/application-update/selected-update-channel/selected-update-channel.injectable.ts @@ -5,13 +5,13 @@ import { getInjectable } from "@ogre-tools/injectable"; import type { IComputedValue } from "mobx"; import { action, computed, observable } from "mobx"; -import type { UpdateChannel, UpdateChannelId } from "../update-channels"; +import type { UpdateChannel, ReleaseChannel } from "../update-channels"; import { updateChannels } from "../update-channels"; import defaultUpdateChannelInjectable from "./default-update-channel.injectable"; export interface SelectedUpdateChannel { value: IComputedValue; - setValue: (channelId?: UpdateChannelId) => void; + setValue: (channelId?: ReleaseChannel) => void; } const selectedUpdateChannelInjectable = getInjectable({ @@ -19,16 +19,16 @@ const selectedUpdateChannelInjectable = getInjectable({ instantiate: (di): SelectedUpdateChannel => { const defaultUpdateChannel = di.inject(defaultUpdateChannelInjectable); - const state = observable.box(defaultUpdateChannel); + const state = observable.box(); return { - value: computed(() => state.get()), + value: computed(() => state.get() ?? defaultUpdateChannel.get()), setValue: action((channelId) => { const targetUpdateChannel = channelId && updateChannels[channelId] ? updateChannels[channelId] - : defaultUpdateChannel; + : defaultUpdateChannel.get(); state.set(targetUpdateChannel); }), diff --git a/src/common/application-update/update-channels.ts b/src/common/application-update/update-channels.ts index 5d166eabdb..1a38974946 100644 --- a/src/common/application-update/update-channels.ts +++ b/src/common/application-update/update-channels.ts @@ -4,7 +4,7 @@ */ -export type UpdateChannelId = "alpha" | "beta" | "latest"; +export type ReleaseChannel = "alpha" | "beta" | "latest"; const latestChannel: UpdateChannel = { id: "latest", @@ -31,7 +31,7 @@ export const updateChannels = { }; export interface UpdateChannel { - readonly id: UpdateChannelId; + readonly id: ReleaseChannel; readonly label: string; readonly moreStableUpdateChannel: UpdateChannel | null; } diff --git a/src/common/base-store.ts b/src/common/base-store.ts index 2c2f66dd23..92383b328d 100644 --- a/src/common/base-store.ts +++ b/src/common/base-store.ts @@ -19,7 +19,7 @@ import { kebabCase } from "lodash"; import { getLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; import directoryForUserDataInjectable from "./app-paths/directory-for-user-data/directory-for-user-data.injectable"; import getConfigurationFileModelInjectable from "./get-configuration-file-model/get-configuration-file-model.injectable"; -import appVersionInjectable from "./vars/app-version.injectable"; +import storeMigrationVersionInjectable from "./vars/store-migration-version.injectable"; export interface BaseStoreParams extends ConfOptions { syncOptions?: { @@ -60,7 +60,7 @@ export abstract class BaseStore extends Singleton { this.storeConfig = getConfigurationFileModel({ projectName: "lens", - projectVersion: di.inject(appVersionInjectable), + projectVersion: di.inject(storeMigrationVersionInjectable), cwd: this.cwd(), ...this.params, }); diff --git a/src/common/catalog-entities/web-link.ts b/src/common/catalog-entities/web-link.ts index 35dc86be57..dade63af16 100644 --- a/src/common/catalog-entities/web-link.ts +++ b/src/common/catalog-entities/web-link.ts @@ -3,9 +3,10 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ +import { getLegacyGlobalDiForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; import type { CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog"; import { CatalogCategory, CatalogEntity, categoryVersion } from "../catalog/catalog-entity"; -import { productName } from "../vars"; +import productNameInjectable from "../vars/product-name.injectable"; import { WeblinkStore } from "../weblink-store"; export type WebLinkStatusPhase = "available" | "unavailable"; @@ -30,6 +31,9 @@ export class WebLink extends CatalogEntity () => {}); diff --git a/src/common/error-reporting/initialize-sentry-reporting.injectable.ts b/src/common/error-reporting/initialize-sentry-reporting.injectable.ts new file mode 100644 index 0000000000..d34005f374 --- /dev/null +++ b/src/common/error-reporting/initialize-sentry-reporting.injectable.ts @@ -0,0 +1,65 @@ +/** + * 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 type { ElectronMainOptions } from "@sentry/electron/main"; +import type { BrowserOptions } from "@sentry/electron/renderer"; +import isProductionInjectable from "../vars/is-production.injectable"; +import sentryDataSourceNameInjectable from "../vars/sentry-dsn-url.injectable"; +import { Dedupe, Offline } from "@sentry/integrations"; +import { inspect } from "util"; +import userStoreInjectable from "../user-store/user-store.injectable"; + +export type InitializeSentryReportingWith = (initSentry: (opts: BrowserOptions | ElectronMainOptions) => void) => void; + +const mapProcessName = (type: "browser" | "renderer" | "worker") => type === "browser" ? "main" : type; + +const initializeSentryReportingWithInjectable = getInjectable({ + id: "initialize-sentry-reporting-with", + instantiate: (di): InitializeSentryReportingWith => { + const sentryDataSourceName = di.inject(sentryDataSourceNameInjectable); + const isProduction = di.inject(isProductionInjectable); + + if (!sentryDataSourceName) { + return () => {}; + } + + return (initSentry) => initSentry({ + beforeSend: (event) => { + // TODO: remove loading from userStoreInjectable so that this can be moved out + const userStore = di.inject(userStoreInjectable); + + if (userStore.allowErrorReporting) { + return event; + } + + /** + * Directly write to stdout so that no other integrations capture this and create an infinite loop + */ + process.stdout.write(`🔒 [SENTRY-BEFORE-SEND-HOOK]: Sentry event is caught but not sent to server.`); + process.stdout.write("🔒 [SENTRY-BEFORE-SEND-HOOK]: === START OF SENTRY EVENT ==="); + process.stdout.write(inspect(event, false, null, true)); + process.stdout.write("🔒 [SENTRY-BEFORE-SEND-HOOK]: === END OF SENTRY EVENT ==="); + + // if return null, the event won't be sent + // ref https://github.com/getsentry/sentry-javascript/issues/2039 + return null; + }, + dsn: sentryDataSourceName, + integrations: [ + new Dedupe(), + new Offline(), + ], + initialScope: { + tags: { + "process": mapProcessName(process.type), + }, + }, + environment: isProduction ? "production" : "development", + }); + }, + causesSideEffects: true, +}); + +export default initializeSentryReportingWithInjectable; diff --git a/src/common/front-end-routing/routes/welcome/welcome-route-config.global-override-for-injectable.ts b/src/common/front-end-routing/routes/welcome/welcome-route-config.global-override-for-injectable.ts deleted file mode 100644 index 703c0798a2..0000000000 --- a/src/common/front-end-routing/routes/welcome/welcome-route-config.global-override-for-injectable.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getGlobalOverride } from "../../../test-utils/get-global-override"; -import welcomeRouteConfig from "./welcome-route-config.injectable"; - -export default getGlobalOverride(welcomeRouteConfig, () => "/welcome"); diff --git a/src/common/front-end-routing/routes/welcome/welcome-route-config.injectable.ts b/src/common/front-end-routing/routes/welcome/welcome-route-config.injectable.ts index 53a61ab99f..4e16df5bb4 100644 --- a/src/common/front-end-routing/routes/welcome/welcome-route-config.injectable.ts +++ b/src/common/front-end-routing/routes/welcome/welcome-route-config.injectable.ts @@ -3,16 +3,12 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import packageJsonInjectable from "../../../vars/package-json.injectable"; +import applicationInformationInjectable from "../../../vars/application-information.injectable"; const welcomeRouteConfigInjectable = getInjectable({ id: "welcome-route-config", - instantiate: (di) => { - const packageJson = di.inject(packageJsonInjectable); - - return packageJson.config.welcomeRoute; - }, + instantiate: (di) => di.inject(applicationInformationInjectable).config.welcomeRoute, }); export default welcomeRouteConfigInjectable; diff --git a/src/common/initializable-state/create.test.ts b/src/common/initializable-state/create.test.ts new file mode 100644 index 0000000000..38980b0a41 --- /dev/null +++ b/src/common/initializable-state/create.test.ts @@ -0,0 +1,77 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import type { AsyncFnMock } from "@async-fn/jest"; +import asyncFn from "@async-fn/jest"; +import type { DiContainer, Injectable } from "@ogre-tools/injectable"; +import { runInAction } from "mobx"; +import { getDiForUnitTesting } from "../../main/getDiForUnitTesting"; +import type { InitializableState } from "./create"; +import { createInitializableState } from "./create"; + +describe("InitializableState tests", () => { + let di: DiContainer; + + beforeEach(() => { + di = getDiForUnitTesting({ doGeneralOverrides: true }); + }); + + describe("when created", () => { + let stateInjectable: Injectable, unknown, void>; + let initMock: AsyncFnMock<() => number>; + + beforeEach(() => { + initMock = asyncFn(); + stateInjectable = createInitializableState({ + id: "my-state", + init: initMock, + }); + + runInAction(() => { + di.register(stateInjectable); + }); + }); + + describe("when injected", () => { + let state: InitializableState; + + beforeEach(() => { + state = di.inject(stateInjectable); + }); + + it("when get is called, throw", () => { + expect(() => state.get()).toThrowError("InitializableState(my-state) has not been initialized yet"); + }); + + describe("when init is called", () => { + beforeEach(() => { + state.init(); + }); + + it("should call provided initialization function", () => { + expect(initMock).toBeCalled(); + }); + + it("when get is called, throw", () => { + expect(() => state.get()).toThrowError("InitializableState(my-state) has not finished initializing"); + }); + + describe("when initialization resolves", () => { + beforeEach(async () => { + await initMock.resolve(42); + }); + + it("when get is called, returns value", () => { + expect(state.get()).toBe(42); + }); + + it("when init is called again, throws", async () => { + await expect(() => state.init()).rejects.toThrow("Cannot initialize InitializableState(my-state) more than once"); + }); + }); + }); + }); + }); +}); diff --git a/src/common/initializable-state/create.ts b/src/common/initializable-state/create.ts new file mode 100644 index 0000000000..829de57d94 --- /dev/null +++ b/src/common/initializable-state/create.ts @@ -0,0 +1,62 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import type { DiContainerForInjection, Injectable, InjectionToken } from "@ogre-tools/injectable"; +import { getInjectable } from "@ogre-tools/injectable"; + +export interface CreateInitializableStateArgs { + id: string; + init: (di: DiContainerForInjection) => Promise | T; + injectionToken?: InjectionToken, void>; +} + +export interface InitializableState { + get: () => T; + init: () => Promise; +} + +type InitializableStateValue = + | { set: false } + | { set: true; value: T } ; + +export function createInitializableState(args: CreateInitializableStateArgs): Injectable, unknown, void> { + const { id, init, injectionToken } = args; + + return getInjectable({ + id, + instantiate: (di) => { + let box: InitializableStateValue = { + set: false, + }; + let initCalled = false; + + return { + init: async () => { + if (initCalled) { + throw new Error(`Cannot initialize InitializableState(${id}) more than once`); + } + + initCalled = true; + box = { + set: true, + value: await init(di), + }; + }, + get: () => { + if (!initCalled) { + throw new Error(`InitializableState(${id}) has not been initialized yet`); + } + + if (box.set === false) { + throw new Error(`InitializableState(${id}) has not finished initializing`); + } + + return box.value; + }, + }; + }, + injectionToken, + }); +} diff --git a/src/common/k8s/resource-stack.ts b/src/common/k8s/resource-stack.ts index d289a375b3..96ecf2e39c 100644 --- a/src/common/k8s/resource-stack.ts +++ b/src/common/k8s/resource-stack.ts @@ -11,8 +11,9 @@ import logger from "../../main/logger"; import { app } from "electron"; import { ClusterStore } from "../cluster-store/cluster-store"; import yaml from "js-yaml"; -import { productName } from "../vars"; import { requestKubectlApplyAll, requestKubectlDeleteAll } from "../../renderer/ipc"; +import { getLegacyGlobalDiForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; +import productNameInjectable from "../vars/product-name.injectable"; export class ResourceStack { constructor(protected cluster: KubernetesCluster, protected name: string) {} @@ -97,6 +98,8 @@ export class ResourceStack { protected async renderTemplates(folderPath: string, templateContext: any): Promise { const resources: string[] = []; + const di = getLegacyGlobalDiForExtensionApi(); + const productName = di.inject(productNameInjectable); logger.info(`[RESOURCE-STACK]: render templates from ${folderPath}`); const files = await fse.readdir(folderPath); diff --git a/src/common/sentry.ts b/src/common/sentry.ts deleted file mode 100644 index 282afa6f32..0000000000 --- a/src/common/sentry.ts +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { Dedupe, Offline } from "@sentry/integrations"; -import { sentryDsn, isProduction } from "./vars"; -import { UserStore } from "./user-store"; -import { inspect } from "util"; -import type { BrowserOptions } from "@sentry/electron/renderer"; -import type { ElectronMainOptions } from "@sentry/electron/main"; - -/** - * "Translate" 'browser' to 'main' as Lens developer more familiar with the term 'main' - */ -function mapProcessName(processType: string) { - if (processType === "browser") { - return "main"; - } - - return processType; -} - -/** - * Initialize Sentry for the current process so to send errors for debugging. - */ -export function initializeSentryReporting(init: (opts: BrowserOptions | ElectronMainOptions) => void) { - const processName = mapProcessName(process.type); - - if (!sentryDsn) { - return; // do nothing if not configured to avoid uncaught error in dev mode - } - - init({ - beforeSend: (event) => { - // default to false, in case instance of UserStore is not created (yet) - const allowErrorReporting = UserStore.getInstance(false)?.allowErrorReporting ?? false; - - if (allowErrorReporting) { - return event; - } - - /** - * Directly write to stdout so that no other integrations capture this and create an infinite loop - */ - process.stdout.write(`🔒 [SENTRY-BEFORE-SEND-HOOK]: allowErrorReporting: ${allowErrorReporting}. Sentry event is caught but not sent to server.`); - process.stdout.write("🔒 [SENTRY-BEFORE-SEND-HOOK]: === START OF SENTRY EVENT ==="); - process.stdout.write(inspect(event, false, null, true)); - process.stdout.write("🔒 [SENTRY-BEFORE-SEND-HOOK]: === END OF SENTRY EVENT ==="); - - // if return null, the event won't be sent - // ref https://github.com/getsentry/sentry-javascript/issues/2039 - return null; - }, - dsn: sentryDsn, - integrations: [ - new Dedupe(), - new Offline(), - ], - initialScope: { - tags: { - "process": processName, - }, - }, - environment: isProduction ? "production" : "development", - }); -} diff --git a/src/common/user-store/user-store.ts b/src/common/user-store/user-store.ts index b806732735..7457548436 100644 --- a/src/common/user-store/user-store.ts +++ b/src/common/user-store/user-store.ts @@ -4,19 +4,16 @@ */ import { app } from "electron"; -import semver from "semver"; import { action, computed, observable, reaction, makeObservable, isObservableArray, isObservableSet, isObservableMap } from "mobx"; import { BaseStore } from "../base-store"; import migrations from "../../migrations/user-store"; -import { getAppVersion } from "../utils/app-version"; import { kubeConfigDefaultPath } from "../kube-helpers"; -import { appEventBus } from "../app-event-bus/event-bus"; import { getOrInsertSet, toggle, toJS, object } from "../../renderer/utils"; import { DESCRIPTORS } from "./preferences-helpers"; import type { UserPreferencesModel, StoreType } from "./preferences-helpers"; import logger from "../../main/logger"; import type { SelectedUpdateChannel } from "../application-update/selected-update-channel/selected-update-channel.injectable"; -import type { UpdateChannelId } from "../application-update/update-channels"; +import type { ReleaseChannel } from "../application-update/update-channels"; export interface UserStoreModel { lastSeenAppVersion: string; @@ -24,7 +21,7 @@ export interface UserStoreModel { } interface Dependencies { - selectedUpdateChannel: SelectedUpdateChannel; + readonly selectedUpdateChannel: SelectedUpdateChannel; } export class UserStore extends BaseStore /* implements UserStoreFlatModel (when strict null is enabled) */ { @@ -98,10 +95,6 @@ export class UserStore extends BaseStore /* implements UserStore */ @observable syncKubeconfigEntries!: StoreType; - @computed get isNewVersion() { - return semver.gt(getAppVersion(), this.lastSeenAppVersion); - } - @computed get resolvedShell(): string | undefined { return this.shell || process.env.SHELL || process.env.PTYSHELL; } @@ -151,12 +144,6 @@ export class UserStore extends BaseStore /* implements UserStore this.colorTheme = DESCRIPTORS.colorTheme.fromStore(undefined); } - @action - saveLastSeenAppVersion() { - appEventBus.emit({ name: "app", action: "whats-new-seen" }); - this.lastSeenAppVersion = getAppVersion(); - } - @action protected fromStore({ lastSeenAppVersion, preferences }: Partial = {}) { logger.debug("UserStore.fromStore()", { lastSeenAppVersion, preferences }); @@ -180,7 +167,7 @@ export class UserStore extends BaseStore /* implements UserStore // TODO: Switch to action-based saving instead saving stores by reaction if (preferences?.updateChannel) { - this.dependencies.selectedUpdateChannel.setValue(preferences?.updateChannel as UpdateChannelId); + this.dependencies.selectedUpdateChannel.setValue(preferences?.updateChannel as ReleaseChannel); } } diff --git a/src/common/utils/app-version.ts b/src/common/utils/app-version.ts index 28882e092b..183cc3e6b2 100644 --- a/src/common/utils/app-version.ts +++ b/src/common/utils/app-version.ts @@ -4,15 +4,6 @@ */ import requestPromise from "request-promise-native"; -import packageInfo from "../../../package.json"; - -export function getAppVersion(): string { - return packageInfo.version; -} - -export function getBundledKubectlVersion(): string { - return packageInfo.config.bundledKubectlVersion; -} export async function getAppVersionFromProxyServer(proxyPort: number): Promise { const response = await requestPromise({ diff --git a/src/common/vars.ts b/src/common/vars.ts index be8b472a5d..a5507e1ee6 100644 --- a/src/common/vars.ts +++ b/src/common/vars.ts @@ -5,7 +5,6 @@ // App's common configuration for any process (main, renderer, build pipeline, etc.) import path from "path"; -import packageInfo from "../../package.json"; import type { ThemeId } from "../renderer/themes/store"; import { lazyInitialized } from "./utils/lazy-initialized"; @@ -25,7 +24,6 @@ export const isWindows = process.platform === "win32"; export const isLinux = process.platform === "linux"; export const isDebugging = ["true", "1", "yes", "y", "on"].includes((process.env.DEBUG ?? "").toLowerCase()); -export const isSnap = !!process.env.SNAP; /** * @deprecated Switch to using isTestEnvInjectable @@ -42,13 +40,6 @@ export const isProduction = process.env.NODE_ENV === "production"; */ export const isDevelopment = !isTestEnv && !isProduction; -export const productName = packageInfo.productName; - -/** - * @deprecated Switch to using appNameInjectable - */ -export const appName = `${packageInfo.productName}${isDevelopment ? "Dev" : ""}`; - export const publicPath = "/build/" as string; export const defaultThemeId: ThemeId = "lens-dark"; export const defaultFontSize = 12; @@ -139,6 +130,3 @@ export const lensBlogWeblinkId = "lens-blog-link"; export const kubernetesDocumentationWeblinkId = "kubernetes-documentation-link"; export const docsUrl = "https://docs.k8slens.dev/main" as string; - -export const sentryDsn = packageInfo.config?.sentryDsn ?? ""; -export const contentSecurityPolicy = packageInfo.config?.contentSecurityPolicy ?? ""; diff --git a/src/main/app-paths/app-name/app-name.injectable.ts b/src/common/vars/app-name.injectable.ts similarity index 83% rename from src/main/app-paths/app-name/app-name.injectable.ts rename to src/common/vars/app-name.injectable.ts index 0a1db468d8..4d6d87421c 100644 --- a/src/main/app-paths/app-name/app-name.injectable.ts +++ b/src/common/vars/app-name.injectable.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import isDevelopmentInjectable from "../../../common/vars/is-development.injectable"; +import isDevelopmentInjectable from "./is-development.injectable"; import productNameInjectable from "./product-name.injectable"; const appNameInjectable = getInjectable({ @@ -15,8 +15,6 @@ const appNameInjectable = getInjectable({ return `${productName}${isDevelopment ? "Dev" : ""}`; }, - - causesSideEffects: true, }); export default appNameInjectable; diff --git a/src/common/vars/app-semantic-version.injectable.ts b/src/common/vars/app-semantic-version.injectable.ts deleted file mode 100644 index ae68ea828d..0000000000 --- a/src/common/vars/app-semantic-version.injectable.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * 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 { SemVer } from "semver"; -import appVersionInjectable from "./app-version.injectable"; - -const appSemanticVersionInjectable = getInjectable({ - id: "app-semantic-version", - instantiate: (di) => new SemVer(di.inject(appVersionInjectable)), -}); - -export default appSemanticVersionInjectable; diff --git a/src/common/vars/app-version.injectable.ts b/src/common/vars/app-version.injectable.ts deleted file mode 100644 index d7647f8318..0000000000 --- a/src/common/vars/app-version.injectable.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * 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 packageJsonInjectable from "./package-json.injectable"; - -const appVersionInjectable = getInjectable({ - id: "app-version", - instantiate: (di) => di.inject(packageJsonInjectable).version, -}); - -export default appVersionInjectable; diff --git a/src/common/vars/application-copyright.injectable.ts b/src/common/vars/application-copyright.injectable.ts new file mode 100644 index 0000000000..cdac64855c --- /dev/null +++ b/src/common/vars/application-copyright.injectable.ts @@ -0,0 +1,13 @@ +/** + * 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 applicationInformationInjectable from "./application-information.injectable"; + +const applicationCopyrightInjectable = getInjectable({ + id: "application-copyright", + instantiate: (di) => di.inject(applicationInformationInjectable).copyright, +}); + +export default applicationCopyrightInjectable; diff --git a/src/common/vars/application-description.injectable.ts b/src/common/vars/application-description.injectable.ts new file mode 100644 index 0000000000..d6c4c9f79b --- /dev/null +++ b/src/common/vars/application-description.injectable.ts @@ -0,0 +1,13 @@ +/** + * 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 applicationInformationInjectable from "./application-information.injectable"; + +const applicationDescriptionInjectable = getInjectable({ + id: "application-description", + instantiate: (di) => di.inject(applicationInformationInjectable).description, +}); + +export default applicationDescriptionInjectable; diff --git a/src/common/vars/application-information.global-override-for-injectable.ts b/src/common/vars/application-information.global-override-for-injectable.ts new file mode 100644 index 0000000000..ac53b9f341 --- /dev/null +++ b/src/common/vars/application-information.global-override-for-injectable.ts @@ -0,0 +1,23 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { getGlobalOverride } from "../test-utils/get-global-override"; +import applicationInformationInjectable from "./application-information.injectable"; + +export default getGlobalOverride(applicationInformationInjectable, () => ({ + productName: "some-product-name", + version: "6.0.0", + build: {}, + config: { + k8sProxyVersion: "0.2.1", + bundledKubectlVersion: "1.23.3", + bundledHelmVersion: "3.7.2", + sentryDsn: "", + contentSecurityPolicy: "script-src 'unsafe-eval' 'self'; frame-src http://*.localhost:*/; img-src * data:", + welcomeRoute: "/welcome", + }, + copyright: "some-copyright-information", + description: "some-descriptive-text", +})); diff --git a/src/common/vars/application-information.injectable.ts b/src/common/vars/application-information.injectable.ts new file mode 100644 index 0000000000..f3a8c27321 --- /dev/null +++ b/src/common/vars/application-information.injectable.ts @@ -0,0 +1,22 @@ +/** + * 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 packageJson from "../../../package.json"; + +export type ApplicationInformation = Pick & { + build: Partial; +}; + +const applicationInformationInjectable = getInjectable({ + id: "application-information", + instantiate: (): ApplicationInformation => { + const { version, config, productName, build, copyright, description } = packageJson; + + return { version, config, productName, build, copyright, description }; + }, + causesSideEffects: true, +}); + +export default applicationInformationInjectable; diff --git a/src/common/vars/build-semantic-version.injectable.ts b/src/common/vars/build-semantic-version.injectable.ts new file mode 100644 index 0000000000..a41efb0bd7 --- /dev/null +++ b/src/common/vars/build-semantic-version.injectable.ts @@ -0,0 +1,30 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { getInjectionToken } from "@ogre-tools/injectable"; +import { SemVer } from "semver"; +import type { InitializableState } from "../initializable-state/create"; +import { createInitializableState } from "../initializable-state/create"; +import type { RequestChannel } from "../utils/channel/request-channel-injection-token"; + +export const buildVersionInjectionToken = getInjectionToken>({ + id: "build-version-token", +}); + +export const buildVersionChannel: RequestChannel = { + id: "build-version", +}; + +const buildSemanticVersionInjectable = createInitializableState({ + id: "build-semantic-version", + init: (di) => { + const buildVersion = di.inject(buildVersionInjectionToken); + + return new SemVer(buildVersion.get()); + }, +}); + +export default buildSemanticVersionInjectable; + diff --git a/src/common/vars/bundled-kubectl-version.injectable.ts b/src/common/vars/bundled-kubectl-version.injectable.ts new file mode 100644 index 0000000000..9542a79834 --- /dev/null +++ b/src/common/vars/bundled-kubectl-version.injectable.ts @@ -0,0 +1,13 @@ +/** + * 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 applicationInformationInjectable from "./application-information.injectable"; + +const bundledKubectlVersionInjectable = getInjectable({ + id: "bundled-kubectl-version", + instantiate: (di) => di.inject(applicationInformationInjectable).config.bundledKubectlVersion, +}); + +export default bundledKubectlVersionInjectable; diff --git a/src/common/vars/content-security-policy.injectable.ts b/src/common/vars/content-security-policy.injectable.ts new file mode 100644 index 0000000000..b6e1e0eb30 --- /dev/null +++ b/src/common/vars/content-security-policy.injectable.ts @@ -0,0 +1,13 @@ +/** + * 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 applicationInformationInjectable from "./application-information.injectable"; + +const contentSecurityPolicyInjectable = getInjectable({ + id: "content-security-policy", + instantiate: (di) => di.inject(applicationInformationInjectable).config.contentSecurityPolicy, +}); + +export default contentSecurityPolicyInjectable; diff --git a/src/common/vars/extension-api-version.injectable.ts b/src/common/vars/extension-api-version.injectable.ts new file mode 100644 index 0000000000..4f7f4d9930 --- /dev/null +++ b/src/common/vars/extension-api-version.injectable.ts @@ -0,0 +1,18 @@ +/** + * 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 { SemVer } from "semver"; +import applicationInformationInjectable from "./application-information.injectable"; + +const extensionApiVersionInjectable = getInjectable({ + id: "extension-api-version", + instantiate: (di) => { + const { major, minor, patch } = new SemVer(di.inject(applicationInformationInjectable).version); + + return `${major}.${minor}.${patch}`; + }, +}); + +export default extensionApiVersionInjectable; diff --git a/src/common/vars/is-snap-package.global-override-for-injectable.ts b/src/common/vars/is-snap-package.global-override-for-injectable.ts new file mode 100644 index 0000000000..cb3ff0a6e9 --- /dev/null +++ b/src/common/vars/is-snap-package.global-override-for-injectable.ts @@ -0,0 +1,9 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { getGlobalOverride } from "../test-utils/get-global-override"; +import isSnapPackageInjectable from "./is-snap-package.injectable"; + +export default getGlobalOverride(isSnapPackageInjectable, () => false); diff --git a/src/common/vars/package-json.injectable.ts b/src/common/vars/is-snap-package.injectable.ts similarity index 55% rename from src/common/vars/package-json.injectable.ts rename to src/common/vars/is-snap-package.injectable.ts index fa132be518..a2c545870b 100644 --- a/src/common/vars/package-json.injectable.ts +++ b/src/common/vars/is-snap-package.injectable.ts @@ -3,12 +3,11 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import packageJson from "../../../package.json"; -const packageJsonInjectable = getInjectable({ - id: "package-json", - instantiate: () => packageJson, +const isSnapPackageInjectable = getInjectable({ + id: "is-snap", + instantiate: () => Boolean(process.env.SNAP), causesSideEffects: true, }); -export default packageJsonInjectable; +export default isSnapPackageInjectable; diff --git a/src/main/app-paths/app-name/product-name.injectable.ts b/src/common/vars/product-name.injectable.ts similarity index 65% rename from src/main/app-paths/app-name/product-name.injectable.ts rename to src/common/vars/product-name.injectable.ts index 8c5c53bfba..910c6afa48 100644 --- a/src/main/app-paths/app-name/product-name.injectable.ts +++ b/src/common/vars/product-name.injectable.ts @@ -3,12 +3,11 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import packageInfo from "../../../../package.json"; +import applicationInformationInjectable from "./application-information.injectable"; const productNameInjectable = getInjectable({ id: "product-name", - instantiate: () => packageInfo.productName, - causesSideEffects: true, + instantiate: (di) => di.inject(applicationInformationInjectable).productName, }); export default productNameInjectable; diff --git a/src/common/vars/release-channel.injectable.ts b/src/common/vars/release-channel.injectable.ts index 78cc79cdb4..33dd26432a 100644 --- a/src/common/vars/release-channel.injectable.ts +++ b/src/common/vars/release-channel.injectable.ts @@ -3,14 +3,14 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import type { UpdateChannelId } from "../application-update/update-channels"; -import appSemanticVersionInjectable from "./app-semantic-version.injectable"; +import type { ReleaseChannel } from "../application-update/update-channels"; +import buildSemanticVersionInjectable from "./build-semantic-version.injectable"; const releaseChannelInjectable = getInjectable({ id: "release-channel", - instantiate: (di): UpdateChannelId => { - const appSemanticVersion = di.inject(appSemanticVersionInjectable); - const currentReleaseChannel = appSemanticVersion.prerelease[0]; + instantiate: (di): ReleaseChannel => { + const buildSemanticVersion = di.inject(buildSemanticVersionInjectable); + const currentReleaseChannel = buildSemanticVersion.get().prerelease[0]; switch (currentReleaseChannel) { case "latest": diff --git a/src/common/vars/sentry-dsn-url.injectable.ts b/src/common/vars/sentry-dsn-url.injectable.ts new file mode 100644 index 0000000000..e33c2fd0de --- /dev/null +++ b/src/common/vars/sentry-dsn-url.injectable.ts @@ -0,0 +1,13 @@ +/** + * 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 applicationInformationInjectable from "./application-information.injectable"; + +const sentryDataSourceNameInjectable = getInjectable({ + id: "sentry-data-source-name", + instantiate: (di) => di.inject(applicationInformationInjectable).config.sentryDsn, +}); + +export default sentryDataSourceNameInjectable; diff --git a/src/common/vars/store-migration-version.injectable.ts b/src/common/vars/store-migration-version.injectable.ts new file mode 100644 index 0000000000..79ab1578a3 --- /dev/null +++ b/src/common/vars/store-migration-version.injectable.ts @@ -0,0 +1,13 @@ +/** + * 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 applicationInformationInjectable from "./application-information.injectable"; + +const storeMigrationVersionInjectable = getInjectable({ + id: "store-migration-version", + instantiate: (di) => di.inject(applicationInformationInjectable).version, +}); + +export default storeMigrationVersionInjectable; diff --git a/src/extensions/__tests__/is-compatible-extension.test.ts b/src/extensions/__tests__/is-compatible-extension.test.ts index d581722139..f2ca144681 100644 --- a/src/extensions/__tests__/is-compatible-extension.test.ts +++ b/src/extensions/__tests__/is-compatible-extension.test.ts @@ -3,65 +3,53 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import assert from "assert"; -import semver from "semver"; import { isCompatibleExtension } from "../extension-discovery/is-compatible-extension/is-compatible-extension"; import type { LensExtensionManifest } from "../lens-extension"; describe("Extension/App versions compatibility checks", () => { it("is compatible with exact version matching", () => { - expect(isCompatible({ extLensEngineVersion: "5.5.0", appVersion: "5.5.0" })).toBeTruthy(); + expect(isCompatible({ extLensEngineVersion: "5.5.0", extensionApiVersion: "5.5.0" })).toBeTruthy(); }); it("is compatible with upper %PATCH versions of base app", () => { - expect(isCompatible({ extLensEngineVersion: "5.5.0", appVersion: "5.5.5" })).toBeTruthy(); + expect(isCompatible({ extLensEngineVersion: "5.5.0", extensionApiVersion: "5.5.5" })).toBeTruthy(); }); it("is compatible with higher %MINOR version of base app", () => { - expect(isCompatible({ extLensEngineVersion: "5.5.0", appVersion: "5.6.0" })).toBeTruthy(); + expect(isCompatible({ extLensEngineVersion: "5.5.0", extensionApiVersion: "5.6.0" })).toBeTruthy(); }); it("is not compatible with higher %MAJOR version of base app", () => { - expect(isCompatible({ extLensEngineVersion: "5.6.0", appVersion: "6.0.0" })).toBeFalsy(); // extension for lens@5 not compatible with lens@6 - expect(isCompatible({ extLensEngineVersion: "6.0.0", appVersion: "5.6.0" })).toBeFalsy(); - }); - - it("is compatible with lensEngine with prerelease", () => { - expect(isCompatible({ - extLensEngineVersion: "^5.4.0-alpha.0", - appVersion: "5.5.0-alpha.0", - })).toBeTruthy(); + expect(isCompatible({ extLensEngineVersion: "5.6.0", extensionApiVersion: "6.0.0" })).toBeFalsy(); // extension for lens@5 not compatible with lens@6 + expect(isCompatible({ extLensEngineVersion: "6.0.0", extensionApiVersion: "5.6.0" })).toBeFalsy(); }); it("supports short version format for manifest.engines.lens", () => { - expect(isCompatible({ extLensEngineVersion: "5.5", appVersion: "5.5.1" })).toBeTruthy(); + expect(isCompatible({ extLensEngineVersion: "5.5", extensionApiVersion: "5.5.1" })).toBeTruthy(); }); it("throws for incorrect or not supported version format", () => { expect(() => isCompatible({ extLensEngineVersion: ">=2.0", - appVersion: "2.0", + extensionApiVersion: "2.0", })).toThrow(/Invalid format/i); expect(() => isCompatible({ extLensEngineVersion: "~2.0", - appVersion: "2.0", + extensionApiVersion: "2.0", })).toThrow(/Invalid format/i); expect(() => isCompatible({ extLensEngineVersion: "*", - appVersion: "1.0", + extensionApiVersion: "1.0", })).toThrow(/Invalid format/i); }); }); -function isCompatible({ extLensEngineVersion = "^1.0", appVersion = "1.0" } = {}): boolean { - const appSemVer = semver.coerce(appVersion); +function isCompatible({ extLensEngineVersion = "^1.0", extensionApiVersion = "1.0" } = {}): boolean { const extensionManifestMock = getExtensionManifestMock(extLensEngineVersion); - assert(appSemVer); - - return isCompatibleExtension({ appSemVer })(extensionManifestMock); + return isCompatibleExtension({ extensionApiVersion })(extensionManifestMock); } function getExtensionManifestMock(lensEngine = "1.0"): LensExtensionManifest { diff --git a/src/extensions/common-api/app.ts b/src/extensions/common-api/app.ts index 6be9a193d1..92ecd19ef9 100644 --- a/src/extensions/common-api/app.ts +++ b/src/extensions/common-api/app.ts @@ -3,14 +3,65 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { getAppVersion } from "../../common/utils"; +import appNameInjectable from "../../common/vars/app-name.injectable"; +import isLinuxInjectable from "../../common/vars/is-linux.injectable"; +import isMacInjectable from "../../common/vars/is-mac.injectable"; +import isSnapPackageInjectable from "../../common/vars/is-snap-package.injectable"; +import isWindowsInjectable from "../../common/vars/is-windows.injectable"; import { asLegacyGlobalFunctionForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api"; +import { getLegacyGlobalDiForExtensionApi } from "../as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; import getEnabledExtensionsInjectable from "./get-enabled-extensions/get-enabled-extensions.injectable"; -import * as Preferences from "./user-preferences"; +import type { UserPreferenceExtensionItems } from "./user-preferences"; +import { Preferences } from "./user-preferences"; +import { slackUrl, issuesTrackerUrl } from "../../common/vars"; +import { buildVersionInjectionToken } from "../../common/vars/build-semantic-version.injectable"; -export const version = getAppVersion(); -export { isSnap, isWindows, isMac, isLinux, appName, slackUrl, issuesTrackerUrl } from "../../common/vars"; +export interface AppExtensionItems { + readonly Preferences: UserPreferenceExtensionItems; + readonly version: string; + readonly appName: string; + readonly slackUrl: string; + readonly issuesTrackerUrl: string; + readonly isSnap: boolean; + readonly isWindows: boolean; + readonly isMac: boolean; + readonly isLinux: boolean; + getEnabledExtensions: () => string[]; +} -export const getEnabledExtensions = asLegacyGlobalFunctionForExtensionApi(getEnabledExtensionsInjectable); +export const App: AppExtensionItems = { + Preferences, + getEnabledExtensions: asLegacyGlobalFunctionForExtensionApi(getEnabledExtensionsInjectable), + get version() { + const di = getLegacyGlobalDiForExtensionApi(); -export { Preferences }; + return di.inject(buildVersionInjectionToken).get(); + }, + get appName() { + const di = getLegacyGlobalDiForExtensionApi(); + + return di.inject(appNameInjectable); + }, + get isSnap() { + const di = getLegacyGlobalDiForExtensionApi(); + + return di.inject(isSnapPackageInjectable); + }, + get isWindows() { + const di = getLegacyGlobalDiForExtensionApi(); + + return di.inject(isWindowsInjectable); + }, + get isMac() { + const di = getLegacyGlobalDiForExtensionApi(); + + return di.inject(isMacInjectable); + }, + get isLinux() { + const di = getLegacyGlobalDiForExtensionApi(); + + return di.inject(isLinuxInjectable); + }, + slackUrl, + issuesTrackerUrl, +}; diff --git a/src/extensions/common-api/index.ts b/src/extensions/common-api/index.ts index 0d07220d1d..6e4b39b1b7 100644 --- a/src/extensions/common-api/index.ts +++ b/src/extensions/common-api/index.ts @@ -4,10 +4,10 @@ */ // APIs -import * as App from "./app"; +import { App } from "./app"; import * as EventBus from "./event-bus"; import * as Store from "./stores"; -import * as Util from "./utils"; +import { Util } from "./utils"; import * as Catalog from "./catalog"; import * as Types from "./types"; import * as Proxy from "./proxy"; diff --git a/src/extensions/common-api/user-preferences.ts b/src/extensions/common-api/user-preferences.ts index 2c44f6f604..3a0a93793b 100644 --- a/src/extensions/common-api/user-preferences.ts +++ b/src/extensions/common-api/user-preferences.ts @@ -4,10 +4,13 @@ */ import { UserStore } from "../../common/user-store"; - -/** - * Get the configured kubectl binaries path. - */ -export function getKubectlPath(): string | undefined { - return UserStore.getInstance().kubectlBinariesPath; +export interface UserPreferenceExtensionItems { + /** + * Get the configured kubectl binaries path. + */ + getKubectlPath: () => string | undefined; } + +export const Preferences: UserPreferenceExtensionItems = { + getKubectlPath: () => UserStore.getInstance().kubectlBinariesPath, +}; diff --git a/src/extensions/common-api/utils.ts b/src/extensions/common-api/utils.ts index 3dea165238..12c9daf988 100644 --- a/src/extensions/common-api/utils.ts +++ b/src/extensions/common-api/utils.ts @@ -4,14 +4,34 @@ */ import openLinkInBrowserInjectable from "../../common/utils/open-link-in-browser.injectable"; +import buildVersionInjectable from "../../main/vars/build-version/build-version.injectable"; import { asLegacyGlobalFunctionForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api"; +import { getLegacyGlobalDiForExtensionApi } from "../as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; +import { Singleton } from "../../common/utils"; +import { prevDefault, stopPropagation } from "../../renderer/utils/prevDefault"; +import type { IClassName } from "../../renderer/utils/cssNames"; +import { cssNames } from "../../renderer/utils/cssNames"; -export { Singleton, getAppVersion } from "../../common/utils"; -export { prevDefault, stopPropagation } from "../../renderer/utils/prevDefault"; -export { cssNames } from "../../renderer/utils/cssNames"; +export interface UtilsExtensionItems { + Singleton: Singleton; + prevDefault: (callback: (evt: E) => R) => (evt: E) => R; + stopPropagation: (evt: Event | React.SyntheticEvent) => void; + cssNames: (...classNames: IClassName[]) => string; + openExternal: (url: string) => Promise; + openBrowser: (url: string) => Promise; + getAppVersion: () => string; +} -/** - * @deprecated Use {@link openBrowser} instead - */ -export const openExternal = asLegacyGlobalFunctionForExtensionApi(openLinkInBrowserInjectable); -export const openBrowser = asLegacyGlobalFunctionForExtensionApi(openLinkInBrowserInjectable); +export const Util: UtilsExtensionItems = { + Singleton, + prevDefault, + stopPropagation, + cssNames, + openExternal: asLegacyGlobalFunctionForExtensionApi(openLinkInBrowserInjectable), + openBrowser: asLegacyGlobalFunctionForExtensionApi(openLinkInBrowserInjectable), + getAppVersion: () => { + const di = getLegacyGlobalDiForExtensionApi(); + + return di.inject(buildVersionInjectable).get(); + }, +}; diff --git a/src/extensions/extension-discovery/extension-discovery.injectable.ts b/src/extensions/extension-discovery/extension-discovery.injectable.ts index 48e9b225a0..df5efadaf6 100644 --- a/src/extensions/extension-discovery/extension-discovery.injectable.ts +++ b/src/extensions/extension-discovery/extension-discovery.injectable.ts @@ -20,21 +20,20 @@ import watchInjectable from "../../common/fs/watch/watch.injectable"; const extensionDiscoveryInjectable = getInjectable({ id: "extension-discovery", - instantiate: (di) => - new ExtensionDiscovery({ - extensionLoader: di.inject(extensionLoaderInjectable), - extensionsStore: di.inject(extensionsStoreInjectable), - extensionInstallationStateStore: di.inject(extensionInstallationStateStoreInjectable), - isCompatibleExtension: di.inject(isCompatibleExtensionInjectable), - installExtension: di.inject(installExtensionInjectable), - installExtensions: di.inject(installExtensionsInjectable), - extensionPackageRootDirectory: di.inject(extensionPackageRootDirectoryInjectable), - staticFilesDirectory: di.inject(staticFilesDirectoryInjectable), - readJsonFile: di.inject(readJsonFileInjectable), - pathExists: di.inject(pathExistsInjectable), - watch: di.inject(watchInjectable), - logger: di.inject(loggerInjectable), - }), + instantiate: (di) => new ExtensionDiscovery({ + extensionLoader: di.inject(extensionLoaderInjectable), + extensionsStore: di.inject(extensionsStoreInjectable), + extensionInstallationStateStore: di.inject(extensionInstallationStateStoreInjectable), + isCompatibleExtension: di.inject(isCompatibleExtensionInjectable), + installExtension: di.inject(installExtensionInjectable), + installExtensions: di.inject(installExtensionsInjectable), + extensionPackageRootDirectory: di.inject(extensionPackageRootDirectoryInjectable), + staticFilesDirectory: di.inject(staticFilesDirectoryInjectable), + readJsonFile: di.inject(readJsonFileInjectable), + pathExists: di.inject(pathExistsInjectable), + watch: di.inject(watchInjectable), + logger: di.inject(loggerInjectable), + }), }); export default extensionDiscoveryInjectable; diff --git a/src/extensions/extension-discovery/extension-discovery.test.ts b/src/extensions/extension-discovery/extension-discovery.test.ts index 7feca8f99d..e5a04bd5eb 100644 --- a/src/extensions/extension-discovery/extension-discovery.test.ts +++ b/src/extensions/extension-discovery/extension-discovery.test.ts @@ -15,10 +15,10 @@ import directoryForUserDataInjectable from "../../common/app-paths/directory-for import mockFs from "mock-fs"; import { delay } from "../../renderer/utils"; import { observable, when } from "mobx"; -import appVersionInjectable from "../../common/vars/app-version.injectable"; import readJsonFileInjectable from "../../common/fs/read-json-file.injectable"; import pathExistsInjectable from "../../common/fs/path-exists.injectable"; import watchInjectable from "../../common/fs/watch/watch.injectable"; +import extensionApiVersionInjectable from "../../common/vars/extension-api-version.injectable"; console = new Console(process.stdout, process.stderr); // fix mockFS @@ -33,7 +33,7 @@ describe("ExtensionDiscovery", () => { di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data"); di.override(installExtensionInjectable, () => () => Promise.resolve()); - di.override(appVersionInjectable, () => "5.0.0"); + di.override(extensionApiVersionInjectable, () => "5.0.0"); readJsonFileMock = jest.fn(); di.override(readJsonFileInjectable, () => readJsonFileMock); diff --git a/src/extensions/extension-discovery/is-compatible-extension/is-compatible-extension.injectable.ts b/src/extensions/extension-discovery/is-compatible-extension/is-compatible-extension.injectable.ts index 75e2f45d4a..de2fd4390f 100644 --- a/src/extensions/extension-discovery/is-compatible-extension/is-compatible-extension.injectable.ts +++ b/src/extensions/extension-discovery/is-compatible-extension/is-compatible-extension.injectable.ts @@ -3,13 +3,13 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import appSemanticVersionInjectable from "../../../common/vars/app-semantic-version.injectable"; +import extensionApiVersionInjectable from "../../../common/vars/extension-api-version.injectable"; import { isCompatibleExtension } from "./is-compatible-extension"; const isCompatibleExtensionInjectable = getInjectable({ id: "is-compatible-extension", instantiate: (di) => isCompatibleExtension({ - appSemVer: di.inject(appSemanticVersionInjectable), + extensionApiVersion: di.inject(extensionApiVersionInjectable), }), }); diff --git a/src/extensions/extension-discovery/is-compatible-extension/is-compatible-extension.ts b/src/extensions/extension-discovery/is-compatible-extension/is-compatible-extension.ts index 717effa1c6..74cbb4fd0c 100644 --- a/src/extensions/extension-discovery/is-compatible-extension/is-compatible-extension.ts +++ b/src/extensions/extension-discovery/is-compatible-extension/is-compatible-extension.ts @@ -2,16 +2,15 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import semver, { type SemVer } from "semver"; +import semver from "semver"; import type { LensExtensionManifest } from "../../lens-extension"; interface Dependencies { - appSemVer: SemVer; + extensionApiVersion: string; } -export const isCompatibleExtension = ({ appSemVer }: Dependencies): ((manifest: LensExtensionManifest) => boolean) => { +export const isCompatibleExtension = ({ extensionApiVersion }: Dependencies): ((manifest: LensExtensionManifest) => boolean) => { return (manifest: LensExtensionManifest): boolean => { - const appVersion = appSemVer.raw.split("-")[0]; // drop prerelease version if any, e.g. "-alpha.0" const manifestLensEngine = manifest.engines.lens; const validVersion = manifestLensEngine.match(/^[\^0-9]\d*\.\d+\b/); // must start from ^ or number @@ -30,7 +29,7 @@ export const isCompatibleExtension = ({ appSemVer }: Dependencies): ((manifest: }) as semver.SemVer; const supportedVersionsByExtension = semver.validRange(`^${extMajor}.${extMinor}`) as string; - return semver.satisfies(appVersion, supportedVersionsByExtension, { + return semver.satisfies(extensionApiVersion, supportedVersionsByExtension, { loose: true, includePrerelease: false, }); diff --git a/src/features/__snapshots__/extension-special-characters-in-page-registrations.test.tsx.snap b/src/features/__snapshots__/extension-special-characters-in-page-registrations.test.tsx.snap index d4cda2d767..dab11ecc9b 100644 --- a/src/features/__snapshots__/extension-special-characters-in-page-registrations.test.tsx.snap +++ b/src/features/__snapshots__/extension-special-characters-in-page-registrations.test.tsx.snap @@ -76,7 +76,7 @@ exports[`extension special characters in page registrations renders 1`] = ` style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your diff --git a/src/features/__snapshots__/navigate-to-extension-page.test.tsx.snap b/src/features/__snapshots__/navigate-to-extension-page.test.tsx.snap index 85d8746662..9dbfb50aea 100644 --- a/src/features/__snapshots__/navigate-to-extension-page.test.tsx.snap +++ b/src/features/__snapshots__/navigate-to-extension-page.test.tsx.snap @@ -76,7 +76,7 @@ exports[`navigate to extension page renders 1`] = ` style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your diff --git a/src/features/add-cluster/__snapshots__/navigation-using-application-menu.test.tsx.snap b/src/features/add-cluster/__snapshots__/navigation-using-application-menu.test.tsx.snap index 55572a5303..132ef5e0b0 100644 --- a/src/features/add-cluster/__snapshots__/navigation-using-application-menu.test.tsx.snap +++ b/src/features/add-cluster/__snapshots__/navigation-using-application-menu.test.tsx.snap @@ -76,7 +76,7 @@ exports[`add-cluster - navigation using application menu renders 1`] = ` style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your diff --git a/src/features/application-update/__snapshots__/force-user-to-update-when-too-long-time-since-update-was-downloaded.test.ts.snap b/src/features/application-update/__snapshots__/force-user-to-update-when-too-long-time-since-update-was-downloaded.test.ts.snap index 5ca948badb..93808e443c 100644 --- a/src/features/application-update/__snapshots__/force-user-to-update-when-too-long-time-since-update-was-downloaded.test.ts.snap +++ b/src/features/application-update/__snapshots__/force-user-to-update-when-too-long-time-since-update-was-downloaded.test.ts.snap @@ -95,7 +95,7 @@ exports[`force user to update when too long since update was downloaded when app style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -314,7 +314,7 @@ exports[`force user to update when too long since update was downloaded when app style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -580,7 +580,7 @@ exports[`force user to update when too long since update was downloaded when app style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your diff --git a/src/features/application-update/__snapshots__/installing-update-using-topbar-button.test.tsx.snap b/src/features/application-update/__snapshots__/installing-update-using-topbar-button.test.tsx.snap index 340122ba28..f136545fc1 100644 --- a/src/features/application-update/__snapshots__/installing-update-using-topbar-button.test.tsx.snap +++ b/src/features/application-update/__snapshots__/installing-update-using-topbar-button.test.tsx.snap @@ -95,7 +95,7 @@ exports[`encourage user to update when sufficient time passed since update was d style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -296,7 +296,7 @@ exports[`encourage user to update when sufficient time passed since update was d style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your diff --git a/src/features/application-update/__snapshots__/installing-update-using-tray.test.ts.snap b/src/features/application-update/__snapshots__/installing-update-using-tray.test.ts.snap index 748ffce692..85da39aa60 100644 --- a/src/features/application-update/__snapshots__/installing-update-using-tray.test.ts.snap +++ b/src/features/application-update/__snapshots__/installing-update-using-tray.test.ts.snap @@ -77,7 +77,7 @@ exports[`installing update using tray when started renders 1`] = ` style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -278,7 +278,7 @@ exports[`installing update using tray when started when user checks for updates style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -479,7 +479,7 @@ exports[`installing update using tray when started when user checks for updates style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -698,7 +698,7 @@ exports[`installing update using tray when started when user checks for updates style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -917,7 +917,7 @@ exports[`installing update using tray when started when user checks for updates style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -1118,7 +1118,7 @@ exports[`installing update using tray when started when user checks for updates style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your diff --git a/src/features/application-update/__snapshots__/installing-update.test.ts.snap b/src/features/application-update/__snapshots__/installing-update.test.ts.snap index 56de9ab127..8d589d432a 100644 --- a/src/features/application-update/__snapshots__/installing-update.test.ts.snap +++ b/src/features/application-update/__snapshots__/installing-update.test.ts.snap @@ -77,7 +77,7 @@ exports[`installing update when started renders 1`] = ` style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -278,7 +278,7 @@ exports[`installing update when started when user checks for updates renders 1`] style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -479,7 +479,7 @@ exports[`installing update when started when user checks for updates when new up style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -698,7 +698,7 @@ exports[`installing update when started when user checks for updates when new up style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -917,7 +917,7 @@ exports[`installing update when started when user checks for updates when new up style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -1118,7 +1118,7 @@ exports[`installing update when started when user checks for updates when no new style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your diff --git a/src/features/application-update/__snapshots__/periodical-checking-of-updates.test.ts.snap b/src/features/application-update/__snapshots__/periodical-checking-of-updates.test.ts.snap index a20988e3c3..25483ce178 100644 --- a/src/features/application-update/__snapshots__/periodical-checking-of-updates.test.ts.snap +++ b/src/features/application-update/__snapshots__/periodical-checking-of-updates.test.ts.snap @@ -77,7 +77,7 @@ exports[`periodical checking of updates given updater is enabled and configurati style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your diff --git a/src/features/application-update/__snapshots__/selection-of-update-stability.test.ts.snap b/src/features/application-update/__snapshots__/selection-of-update-stability.test.ts.snap index 0bb7a1f07a..6c0e7da36c 100644 --- a/src/features/application-update/__snapshots__/selection-of-update-stability.test.ts.snap +++ b/src/features/application-update/__snapshots__/selection-of-update-stability.test.ts.snap @@ -77,7 +77,7 @@ exports[`selection of update stability when started renders 1`] = ` style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your diff --git a/src/features/application-update/analytics-for-installing-update.test.ts b/src/features/application-update/analytics-for-installing-update.test.ts index 60523c5e49..625022b040 100644 --- a/src/features/application-update/analytics-for-installing-update.test.ts +++ b/src/features/application-update/analytics-for-installing-update.test.ts @@ -16,10 +16,10 @@ import processCheckingForUpdatesInjectable from "../../main/application-update/c import type { DownloadPlatformUpdate } from "../../main/application-update/download-platform-update/download-platform-update.injectable"; import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable"; import quitAndInstallUpdateInjectable from "../../main/application-update/quit-and-install-update.injectable"; -import appVersionInjectable from "../../common/vars/app-version.injectable"; import periodicalCheckForUpdatesInjectable from "../../main/application-update/periodical-check-for-updates/periodical-check-for-updates.injectable"; import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time"; import emitEventInjectable from "../../common/app-event-bus/emit-event.injectable"; +import getBuildVersionInjectable from "../../main/vars/build-version/get-build-version.injectable"; describe("analytics for installing update", () => { let builder: ApplicationBuilder; @@ -36,7 +36,7 @@ describe("analytics for installing update", () => { analyticsListenerMock = jest.fn(); builder.beforeApplicationStart(mainDi => { - mainDi.override(appVersionInjectable, () => "42.0.0"); + mainDi.override(getBuildVersionInjectable, () => () => "42.0.0"); checkForPlatformUpdatesMock = asyncFn(); diff --git a/src/features/application-update/downgrading-version-update.test.ts b/src/features/application-update/downgrading-version-update.test.ts index eb35e84be9..8f56ebd15c 100644 --- a/src/features/application-update/downgrading-version-update.test.ts +++ b/src/features/application-update/downgrading-version-update.test.ts @@ -13,8 +13,8 @@ import checkForPlatformUpdatesInjectable from "../../main/application-update/che import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable"; import selectedUpdateChannelInjectable from "../../common/application-update/selected-update-channel/selected-update-channel.injectable"; import type { DiContainer } from "@ogre-tools/injectable"; -import appVersionInjectable from "../../common/vars/app-version.injectable"; import { updateChannels } from "../../common/application-update/update-channels"; +import getBuildVersionInjectable from "../../main/vars/build-version/get-build-version.injectable"; describe("downgrading version update", () => { let applicationBuilder: ApplicationBuilder; @@ -102,7 +102,7 @@ describe("downgrading version update", () => { }, ].forEach(({ appVersion, updateChannel, downgradeIsAllowed }) => { it(`given application version "${appVersion}" and update channel "${updateChannel.id}", when checking for updates, can${downgradeIsAllowed ? "": "not"} downgrade`, async () => { - mainDi.override(appVersionInjectable, () => appVersion); + mainDi.override(getBuildVersionInjectable, () => () => appVersion); await applicationBuilder.render(); diff --git a/src/features/application-update/selection-of-update-stability.test.ts b/src/features/application-update/selection-of-update-stability.test.ts index 3e7ce4a893..d948573dcd 100644 --- a/src/features/application-update/selection-of-update-stability.test.ts +++ b/src/features/application-update/selection-of-update-stability.test.ts @@ -12,7 +12,7 @@ import type { CheckForPlatformUpdates } from "../../main/application-update/chec import checkForPlatformUpdatesInjectable from "../../main/application-update/check-for-platform-updates/check-for-platform-updates.injectable"; import type { AsyncFnMock } from "@async-fn/jest"; import asyncFn from "@async-fn/jest"; -import type { UpdateChannel, UpdateChannelId } from "../../common/application-update/update-channels"; +import type { UpdateChannel, ReleaseChannel } from "../../common/application-update/update-channels"; import { updateChannels } from "../../common/application-update/update-channels"; import type { DownloadPlatformUpdate } from "../../main/application-update/download-platform-update/download-platform-update.injectable"; import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable"; @@ -21,8 +21,8 @@ import type { IComputedValue } from "mobx"; import setUpdateOnQuitInjectable from "../../main/electron-app/features/set-update-on-quit.injectable"; import showInfoNotificationInjectable from "../../renderer/components/notifications/show-info-notification.injectable"; import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable"; -import appVersionInjectable from "../../common/vars/app-version.injectable"; import type { DiContainer } from "@ogre-tools/injectable"; +import getBuildVersionInjectable from "../../main/vars/build-version/get-build-version.injectable"; describe("selection of update stability", () => { let builder: ApplicationBuilder; @@ -89,7 +89,7 @@ describe("selection of update stability", () => { describe('given update channel "alpha" is selected, when checking for updates', () => { let selectedUpdateChannel: { value: IComputedValue; - setValue: (channelId: UpdateChannelId) => void; + setValue: (channelId: ReleaseChannel) => void; }; beforeEach(() => { @@ -180,7 +180,7 @@ describe("selection of update stability", () => { describe('given update channel "beta" is selected', () => { let selectedUpdateChannel: { value: IComputedValue; - setValue: (channelId: UpdateChannelId) => void; + setValue: (channelId: ReleaseChannel) => void; }; beforeEach(() => { @@ -231,16 +231,12 @@ describe("selection of update stability", () => { }); it("given valid update channel selection is stored, when checking for updates, checks for updates from the update channel", async () => { - builder.beforeApplicationStart((mainDi) => { - // TODO: Switch to more natural way of setting initial value - // TODO: UserStore is currently responsible for getting and setting initial value - const selectedUpdateChannel = mainDi.inject(selectedUpdateChannelInjectable); - - selectedUpdateChannel.setValue(updateChannels.beta.id); - }); - await builder.render(); + // TODO: Switch to more natural way of setting initial value + // TODO: UserStore is currently responsible for getting and setting initial value + mainDi.inject(selectedUpdateChannelInjectable).setValue(updateChannels.beta.id); + const processCheckingForUpdates = mainDi.inject(processCheckingForUpdatesInjectable); processCheckingForUpdates("irrelevant"); @@ -249,16 +245,12 @@ describe("selection of update stability", () => { }); it("given invalid update channel selection is stored, when checking for updates, checks for updates from the update channel", async () => { - builder.beforeApplicationStart((mainDi) => { - // TODO: Switch to more natural way of setting initial value - // TODO: UserStore is currently responsible for getting and setting initial value - const selectedUpdateChannel = mainDi.inject(selectedUpdateChannelInjectable); - - selectedUpdateChannel.setValue("something-invalid" as UpdateChannelId); - }); - await builder.render(); + // TODO: Switch to more natural way of setting initial value + // TODO: UserStore is currently responsible for getting and setting initial value + mainDi.inject(selectedUpdateChannelInjectable).setValue("something-invalid" as ReleaseChannel); + const processCheckingForUpdates = mainDi.inject(processCheckingForUpdatesInjectable); processCheckingForUpdates("irrelevant"); @@ -268,7 +260,7 @@ describe("selection of update stability", () => { it('given no update channel selection is stored and currently using stable release, when user checks for updates, checks for updates from "latest" update channel by default', async () => { builder.beforeApplicationStart((mainDi) => { - mainDi.override(appVersionInjectable, () => "1.0.0"); + mainDi.override(getBuildVersionInjectable, () => () => "1.0.0"); }); await builder.render(); @@ -285,7 +277,7 @@ describe("selection of update stability", () => { it('given no update channel selection is stored and currently using alpha release, when checking for updates, checks for updates from "alpha" channel', async () => { builder.beforeApplicationStart((mainDi) => { - mainDi.override(appVersionInjectable, () => "1.0.0-alpha"); + mainDi.override(getBuildVersionInjectable, () => () => "1.0.0-alpha"); }); await builder.render(); @@ -299,7 +291,7 @@ describe("selection of update stability", () => { it('given no update channel selection is stored and currently using beta release, when checking for updates, checks for updates from "beta" channel', async () => { builder.beforeApplicationStart((mainDi) => { - mainDi.override(appVersionInjectable, () => "1.0.0-beta"); + mainDi.override(getBuildVersionInjectable, () => () => "1.0.0-beta"); }); await builder.render(); @@ -312,18 +304,12 @@ describe("selection of update stability", () => { }); it("given update channel selection is stored and currently using prerelease, when checking for updates, checks for updates from stored channel", async () => { - builder.beforeApplicationStart((mainDi) => { - mainDi.override(appVersionInjectable, () => "1.0.0-alpha"); - - // TODO: Switch to more natural way of setting initial value - // TODO: UserStore is currently responsible for getting and setting initial value - const selectedUpdateChannel = mainDi.inject(selectedUpdateChannelInjectable); - - selectedUpdateChannel.setValue(updateChannels.beta.id); - }); - await builder.render(); + // TODO: Switch to more natural way of setting initial value + // TODO: UserStore is currently responsible for getting and setting initial value + mainDi.inject(selectedUpdateChannelInjectable).setValue(updateChannels.beta.id); + const processCheckingForUpdates = mainDi.inject(processCheckingForUpdatesInjectable); processCheckingForUpdates("irrelevant"); diff --git a/src/features/command-pallet/__snapshots__/keyboard-shortcuts.test.tsx.snap b/src/features/command-pallet/__snapshots__/keyboard-shortcuts.test.tsx.snap index 574a757319..6704a798ae 100644 --- a/src/features/command-pallet/__snapshots__/keyboard-shortcuts.test.tsx.snap +++ b/src/features/command-pallet/__snapshots__/keyboard-shortcuts.test.tsx.snap @@ -158,7 +158,7 @@ exports[`Command Pallet: keyboard shortcut tests when on linux renders 1`] = ` style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -440,7 +440,7 @@ exports[`Command Pallet: keyboard shortcut tests when on linux when pressing ESC style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -722,7 +722,7 @@ exports[`Command Pallet: keyboard shortcut tests when on linux when pressing SHI style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -1016,7 +1016,7 @@ exports[`Command Pallet: keyboard shortcut tests when on linux when pressing SHI style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -1217,7 +1217,7 @@ exports[`Command Pallet: keyboard shortcut tests when on macOS renders 1`] = ` style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -1418,7 +1418,7 @@ exports[`Command Pallet: keyboard shortcut tests when on macOS when pressing ESC style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -1619,7 +1619,7 @@ exports[`Command Pallet: keyboard shortcut tests when on macOS when pressing SHI style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -1832,7 +1832,7 @@ exports[`Command Pallet: keyboard shortcut tests when on macOS when pressing SHI style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your diff --git a/src/features/extensions/__snapshots__/navigation-using-application-menu.test.ts.snap b/src/features/extensions/__snapshots__/navigation-using-application-menu.test.ts.snap index 689d9267e3..66a49f4355 100644 --- a/src/features/extensions/__snapshots__/navigation-using-application-menu.test.ts.snap +++ b/src/features/extensions/__snapshots__/navigation-using-application-menu.test.ts.snap @@ -76,7 +76,7 @@ exports[`extensions - navigation using application menu renders 1`] = ` style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your diff --git a/src/features/preferences/__snapshots__/navigation-using-application-menu.test.ts.snap b/src/features/preferences/__snapshots__/navigation-using-application-menu.test.ts.snap index 201cf9ec74..df792b6e42 100644 --- a/src/features/preferences/__snapshots__/navigation-using-application-menu.test.ts.snap +++ b/src/features/preferences/__snapshots__/navigation-using-application-menu.test.ts.snap @@ -76,7 +76,7 @@ exports[`preferences - navigation using application menu renders 1`] = ` style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your diff --git a/src/features/preferences/__snapshots__/navigation-using-tray.test.ts.snap b/src/features/preferences/__snapshots__/navigation-using-tray.test.ts.snap index 1c243cc2b9..b34af2b18c 100644 --- a/src/features/preferences/__snapshots__/navigation-using-tray.test.ts.snap +++ b/src/features/preferences/__snapshots__/navigation-using-tray.test.ts.snap @@ -77,7 +77,7 @@ exports[`show-about-using-tray renders 1`] = ` style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your diff --git a/src/features/preferences/navigation-to-telemetry-preferences.test.tsx b/src/features/preferences/navigation-to-telemetry-preferences.test.tsx index c4a76bed81..f424165364 100644 --- a/src/features/preferences/navigation-to-telemetry-preferences.test.tsx +++ b/src/features/preferences/navigation-to-telemetry-preferences.test.tsx @@ -7,7 +7,7 @@ import React from "react"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import navigateToTelemetryPreferencesInjectable from "../../common/front-end-routing/routes/preferences/telemetry/navigate-to-telemetry-preferences.injectable"; -import sentryDnsUrlInjectable from "../../renderer/components/+preferences/sentry-dns-url.injectable"; +import sentryDataSourceNameInjectable from "../../common/vars/sentry-dsn-url.injectable"; import type { FakeExtensionOptions } from "../../renderer/components/test-utils/get-extension-fake"; describe("preferences - navigation to telemetry preferences", () => { @@ -114,7 +114,7 @@ describe("preferences - navigation to telemetry preferences", () => { beforeEach(async () => { builder.beforeWindowStart((windowDi) => { - windowDi.override(sentryDnsUrlInjectable, () => "some-sentry-dns-url"); + windowDi.override(sentryDataSourceNameInjectable, () => "some-sentry-dns-url"); }); rendered = await builder.render(); @@ -144,7 +144,7 @@ describe("preferences - navigation to telemetry preferences", () => { beforeEach(async () => { builder.beforeWindowStart((windowDi) => { - windowDi.override(sentryDnsUrlInjectable, () => null); + windowDi.override(sentryDataSourceNameInjectable, () => null); }); rendered = await builder.render(); diff --git a/src/features/status-bar/__snapshots__/status-bar-items-originating-from-extensions.test.tsx.snap b/src/features/status-bar/__snapshots__/status-bar-items-originating-from-extensions.test.tsx.snap index af828132d2..3272b6688f 100644 --- a/src/features/status-bar/__snapshots__/status-bar-items-originating-from-extensions.test.tsx.snap +++ b/src/features/status-bar/__snapshots__/status-bar-items-originating-from-extensions.test.tsx.snap @@ -77,7 +77,7 @@ exports[`status-bar-items-originating-from-extensions when application starts wh style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your diff --git a/src/features/welcome/__snapshots__/navigation-using-application-menu.test.ts.snap b/src/features/welcome/__snapshots__/navigation-using-application-menu.test.ts.snap index f1188dbf9d..fe3b7f7d61 100644 --- a/src/features/welcome/__snapshots__/navigation-using-application-menu.test.ts.snap +++ b/src/features/welcome/__snapshots__/navigation-using-application-menu.test.ts.snap @@ -76,7 +76,7 @@ exports[`welcome - navigation using application menu renders 1`] = ` style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your @@ -915,7 +915,7 @@ exports[`welcome - navigation using application menu when navigated somewhere el style="width: 320px;" >

- Welcome to OpenLens! + Welcome to some-product-name!

To get you started we have auto-detected your clusters in your diff --git a/src/main/app-paths/setup-app-paths.injectable.ts b/src/main/app-paths/setup-app-paths.injectable.ts index 816c58db8b..3626bbd9c0 100644 --- a/src/main/app-paths/setup-app-paths.injectable.ts +++ b/src/main/app-paths/setup-app-paths.injectable.ts @@ -6,7 +6,6 @@ import { getInjectable } from "@ogre-tools/injectable"; import type { AppPaths } from "../../common/app-paths/app-path-injection-token"; import getElectronAppPathInjectable from "./get-electron-app-path/get-electron-app-path.injectable"; import setElectronAppPathInjectable from "./set-electron-app-path/set-electron-app-path.injectable"; -import appNameInjectable from "./app-name/app-name.injectable"; import directoryForIntegrationTestingInjectable from "./directory-for-integration-testing/directory-for-integration-testing.injectable"; import appPathsStateInjectable from "../../common/app-paths/app-paths-state.injectable"; import { pathNames } from "../../common/app-paths/app-path-names"; @@ -14,6 +13,7 @@ import { fromPairs, map } from "lodash/fp"; import { pipeline } from "@ogre-tools/fp"; import joinPathsInjectable from "../../common/path/join-paths.injectable"; import { beforeElectronIsReadyInjectionToken } from "../start-main-application/runnable-tokens/before-electron-is-ready-injection-token"; +import appNameInjectable from "../../common/vars/app-name.injectable"; const setupAppPathsInjectable = getInjectable({ id: "setup-app-paths", diff --git a/src/main/application-update/check-for-platform-updates/check-for-platform-updates.test.ts b/src/main/application-update/check-for-platform-updates/check-for-platform-updates.test.ts index b826a1a5a7..17e750c52e 100644 --- a/src/main/application-update/check-for-platform-updates/check-for-platform-updates.test.ts +++ b/src/main/application-update/check-for-platform-updates/check-for-platform-updates.test.ts @@ -9,7 +9,7 @@ import asyncFn from "@async-fn/jest"; import type { AppUpdater, UpdateCheckResult } from "electron-updater"; import type { CheckForPlatformUpdates } from "./check-for-platform-updates.injectable"; import checkForPlatformUpdatesInjectable from "./check-for-platform-updates.injectable"; -import type { UpdateChannel, UpdateChannelId } from "../../../common/application-update/update-channels"; +import type { UpdateChannel, ReleaseChannel } from "../../../common/application-update/update-channels"; import { getPromiseStatus } from "../../../common/test-utils/get-promise-status"; import loggerInjectable from "../../../common/logger.injectable"; import type { Logger } from "../../../common/logger"; @@ -47,7 +47,7 @@ describe("check-for-platform-updates", () => { beforeEach(() => { const testUpdateChannel: UpdateChannel = { - id: "some-update-channel" as UpdateChannelId, + id: "some-update-channel" as ReleaseChannel, label: "Some update channel", moreStableUpdateChannel: null, }; diff --git a/src/main/application-update/emit-current-version-to-analytics.injectable.ts b/src/main/application-update/emit-current-version-to-analytics.injectable.ts index 7ec8d0b3b5..61dd38ea87 100644 --- a/src/main/application-update/emit-current-version-to-analytics.injectable.ts +++ b/src/main/application-update/emit-current-version-to-analytics.injectable.ts @@ -6,14 +6,14 @@ import { getInjectable } from "@ogre-tools/injectable"; import { afterApplicationIsLoadedInjectionToken } from "../start-main-application/runnable-tokens/after-application-is-loaded-injection-token"; import emitEventInjectable from "../../common/app-event-bus/emit-event.injectable"; import { getCurrentDateTime } from "../../common/utils/date/get-current-date-time"; -import appVersionInjectable from "../../common/vars/app-version.injectable"; +import buildVersionInjectable from "../vars/build-version/build-version.injectable"; const emitCurrentVersionToAnalyticsInjectable = getInjectable({ id: "emit-current-version-to-analytics", instantiate: (di) => { const emitEvent = di.inject(emitEventInjectable); - const appVersion = di.inject(appVersionInjectable); + const buildVersion = di.inject(buildVersionInjectable); return { run: () => { @@ -22,7 +22,7 @@ const emitCurrentVersionToAnalyticsInjectable = getInjectable({ action: "current-version", params: { - version: appVersion, + version: buildVersion.get(), currentDateTime: getCurrentDateTime(), }, }); diff --git a/src/main/application-update/publish-is-configured.injectable.ts b/src/main/application-update/publish-is-configured.injectable.ts index 321adc8a22..6a3fca2f7f 100644 --- a/src/main/application-update/publish-is-configured.injectable.ts +++ b/src/main/application-update/publish-is-configured.injectable.ts @@ -3,18 +3,11 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import packageJsonInjectable from "../../common/vars/package-json.injectable"; -import { has } from "lodash/fp"; +import applicationInformationInjectable from "../../common/vars/application-information.injectable"; -// TOOO: Rename to something less technical const publishIsConfiguredInjectable = getInjectable({ id: "publish-is-configured", - - instantiate: (di) => { - const packageJson = di.inject(packageJsonInjectable); - - return has("build.publish", packageJson); - }, + instantiate: (di) => Boolean(di.inject(applicationInformationInjectable).build.publish?.length), }); export default publishIsConfiguredInjectable; diff --git a/src/main/build-version/setup-channel.injectable.ts b/src/main/build-version/setup-channel.injectable.ts new file mode 100644 index 0000000000..a34edc0eac --- /dev/null +++ b/src/main/build-version/setup-channel.injectable.ts @@ -0,0 +1,23 @@ +/** + * 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 { requestChannelListenerInjectionToken } from "../../common/utils/channel/request-channel-listener-injection-token"; +import { buildVersionChannel } from "../../common/vars/build-semantic-version.injectable"; +import buildVersionInjectable from "../vars/build-version/build-version.injectable"; + +const setupBuildVersionRequestChannelInjectable = getInjectable({ + id: "setup-build-version-request-channel", + instantiate: (di) => { + const buildVersion = di.inject(buildVersionInjectable); + + return { + channel: buildVersionChannel, + handler: () => buildVersion.get(), + }; + }, + injectionToken: requestChannelListenerInjectionToken, +}); + +export default setupBuildVersionRequestChannelInjectable; diff --git a/src/main/menu/build-version.global-override-for-injectable.ts b/src/main/electron-app/electron-app.global-override-for-injectable.ts similarity index 56% rename from src/main/menu/build-version.global-override-for-injectable.ts rename to src/main/electron-app/electron-app.global-override-for-injectable.ts index 9c2331f72d..eeaa1765b7 100644 --- a/src/main/menu/build-version.global-override-for-injectable.ts +++ b/src/main/electron-app/electron-app.global-override-for-injectable.ts @@ -4,6 +4,8 @@ */ import { getGlobalOverride } from "../../common/test-utils/get-global-override"; -import buildVersionInjectable from "./build-version.injectable"; +import electronAppInjectable from "./electron-app.injectable"; -export default getGlobalOverride(buildVersionInjectable, () => "6.0.0"); +export default getGlobalOverride(electronAppInjectable, () => ({ + getVersion: () => "6.0.0", +} as Electron.App)); diff --git a/src/main/electron-app/runnables/setup-application-name.injectable.ts b/src/main/electron-app/runnables/setup-application-name.injectable.ts index a5f85301c0..3a8efdfe05 100644 --- a/src/main/electron-app/runnables/setup-application-name.injectable.ts +++ b/src/main/electron-app/runnables/setup-application-name.injectable.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import appNameInjectable from "../../app-paths/app-name/app-name.injectable"; +import appNameInjectable from "../../../common/vars/app-name.injectable"; import { beforeElectronIsReadyInjectionToken } from "../../start-main-application/runnable-tokens/before-electron-is-ready-injection-token"; import electronAppInjectable from "../electron-app.injectable"; diff --git a/src/main/getDiForUnitTesting.ts b/src/main/getDiForUnitTesting.ts index f63e6f0518..579e5eafec 100644 --- a/src/main/getDiForUnitTesting.ts +++ b/src/main/getDiForUnitTesting.ts @@ -7,7 +7,6 @@ import { kebabCase, noop, chunk } from "lodash/fp"; import type { DiContainer, Injectable } from "@ogre-tools/injectable"; import { createContainer } from "@ogre-tools/injectable"; import { Environments, setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; -import appNameInjectable from "./app-paths/app-name/app-name.injectable"; import writeJsonFileInjectable from "../common/fs/write-json-file.injectable"; import readJsonFileInjectable from "../common/fs/read-json-file.injectable"; import readFileInjectable from "../common/fs/read-file.injectable"; @@ -33,7 +32,6 @@ import lensResourcesDirInjectable from "../common/vars/lens-resources-dir.inject import environmentVariablesInjectable from "../common/utils/environment-variables.injectable"; import setupIpcMainHandlersInjectable from "./electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.injectable"; import setupLensProxyInjectable from "./start-main-application/runnables/setup-lens-proxy.injectable"; -import setupSentryInjectable from "./start-main-application/runnables/setup-sentry.injectable"; import setupShellInjectable from "./start-main-application/runnables/setup-shell.injectable"; import setupSyncingOfWeblinksInjectable from "./start-main-application/runnables/setup-syncing-of-weblinks.injectable"; import stopServicesAndExitAppInjectable from "./stop-services-and-exit-app.injectable"; @@ -63,7 +61,6 @@ import broadcastMessageInjectable from "../common/ipc/broadcast-message.injectab import getElectronThemeInjectable from "./electron-app/features/get-electron-theme.injectable"; import syncThemeFromOperatingSystemInjectable from "./electron-app/features/sync-theme-from-operating-system.injectable"; import platformInjectable from "../common/vars/platform.injectable"; -import productNameInjectable from "./app-paths/app-name/product-name.injectable"; import electronQuitAndInstallUpdateInjectable from "./electron-app/features/electron-quit-and-install-update.injectable"; import electronUpdaterIsActiveInjectable from "./electron-app/features/electron-updater-is-active.injectable"; import publishIsConfiguredInjectable from "./application-update/publish-is-configured.injectable"; @@ -73,7 +70,6 @@ import setUpdateOnQuitInjectable from "./electron-app/features/set-update-on-qui import downloadPlatformUpdateInjectable from "./application-update/download-platform-update/download-platform-update.injectable"; import startCatalogSyncInjectable from "./catalog-sync-to-renderer/start-catalog-sync.injectable"; import startKubeConfigSyncInjectable from "./start-main-application/runnables/kube-config-sync/start-kube-config-sync.injectable"; -import appVersionInjectable from "../common/vars/app-version.injectable"; import getRandomIdInjectable from "../common/utils/get-random-id.injectable"; import periodicalCheckForUpdatesInjectable from "./application-update/periodical-check-for-updates/periodical-check-for-updates.injectable"; import execFileInjectable from "../common/fs/exec-file.injectable"; @@ -148,9 +144,6 @@ export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {}) di.override(environmentVariablesInjectable, () => ({})); di.override(commandLineArgumentsInjectable, () => []); - di.override(productNameInjectable, () => "some-product-name"); - di.override(appVersionInjectable, () => "1.0.0"); - di.override(clusterFramesInjectable, () => observable.map()); di.override(stopServicesAndExitAppInjectable, () => () => {}); @@ -179,7 +172,6 @@ export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {}) // TODO: Remove usages of globally exported appEventBus to get rid of this di.override(appEventBusInjectable, () => new EventEmitter<[AppEvent]>()); - di.override(appNameInjectable, () => "some-app-name"); di.override(broadcastMessageInjectable, () => (channel) => { throw new Error(`Tried to broadcast message to channel "${channel}" over IPC without explicit override.`); }); @@ -210,7 +202,6 @@ const overrideRunnablesHavingSideEffects = (di: DiContainer) => { initializeExtensionsInjectable, setupIpcMainHandlersInjectable, setupLensProxyInjectable, - setupSentryInjectable, setupShellInjectable, setupSyncingOfWeblinksInjectable, setupSystemCaInjectable, diff --git a/src/main/kubectl/bundled-kubectl.injectable.ts b/src/main/kubectl/bundled-kubectl.injectable.ts index a06cbedff9..e7ecb7c7f8 100644 --- a/src/main/kubectl/bundled-kubectl.injectable.ts +++ b/src/main/kubectl/bundled-kubectl.injectable.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { getBundledKubectlVersion } from "../../common/utils"; +import bundledKubectlVersionInjectable from "../../common/vars/bundled-kubectl-version.injectable"; import createKubectlInjectable from "./create-kubectl.injectable"; const bundledKubectlInjectable = getInjectable({ @@ -11,8 +11,7 @@ const bundledKubectlInjectable = getInjectable({ instantiate: (di) => { const createKubectl = di.inject(createKubectlInjectable); - - const bundledKubectlVersion = getBundledKubectlVersion(); + const bundledKubectlVersion = di.inject(bundledKubectlVersionInjectable); return createKubectl(bundledKubectlVersion); }, diff --git a/src/main/kubectl/create-kubectl.injectable.ts b/src/main/kubectl/create-kubectl.injectable.ts index 1e13b7d02c..d0187f7ba4 100644 --- a/src/main/kubectl/create-kubectl.injectable.ts +++ b/src/main/kubectl/create-kubectl.injectable.ts @@ -12,6 +12,8 @@ import normalizedPlatformInjectable from "../../common/vars/normalized-platform. import kubectlBinaryNameInjectable from "./binary-name.injectable"; import bundledKubectlBinaryPathInjectable from "./bundled-binary-path.injectable"; import baseBundledBinariesDirectoryInjectable from "../../common/vars/base-bundled-binaries-dir.injectable"; +import bundledKubectlVersionInjectable from "../../common/vars/bundled-kubectl-version.injectable"; +import kubectlVersionMapInjectable from "./version-map.injectable"; const createKubectlInjectable = getInjectable({ id: "create-kubectl", @@ -25,6 +27,8 @@ const createKubectlInjectable = getInjectable({ kubectlBinaryName: di.inject(kubectlBinaryNameInjectable), bundledKubectlBinaryPath: di.inject(bundledKubectlBinaryPathInjectable), baseBundeledBinariesDirectory: di.inject(baseBundledBinariesDirectoryInjectable), + bundledKubectlVersion: di.inject(bundledKubectlVersionInjectable), + kubectlVersionMap: di.inject(kubectlVersionMapInjectable), }; return (clusterVersion: string) => new Kubectl(dependencies, clusterVersion); diff --git a/src/main/kubectl/kubectl.ts b/src/main/kubectl/kubectl.ts index 2e70f3c7ee..182d540692 100644 --- a/src/main/kubectl/kubectl.ts +++ b/src/main/kubectl/kubectl.ts @@ -9,7 +9,6 @@ import { promiseExecFile } from "../../common/utils/promise-exec"; import logger from "../logger"; import { ensureDir, pathExists } from "fs-extra"; import * as lockFile from "proper-lockfile"; -import { getBundledKubectlVersion } from "../../common/utils/app-version"; import { SemVer } from "semver"; import { defaultPackageMirror, packageMirrors } from "../../common/user-store/preferences-helpers"; import got from "got/dist/source"; @@ -17,26 +16,6 @@ import { promisify } from "util"; import stream from "stream"; import { noop } from "lodash/fp"; -const bundledVersion = getBundledKubectlVersion(); -const kubectlMap: Map = new Map([ - ["1.7", "1.8.15"], - ["1.8", "1.9.10"], - ["1.9", "1.10.13"], - ["1.10", "1.11.10"], - ["1.11", "1.12.10"], - ["1.12", "1.13.12"], - ["1.13", "1.13.12"], - ["1.14", "1.14.10"], - ["1.15", "1.15.11"], - ["1.16", "1.16.15"], - ["1.17", "1.17.17"], - ["1.18", "1.18.20"], - ["1.19", "1.19.12"], - ["1.20", "1.20.8"], - ["1.21", "1.21.9"], - ["1.22", "1.22.6"], - ["1.23", bundledVersion], -]); const initScriptVersionString = "# lens-initscript v3"; export interface KubectlDependencies { @@ -52,6 +31,8 @@ export interface KubectlDependencies { readonly downloadKubectlBinaries: boolean; readonly downloadMirror: string; }; + readonly bundledKubectlVersion: string; + readonly kubectlVersionMap: Map; } export class Kubectl { @@ -60,7 +41,6 @@ export class Kubectl { protected readonly path: string; protected readonly dirname: string; - public static readonly bundledKubectlVersion = bundledVersion; public static invalidBundle = false; constructor(protected readonly dependencies: KubectlDependencies, clusterVersion: string) { @@ -69,10 +49,10 @@ export class Kubectl { try { version = new SemVer(clusterVersion); } catch { - version = new SemVer(Kubectl.bundledKubectlVersion); + version = new SemVer(this.dependencies.bundledKubectlVersion); } - const fromMajorMinor = kubectlMap.get(`${version.major}.${version.minor}`); + const fromMajorMinor = this.dependencies.kubectlVersionMap.get(`${version.major}.${version.minor}`); /** * minorVersion is the first two digits of kube server version if the version map includes that, @@ -189,7 +169,7 @@ export class Kubectl { } protected async checkBundled(): Promise { - if (this.kubectlVersion === Kubectl.bundledKubectlVersion) { + if (this.kubectlVersion === this.dependencies.bundledKubectlVersion) { try { const exist = await pathExists(this.path); diff --git a/src/main/kubectl/version-map.injectable.ts b/src/main/kubectl/version-map.injectable.ts new file mode 100644 index 0000000000..2beee76e0c --- /dev/null +++ b/src/main/kubectl/version-map.injectable.ts @@ -0,0 +1,35 @@ +/** + * 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 bundledKubectlVersionInjectable from "../../common/vars/bundled-kubectl-version.injectable"; + +const kubectlVersionMapInjectable = getInjectable({ + id: "kubectl-version-map", + instantiate: (di) => { + const bundledKubectlVersion = di.inject(bundledKubectlVersionInjectable); + + return new Map([ + ["1.7", "1.8.15"], + ["1.8", "1.9.10"], + ["1.9", "1.10.13"], + ["1.10", "1.11.10"], + ["1.11", "1.12.10"], + ["1.12", "1.13.12"], + ["1.13", "1.13.12"], + ["1.14", "1.14.10"], + ["1.15", "1.15.11"], + ["1.16", "1.16.15"], + ["1.17", "1.17.17"], + ["1.18", "1.18.20"], + ["1.19", "1.19.12"], + ["1.20", "1.20.8"], + ["1.21", "1.21.9"], + ["1.22", "1.22.6"], + ["1.23", bundledKubectlVersion], + ]); + }, +}); + +export default kubectlVersionMapInjectable; diff --git a/src/main/lens-proxy/lens-proxy.injectable.ts b/src/main/lens-proxy/lens-proxy.injectable.ts index 34cb327339..5138ac191e 100644 --- a/src/main/lens-proxy/lens-proxy.injectable.ts +++ b/src/main/lens-proxy/lens-proxy.injectable.ts @@ -10,26 +10,20 @@ import httpProxy from "http-proxy"; import clusterManagerInjectable from "../cluster-manager.injectable"; import shellApiRequestInjectable from "./proxy-functions/shell-api-request/shell-api-request.injectable"; import lensProxyPortInjectable from "./lens-proxy-port.injectable"; +import contentSecurityPolicyInjectable from "../../common/vars/content-security-policy.injectable"; const lensProxyInjectable = getInjectable({ id: "lens-proxy", - instantiate: (di) => { - const clusterManager = di.inject(clusterManagerInjectable); - const router = di.inject(routerInjectable); - const shellApiRequest = di.inject(shellApiRequestInjectable); - const proxy = httpProxy.createProxy(); - const lensProxyPort = di.inject(lensProxyPortInjectable); - - return new LensProxy({ - router, - proxy, - kubeApiUpgradeRequest, - shellApiRequest, - getClusterForRequest: clusterManager.getClusterForRequest, - lensProxyPort, - }); - }, + instantiate: (di) => new LensProxy({ + router: di.inject(routerInjectable), + proxy: httpProxy.createProxy(), + kubeApiUpgradeRequest, + shellApiRequest: di.inject(shellApiRequestInjectable), + getClusterForRequest: di.inject(clusterManagerInjectable).getClusterForRequest, + lensProxyPort: di.inject(lensProxyPortInjectable), + contentSecurityPolicy: di.inject(contentSecurityPolicyInjectable), + }), }); export default lensProxyInjectable; diff --git a/src/main/lens-proxy/lens-proxy.ts b/src/main/lens-proxy/lens-proxy.ts index 5e58104d60..2a75470154 100644 --- a/src/main/lens-proxy/lens-proxy.ts +++ b/src/main/lens-proxy/lens-proxy.ts @@ -7,7 +7,7 @@ import net from "net"; import type http from "http"; import spdy from "spdy"; import type httpProxy from "http-proxy"; -import { apiPrefix, apiKubePrefix, contentSecurityPolicy } from "../../common/vars"; +import { apiPrefix, apiKubePrefix } from "../../common/vars"; import type { Router } from "../router/router"; import type { ClusterContextHandler } from "../context-handler/context-handler"; import logger from "../logger"; @@ -26,9 +26,10 @@ interface Dependencies { getClusterForRequest: GetClusterForRequest; shellApiRequest: (args: ProxyApiRequestArgs) => void | Promise; kubeApiUpgradeRequest: (args: ProxyApiRequestArgs) => void | Promise; - router: Router; - proxy: httpProxy; - lensProxyPort: { set: (portNumber: number) => void }; + readonly router: Router; + readonly proxy: httpProxy; + readonly lensProxyPort: { set: (portNumber: number) => void }; + readonly contentSecurityPolicy: string; } const watchParam = "watch"; @@ -63,7 +64,7 @@ export class LensProxy { protected closed = false; protected retryCounters = new Map(); - constructor(private dependencies: Dependencies) { + constructor(private readonly dependencies: Dependencies) { this.configureProxy(dependencies.proxy); this.proxyServer = spdy.createServer({ @@ -239,10 +240,7 @@ export class LensProxy { } } - if (contentSecurityPolicy) { - res.setHeader("Content-Security-Policy", contentSecurityPolicy); - } - + res.setHeader("Content-Security-Policy", this.dependencies.contentSecurityPolicy); this.dependencies.router.route(cluster, req, res); } } diff --git a/src/main/menu/application-menu-items.injectable.ts b/src/main/menu/application-menu-items.injectable.ts index 34d0955d77..bf1197ac1f 100644 --- a/src/main/menu/application-menu-items.injectable.ts +++ b/src/main/menu/application-menu-items.injectable.ts @@ -3,12 +3,11 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { docsUrl, productName, supportUrl } from "../../common/vars"; +import { docsUrl, supportUrl } from "../../common/vars"; import { broadcastMessage } from "../../common/ipc"; import type { MenuItemConstructorOptions } from "electron"; import { webContents } from "electron"; import loggerInjectable from "../../common/logger.injectable"; -import appNameInjectable from "../app-paths/app-name/app-name.injectable"; import electronMenuItemsInjectable from "./electron-menu-items.injectable"; import updatingIsEnabledInjectable from "../application-update/updating-is-enabled.injectable"; import navigateToPreferencesInjectable from "../../common/front-end-routing/routes/preferences/navigate-to-preferences.injectable"; @@ -24,6 +23,8 @@ import reloadCurrentApplicationWindowInjectable from "../start-main-application/ import showApplicationWindowInjectable from "../start-main-application/lens-window/show-application-window.injectable"; import processCheckingForUpdatesInjectable from "../application-update/check-for-updates/process-checking-for-updates.injectable"; import openLinkInBrowserInjectable from "../../common/utils/open-link-in-browser.injectable"; +import appNameInjectable from "../../common/vars/app-name.injectable"; +import productNameInjectable from "../../common/vars/product-name.injectable"; function ignoreIf(check: boolean, menuItems: MenuItemOpts[]) { return check ? [] : menuItems; @@ -39,6 +40,7 @@ const applicationMenuItemsInjectable = getInjectable({ instantiate: (di) => { const logger = di.inject(loggerInjectable); const appName = di.inject(appNameInjectable); + const productName = di.inject(productNameInjectable); const isMac = di.inject(isMacInjectable); const updatingIsEnabled = di.inject(updatingIsEnabledInjectable); const electronMenuItems = di.inject(electronMenuItemsInjectable); diff --git a/src/main/menu/build-version.injectable.ts b/src/main/menu/build-version.injectable.ts deleted file mode 100644 index d94594cc84..0000000000 --- a/src/main/menu/build-version.injectable.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * 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 electronAppInjectable from "../electron-app/electron-app.injectable"; - -const buildVersionInjectable = getInjectable({ - id: "build-version", - instantiate: (di) => di.inject(electronAppInjectable).getVersion(), -}); - -export default buildVersionInjectable; diff --git a/src/main/menu/menu.ts b/src/main/menu/menu.ts index 1454f38999..2082a35ed8 100644 --- a/src/main/menu/menu.ts +++ b/src/main/menu/menu.ts @@ -3,36 +3,10 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { Menu } from "electron"; -import { appName, isWindows, productName } from "../../common/vars"; -import packageJson from "../../../package.json"; import type { MenuItemOpts } from "./application-menu-items.injectable"; -import type { ShowMessagePopup } from "../electron-app/features/show-message-popup.injectable"; export type MenuTopId = "mac" | "file" | "edit" | "view" | "help"; -interface Dependencies { - appVersion: string; - extensionApiVersion: string; - showMessagePopup: ShowMessagePopup; -} - -export const showAbout = ({ showMessagePopup, extensionApiVersion, appVersion }: Dependencies) => async () => { - const appInfo = [ - `${appName}: ${appVersion}`, - `Extension API: ${extensionApiVersion}`, - `Electron: ${process.versions.electron}`, - `Chrome: ${process.versions.chrome}`, - `Node: ${process.versions.node}`, - packageJson.copyright, - ]; - - await showMessagePopup( - `${isWindows ? " ".repeat(2) : ""}${appName}`, - productName, - appInfo.join("\r\n"), - ); -}; - export function buildMenu(applicationMenuItems: MenuItemOpts[]) { Menu.setApplicationMenu( Menu.buildFromTemplate(applicationMenuItems), diff --git a/src/main/menu/show-about.injectable.ts b/src/main/menu/show-about.injectable.ts index b65530261d..e19c2b0bfa 100644 --- a/src/main/menu/show-about.injectable.ts +++ b/src/main/menu/show-about.injectable.ts @@ -3,20 +3,43 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { showAbout } from "./menu"; import showMessagePopupInjectable from "../electron-app/features/show-message-popup.injectable"; -import appVersionInjectable from "../../common/vars/app-version.injectable"; -import buildVersionInjectable from "./build-version.injectable"; +import isWindowsInjectable from "../../common/vars/is-windows.injectable"; +import appNameInjectable from "../../common/vars/app-name.injectable"; +import productNameInjectable from "../../common/vars/product-name.injectable"; +import buildVersionInjectable from "../vars/build-version/build-version.injectable"; +import extensionApiVersionInjectable from "../../common/vars/extension-api-version.injectable"; +import applicationCopyrightInjectable from "../../common/vars/application-copyright.injectable"; const showAboutInjectable = getInjectable({ id: "show-about", - instantiate: (di) => - showAbout({ - appVersion: di.inject(buildVersionInjectable), - extensionApiVersion: di.inject(appVersionInjectable), - showMessagePopup: di.inject(showMessagePopupInjectable), - }), + instantiate: (di) => { + const buildVersion = di.inject(buildVersionInjectable); + const extensionApiVersion = di.inject(extensionApiVersionInjectable); + const showMessagePopup = di.inject(showMessagePopupInjectable); + const isWindows = di.inject(isWindowsInjectable); + const appName = di.inject(appNameInjectable); + const productName = di.inject(productNameInjectable); + const applicationCopyright = di.inject(applicationCopyrightInjectable); + + return () => { + const appInfo = [ + `${appName}: ${buildVersion.get()}`, + `Extension API: ${extensionApiVersion}`, + `Electron: ${process.versions.electron}`, + `Chrome: ${process.versions.chrome}`, + `Node: ${process.versions.node}`, + applicationCopyright, + ]; + + showMessagePopup( + `${isWindows ? " ".repeat(2) : ""}${appName}`, + productName, + appInfo.join("\r\n"), + ); + }; + }, }); export default showAboutInjectable; diff --git a/src/main/routes/static-file-route.injectable.ts b/src/main/routes/static-file-route.injectable.ts index 86fa4b2fc5..2650410d0b 100644 --- a/src/main/routes/static-file-route.injectable.ts +++ b/src/main/routes/static-file-route.injectable.ts @@ -6,7 +6,7 @@ import type { SupportedFileExtension } from "../router/router-content-types"; import { contentTypes } from "../router/router-content-types"; import logger from "../logger"; import { getRouteInjectable } from "../router/router.injectable"; -import { appName, publicPath } from "../../common/vars"; +import { publicPath } from "../../common/vars"; import path from "path"; import isDevelopmentInjectable from "../../common/vars/is-development.injectable"; import httpProxy from "http-proxy"; @@ -19,66 +19,78 @@ import { webpackDevServerPort } from "../../../webpack/vars"; import type { LensApiRequest, RouteResponse } from "../router/route"; import { route } from "../router/route"; import staticFilesDirectoryInjectable from "../../common/vars/static-files-directory.injectable"; +import appNameInjectable from "../../common/vars/app-name.injectable"; interface ProductionDependencies { readFileBuffer: (path: string) => Promise; getAbsolutePath: GetAbsolutePath; joinPaths: JoinPaths; staticFilesDirectory: string; + appName: string; } -const handleStaticFileInProduction = - ({ readFileBuffer, getAbsolutePath, joinPaths, staticFilesDirectory }: ProductionDependencies) => - async ({ params }: LensApiRequest<"/{path*}">): Promise> => { - let filePath = params.path; +const handleStaticFileInProduction = ({ + readFileBuffer, + getAbsolutePath, + joinPaths, + staticFilesDirectory, + appName, +}: ProductionDependencies) => ( + async ({ params }: LensApiRequest<"/{path*}">): Promise> => { + let filePath = params.path; - for (let retryCount = 0; retryCount < 5; retryCount += 1) { - const asset = joinPaths(staticFilesDirectory, filePath); - const normalizedFilePath = getAbsolutePath(asset); + for (let retryCount = 0; retryCount < 5; retryCount += 1) { + const asset = joinPaths(staticFilesDirectory, filePath); + const normalizedFilePath = getAbsolutePath(asset); + + if (!normalizedFilePath.startsWith(staticFilesDirectory)) { + return { statusCode: 404 }; + } + + try { + const fileExtension = path + .extname(asset) + .slice(1) as SupportedFileExtension; + + const contentType = contentTypes[fileExtension] || contentTypes.txt; + + return { response: await readFileBuffer(asset), contentType }; + } catch (err) { + if (retryCount > 5) { + logger.error("handleStaticFile:", String(err)); - if (!normalizedFilePath.startsWith(staticFilesDirectory)) { return { statusCode: 404 }; } - try { - const fileExtension = path - .extname(asset) - .slice(1) as SupportedFileExtension; - - const contentType = contentTypes[fileExtension] || contentTypes.txt; - - return { response: await readFileBuffer(asset), contentType }; - } catch (err) { - if (retryCount > 5) { - logger.error("handleStaticFile:", String(err)); - - return { statusCode: 404 }; - } - - filePath = `${publicPath}/${appName}.html`; - } + filePath = `${publicPath}/${appName}.html`; } + } - return { statusCode: 404 }; - }; + return { statusCode: 404 }; + } +); interface DevelopmentDependencies { proxy: httpProxy; + appName: string; } -const handleStaticFileInDevelopment = - ({ proxy }: DevelopmentDependencies) => - ({ raw: { req, res }}: LensApiRequest<"/{path*}">): RouteResponse => { - if (req.url === "/" || !req.url?.startsWith("/build/")) { - req.url = `${publicPath}/${appName}.html`; - } +const handleStaticFileInDevelopment = ({ + proxy, + appName, +}: DevelopmentDependencies) => ( + ({ raw: { req, res }}: LensApiRequest<"/{path*}">): RouteResponse => { + if (req.url === "/" || !req.url?.startsWith("/build/")) { + req.url = `${publicPath}/${appName}.html`; + } - proxy.web(req, res, { - target: `http://127.0.0.1:${webpackDevServerPort}`, - }); + proxy.web(req, res, { + target: `http://127.0.0.1:${webpackDevServerPort}`, + }); - return { proxy }; - }; + return { proxy }; + } +); const staticFileRouteInjectable = getRouteInjectable({ id: "static-file-route", @@ -89,6 +101,7 @@ const staticFileRouteInjectable = getRouteInjectable({ const getAbsolutePath = di.inject(getAbsolutePathInjectable); const joinPaths = di.inject(joinPathsInjectable); const staticFilesDirectory = di.inject(staticFilesDirectoryInjectable); + const appName = di.inject(appNameInjectable); return route({ method: "get", @@ -97,12 +110,14 @@ const staticFileRouteInjectable = getRouteInjectable({ isDevelopment ? handleStaticFileInDevelopment({ proxy: httpProxy.createProxy(), + appName, }) : handleStaticFileInProduction({ readFileBuffer, getAbsolutePath, joinPaths, staticFilesDirectory, + appName, }), ); }, diff --git a/src/main/routes/versions/get-version-route.injectable.ts b/src/main/routes/versions/get-version-route.injectable.ts index aa846c171c..d132e242d6 100644 --- a/src/main/routes/versions/get-version-route.injectable.ts +++ b/src/main/routes/versions/get-version-route.injectable.ts @@ -3,20 +3,24 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getRouteInjectable } from "../../router/router.injectable"; -import { getAppVersion } from "../../../common/utils"; import { route } from "../../router/route"; +import buildVersionInjectable from "../../vars/build-version/build-version.injectable"; const getVersionRouteInjectable = getRouteInjectable({ id: "get-version-route", - instantiate: () => route({ - method: "get", - path: `/version`, - })(() => ({ - response: { - version: getAppVersion(), - }, - })), + instantiate: (di) => { + const buildVersion = di.inject(buildVersionInjectable); + + return route({ + method: "get", + path: `/version`, + })(() => ({ + response: { + version: buildVersion.get(), + }, + })); + }, }); export default getVersionRouteInjectable; diff --git a/src/main/shell-sync.ts b/src/main/shell-sync.ts deleted file mode 100644 index d2c58d0abe..0000000000 --- a/src/main/shell-sync.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { shellEnv } from "./utils/shell-env"; -import os from "os"; -import { app } from "electron"; -import logger from "./logger"; -import { isSnap } from "../common/vars"; -import { unionPATHs } from "../common/utils/union-env-path"; - -/** - * shellSync loads what would have been the environment if this application was - * run from the command line, into the process.env object. This is especially - * useful on macos where this always needs to be done. - */ -export async function shellSync() { - const env = await shellEnv(os.userInfo().shell); - - if (!env.LANG) { - // the LANG env var expects an underscore instead of electron's dash - env.LANG = `${app.getLocale().replace("-", "_")}.UTF-8`; - } else if (!env.LANG.endsWith(".UTF-8")) { - env.LANG += ".UTF-8"; - } - - if (!isSnap) { - // Prefer the synced PATH over the initial one - process.env.PATH = unionPATHs(env.PATH ?? "", process.env.PATH ?? ""); - } - - // The spread operator allows joining of objects. The precedence is last to first. - process.env = { - ...env, - ...process.env, - }; - - logger.debug(`[SHELL-SYNC]: Synced shell env, and updating`, env, process.env); -} diff --git a/src/main/start-main-application/lens-window/application-window/create-application-window.injectable.ts b/src/main/start-main-application/lens-window/application-window/create-application-window.injectable.ts index 1652b67f9b..fcc46ff7a3 100644 --- a/src/main/start-main-application/lens-window/application-window/create-application-window.injectable.ts +++ b/src/main/start-main-application/lens-window/application-window/create-application-window.injectable.ts @@ -6,11 +6,11 @@ import { getInjectable } from "@ogre-tools/injectable"; import createLensWindowInjectable from "./create-lens-window.injectable"; import lensProxyPortInjectable from "../../../lens-proxy/lens-proxy-port.injectable"; import isMacInjectable from "../../../../common/vars/is-mac.injectable"; -import appNameInjectable from "../../../app-paths/app-name/app-name.injectable"; import appEventBusInjectable from "../../../../common/app-event-bus/app-event-bus.injectable"; import waitUntilBundledExtensionsAreLoadedInjectable from "./wait-until-bundled-extensions-are-loaded.injectable"; import { applicationWindowInjectionToken } from "./application-window-injection-token"; import { runInAction } from "mobx"; +import appNameInjectable from "../../../../common/vars/app-name.injectable"; const createApplicationWindowInjectable = getInjectable({ id: "create-application-window", diff --git a/src/main/start-main-application/runnables/sentry/initialize-on-main.global-override-for-injectable.ts b/src/main/start-main-application/runnables/sentry/initialize-on-main.global-override-for-injectable.ts new file mode 100644 index 0000000000..3850c736a0 --- /dev/null +++ b/src/main/start-main-application/runnables/sentry/initialize-on-main.global-override-for-injectable.ts @@ -0,0 +1,9 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { getGlobalOverride } from "../../../../common/test-utils/get-global-override"; +import initializeSentryOnMainInjectable from "./initialize-on-main.injectable"; + +export default getGlobalOverride(initializeSentryOnMainInjectable, () => () => {}); diff --git a/src/main/start-main-application/runnables/sentry/initialize-on-main.injectable.ts b/src/main/start-main-application/runnables/sentry/initialize-on-main.injectable.ts new file mode 100644 index 0000000000..e60f16ff46 --- /dev/null +++ b/src/main/start-main-application/runnables/sentry/initialize-on-main.injectable.ts @@ -0,0 +1,14 @@ +/** + * 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 { init } from "@sentry/electron/main"; + +const initializeSentryOnMainInjectable = getInjectable({ + id: "initialize-sentry-on-main", + instantiate: () => init, + causesSideEffects: true, +}); + +export default initializeSentryOnMainInjectable; diff --git a/src/main/start-main-application/runnables/sentry/setup.injectable.ts b/src/main/start-main-application/runnables/sentry/setup.injectable.ts new file mode 100644 index 0000000000..59eacc4199 --- /dev/null +++ b/src/main/start-main-application/runnables/sentry/setup.injectable.ts @@ -0,0 +1,23 @@ +/** + * 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 { beforeElectronIsReadyInjectionToken } from "../../runnable-tokens/before-electron-is-ready-injection-token"; +import initializeSentryReportingWithInjectable from "../../../../common/error-reporting/initialize-sentry-reporting.injectable"; +import initializeSentryOnMainInjectable from "./initialize-on-main.injectable"; + +const setupSentryInjectable = getInjectable({ + id: "setup-sentry", + instantiate: (di) => { + const initializeSentryReportingWith = di.inject(initializeSentryReportingWithInjectable); + const initializeSentryOnMain = di.inject(initializeSentryOnMainInjectable); + + return { + run: () => initializeSentryReportingWith(initializeSentryOnMain), + }; + }, + injectionToken: beforeElectronIsReadyInjectionToken, +}); + +export default setupSentryInjectable; diff --git a/src/main/start-main-application/runnables/setup-lens-proxy.injectable.ts b/src/main/start-main-application/runnables/setup-lens-proxy.injectable.ts index 8b90bcf5e3..a75f55ec72 100644 --- a/src/main/start-main-application/runnables/setup-lens-proxy.injectable.ts +++ b/src/main/start-main-application/runnables/setup-lens-proxy.injectable.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { getAppVersion, getAppVersionFromProxyServer } from "../../../common/utils"; +import { getAppVersionFromProxyServer } from "../../../common/utils"; import exitAppInjectable from "../../electron-app/features/exit-app.injectable"; import lensProxyInjectable from "../../lens-proxy/lens-proxy.injectable"; import loggerInjectable from "../../../common/logger.injectable"; @@ -11,6 +11,7 @@ import lensProxyPortInjectable from "../../lens-proxy/lens-proxy-port.injectable import isWindowsInjectable from "../../../common/vars/is-windows.injectable"; import showErrorPopupInjectable from "../../electron-app/features/show-error-popup.injectable"; import { beforeApplicationIsLoadingInjectionToken } from "../runnable-tokens/before-application-is-loading-injection-token"; +import buildVersionInjectable from "../../vars/build-version/build-version.injectable"; const setupLensProxyInjectable = getInjectable({ id: "setup-lens-proxy", @@ -22,6 +23,7 @@ const setupLensProxyInjectable = getInjectable({ const lensProxyPort = di.inject(lensProxyPortInjectable); const isWindows = di.inject(isWindowsInjectable); const showErrorPopup = di.inject(showErrorPopupInjectable); + const buildVersion = di.inject(buildVersionInjectable); return { run: async () => { @@ -41,7 +43,7 @@ const setupLensProxyInjectable = getInjectable({ lensProxyPort.get(), ); - if (getAppVersion() !== versionFromProxy) { + if (buildVersion.get() !== versionFromProxy) { logger.error("Proxy server responded with invalid response"); return exitApp(); diff --git a/src/main/start-main-application/runnables/setup-sentry.injectable.ts b/src/main/start-main-application/runnables/setup-sentry.injectable.ts deleted file mode 100644 index 4ba3763a16..0000000000 --- a/src/main/start-main-application/runnables/setup-sentry.injectable.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * 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 { initializeSentryReporting } from "../../../common/sentry"; -import { init } from "@sentry/electron/main"; -import { beforeElectronIsReadyInjectionToken } from "../runnable-tokens/before-electron-is-ready-injection-token"; - -const setupSentryInjectable = getInjectable({ - id: "setup-sentry", - - instantiate: () => ({ - run: () => { - initializeSentryReporting(init); - }, - }), - - causesSideEffects: true, - - injectionToken: beforeElectronIsReadyInjectionToken, -}); - -export default setupSentryInjectable; diff --git a/src/main/start-main-application/runnables/setup-shell.injectable.ts b/src/main/start-main-application/runnables/setup-shell.injectable.ts index 0f23e0f2e8..80800e8073 100644 --- a/src/main/start-main-application/runnables/setup-shell.injectable.ts +++ b/src/main/start-main-application/runnables/setup-shell.injectable.ts @@ -3,21 +3,47 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { shellSync } from "../../shell-sync"; import loggerInjectable from "../../../common/logger.injectable"; import { onLoadOfApplicationInjectionToken } from "../runnable-tokens/on-load-of-application-injection-token"; +import { shellEnv } from "../../utils/shell-env"; +import os from "os"; +import { unionPATHs } from "../../../common/utils/union-env-path"; +import isSnapPackageInjectable from "../../../common/vars/is-snap-package.injectable"; +import electronAppInjectable from "../../electron-app/electron-app.injectable"; const setupShellInjectable = getInjectable({ id: "setup-shell", instantiate: (di) => { const logger = di.inject(loggerInjectable); + const isSnapPackage = di.inject(isSnapPackageInjectable); + const electronApp = di.inject(electronAppInjectable); return { run: async () => { logger.info("🐚 Syncing shell environment"); - await shellSync(); + const env = await shellEnv(os.userInfo().shell); + + if (!env.LANG) { + // the LANG env var expects an underscore instead of electron's dash + env.LANG = `${electronApp.getLocale().replace("-", "_")}.UTF-8`; + } else if (!env.LANG.endsWith(".UTF-8")) { + env.LANG += ".UTF-8"; + } + + if (!isSnapPackage) { + // Prefer the synced PATH over the initial one + process.env.PATH = unionPATHs(env.PATH ?? "", process.env.PATH ?? ""); + } + + // The spread operator allows joining of objects. The precedence is last to first. + process.env = { + ...env, + ...process.env, + }; + + logger.debug(`[SHELL-SYNC]: Synced shell env, and updating`, env, process.env); }, }; }, diff --git a/src/main/tray/electron-tray/electron-tray.injectable.ts b/src/main/tray/electron-tray/electron-tray.injectable.ts index d8b264060a..96add28ac7 100644 --- a/src/main/tray/electron-tray/electron-tray.injectable.ts +++ b/src/main/tray/electron-tray/electron-tray.injectable.ts @@ -4,12 +4,12 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { Menu, Tray } from "electron"; -import packageJsonInjectable from "../../../common/vars/package-json.injectable"; import showApplicationWindowInjectable from "../../start-main-application/lens-window/show-application-window.injectable"; import isWindowsInjectable from "../../../common/vars/is-windows.injectable"; import loggerInjectable from "../../../common/logger.injectable"; import { convertToElectronMenuTemplate } from "../reactive-tray-menu-items/converters"; import trayIconInjectable from "../menu-icon/tray-icon.injectable"; +import applicationDescriptionInjectable from "../../../common/vars/application-description.injectable"; const TRAY_LOG_PREFIX = "[TRAY]"; @@ -34,7 +34,7 @@ const electronTrayInjectable = getInjectable({ id: "electron-tray", instantiate: (di): ElectronTray => { - const packageJson = di.inject(packageJsonInjectable); + const applicationDescription = di.inject(applicationDescriptionInjectable); const showApplicationWindow = di.inject(showApplicationWindowInjectable); const isWindows = di.inject(isWindowsInjectable); const logger = di.inject(loggerInjectable); @@ -46,7 +46,7 @@ const electronTrayInjectable = getInjectable({ start: () => { tray = new Tray(trayIcon.get().iconPath); - tray.setToolTip(packageJson.description); + tray.setToolTip(applicationDescription); tray.setIgnoreDoubleClickEvents(true); if (isWindows) { diff --git a/src/main/tray/tray-menu-item/implementations/about-app-tray-item.injectable.ts b/src/main/tray/tray-menu-item/implementations/about-app-tray-item.injectable.ts index 5fb1a9f34f..5f2432966d 100644 --- a/src/main/tray/tray-menu-item/implementations/about-app-tray-item.injectable.ts +++ b/src/main/tray/tray-menu-item/implementations/about-app-tray-item.injectable.ts @@ -3,7 +3,6 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import productNameInjectable from "../../../app-paths/app-name/product-name.injectable"; import showApplicationWindowInjectable from "../../../start-main-application/lens-window/show-application-window.injectable"; import showAboutInjectable from "../../../menu/show-about.injectable"; import { trayMenuItemInjectionToken } from "../tray-menu-item-injection-token"; @@ -11,6 +10,7 @@ import { computed } from "mobx"; import withErrorLoggingInjectable from "../../../../common/utils/with-error-logging/with-error-logging.injectable"; import { withErrorSuppression } from "../../../../common/utils/with-error-suppression/with-error-suppression"; import { pipeline } from "@ogre-tools/fp"; +import productNameInjectable from "../../../../common/vars/product-name.injectable"; const aboutAppTrayItemInjectable = getInjectable({ id: "about-app-tray-item", @@ -32,15 +32,10 @@ const aboutAppTrayItemInjectable = getInjectable({ click: pipeline( async () => { await showApplicationWindow(); - - await showAbout(); + showAbout(); }, - withErrorLoggingFor(() => "[TRAY]: Opening of show about failed."), - - // TODO: Find out how to improve typing so that instead of - // x => withErrorSuppression(x) there could only be withErrorSuppression - (x) => withErrorSuppression(x), + withErrorSuppression, ), }; }, diff --git a/src/main/tray/tray-menu-item/implementations/open-app-tray-item.injectable.ts b/src/main/tray/tray-menu-item/implementations/open-app-tray-item.injectable.ts index ff19d7718a..9958448796 100644 --- a/src/main/tray/tray-menu-item/implementations/open-app-tray-item.injectable.ts +++ b/src/main/tray/tray-menu-item/implementations/open-app-tray-item.injectable.ts @@ -4,12 +4,12 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { trayMenuItemInjectionToken } from "../tray-menu-item-injection-token"; -import productNameInjectable from "../../../app-paths/app-name/product-name.injectable"; import showApplicationWindowInjectable from "../../../start-main-application/lens-window/show-application-window.injectable"; import { computed } from "mobx"; import withErrorLoggingInjectable from "../../../../common/utils/with-error-logging/with-error-logging.injectable"; import { withErrorSuppression } from "../../../../common/utils/with-error-suppression/with-error-suppression"; import { pipeline } from "@ogre-tools/fp"; +import productNameInjectable from "../../../../common/vars/product-name.injectable"; const openAppTrayItemInjectable = getInjectable({ id: "open-app-tray-item", @@ -28,15 +28,9 @@ const openAppTrayItemInjectable = getInjectable({ visible: computed(() => true), click: pipeline( - async () => { - await showApplicationWindow(); - }, - + showApplicationWindow, withErrorLoggingFor(() => "[TRAY]: Opening of application window failed."), - - // TODO: Find out how to improve typing so that instead of - // x => withErrorSuppression(x) there could only be withErrorSuppression - (x) => withErrorSuppression(x), + withErrorSuppression, ), }; }, diff --git a/src/main/vars/build-version/build-version.injectable.ts b/src/main/vars/build-version/build-version.injectable.ts new file mode 100644 index 0000000000..5e560282b9 --- /dev/null +++ b/src/main/vars/build-version/build-version.injectable.ts @@ -0,0 +1,19 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { createInitializableState } from "../../../common/initializable-state/create"; +import { buildVersionInjectionToken } from "../../../common/vars/build-semantic-version.injectable"; +import getBuildVersionInjectable from "./get-build-version.injectable"; + +const buildVersionInjectable = createInitializableState({ + id: "build-version", + init: (di) => { + const getBuildVersion = di.inject(getBuildVersionInjectable); + + return getBuildVersion(); + }, + injectionToken: buildVersionInjectionToken, +}); + +export default buildVersionInjectable; diff --git a/src/main/vars/build-version/get-build-version.injectable.ts b/src/main/vars/build-version/get-build-version.injectable.ts new file mode 100644 index 0000000000..ddbef55262 --- /dev/null +++ b/src/main/vars/build-version/get-build-version.injectable.ts @@ -0,0 +1,17 @@ +/** + * 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 electronAppInjectable from "../../electron-app/electron-app.injectable"; + +const getBuildVersionInjectable = getInjectable({ + id: "get-build-version", + instantiate: (di) => { + const electronApp = di.inject(electronAppInjectable); + + return () => electronApp.getVersion(); + }, +}); + +export default getBuildVersionInjectable; diff --git a/src/main/vars/build-version/init.injectable.ts b/src/main/vars/build-version/init.injectable.ts new file mode 100644 index 0000000000..0d879715a4 --- /dev/null +++ b/src/main/vars/build-version/init.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 { beforeApplicationIsLoadingInjectionToken } from "../../start-main-application/runnable-tokens/before-application-is-loading-injection-token"; +import buildVersionInjectable from "./build-version.injectable"; + +const initializeBuildVersionAsyncSyncBoxInjectable = getInjectable({ + id: "initialize-build-version-async-sync-box", + instantiate: (di) => { + const buildVersion = di.inject(buildVersionInjectable); + + return { + run: () => buildVersion.init(), + }; + }, + injectionToken: beforeApplicationIsLoadingInjectionToken, +}); + +export default initializeBuildVersionAsyncSyncBoxInjectable; diff --git a/src/main/vars/default-update-channel/init.injectable.ts b/src/main/vars/default-update-channel/init.injectable.ts new file mode 100644 index 0000000000..e63b12bac1 --- /dev/null +++ b/src/main/vars/default-update-channel/init.injectable.ts @@ -0,0 +1,23 @@ +/** + * 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 defaultUpdateChannelInjectable from "../../../common/application-update/selected-update-channel/default-update-channel.injectable"; +import initSemanticBuildVersionInjectable from "../../../renderer/vars/semantic-build-version/init.injectable"; +import { beforeApplicationIsLoadingInjectionToken } from "../../start-main-application/runnable-tokens/before-application-is-loading-injection-token"; + +const initDefaultUpdateChannelInjectableInjectable = getInjectable({ + id: "init-default-update-channel-injectable", + instantiate: (di) => { + const defaultUpdateChannel = di.inject(defaultUpdateChannelInjectable); + + return { + run: () => defaultUpdateChannel.init(), + runAfter: di.inject(initSemanticBuildVersionInjectable), + }; + }, + injectionToken: beforeApplicationIsLoadingInjectionToken, +}); + +export default initDefaultUpdateChannelInjectableInjectable; diff --git a/src/main/vars/semantic-build-version/init.injectable.ts b/src/main/vars/semantic-build-version/init.injectable.ts new file mode 100644 index 0000000000..8b33e27576 --- /dev/null +++ b/src/main/vars/semantic-build-version/init.injectable.ts @@ -0,0 +1,23 @@ +/** + * 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 buildSemanticVersionInjectable from "../../../common/vars/build-semantic-version.injectable"; +import { beforeApplicationIsLoadingInjectionToken } from "../../start-main-application/runnable-tokens/before-application-is-loading-injection-token"; +import initializeBuildVersionInjectable from "../build-version/init.injectable"; + +const initSemanticBuildVersionInjectable = getInjectable({ + id: "init-semantic-build-version", + instantiate: (di) => { + const buildSemanticVersion = di.inject(buildSemanticVersionInjectable); + + return { + run: () => buildSemanticVersion.init(), + runAfter: di.inject(initializeBuildVersionInjectable), + }; + }, + injectionToken: beforeApplicationIsLoadingInjectionToken, +}); + +export default initSemanticBuildVersionInjectable; diff --git a/src/migrations/cluster-store/snap.ts b/src/migrations/cluster-store/snap.ts index 9128dca82a..eb02cac81c 100644 --- a/src/migrations/cluster-store/snap.ts +++ b/src/migrations/cluster-store/snap.ts @@ -6,13 +6,14 @@ // Fix embedded kubeconfig paths under snap config import type { ClusterModel } from "../../common/cluster-types"; -import { getAppVersion } from "../../common/utils/app-version"; import fs from "fs"; import type { MigrationDeclaration } from "../helpers"; import { migrationLog } from "../helpers"; +import packageJson from "../../../package.json"; export default { - version: getAppVersion(), // Run always after upgrade + // TODO: replace with injection once migrations are made as injectables + version: packageJson.version, // Run always after upgrade run(store) { if (!process.env["SNAP"]) return; diff --git a/src/migrations/weblinks-store/currentVersion.ts b/src/migrations/weblinks-store/currentVersion.ts index 6a319bc286..40025e64cb 100644 --- a/src/migrations/weblinks-store/currentVersion.ts +++ b/src/migrations/weblinks-store/currentVersion.ts @@ -3,13 +3,14 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { getAppVersion } from "../../common/utils"; import { lensSlackWeblinkId, slackUrl } from "../../common/vars"; import type { WeblinkData } from "../../common/weblink-store"; import type { MigrationDeclaration } from "../helpers"; +import packageJson from "../../../package.json"; export default { - version: getAppVersion(), // Run always after upgrade + // TODO: replace with injection once migrations are made as injectables + version: packageJson.version, // Run always after upgrade run(store) { const weblinksRaw: any = store.get("weblinks"); const weblinks = (Array.isArray(weblinksRaw) ? weblinksRaw : []) as WeblinkData[]; diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx index 5573dbdbd2..2ebd849805 100644 --- a/src/renderer/bootstrap.tsx +++ b/src/renderer/bootstrap.tsx @@ -20,7 +20,6 @@ import configurePackages from "../common/configure-packages"; import * as initializers from "./initializers"; import logger from "../common/logger"; import { WeblinkStore } from "../common/weblink-store"; -import { initializeSentryReporting } from "../common/sentry"; import { registerCustomThemes } from "./components/monaco-editor"; import { getDi } from "./getDi"; import { DiContextProvider } from "@ogre-tools/injectable-react"; @@ -46,6 +45,7 @@ import kubernetesClusterCategoryInjectable from "../common/catalog/categories/ku import autoRegistrationInjectable from "../common/k8s-api/api-manager/auto-registration.injectable"; import assert from "assert"; import startFrameInjectable from "./start-frame/start-frame.injectable"; +import initializeSentryReportingWithInjectable from "../common/error-reporting/initialize-sentry-reporting.injectable"; configurePackages(); // global packages registerCustomThemes(); // monaco editor themes @@ -62,8 +62,10 @@ async function attachChromeDebugger() { } export async function bootstrap(di: DiContainer) { + const initializeSentryReportingWith = di.inject(initializeSentryReportingWithInjectable); + if (process.isMainFrame) { - initializeSentryReporting(init); + initializeSentryReportingWith(init); } const startFrame = di.inject(startFrameInjectable); diff --git a/src/renderer/components/+preferences/preferences-navigation/telemetry-preferences-navigation-item.injectable.ts b/src/renderer/components/+preferences/preferences-navigation/telemetry-preferences-navigation-item.injectable.ts index 1f95c74a0d..6840c360cd 100644 --- a/src/renderer/components/+preferences/preferences-navigation/telemetry-preferences-navigation-item.injectable.ts +++ b/src/renderer/components/+preferences/preferences-navigation/telemetry-preferences-navigation-item.injectable.ts @@ -8,14 +8,14 @@ import routeIsActiveInjectable from "../../../routes/route-is-active.injectable" import { computed } from "mobx"; import telemetryPreferenceItemsInjectable from "../telemetry-preference-items.injectable"; import telemetryPreferencesRouteInjectable from "../../../../common/front-end-routing/routes/preferences/telemetry/telemetry-preferences-route.injectable"; -import sentryDnsUrlInjectable from "../sentry-dns-url.injectable"; +import sentryDataSourceNameInjectable from "../../../../common/vars/sentry-dsn-url.injectable"; import navigateToPreferenceTabInjectable from "./navigate-to-preference-tab.injectable"; const terminalPreferencesNavigationItemInjectable = getInjectable({ id: "telemetry-preferences-navigation-item", instantiate: (di) => { - const sentryDnsUrl = di.inject(sentryDnsUrlInjectable); + const sentryDataSourceName = di.inject(sentryDataSourceNameInjectable); const telemetryPreferenceItems = di.inject( telemetryPreferenceItemsInjectable, @@ -37,7 +37,7 @@ const terminalPreferencesNavigationItemInjectable = getInjectable({ isActive: routeIsActive, isVisible: computed( - () => !!sentryDnsUrl || telemetryPreferenceItems.get().length > 0, + () => !!sentryDataSourceName || telemetryPreferenceItems.get().length > 0, ), orderNumber: 60, diff --git a/src/renderer/components/+preferences/sentry-dns-url.injectable.ts b/src/renderer/components/+preferences/sentry-dns-url.injectable.ts deleted file mode 100644 index 5f337436fc..0000000000 --- a/src/renderer/components/+preferences/sentry-dns-url.injectable.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * 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 { sentryDsn } from "../../../common/vars"; - -const sentryDnsUrlInjectable = getInjectable({ - id: "sentry-dns-url", - instantiate: () => sentryDsn, -}); - -export default sentryDnsUrlInjectable; diff --git a/src/renderer/components/+preferences/telemetry.tsx b/src/renderer/components/+preferences/telemetry.tsx index 26809ee2f2..6367042c61 100644 --- a/src/renderer/components/+preferences/telemetry.tsx +++ b/src/renderer/components/+preferences/telemetry.tsx @@ -12,7 +12,7 @@ import type { IComputedValue } from "mobx"; import { withInjectables } from "@ogre-tools/injectable-react"; import { Preferences } from "./preferences"; import telemetryPreferenceItemsInjectable from "./telemetry-preference-items.injectable"; -import sentryDnsUrlInjectable from "./sentry-dns-url.injectable"; +import sentryDataSourceNameInjectable from "../../../common/vars/sentry-dsn-url.injectable"; import userStoreInjectable from "../../../common/user-store/user-store.injectable"; import type { AppPreferenceRegistration } from "./app-preferences/app-preference-registration"; @@ -74,7 +74,7 @@ export const Telemetry = withInjectables( { getProps: (di) => ({ telemetryPreferenceItems: di.inject(telemetryPreferenceItemsInjectable), - sentryDnsUrl: di.inject(sentryDnsUrlInjectable), + sentryDnsUrl: di.inject(sentryDataSourceNameInjectable), userStore: di.inject(userStoreInjectable), }), }, diff --git a/src/renderer/components/+welcome/welcome.tsx b/src/renderer/components/+welcome/welcome.tsx index 4be617ae73..cf413748bc 100644 --- a/src/renderer/components/+welcome/welcome.tsx +++ b/src/renderer/components/+welcome/welcome.tsx @@ -10,12 +10,13 @@ import type { IComputedValue } from "mobx"; import type { CarouselProps } from "react-material-ui-carousel"; import LegacyCarousel from "react-material-ui-carousel"; import { Icon } from "../icon"; -import { productName, slackUrl } from "../../../common/vars"; +import { slackUrl } from "../../../common/vars"; import { withInjectables } from "@ogre-tools/injectable-react"; import welcomeMenuItemsInjectable from "./welcome-menu-items/welcome-menu-items.injectable"; import type { WelcomeMenuRegistration } from "./welcome-menu-items/welcome-menu-registration"; import welcomeBannerItemsInjectable from "./welcome-banner-items/welcome-banner-items.injectable"; import type { WelcomeBannerRegistration } from "./welcome-banner-items/welcome-banner-registration"; +import productNameInjectable from "../../../common/vars/product-name.injectable"; export const defaultWidth = 320; @@ -25,9 +26,14 @@ const Carousel = LegacyCarousel as React.ComponentType; interface Dependencies { welcomeMenuItems: IComputedValue; welcomeBannerItems: IComputedValue; + productName: string; } -const NonInjectedWelcome = observer(({ welcomeMenuItems, welcomeBannerItems }: Dependencies) => { +const NonInjectedWelcome = observer(({ + welcomeMenuItems, + welcomeBannerItems, + productName, +}: Dependencies) => { const welcomeBanners = welcomeBannerItems.get(); // if there is banner with specified width, use it to calculate the width of the container @@ -129,5 +135,6 @@ export const Welcome = withInjectables(NonInjectedWelcome, { getProps: (di) => ({ welcomeMenuItems: di.inject(welcomeMenuItemsInjectable), welcomeBannerItems: di.inject(welcomeBannerItemsInjectable), + productName: di.inject(productNameInjectable), }), }); diff --git a/src/renderer/components/cluster-settings/components/cluster-prometheus-setting.tsx b/src/renderer/components/cluster-settings/components/cluster-prometheus-setting.tsx index ad777248ad..c4f689bb58 100644 --- a/src/renderer/components/cluster-settings/components/cluster-prometheus-setting.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-prometheus-setting.tsx @@ -11,10 +11,11 @@ import type { SelectOption } from "../../select"; import { Select } from "../../select"; import { Input } from "../../input"; import { observable, computed, autorun, makeObservable } from "mobx"; -import { productName } from "../../../../common/vars"; import type { MetricProviderInfo } from "../../../../common/k8s-api/endpoints/metrics.api"; import { metricsApi } from "../../../../common/k8s-api/endpoints/metrics.api"; import { Spinner } from "../../spinner"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import productNameInjectable from "../../../../common/vars/product-name.injectable"; export interface ClusterPrometheusSettingProps { cluster: Cluster; @@ -24,8 +25,12 @@ const autoDetectPrometheus = Symbol("auto-detect-prometheus"); type ProviderValue = typeof autoDetectPrometheus | string; +interface Dependencies { + productName: string; +} + @observer -export class ClusterPrometheusSetting extends React.Component { +class NonInjectedClusterPrometheusSetting extends React.Component { @observable path = ""; @observable selectedOption: ProviderValue = autoDetectPrometheus; @observable loading = true; @@ -46,7 +51,7 @@ export class ClusterPrometheusSetting extends React.Component - {`An address to an existing Prometheus installation (/:). ${productName} tries to auto-detect address if left empty.`} + {`An address to an existing Prometheus installation (/:). ${this.props.productName} tries to auto-detect address if left empty.`} @@ -164,3 +169,10 @@ export class ClusterPrometheusSetting extends React.Component(NonInjectedClusterPrometheusSetting, { + getProps: (di, props) => ({ + ...props, + productName: di.inject(productNameInjectable), + }), +}); diff --git a/src/renderer/getDiForUnitTesting.tsx b/src/renderer/getDiForUnitTesting.tsx index 469de713b0..5d45d4d3e3 100644 --- a/src/renderer/getDiForUnitTesting.tsx +++ b/src/renderer/getDiForUnitTesting.tsx @@ -35,7 +35,6 @@ import apiManagerInjectable from "../common/k8s-api/api-manager/manager.injectab import setupOnApiErrorListenersInjectable from "./api/setup-on-api-errors.injectable"; import { observable, computed, runInAction } from "mobx"; import defaultShellInjectable from "./components/+preferences/default-shell.injectable"; -import appVersionInjectable from "../common/vars/app-version.injectable"; import requestAnimationFrameInjectable from "./components/animate/request-animation-frame.injectable"; import getRandomIdInjectable from "../common/utils/get-random-id.injectable"; import getFilePathsInjectable from "./components/+preferences/kubernetes/helm-charts/adding-of-custom-helm-repository/helm-file-input/get-file-paths.injectable"; @@ -114,8 +113,6 @@ export const getDiForUnitTesting = ( di.override(getAbsolutePathInjectable, () => getAbsolutePathFake); di.override(joinPathsInjectable, () => joinPathsFake); - di.override(appVersionInjectable, () => "1.0.0"); - di.override(historyInjectable, () => createMemoryHistory()); di.override(legacyOnChannelListenInjectable, () => () => noop); diff --git a/src/renderer/utils/prevDefault.ts b/src/renderer/utils/prevDefault.ts index 3706c04721..73bb834021 100644 --- a/src/renderer/utils/prevDefault.ts +++ b/src/renderer/utils/prevDefault.ts @@ -17,7 +17,7 @@ import type React from "react"; // console.log('stay on the page and open dialog'))}/> // -export function prevDefault(callback: (evt: E) => any) { +export function prevDefault(callback: (evt: E) => R): (event: E) => R { return function (evt: E) { evt.preventDefault(); evt.stopPropagation(); diff --git a/src/renderer/vars/build-version/build-version.injectable.ts b/src/renderer/vars/build-version/build-version.injectable.ts new file mode 100644 index 0000000000..a63a4102b0 --- /dev/null +++ b/src/renderer/vars/build-version/build-version.injectable.ts @@ -0,0 +1,19 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { createInitializableState } from "../../../common/initializable-state/create"; +import { requestFromChannelInjectionToken } from "../../../common/utils/channel/request-from-channel-injection-token"; +import { buildVersionChannel, buildVersionInjectionToken } from "../../../common/vars/build-semantic-version.injectable"; + +const buildVersionInjectable = createInitializableState({ + id: "build-version", + init: (di) => { + const requestFromChannel = di.inject(requestFromChannelInjectionToken); + + return requestFromChannel(buildVersionChannel); + }, + injectionToken: buildVersionInjectionToken, +}); + +export default buildVersionInjectable; diff --git a/src/renderer/vars/build-version/init.injectable.ts b/src/renderer/vars/build-version/init.injectable.ts new file mode 100644 index 0000000000..0dc867f0ca --- /dev/null +++ b/src/renderer/vars/build-version/init.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 { beforeFrameStartsInjectionToken } from "../../before-frame-starts/before-frame-starts-injection-token"; +import buildVersionInjectable from "./build-version.injectable"; + +const initializeBuildVersionInjectable = getInjectable({ + id: "initialize-build-version", + instantiate: (di) => { + const buildVersion = di.inject(buildVersionInjectable); + + return { + run: () => buildVersion.init(), + }; + }, + injectionToken: beforeFrameStartsInjectionToken, +}); + +export default initializeBuildVersionInjectable; diff --git a/src/renderer/vars/default-update-channel/init.injectable.ts b/src/renderer/vars/default-update-channel/init.injectable.ts new file mode 100644 index 0000000000..fb737c766b --- /dev/null +++ b/src/renderer/vars/default-update-channel/init.injectable.ts @@ -0,0 +1,23 @@ +/** + * 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 defaultUpdateChannelInjectable from "../../../common/application-update/selected-update-channel/default-update-channel.injectable"; +import initSemanticBuildVersionInjectable from "../../../renderer/vars/semantic-build-version/init.injectable"; +import { beforeFrameStartsInjectionToken } from "../../before-frame-starts/before-frame-starts-injection-token"; + +const initDefaultUpdateChannelInjectableInjectable = getInjectable({ + id: "init-default-update-channel-injectable", + instantiate: (di) => { + const defaultUpdateChannel = di.inject(defaultUpdateChannelInjectable); + + return { + run: () => defaultUpdateChannel.init(), + runAfter: di.inject(initSemanticBuildVersionInjectable), + }; + }, + injectionToken: beforeFrameStartsInjectionToken, +}); + +export default initDefaultUpdateChannelInjectableInjectable; diff --git a/src/renderer/vars/semantic-build-version/init.injectable.ts b/src/renderer/vars/semantic-build-version/init.injectable.ts new file mode 100644 index 0000000000..572ccc63ac --- /dev/null +++ b/src/renderer/vars/semantic-build-version/init.injectable.ts @@ -0,0 +1,23 @@ +/** + * 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 buildSemanticVersionInjectable from "../../../common/vars/build-semantic-version.injectable"; +import { beforeFrameStartsInjectionToken } from "../../before-frame-starts/before-frame-starts-injection-token"; +import initializeBuildVersionInjectable from "../build-version/init.injectable"; + +const initSemanticBuildVersionInjectable = getInjectable({ + id: "init-semantic-build-version", + instantiate: (di) => { + const buildSemanticVersion = di.inject(buildSemanticVersionInjectable); + + return { + run: () => buildSemanticVersion.init(), + runAfter: di.inject(initializeBuildVersionInjectable), + }; + }, + injectionToken: beforeFrameStartsInjectionToken, +}); + +export default initSemanticBuildVersionInjectable;