From 8dc0177cb2ee6a0e40127dfde527141e3a9ae005 Mon Sep 17 00:00:00 2001 From: Antti Lustila Date: Fri, 24 Mar 2023 16:17:13 +0200 Subject: [PATCH 01/35] Export `getPodsByOwnerId` to extension API (#7225) Signed-off-by: Sebastian Malton Co-authored-by: Sebastian Malton --- packages/core/src/extensions/common-api/k8s-api.ts | 6 ++++-- .../src/renderer/components/+workloads-daemonsets/store.ts | 3 +++ .../core/src/renderer/components/+workloads-jobs/store.ts | 3 +++ .../src/renderer/components/+workloads-replicasets/store.ts | 3 +++ .../renderer/components/+workloads-statefulsets/store.ts | 3 +++ 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/core/src/extensions/common-api/k8s-api.ts b/packages/core/src/extensions/common-api/k8s-api.ts index 20e687ff6d..dfb96860c0 100644 --- a/packages/core/src/extensions/common-api/k8s-api.ts +++ b/packages/core/src/extensions/common-api/k8s-api.ts @@ -32,11 +32,13 @@ import type { KubeJsonApi as InternalKubeJsonApi } from "../../common/k8s-api/ku import createKubeJsonApiInjectable from "../../common/k8s-api/create-kube-json-api.injectable"; import type { RequestInit } from "@k8slens/node-fetch"; import createKubeJsonApiForClusterInjectable from "../../common/k8s-api/create-kube-json-api-for-cluster.injectable"; +import getPodsByOwnerIdInjectable from "../../renderer/components/+workloads-pods/get-pods-by-owner-id.injectable"; export const apiManager = asLegacyGlobalForExtensionApi(apiManagerInjectable); export const forCluster = asLegacyGlobalFunctionForExtensionApi(createKubeApiForClusterInjectable); export const forRemoteCluster = asLegacyGlobalFunctionForExtensionApi(createKubeApiForRemoteClusterInjectable); export const createResourceStack = asLegacyGlobalFunctionForExtensionApi(createResourceStackInjectable); +export const getPodsByOwnerId = asLegacyGlobalFunctionForExtensionApi(getPodsByOwnerIdInjectable); const getKubeApiDeps = (): KubeApiDependencies => { const di = getLegacyGlobalDiForExtensionApi(); @@ -50,7 +52,7 @@ const getKubeApiDeps = (): KubeApiDependencies => { export interface ExternalKubeApiOptions { /** * If `true` then on creation of the `KubeApi`instance a call to `apiManager.registerApi` will be - * made. This is `true` by default to maintain backwards compatability. + * made. This is `true` by default to maintain backwards compatibility. * * Setting this to `false` might make `KubeObject`'s details drawer stop working. * @@ -200,7 +202,7 @@ export type { } from "../../common/k8s-api/kube-object.store"; /** - * @deprecated This type is only present for backwards compatable typescript support + * @deprecated This type is only present for backwards compatible typescript support */ export interface IgnoredKubeApiOptions { /** diff --git a/packages/core/src/renderer/components/+workloads-daemonsets/store.ts b/packages/core/src/renderer/components/+workloads-daemonsets/store.ts index 1345468b62..0a5e0b8f65 100644 --- a/packages/core/src/renderer/components/+workloads-daemonsets/store.ts +++ b/packages/core/src/renderer/components/+workloads-daemonsets/store.ts @@ -18,6 +18,9 @@ export class DaemonSetStore extends KubeObjectStore { super(dependencies, api, opts); } + /** + * @deprecated Switch to using `getPodsByOwnerId` directly + */ getChildPods(daemonSet: DaemonSet): Pod[] { return this.dependencies.getPodsByOwnerId(daemonSet.getId()); } diff --git a/packages/core/src/renderer/components/+workloads-jobs/store.ts b/packages/core/src/renderer/components/+workloads-jobs/store.ts index 2f6f671aad..d55153c6fa 100644 --- a/packages/core/src/renderer/components/+workloads-jobs/store.ts +++ b/packages/core/src/renderer/components/+workloads-jobs/store.ts @@ -19,6 +19,9 @@ export class JobStore extends KubeObjectStore { super(dependencies, api, opts); } + /** + * @deprecated Switch to using `getPodsByOwnerId` directly + */ getChildPods(job: Job): Pod[] { return this.dependencies.getPodsByOwnerId(job.getId()); } diff --git a/packages/core/src/renderer/components/+workloads-replicasets/store.ts b/packages/core/src/renderer/components/+workloads-replicasets/store.ts index 1a6ac96610..e0873e9386 100644 --- a/packages/core/src/renderer/components/+workloads-replicasets/store.ts +++ b/packages/core/src/renderer/components/+workloads-replicasets/store.ts @@ -18,6 +18,9 @@ export class ReplicaSetStore extends KubeObjectStore super(dependencies, api, opts); } + /** + * @deprecated Switch to using `getPodsByOwnerId` directly + */ getChildPods(replicaSet: ReplicaSet) { return this.dependencies.getPodsByOwnerId(replicaSet.getId()); } diff --git a/packages/core/src/renderer/components/+workloads-statefulsets/store.ts b/packages/core/src/renderer/components/+workloads-statefulsets/store.ts index bdedcdcaf7..28a581ed4a 100644 --- a/packages/core/src/renderer/components/+workloads-statefulsets/store.ts +++ b/packages/core/src/renderer/components/+workloads-statefulsets/store.ts @@ -18,6 +18,9 @@ export class StatefulSetStore extends KubeObjectStore Date: Mon, 27 Mar 2023 12:22:37 +0300 Subject: [PATCH 02/35] Fix download all logs for pod with few containers (#7413) * Use container name as downloaded file name Signed-off-by: Alex Andreev * Specify container to call for logs query Signed-off-by: Alex Andreev * Fixing tests Signed-off-by: Alex Andreev --------- Signed-off-by: Alex Andreev --- packages/core/src/features/pod-logs/download-logs.test.tsx | 6 +++--- .../components/dock/logs/download-all-logs.injectable.ts | 2 +- .../src/renderer/components/dock/logs/logs-view-model.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/core/src/features/pod-logs/download-logs.test.tsx b/packages/core/src/features/pod-logs/download-logs.test.tsx index 9cd378a6d4..87bcf740d3 100644 --- a/packages/core/src/features/pod-logs/download-logs.test.tsx +++ b/packages/core/src/features/pod-logs/download-logs.test.tsx @@ -190,12 +190,12 @@ describe("download logs options in logs dock tab", () => { it("logs have been called with query", () => { expect(callForLogsMock).toHaveBeenCalledWith( { name: "dockerExporter", namespace: "default" }, - { "previous": true, "timestamps": false }, + { "previous": true, "timestamps": false, container: "docker-exporter" }, ); }); it("shows save dialog with proper attributes", async () => { - expect(openSaveFileDialogMock).toHaveBeenCalledWith("dockerExporter.log", "all-logs", "text/plain"); + expect(openSaveFileDialogMock).toHaveBeenCalledWith("docker-exporter.log", "all-logs", "text/plain"); }); it("doesn't block download dropdown for interaction after click", async () => { @@ -265,7 +265,7 @@ describe("download logs options in logs dock tab", () => { it("logs have been called", () => { expect(callForLogsMock).toHaveBeenCalledWith( { name: "dockerExporter", namespace: "default" }, - { "previous": true, "timestamps": false }, + { "previous": true, "timestamps": false, container: "docker-exporter" }, ); }); diff --git a/packages/core/src/renderer/components/dock/logs/download-all-logs.injectable.ts b/packages/core/src/renderer/components/dock/logs/download-all-logs.injectable.ts index 089652af0e..45e9700564 100644 --- a/packages/core/src/renderer/components/dock/logs/download-all-logs.injectable.ts +++ b/packages/core/src/renderer/components/dock/logs/download-all-logs.injectable.ts @@ -25,7 +25,7 @@ const downloadAllLogsInjectable = getInjectable({ }); if (logs) { - openSaveFileDialog(`${params.name}.log`, logs, "text/plain"); + openSaveFileDialog(`${query.container}.log`, logs, "text/plain"); } else { showErrorNotification("No logs to download"); } diff --git a/packages/core/src/renderer/components/dock/logs/logs-view-model.ts b/packages/core/src/renderer/components/dock/logs/logs-view-model.ts index a54c0f64f6..fbf79a4010 100644 --- a/packages/core/src/renderer/components/dock/logs/logs-view-model.ts +++ b/packages/core/src/renderer/components/dock/logs/logs-view-model.ts @@ -101,7 +101,7 @@ export class LogTabViewModel { if (pod && tabData) { const params = { name: pod.getName(), namespace: pod.getNs() }; - const query = { timestamps: tabData.showTimestamps, previous: tabData.showPrevious }; + const query = { timestamps: tabData.showTimestamps, previous: tabData.showPrevious, container: tabData.selectedContainer }; return this.dependencies.downloadAllLogs(params, query); } From 1deb9883399a65f6cba8630950e6d2c385fbfdcd Mon Sep 17 00:00:00 2001 From: Janne Savolainen Date: Mon, 27 Mar 2023 12:55:15 +0300 Subject: [PATCH 03/35] Update webstorm configs (#7415) Signed-off-by: Janne Savolainen --- .idea/inspectionProfiles/Project_Default.xml | 1 + .idea/jsLinters/eslint.xml | 6 ++++++ .idea/lens.iml | 7 ++++--- 3 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 .idea/jsLinters/eslint.xml diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index e4063525ae..15223a3492 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -2,5 +2,6 @@ \ No newline at end of file diff --git a/.idea/jsLinters/eslint.xml b/.idea/jsLinters/eslint.xml new file mode 100644 index 0000000000..541945bb08 --- /dev/null +++ b/.idea/jsLinters/eslint.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/lens.iml b/.idea/lens.iml index 3bef0f9888..df2c450ec8 100644 --- a/.idea/lens.iml +++ b/.idea/lens.iml @@ -6,11 +6,12 @@ - - - + + + + From 4f2ba5df48282a03db5ed5288039b0f82c3a2e94 Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Mon, 27 Mar 2023 19:14:57 +0300 Subject: [PATCH 04/35] Fix Cannot find module '@k8slens/cluster-settings' while running in dev mode (#7412) * Adding 'prepare' commands to cluster-settings package Signed-off-by: Alex Andreev * Remove unused "lint" command from cluster-settings package Signed-off-by: Alex Andreev --------- Signed-off-by: Alex Andreev --- packages/cluster-settings/package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/cluster-settings/package.json b/packages/cluster-settings/package.json index 199347dcf4..f71236a0df 100644 --- a/packages/cluster-settings/package.json +++ b/packages/cluster-settings/package.json @@ -18,6 +18,8 @@ "clean": "rimraf dist/", "generate-types": "tsc --d --declarationDir ./dist --declarationMap --emitDeclarationOnly", "build": "npm run generate-types && swc ./src/index.ts -d ./dist", + "prepare": "npm run build", + "prepare:dev": "npm run build", "prepare:test": "npm run build" }, "devDependencies": { From ba4a283af9e8b30e9a2f6207e70976119a93c1a6 Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Tue, 28 Mar 2023 16:42:51 +0300 Subject: [PATCH 05/35] Refactor electron window setCertificateVerifyProc (#7185) * refactor electron window setCertificateVerifyProc Signed-off-by: Jari Kolehmainen * use ChromiumNetError enum in tests Signed-off-by: Jari Kolehmainen * Fix unit tests Signed-off-by: Sebastian Malton --------- Signed-off-by: Jari Kolehmainen Signed-off-by: Sebastian Malton Co-authored-by: Sebastian Malton --- .../session-certificate-verifier.test.ts | 78 +++++++++++++++++++ .../create-electron-window.injectable.ts | 22 +----- ...session-certificate-verifier.injectable.ts | 36 +++++++++ 3 files changed, 117 insertions(+), 19 deletions(-) create mode 100644 packages/core/src/main/start-main-application/lens-window/application-window/__test__/session-certificate-verifier.test.ts create mode 100644 packages/core/src/main/start-main-application/lens-window/application-window/session-certificate-verifier.injectable.ts diff --git a/packages/core/src/main/start-main-application/lens-window/application-window/__test__/session-certificate-verifier.test.ts b/packages/core/src/main/start-main-application/lens-window/application-window/__test__/session-certificate-verifier.test.ts new file mode 100644 index 0000000000..a8db1947a3 --- /dev/null +++ b/packages/core/src/main/start-main-application/lens-window/application-window/__test__/session-certificate-verifier.test.ts @@ -0,0 +1,78 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import type { DiContainer } from "@ogre-tools/injectable"; +import setupLensProxyCertificateInjectable from "../../../../start-main-application/runnables/setup-lens-proxy-certificate.injectable"; +import lensProxyCertificateInjectable from "../../../../../common/certificate/lens-proxy-certificate.injectable"; +import { getDiForUnitTesting } from "../../../../getDiForUnitTesting"; +import sessionCertificateVerifierInjectable, { ChromiumNetError } from "../session-certificate-verifier.injectable"; + +const externalCertificate = `-----BEGIN CERTIFICATE----- +MIIFzzCCBLegAwIBAgIQByL1wEn7yGRLqHZvmBzvpTANBgkqhkiG9w0BAQsFADA8 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRwwGgYDVQQDExNBbWF6b24g +UlNBIDIwNDggTTAyMB4XDTIzMDIwOTAwMDAwMFoXDTIzMTAxNDIzNTk1OVowFjEU +MBIGA1UEAxMLazhzbGVucy5kZXYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQDNdPm5tKztUpgHgDHjktelNvRsaj4QHTzShUP5p2uGu+lNHhPByp3+fp8p +v6V4PhRyH006RcyvUkQlEOiprP0fF/L16Jlrlo13N7hspVS4drlxE0v4JcLxBKm8 +pwsv7bfeZ7g6SWKA/0wbSTk8AyL0rCgcpMUWyPloq3gInO1x7kazgCAgrB34CSdj +JyD1Y8Od8eH8C9qdRlTcV0rG8y2np8YbK1lF77CXjD2feGjiUAMUAtArGKCZOc33 +erdhvXgJQ1/SgWcEbbhEZ7j8cfH6y7hPPmU43epyePvY0SZ7x1PBt870W1LjG6lq +pfzqxVVxmT6Txiktnd/6cHCzfxjbAgMBAAGjggLxMIIC7TAfBgNVHSMEGDAWgBTA +MVLNWlDDgnx0cc7L6Zz5euuC4jAdBgNVHQ4EFgQUcC3Qdy61LUiE9hOvDJGYC/yt +fu0wJQYDVR0RBB4wHIILazhzbGVucy5kZXaCDSouazhzbGVucy5kZXYwDgYDVR0P +AQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA7BgNVHR8E +NDAyMDCgLqAshipodHRwOi8vY3JsLnIybTAyLmFtYXpvbnRydXN0LmNvbS9yMm0w +Mi5jcmwwEwYDVR0gBAwwCjAIBgZngQwBAgEwdQYIKwYBBQUHAQEEaTBnMC0GCCsG +AQUFBzABhiFodHRwOi8vb2NzcC5yMm0wMi5hbWF6b250cnVzdC5jb20wNgYIKwYB +BQUHMAKGKmh0dHA6Ly9jcnQucjJtMDIuYW1hem9udHJ1c3QuY29tL3IybTAyLmNl +cjAMBgNVHRMBAf8EAjAAMIIBfAYKKwYBBAHWeQIEAgSCAWwEggFoAWYAdQDoPtDa +PvUGNTLnVyi8iWvJA9PL0RFr7Otp4Xd9bQa9bgAAAYY4etOIAAAEAwBGMEQCIGT/ +/BWgTcOFQdzEX2qKlArMTvMwXggEY+m4ervIFLFnAiAyuX0I9jbGBI1XBiQ2mjXT +FIGw3TMF5b4rrCwhkRBG/gB1ALNzdwfhhFD4Y4bWBancEQlKeS2xZwwLh9zwAw55 +NqWaAAABhjh6084AAAQDAEYwRAIgewezL8S3+qwozF4fNt+0FiV95luazD1yKb35 +ZeOqudACIC7eFoZsaySOOivbqIp+nr9PB3qD08C1VKoi/LmnDp+3AHYAtz77JN+c +Tbp18jnFulj0bF38Qs96nzXEnh0JgSXttJkAAAGGOHrTlgAABAMARzBFAiAmZyNU +1H54FbGdwwXVXPxNYVE3MUlHswkR56WvWkvJ0wIhAJELvOBDIsCJ5uxTam2Xaxe0 +nZ+YTVzXDoQAfHplV1N6MA0GCSqGSIb3DQEBCwUAA4IBAQAghl2vkfW4Gph6Ez/v +EA/INeDXSErm/o3zBv4uTS7kuINPAtTlDtVJW/usw++F5fmgjmyNVc94y35hFG9Q +8LTDgJWvxekmiJJ+FCAxbpkhqXjHhugXwoUvAKktpyFnw+1cliYeA01EevOhnN+n +ux6vjEyhhEZm/JV/TXWaNSmVprXRXwc1m5dQzEEqkXgIhhhSK7E/63L+Zm548cjp +LAp+pJnaHfg0a83QnPWyZeyob+GklQjEdx64i+7wAhhpUp1Ge2TnFfs6zQGv2Y7/ +mgyzhHkKlUwQb5pi0rgR4oqKhnItyXjWqN3Y3wefTJblIs2sxEtYEzBUwlQZ3YM/ +ycM4 +-----END CERTIFICATE-----`; + +describe("sessionCertificateVerifier", () => { + let di: DiContainer; + + beforeEach(() => { + di = getDiForUnitTesting(); + di.unoverride(lensProxyCertificateInjectable); + di.inject(setupLensProxyCertificateInjectable).run(); + }); + + it("marks lens proxy certificate as trusted", () => { + const sessionCertificateVerifier = di.inject(sessionCertificateVerifierInjectable); + const lensProxyCertificate = di.inject(lensProxyCertificateInjectable).get(); + const callback = jest.fn(); + + sessionCertificateVerifier({ + certificate: { data: lensProxyCertificate.cert }, + } as any, callback); + + expect(callback).toHaveBeenCalledWith(ChromiumNetError.SUCCESS); + }); + + it("passes verification to chromium on non lens proxy certificate", () => { + const sessionCertificateVerifier = di.inject(sessionCertificateVerifierInjectable); + const callback = jest.fn(); + + sessionCertificateVerifier({ + certificate: { data: externalCertificate }, + } as any, callback); + + expect(callback).toHaveBeenCalledWith(ChromiumNetError.RESULT_FROM_CHROMIUM); + }); +}); diff --git a/packages/core/src/main/start-main-application/lens-window/application-window/create-electron-window.injectable.ts b/packages/core/src/main/start-main-application/lens-window/application-window/create-electron-window.injectable.ts index b53f58c838..0693c71643 100644 --- a/packages/core/src/main/start-main-application/lens-window/application-window/create-electron-window.injectable.ts +++ b/packages/core/src/main/start-main-application/lens-window/application-window/create-electron-window.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 { timingSafeEqual, X509Certificate } from "crypto"; import loggerInjectable from "../../../../common/logger.injectable"; import applicationWindowStateInjectable from "./application-window-state.injectable"; import { BrowserWindow } from "electron"; @@ -14,8 +13,8 @@ import getAbsolutePathInjectable from "../../../../common/path/get-absolute-path import lensResourcesDirInjectable from "../../../../common/vars/lens-resources-dir.injectable"; import isLinuxInjectable from "../../../../common/vars/is-linux.injectable"; import pathExistsSyncInjectable from "../../../../common/fs/path-exists-sync.injectable"; -import lensProxyCertificateInjectable from "../../../../common/certificate/lens-proxy-certificate.injectable"; import { applicationInformationToken } from "@k8slens/application"; +import sessionCertificateVerifierInjectable from "./session-certificate-verifier.injectable"; export type ElectronWindowTitleBarStyle = "hiddenInset" | "hidden" | "default" | "customButtonsOnHover"; @@ -27,13 +26,6 @@ export interface UrlSource { } export type ContentSource = RequireExactlyOne; -// see https://www.electronjs.org/docs/latest/api/session#sessetcertificateverifyprocproc -enum ChromiumNetError { - SUCCESS = 0, - FAILURE = -2, - RESULT_FROM_CHROMIUM = -3, -} - export interface ElectronWindowConfiguration { id: string; title: string; @@ -64,8 +56,7 @@ const createElectronWindowInjectable = getInjectable({ const isLinux = di.inject(isLinuxInjectable); const applicationInformation = di.inject(applicationInformationToken); const pathExistsSync = di.inject(pathExistsSyncInjectable); - const lensProxyCertificate = di.inject(lensProxyCertificateInjectable).get(); - const lensProxyX509Cert = new X509Certificate(lensProxyCertificate.cert); + const sessionCertificateVerifier = di.inject(sessionCertificateVerifierInjectable); return (configuration) => { const applicationWindowState = di.inject( @@ -119,14 +110,7 @@ const createElectronWindowInjectable = getInjectable({ applicationWindowState.manage(browserWindow); - browserWindow.webContents.session.setCertificateVerifyProc((request, shouldBeTrusted) => { - const { certificate } = request; - const cert = new X509Certificate(certificate.data); - const shouldTrustCert = cert.raw.length === lensProxyX509Cert.raw.length - && timingSafeEqual(cert.raw, lensProxyX509Cert.raw); - - shouldBeTrusted(shouldTrustCert ? ChromiumNetError.SUCCESS : ChromiumNetError.RESULT_FROM_CHROMIUM); - }); + browserWindow.webContents.session.setCertificateVerifyProc(sessionCertificateVerifier); browserWindow .on("focus", () => { diff --git a/packages/core/src/main/start-main-application/lens-window/application-window/session-certificate-verifier.injectable.ts b/packages/core/src/main/start-main-application/lens-window/application-window/session-certificate-verifier.injectable.ts new file mode 100644 index 0000000000..33ec0d1f09 --- /dev/null +++ b/packages/core/src/main/start-main-application/lens-window/application-window/session-certificate-verifier.injectable.ts @@ -0,0 +1,36 @@ +/** + * 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 { timingSafeEqual, X509Certificate } from "crypto"; +import type { Request } from "electron"; +import lensProxyCertificateInjectable from "../../../../common/certificate/lens-proxy-certificate.injectable"; + +// see https://www.electronjs.org/docs/latest/api/session#sessetcertificateverifyprocproc +export enum ChromiumNetError { + SUCCESS = 0, + FAILURE = -2, + RESULT_FROM_CHROMIUM = -3, +} + +export type CertificateVerificationCallback = (error: ChromiumNetError) => void; + +const sessionCertificateVerifierInjectable = getInjectable({ + id: "session-certificate-verifier", + instantiate: (di) => { + const lensProxyCertificate = di.inject(lensProxyCertificateInjectable).get(); + const lensProxyX509Cert = new X509Certificate(lensProxyCertificate.cert); + + return (request: Request, shouldBeTrusted: CertificateVerificationCallback) => { + const { certificate } = request; + const cert = new X509Certificate(certificate.data); + const shouldTrustCert = cert.raw.length === lensProxyX509Cert.raw.length + && timingSafeEqual(cert.raw, lensProxyX509Cert.raw); + + shouldBeTrusted(shouldTrustCert ? ChromiumNetError.SUCCESS : ChromiumNetError.RESULT_FROM_CHROMIUM); + }; + }, +}); + +export default sessionCertificateVerifierInjectable; From 49f0a1af9c975e4eabeb3eefacc75c2cb0098e15 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 28 Mar 2023 10:54:25 -0400 Subject: [PATCH 06/35] Remove `BaseStore` and replace with composition of dependencies (#7002) * Rename ExtensionStore -> BaseExtensionStore - The name was too close to ExtensionsStore Signed-off-by: Sebastian Malton * Move ExtensionsStore to new format Signed-off-by: Sebastian Malton * Move ClusterStore to new format Signed-off-by: Sebastian Malton * Move UserStore to new format Signed-off-by: Sebastian Malton * Cleanup types to remove multiple cast locations Signed-off-by: Sebastian Malton * Move HotbarStore to new format Signed-off-by: Sebastian Malton * Move WeblinkStore to new format Signed-off-by: Sebastian Malton * Move FileSystemProvisionerStore to new format Signed-off-by: Sebastian Malton * Update snapshots Signed-off-by: Sebastian Malton * Clean up impl and rename to better describe intent Signed-off-by: Sebastian Malton * Fix remaining type errors Signed-off-by: Sebastian Malton * Fully split apart the enabled extensions storage Signed-off-by: Sebastian Malton * Fully split apart the clusters storage Signed-off-by: Sebastian Malton * Fully split apart the hotbar storage Signed-off-by: Sebastian Malton * Fully split apart the weblinks storage Signed-off-by: Sebastian Malton * Fully split apart the user preferences storage Signed-off-by: Sebastian Malton * Fix crashing Signed-off-by: Sebastian Malton * Fix tests and snapshots Signed-off-by: Sebastian Malton * Fix integration test failures Signed-off-by: Sebastian Malton * Improve typing to prevent errors in the future. Signed-off-by: Sebastian Malton * Cleanup @k8slens/messaging and friends - To fix type errors Signed-off-by: Sebastian Malton * Fix lint issue Signed-off-by: Sebastian Malton * Fix type errors Signed-off-by: Sebastian Malton * Fix global override not being complete enough causing tests to fail Signed-off-by: Sebastian Malton * Bump memory for unit tests on CI Signed-off-by: Sebastian Malton * Attempt to fix memory issue on CI again Signed-off-by: Sebastian Malton * Fixup test because of new injectables Signed-off-by: Sebastian Malton * Upgrade Jest Signed-off-by: Sebastian Malton * Fix unit tests falling over Signed-off-by: Sebastian Malton * Back out jest config change Signed-off-by: Sebastian Malton * Remove console log Signed-off-by: Sebastian Malton * Update snapshot Signed-off-by: Sebastian Malton * Fix tests by matching equality instead of snapshots Signed-off-by: Sebastian Malton * Fix tests by forcing specific snapshot style - Ubuntu CI seems to format arrays in snapshots differently than macOS locally Signed-off-by: Sebastian Malton --------- Signed-off-by: Sebastian Malton --- .github/workflows/test.yml | 4 +- package-lock.json | 2100 ++++++++++++++++- packages/core/package.json | 5 +- .../src/common/__tests__/hotbar-store.test.ts | 356 --- .../src/common/__tests__/user-store.test.ts | 44 +- .../core/src/common/base-store/base-store.ts | 156 -- .../src/common/base-store/channel-prefix.ts | 11 - .../base-store/migrations.injectable.ts | 46 - .../src/common/catalog-entities/web-link.ts | 6 +- packages/core/src/common/catalog/helpers.ts | 83 + .../cluster-store/cluster-store.injectable.ts | 40 - .../src/common/cluster-store/cluster-store.ts | 107 - .../initialize-sentry-reporting.injectable.ts | 6 +- .../common/fetch/proxy-fetch.injectable.ts | 4 +- .../config-maps-route.injectable.ts | 2 +- ...zontal-pod-autoscalers-route.injectable.ts | 2 +- .../config/leases/leases-route.injectable.ts | 2 +- .../limit-ranges-route.injectable.ts | 2 +- ...pod-disruption-budgets-route.injectable.ts | 2 +- .../priority-classes-route.injectable.ts | 2 +- .../resource-quotas-route.injectable.ts | 2 +- .../runtime-classes-route.injectable.ts | 2 +- .../secrets/secrets-route.injectable.ts | 2 +- ...rtical-pod-autoscalers-route.injectable.ts | 2 +- .../cluster/events/events-route.injectable.ts | 2 +- .../namespaces/namespaces-route.injectable.ts | 2 +- .../endpoints/endpoints-route.injectable.ts | 2 +- .../ingress-classeses-route.injectable.ts | 2 +- .../ingresses/ingresses-route.injectable.ts | 2 +- .../network-policies-route.injectable.ts | 2 +- .../services/services-route.injectable.ts | 2 +- .../cluster/nodes/nodes-route.injectable.ts | 2 +- .../cluster-overview-route.injectable.ts | 2 +- ...rsistent-volume-claims-route.injectable.ts | 2 +- .../persistent-volumes-route.injectable.ts | 2 +- .../storage-classes-route.injectable.ts | 2 +- .../cluster-role-bindings-route.injectable.ts | 2 +- .../cluster-roles-route.injectable.ts | 2 +- .../pod-security-policies-route.injectable.ts | 2 +- .../role-bindings-route.injectable.ts | 2 +- .../roles/roles-route.injectable.ts | 2 +- .../service-accounts-route.injectable.ts | 2 +- .../cron-jobs/cron-jobs-route.injectable.ts | 2 +- .../daemonsets/daemonsets-route.injectable.ts | 2 +- .../deployments-route.injectable.ts | 2 +- .../workloads/jobs/jobs-route.injectable.ts | 2 +- .../workloads/pods/pods-route.injectable.ts | 2 +- .../replicasets-route.injectable.ts | 2 +- ...replicationcontrollers-route.injectable.ts | 2 +- .../statefulsets-route.injectable.ts | 2 +- ...at-all-routes-have-route-component.test.ts | 10 +- packages/core/src/common/fs/fs.injectable.ts | 2 + ...le-model.global-override-for-injectable.ts | 23 +- .../common/hotbars/add-hotbar.injectable.ts | 20 - .../src/common/hotbars/store.injectable.ts | 38 - packages/core/src/common/hotbars/store.ts | 351 --- .../os/home-directory-path.injectable.ts | 2 +- .../persistent-storage/channel-prefix.ts | 15 + .../persistent-storage/create.injectable.ts | 158 ++ .../disable-sync.ts | 4 +- .../migrations.injectable.ts | 58 + .../save-to-file.ts | 0 .../storage-migration-version.injectable.ts | 32 + .../src/common/protocol-handler/router.ts | 6 +- packages/core/src/common/user-store/index.ts | 7 - .../src/common/user-store/migrations-token.ts | 11 - .../user-store/user-store.injectable.ts | 42 - .../core/src/common/user-store/user-store.ts | 156 -- ...timezone.global-override-for-injectable.ts | 0 .../current-timezone.injectable.ts | 0 ...ser-info.global-override-for-injectable.ts | 0 .../user-info.injectable.ts | 0 .../weblink-store.injectable.ts | 35 - .../common/weblinks-store/weblink-store.ts | 74 - .../__tests__/extension-loader.test.ts | 85 +- .../src/extensions/base-extension-store.ts | 103 + .../core/src/extensions/common-api/app.ts | 12 +- .../get-enabled-extensions.injectable.ts | 15 - .../core/src/extensions/common-api/stores.ts | 13 +- .../extension-discovery.injectable.ts | 4 +- .../extension-discovery.ts | 6 +- .../extension-loader.injectable.ts | 2 +- .../extension-loader/extension-loader.ts | 16 +- ...ystem-provisioner-store-injection-token.ts | 6 +- ...ile-system-provisioner-store.injectable.ts | 50 +- .../file-system-provisioner-store.ts | 52 - .../update-extensions-state.injectable.ts | 13 - .../core/src/extensions/extension-store.ts | 97 - .../extensions-store.injectable.ts | 33 - .../extensions-store/extensions-store.ts | 63 - .../lens-extension-set-dependencies.ts | 4 +- .../core/src/extensions/lens-extension.ts | 2 +- .../src/extensions/renderer-api/k8s-api.ts | 2 +- ...acters-in-page-registrations.test.tsx.snap | 4 +- .../navigate-to-extension-page.test.tsx.snap | 10 +- .../navigating-between-routes.test.tsx.snap | 4 +- ...ation-using-application-menu.test.tsx.snap | 4 +- .../application-menu.test.ts.snap | 244 +- .../application-menu/application-menu.test.ts | 10 +- .../installing-update.test.ts.snap | 16 +- ...g-update-using-topbar-button.test.tsx.snap | 4 +- .../installing-update-using-tray.test.ts.snap | 12 +- .../__snapshots__/force-update.test.ts.snap | 6 +- ...eriodical-checking-of-updates.test.ts.snap | 2 +- ...selection-of-update-stability.test.ts.snap | 2 +- .../entity-running.test.tsx.snap | 4 +- .../opening-entity-details.test.tsx.snap | 18 +- .../catalog/opening-entity-details.test.tsx | 51 +- .../main/request-activation.injectable.ts | 2 +- .../main/request-deactivation.injectable.ts | 2 +- .../delete-cluster-dialog.test.tsx.snap | 10 +- .../delete-channel-listener.injectable.ts | 10 +- .../refresh-accessibility-technical.test.ts | 8 +- .../allowed-resources-injection-token.ts | 2 +- .../main/handle-initial.injectable.ts | 6 +- .../state-sync/main/setup-sync.injectable.ts | 8 +- .../renderer/listener.injectable.ts | 2 +- .../renderer/setup-sync.injectable.ts | 4 +- .../cluster/storage/cluster-storage.test.ts} | 95 +- .../cluster/storage/common/add.injectable.ts | 39 + .../storage/common/clusters.injectable.ts | 18 + .../storage/common}/get-by-id.injectable.ts | 10 +- .../storage/common}/migration-token.ts | 2 +- .../common}/read-cluster-config.injectable.ts | 6 +- .../storage/common/state.injectable.ts | 15 + .../storage/common/storage.injectable.ts | 72 + .../main/init.injectable.ts | 10 +- .../renderer/init.injectable.ts | 8 +- .../visibility-of-sidebar-items.test.tsx | 2 +- .../keyboard-shortcuts.test.tsx.snap | 16 +- ...-settings-for-correct-entity.test.tsx.snap | 8 +- ...owing-settings-for-correct-entity.test.tsx | 50 +- ...gation-using-application-menu.test.ts.snap | 4 +- .../common/enabled-extensions.injectable.ts | 24 + .../enabled/common/is-enabled.injectable.ts | 24 + .../extensions/enabled/common/migrations.ts | 11 + .../enabled/common/state.injectable.ts | 19 + .../enabled/common/storage.injectable.ts | 39 + .../enabled/common/update-state.injectable.ts | 23 + .../enabled/main/load-storage.injectable.ts | 21 + .../main/v6.5.0-migration.injectable.ts | 26 + .../renderer/load-storage.injectable.ts | 21 + ...elm-repository-in-preferences.test.ts.snap | 24 +- ...tory-from-list-in-preferences.test.ts.snap | 20 +- ...m-repositories-in-preferences.test.ts.snap | 20 +- ...ive-repository-in-preferences.test.ts.snap | 8 +- .../common/active-hotbar-index.injectable.ts | 24 + .../storage/common/active-id.injectable.ts | 13 + .../storage/common/active.injectable.ts | 24 + .../hotbar/storage/common/add.injectable.ts | 33 + .../compute-display-index.injectable.ts | 19 + .../compute-display-label.injectable.ts | 20 + .../common/compute-hotbar-index.injectable.ts | 31 + .../common/create-hotbar.injectable.ts | 24 + .../storage/common/find-by-name.injectable.ts | 21 + .../storage/common/get-by-id.injectable.ts | 20 + .../features/hotbar/storage/common/hotbar.ts | 175 ++ .../storage/common/hotbars.injectable.ts | 18 + .../storage/common}/migrations-token.ts | 2 +- .../remove-entity-from-all.injectable.ts | 24 + .../storage/common/remove.injectable.ts | 33 + .../common/set-as-active.injectable.ts | 40 + .../hotbar/storage/common/state.injectable.ts | 14 + .../storage/common/storage.injectable.ts | 116 + .../common/switch-to-next.injectable.ts | 32 + .../common/switch-to-previous.injectable.ts | 32 + .../storage/common/toggling.injectable.ts | 25 + .../hotbar/storage/common}/types.ts | 15 +- .../storage/main/5.0.0-alpha.0.injectable.ts | 30 + .../storage/main}/5.0.0-alpha.2.injectable.ts | 6 +- .../storage/main/5.0.0-beta.10.injectable.ts | 168 ++ .../storage/main/5.0.0-beta.5.injectable.ts | 51 + .../main/load-storage.injectable.ts} | 12 +- .../renderer/init.injectable.ts | 14 +- .../hotbar/storage/storage-technical.test.ts | 373 +++ .../closing-preferences.test.tsx.snap | 16 +- ...nsion-adding-preference-tabs.test.tsx.snap | 2 +- .../hiding-of-empty-branches.test.tsx.snap | 6 +- ...n-to-application-preferences.test.tsx.snap | 10 +- ...igation-to-editor-preferences.test.ts.snap | 4 +- ...tension-specific-preferences.test.tsx.snap | 18 +- ...ion-to-kubernetes-preferences.test.ts.snap | 4 +- ...vigation-to-proxy-preferences.test.ts.snap | 4 +- ...ion-to-telemetry-preferences.test.tsx.snap | 10 +- ...ation-to-terminal-preferences.test.ts.snap | 4 +- ...gation-using-application-menu.test.ts.snap | 4 +- .../navigation-using-tray.test.ts.snap | 4 +- .../urls-of-legacy-extensions.test.tsx.snap | 10 +- .../extension-install-registry.tsx | 38 +- .../application/start-up/start-up.tsx | 26 +- .../application/theme/theme.tsx | 16 +- .../application/timezone/timezone.tsx | 18 +- .../editor-font-family/editor-font-family.tsx | 22 +- .../editor-font-size/editor-font-size.tsx | 22 +- .../editor/line-numbers/line-numbers.tsx | 25 +- .../editor/minimap/minimap.tsx | 22 +- .../editor/tab-size/tab-size.tsx | 22 +- .../kubeconfig-sync/kubeconfig-sync.tsx | 12 +- .../kubectl-binary-download.tsx | 27 +- .../kubectl-directory-for-binaries.tsx | 30 +- .../kubectl-download-mirror.tsx | 30 +- .../kubectl-path-to-binary.tsx | 68 +- .../allow-untrusted-certificates.tsx | 28 +- .../proxy/http-proxy-url/http-proxy-url.tsx | 60 +- .../automatic-error-reporting.tsx | 26 +- .../copy-paste-from-terminal.tsx | 49 +- .../terminal-font-options.injectable.tsx | 12 +- .../terminal-font-size/terminal-font-size.tsx | 52 +- .../terminal-shell-path.tsx | 53 +- .../terminal-theme/terminal-theme.tsx | 17 +- .../shell-sync/main/setup-shell.injectable.ts | 2 +- ...-originating-from-extensions.test.tsx.snap | 2 +- .../renderer/initialize.injectable.ts | 2 +- ...dability-using-extension-api.test.tsx.snap | 8 +- .../common}/https-proxy.injectable.ts | 4 +- .../is-table-column-hidden.injectable.ts | 38 + .../common}/kubeconfig-syncs.injectable.ts | 4 +- .../common}/lens-color-theme.injectable.ts | 8 +- .../common/migrations-token.ts | 11 + .../preference-descriptors.injectable.ts | 16 +- .../common}/preferences-helpers.ts | 4 +- .../common/reset-theme.injectable.ts | 24 + .../common}/shell-setting.injectable.ts | 8 +- .../common/state.injectable.ts | 19 + .../common/storage.injectable.ts | 88 + .../common}/terminal-config.injectable.ts | 9 +- .../terminal-copy-on-select.injectable.ts | 6 +- .../common}/terminal-theme.injectable.ts | 8 +- ...ggle-table-column-visibility.injectable.ts | 23 + .../main}/5.0.0-alpha.3.injectable.ts | 10 +- .../main}/5.0.3-beta.1.injectable.ts | 14 +- .../main}/file-name-migration.injectable.ts | 18 +- .../main/load-storage.injectable.ts | 26 + .../sync-open-at-login-with-os.injectable.ts | 8 +- .../renderer/load-storage.injectable.ts | 23 + .../weblinks/common/add.injectable.ts | 41 + .../weblinks/common}/migration-token.ts | 2 +- .../weblinks/common/remove.injectable.ts | 20 + .../weblinks/common/state.injectable.ts | 14 + .../weblinks/common/storage.injectable.ts | 47 + .../weblinks/common/weblinks.injectable.ts | 18 + .../weblinks/main}/5.1.4.injectable.ts | 6 +- .../weblinks/main}/5.4.5-beta.1.injectable.ts | 6 +- .../main}/currentVersion.injectable.ts | 6 +- .../weblinks/main}/links.ts | 0 .../weblinks/main/load-storage.injectable.ts} | 16 +- .../setup-syncing-of-weblinks.injectable.ts | 34 + .../stop-validating-weblinks.injectable.ts | 23 + ...weblink.global-override-for-injectable.ts} | 4 +- .../main/validate-weblink.injectable.ts | 42 + .../main/weblink-verification.injectable.ts | 105 + .../main/weblink-verifications.injectable.ts | 15 + .../renderer/load-storage.injectable.ts | 21 + ...gation-using-application-menu.test.ts.snap | 6 +- ...disable-sync-in-ipc-listener.injectable.ts | 4 +- .../ipc-channel-prefix.injectable.ts | 4 +- .../persist-state-to-config.injectable.ts | 2 +- .../__test__/kubeconfig-sync.test.ts | 9 +- .../core/src/main/catalog-sources/index.ts | 6 - .../compute-diff.injectable.ts | 2 +- .../kubeconfig-sync/manager.injectable.ts | 2 +- .../kubeconfig-sync/manager.ts | 2 +- .../sync-weblinks.injectable.ts | 19 - .../core/src/main/catalog-sources/weblinks.ts | 93 - .../src/main/cluster/manager.injectable.ts | 8 +- packages/core/src/main/cluster/manager.ts | 31 +- .../3.6.0-beta.1.injectable.ts | 2 +- .../5.0.0-beta.10.injectable.ts | 2 +- .../5.0.0-beta.13.injectable.ts | 2 +- .../store-migrations/snap.injectable.ts | 2 +- .../allowed-resources.injectable.ts | 2 +- .../setup-ipc-main-handlers.injectable.ts | 6 +- .../setup-ipc-main-handlers.ts | 11 +- .../create-extension-instance.injectable.ts | 4 +- packages/core/src/main/getDiForUnitTesting.ts | 2 +- .../helm/exec-helm/exec-env.injectable.ts | 2 +- .../migrations/5.0.0-alpha.0.injectable.ts | 34 - .../migrations/5.0.0-beta.10.injectable.ts | 182 -- .../migrations/5.0.0-beta.5.injectable.ts | 54 - .../kubectl/apply-all-handler.injectable.ts | 16 +- .../main/kubectl/create-kubectl.injectable.ts | 4 +- .../kubectl/delete-all-handler.injectable.ts | 17 +- packages/core/src/main/kubectl/kubectl.ts | 18 +- .../get-cluster-for-request.injectable.ts | 2 +- .../protocol-handler/__test__/router.test.ts | 31 +- .../lens-protocol-router-main.injectable.ts | 17 +- .../lens-protocol-router-main.ts | 16 +- .../local-shell-session.ts | 8 +- .../local-shell-session/open.injectable.ts | 6 +- .../node-shell-session/open.injectable.ts | 2 +- .../main/stores/init-user-store.injectable.ts | 26 - .../get-active-cluster-entity.injectable.ts | 14 +- ...disable-sync-in-ipc-listener.injectable.ts | 4 +- .../ipc-channel-prefix.injectable.ts | 4 +- .../persist-state-to-config.injectable.ts | 2 +- ...es-cluster-context-menu-open.injectable.ts | 2 +- .../hosted-cluster.injectable.ts | 10 +- .../should-show-resource.injectable.ts | 2 +- .../+catalog/__tests__/custom-columns.test.ts | 2 - .../renderer/components/+catalog/catalog.tsx | 12 +- .../columns/named-category.injectable.ts | 27 + .../columns/named-category.injectable.tsx | 65 - ...-named-category-column-cell.injectable.tsx | 59 + .../+catalog/hotbar-toggle-menu-item.tsx | 31 +- .../general-settings.injectable.tsx | 4 +- .../metrics-settings.injectable.tsx | 4 +- .../namespace-settings.injectable.tsx | 4 +- .../node-shell-settings.injectable.tsx | 4 +- .../proxy-settings.injectable.tsx | 4 +- .../terminal-settings.injectable.tsx | 4 +- .../get-base-registry-url.injectable.tsx | 6 +- .../workloads/workloads.injectable.ts | 2 +- .../src/renderer/components/avatar/avatar.tsx | 40 +- .../catalog-entities/weblink-add-command.tsx | 10 +- .../cluster-frame-handler.injectable.ts | 2 +- .../cluster-manager/cluster-frame-handler.ts | 2 +- .../cluster-manager/cluster-view.tsx | 4 +- .../components/delete-cluster-dialog/view.tsx | 10 +- .../renderer/components/dock/logs/list.tsx | 10 +- .../terminal/create-terminal.injectable.ts | 5 +- .../components/dock/terminal/terminal.ts | 2 +- .../hotbar-remove-command.test.tsx.snap | 97 + .../__tests__/hotbar-remove-command.test.tsx | 79 +- .../components/hotbar/hotbar-add-command.tsx | 6 +- .../components/hotbar/hotbar-menu.tsx | 265 +-- .../hotbar/hotbar-remove-command.tsx | 31 +- .../hotbar/hotbar-rename-command.tsx | 38 +- .../components/hotbar/hotbar-selector.tsx | 49 +- .../hotbar/hotbar-switch-command.tsx | 31 +- .../unique-hotbar-name.injectable.ts | 6 +- .../components/item-object-list/content.tsx | 16 +- .../sidebar-cluster.test.tsx.snap | 36 + .../layout/__tests__/sidebar-cluster.test.tsx | 60 +- .../components/layout/sidebar-cluster.tsx | 17 +- .../components/locale-date/locale-date.tsx | 12 +- .../monaco-editor/monaco-editor.tsx | 33 +- .../test-utils/get-extension-fake.ts | 6 +- .../create-extension-instance.injectable.ts | 4 +- .../add-sync-entries.injectable.tsx | 6 +- .../renderer/initializers/workload-events.tsx | 2 +- ...amespaces-forbidden-handler.injectable.tsx | 2 +- .../ipc/register-ipc-listeners.injectable.ts | 2 +- ...-protocol-add-route-handlers.injectable.ts | 4 +- .../bind-protocol-add-route-handlers.tsx | 2 +- ...ens-protocol-router-renderer.injectable.ts | 4 +- .../stores/init-user-store.injectable.ts | 23 - .../src/renderer/themes/active.injectable.ts | 2 +- .../themes/apply-lens-theme.injectable.ts | 6 +- .../setup-apply-active-theme.injectable.ts | 2 +- .../themes/terminal-colors.injectable.ts | 2 +- .../src/test-utils/override-fs-with-fakes.ts | 1 + packages/core/src/test-utils/use-fake-time.ts | 6 +- packages/open-lens/package.json | 2 +- .../features/actual/channel.no-coverage.ts | 5 - .../agnostic/src/features/actual/index.ts | 2 - .../listening-of-channels.injectable.ts | 15 +- ...essage-channel-listener-injection-token.ts | 7 +- ...equest-channel-listener-injection-token.ts | 7 +- ...ist-message-channel-listener.injectable.ts | 2 +- ...ist-message-channel-listener.injectable.ts | 2 +- .../get-message-bridge-fake.ts | 55 +- .../utilities/src/abort-controller.ts | 8 + .../utilities/src/collection-functions.ts | 6 +- .../utility-features/utilities/src/delay.ts | 4 +- .../utility-features/utilities/src/iter.ts | 8 + 365 files changed, 6733 insertions(+), 3972 deletions(-) delete mode 100644 packages/core/src/common/__tests__/hotbar-store.test.ts delete mode 100644 packages/core/src/common/base-store/base-store.ts delete mode 100644 packages/core/src/common/base-store/channel-prefix.ts delete mode 100644 packages/core/src/common/base-store/migrations.injectable.ts create mode 100644 packages/core/src/common/catalog/helpers.ts delete mode 100644 packages/core/src/common/cluster-store/cluster-store.injectable.ts delete mode 100644 packages/core/src/common/cluster-store/cluster-store.ts delete mode 100644 packages/core/src/common/hotbars/add-hotbar.injectable.ts delete mode 100644 packages/core/src/common/hotbars/store.injectable.ts delete mode 100644 packages/core/src/common/hotbars/store.ts create mode 100644 packages/core/src/common/persistent-storage/channel-prefix.ts create mode 100644 packages/core/src/common/persistent-storage/create.injectable.ts rename packages/core/src/common/{base-store => persistent-storage}/disable-sync.ts (54%) create mode 100644 packages/core/src/common/persistent-storage/migrations.injectable.ts rename packages/core/src/common/{base-store => persistent-storage}/save-to-file.ts (100%) create mode 100644 packages/core/src/common/persistent-storage/storage-migration-version.injectable.ts delete mode 100644 packages/core/src/common/user-store/index.ts delete mode 100644 packages/core/src/common/user-store/migrations-token.ts delete mode 100644 packages/core/src/common/user-store/user-store.injectable.ts delete mode 100644 packages/core/src/common/user-store/user-store.ts rename packages/core/src/common/{user-store => vars}/current-timezone.global-override-for-injectable.ts (100%) rename packages/core/src/common/{user-store => vars}/current-timezone.injectable.ts (100%) rename packages/core/src/common/{user-store => vars}/user-info.global-override-for-injectable.ts (100%) rename packages/core/src/common/{user-store => vars}/user-info.injectable.ts (100%) delete mode 100644 packages/core/src/common/weblinks-store/weblink-store.injectable.ts delete mode 100644 packages/core/src/common/weblinks-store/weblink-store.ts create mode 100644 packages/core/src/extensions/base-extension-store.ts delete mode 100644 packages/core/src/extensions/common-api/get-enabled-extensions/get-enabled-extensions.injectable.ts delete mode 100644 packages/core/src/extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.ts delete mode 100644 packages/core/src/extensions/extension-loader/update-extensions-state/update-extensions-state.injectable.ts delete mode 100644 packages/core/src/extensions/extension-store.ts delete mode 100644 packages/core/src/extensions/extensions-store/extensions-store.injectable.ts delete mode 100644 packages/core/src/extensions/extensions-store/extensions-store.ts rename packages/core/src/{common/cluster-store => features/cluster/showing-kube-resources/common}/allowed-resources-injection-token.ts (84%) rename packages/core/src/{common/__tests__/cluster-store.test.ts => features/cluster/storage/cluster-storage.test.ts} (70%) create mode 100644 packages/core/src/features/cluster/storage/common/add.injectable.ts create mode 100644 packages/core/src/features/cluster/storage/common/clusters.injectable.ts rename packages/core/src/{common/cluster-store => features/cluster/storage/common}/get-by-id.injectable.ts (59%) rename packages/core/src/{common/cluster-store => features/cluster/storage/common}/migration-token.ts (76%) rename packages/core/src/{common/cluster-store => features/cluster/storage/common}/read-cluster-config.injectable.ts (77%) create mode 100644 packages/core/src/features/cluster/storage/common/state.injectable.ts create mode 100644 packages/core/src/features/cluster/storage/common/storage.injectable.ts rename packages/core/src/features/cluster/{store => storage}/main/init.injectable.ts (60%) rename packages/core/src/features/cluster/{store => storage}/renderer/init.injectable.ts (67%) create mode 100644 packages/core/src/features/extensions/enabled/common/enabled-extensions.injectable.ts create mode 100644 packages/core/src/features/extensions/enabled/common/is-enabled.injectable.ts create mode 100644 packages/core/src/features/extensions/enabled/common/migrations.ts create mode 100644 packages/core/src/features/extensions/enabled/common/state.injectable.ts create mode 100644 packages/core/src/features/extensions/enabled/common/storage.injectable.ts create mode 100644 packages/core/src/features/extensions/enabled/common/update-state.injectable.ts create mode 100644 packages/core/src/features/extensions/enabled/main/load-storage.injectable.ts create mode 100644 packages/core/src/features/extensions/enabled/main/v6.5.0-migration.injectable.ts create mode 100644 packages/core/src/features/extensions/enabled/renderer/load-storage.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/active-hotbar-index.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/active-id.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/active.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/add.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/compute-display-index.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/compute-display-label.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/compute-hotbar-index.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/create-hotbar.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/find-by-name.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/get-by-id.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/hotbar.ts create mode 100644 packages/core/src/features/hotbar/storage/common/hotbars.injectable.ts rename packages/core/src/{common/hotbars => features/hotbar/storage/common}/migrations-token.ts (76%) create mode 100644 packages/core/src/features/hotbar/storage/common/remove-entity-from-all.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/remove.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/set-as-active.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/state.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/storage.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/switch-to-next.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/switch-to-previous.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/common/toggling.injectable.ts rename packages/core/src/{common/hotbars => features/hotbar/storage/common}/types.ts (56%) create mode 100644 packages/core/src/features/hotbar/storage/main/5.0.0-alpha.0.injectable.ts rename packages/core/src/{main/hotbar-store/migrations => features/hotbar/storage/main}/5.0.0-alpha.2.injectable.ts (76%) create mode 100644 packages/core/src/features/hotbar/storage/main/5.0.0-beta.10.injectable.ts create mode 100644 packages/core/src/features/hotbar/storage/main/5.0.0-beta.5.injectable.ts rename packages/core/src/features/hotbar/{store/main/init.injectable.ts => storage/main/load-storage.injectable.ts} (66%) rename packages/core/src/features/hotbar/{store => storage}/renderer/init.injectable.ts (53%) create mode 100644 packages/core/src/features/hotbar/storage/storage-technical.test.ts rename packages/core/src/{common/user-store => features/user-preferences/common}/https-proxy.injectable.ts (78%) create mode 100644 packages/core/src/features/user-preferences/common/is-table-column-hidden.injectable.ts rename packages/core/src/{common/user-store => features/user-preferences/common}/kubeconfig-syncs.injectable.ts (68%) rename packages/core/src/{common/user-store => features/user-preferences/common}/lens-color-theme.injectable.ts (78%) create mode 100644 packages/core/src/features/user-preferences/common/migrations-token.ts rename packages/core/src/{common/user-store => features/user-preferences/common}/preference-descriptors.injectable.ts (89%) rename packages/core/src/{common/user-store => features/user-preferences/common}/preferences-helpers.ts (94%) create mode 100644 packages/core/src/features/user-preferences/common/reset-theme.injectable.ts rename packages/core/src/{common/user-store => features/user-preferences/common}/shell-setting.injectable.ts (63%) create mode 100644 packages/core/src/features/user-preferences/common/state.injectable.ts create mode 100644 packages/core/src/features/user-preferences/common/storage.injectable.ts rename packages/core/src/{common/user-store => features/user-preferences/common}/terminal-config.injectable.ts (60%) rename packages/core/src/{common/user-store => features/user-preferences/common}/terminal-copy-on-select.injectable.ts (69%) rename packages/core/src/{common/user-store => features/user-preferences/common}/terminal-theme.injectable.ts (79%) create mode 100644 packages/core/src/features/user-preferences/common/toggle-table-column-visibility.injectable.ts rename packages/core/src/{main/user-store/migrations => features/user-preferences/main}/5.0.0-alpha.3.injectable.ts (70%) rename packages/core/src/{main/user-store/migrations => features/user-preferences/main}/5.0.3-beta.1.injectable.ts (87%) rename packages/core/src/{common/user-store => features/user-preferences/main}/file-name-migration.injectable.ts (64%) create mode 100644 packages/core/src/features/user-preferences/main/load-storage.injectable.ts rename packages/core/src/{main/user-store => features/user-preferences/main}/sync-open-at-login-with-os.injectable.ts (72%) create mode 100644 packages/core/src/features/user-preferences/renderer/load-storage.injectable.ts create mode 100644 packages/core/src/features/weblinks/common/add.injectable.ts rename packages/core/src/{common/weblinks-store => features/weblinks/common}/migration-token.ts (77%) create mode 100644 packages/core/src/features/weblinks/common/remove.injectable.ts create mode 100644 packages/core/src/features/weblinks/common/state.injectable.ts create mode 100644 packages/core/src/features/weblinks/common/storage.injectable.ts create mode 100644 packages/core/src/features/weblinks/common/weblinks.injectable.ts rename packages/core/src/{main/weblinks-store/migrations => features/weblinks/main}/5.1.4.injectable.ts (86%) rename packages/core/src/{main/weblinks-store/migrations => features/weblinks/main}/5.4.5-beta.1.injectable.ts (89%) rename packages/core/src/{main/weblinks-store/migrations => features/weblinks/main}/currentVersion.injectable.ts (87%) rename packages/core/src/{main/weblinks-store => features/weblinks/main}/links.ts (100%) rename packages/core/src/{main/start-main-application/runnables/setup-syncing-of-weblinks.injectable.ts => features/weblinks/main/load-storage.injectable.ts} (55%) create mode 100644 packages/core/src/features/weblinks/main/setup-syncing-of-weblinks.injectable.ts create mode 100644 packages/core/src/features/weblinks/main/stop-validating-weblinks.injectable.ts rename packages/core/src/{common/user-store/file-name-migration.global-override-for-injectable.ts => features/weblinks/main/validate-weblink.global-override-for-injectable.ts} (53%) create mode 100644 packages/core/src/features/weblinks/main/validate-weblink.injectable.ts create mode 100644 packages/core/src/features/weblinks/main/weblink-verification.injectable.ts create mode 100644 packages/core/src/features/weblinks/main/weblink-verifications.injectable.ts create mode 100644 packages/core/src/features/weblinks/renderer/load-storage.injectable.ts delete mode 100644 packages/core/src/main/catalog-sources/index.ts delete mode 100644 packages/core/src/main/catalog-sources/sync-weblinks.injectable.ts delete mode 100644 packages/core/src/main/catalog-sources/weblinks.ts delete mode 100644 packages/core/src/main/hotbar-store/migrations/5.0.0-alpha.0.injectable.ts delete mode 100644 packages/core/src/main/hotbar-store/migrations/5.0.0-beta.10.injectable.ts delete mode 100644 packages/core/src/main/hotbar-store/migrations/5.0.0-beta.5.injectable.ts delete mode 100644 packages/core/src/main/stores/init-user-store.injectable.ts create mode 100644 packages/core/src/renderer/components/+catalog/columns/named-category.injectable.ts delete mode 100644 packages/core/src/renderer/components/+catalog/columns/named-category.injectable.tsx create mode 100644 packages/core/src/renderer/components/+catalog/columns/render-named-category-column-cell.injectable.tsx create mode 100644 packages/core/src/renderer/components/hotbar/__tests__/__snapshots__/hotbar-remove-command.test.tsx.snap create mode 100644 packages/core/src/renderer/components/layout/__tests__/__snapshots__/sidebar-cluster.test.tsx.snap delete mode 100644 packages/core/src/renderer/stores/init-user-store.injectable.ts delete mode 100644 packages/technical-features/messaging/agnostic/src/features/actual/channel.no-coverage.ts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c733570f07..fb972b31d6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -121,5 +121,7 @@ jobs: retry_on: error command: npm ci - - run: npm run test:unit + - run: | + npm run build -- --ignore open-lens + npm run test:unit name: Run tests diff --git a/package-lock.json b/package-lock.json index 946b5f8168..c06df90bc6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3313,6 +3313,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/node": "*", @@ -3329,6 +3330,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -3340,6 +3342,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -3355,12 +3358,14 @@ "node_modules/@jest/console/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/@jest/console/node_modules/jest-util": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/node": "*", @@ -3377,6 +3382,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.3.tgz", "integrity": "sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==", + "peer": true, "dependencies": { "@jest/console": "^28.1.3", "@jest/reporters": "^28.1.3", @@ -3424,6 +3430,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", + "peer": true, "dependencies": { "@jest/environment": "^28.1.3", "@jest/expect": "^28.1.3", @@ -3437,6 +3444,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -3448,6 +3456,7 @@ "version": "28.1.2", "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", + "peer": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.13", "callsites": "^3.0.0", @@ -3461,6 +3470,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "peer": true, "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^28.1.3", @@ -3486,6 +3496,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -3501,12 +3512,14 @@ "node_modules/@jest/core/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/@jest/core/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "peer": true, "engines": { "node": ">=10" }, @@ -3517,12 +3530,14 @@ "node_modules/@jest/core/node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "peer": true }, "node_modules/@jest/core/node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "peer": true, "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -3545,6 +3560,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "peer": true, "engines": { "node": ">=10" }, @@ -3556,6 +3572,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "peer": true, "engines": { "node": ">=8" }, @@ -3567,6 +3584,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/graceful-fs": "^4.1.3", @@ -3591,6 +3609,7 @@ "version": "28.0.2", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "peer": true, "engines": { "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } @@ -3599,6 +3618,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", + "peer": true, "dependencies": { "@jest/environment": "^28.1.3", "@jest/fake-timers": "^28.1.3", @@ -3631,6 +3651,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/node": "*", @@ -3647,6 +3668,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "peer": true, "dependencies": { "path-key": "^3.0.0" }, @@ -3658,6 +3680,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", @@ -3671,12 +3694,14 @@ "node_modules/@jest/core/node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "peer": true }, "node_modules/@jest/core/node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -3771,6 +3796,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz", "integrity": "sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==", + "peer": true, "dependencies": { "expect": "^28.1.3", "jest-snapshot": "^28.1.3" @@ -4094,6 +4120,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz", "integrity": "sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg==", + "peer": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "^28.1.3", @@ -4137,6 +4164,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -4148,6 +4176,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "peer": true, "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^28.1.3", @@ -4173,6 +4202,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -4188,17 +4218,20 @@ "node_modules/@jest/reporters/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/@jest/reporters/node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "peer": true }, "node_modules/@jest/reporters/node_modules/jest-haste-map": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/graceful-fs": "^4.1.3", @@ -4223,6 +4256,7 @@ "version": "28.0.2", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "peer": true, "engines": { "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } @@ -4231,6 +4265,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/node": "*", @@ -4271,6 +4306,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", + "peer": true, "dependencies": { "@jest/console": "^28.1.3", "@jest/types": "^28.1.3", @@ -4285,6 +4321,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -4296,6 +4333,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -4311,12 +4349,14 @@ "node_modules/@jest/test-result/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/@jest/test-sequencer": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz", "integrity": "sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw==", + "peer": true, "dependencies": { "@jest/test-result": "^28.1.3", "graceful-fs": "^4.2.9", @@ -4331,6 +4371,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -4342,6 +4383,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -4357,12 +4399,14 @@ "node_modules/@jest/test-sequencer/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/@jest/test-sequencer/node_modules/jest-haste-map": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/graceful-fs": "^4.1.3", @@ -4387,6 +4431,7 @@ "version": "28.0.2", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "peer": true, "engines": { "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } @@ -4395,6 +4440,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/node": "*", @@ -9135,6 +9181,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", "integrity": "sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==", + "peer": true, "dependencies": { "@jest/transform": "^28.1.3", "@types/babel__core": "^7.1.14", @@ -9155,6 +9202,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -9166,6 +9214,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "peer": true, "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^28.1.3", @@ -9191,6 +9240,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -9206,17 +9256,20 @@ "node_modules/babel-jest/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/babel-jest/node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "peer": true }, "node_modules/babel-jest/node_modules/jest-haste-map": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/graceful-fs": "^4.1.3", @@ -9241,6 +9294,7 @@ "version": "28.0.2", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "peer": true, "engines": { "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } @@ -9249,6 +9303,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/node": "*", @@ -9280,6 +9335,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz", "integrity": "sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q==", + "peer": true, "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", @@ -9384,6 +9440,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz", "integrity": "sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A==", + "peer": true, "dependencies": { "babel-plugin-jest-hoist": "^28.1.3", "babel-preset-current-node-syntax": "^1.0.0" @@ -12876,6 +12933,7 @@ "version": "0.10.2", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "peer": true, "engines": { "node": ">=12" }, @@ -17735,6 +17793,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", + "peer": true, "dependencies": { "@jest/core": "^28.1.3", "@jest/types": "^28.1.3", @@ -17770,6 +17829,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.1.3.tgz", "integrity": "sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==", + "peer": true, "dependencies": { "execa": "^5.0.0", "p-limit": "^3.1.0" @@ -17782,6 +17842,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "peer": true, "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -17804,6 +17865,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "peer": true, "engines": { "node": ">=10" }, @@ -17815,6 +17877,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "peer": true, "engines": { "node": ">=8" }, @@ -17826,6 +17889,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "peer": true, "dependencies": { "path-key": "^3.0.0" }, @@ -17837,6 +17901,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.3.tgz", "integrity": "sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==", + "peer": true, "dependencies": { "@jest/environment": "^28.1.3", "@jest/expect": "^28.1.3", @@ -17866,6 +17931,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", + "peer": true, "dependencies": { "@jest/environment": "^28.1.3", "@jest/expect": "^28.1.3", @@ -17879,6 +17945,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -17890,6 +17957,7 @@ "version": "28.1.2", "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", + "peer": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.13", "callsites": "^3.0.0", @@ -17903,6 +17971,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "peer": true, "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^28.1.3", @@ -17928,6 +17997,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -17943,12 +18013,14 @@ "node_modules/jest-circus/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/jest-circus/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "peer": true, "engines": { "node": ">=10" }, @@ -17959,12 +18031,14 @@ "node_modules/jest-circus/node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "peer": true }, "node_modules/jest-circus/node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "peer": true, "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -17987,6 +18061,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "peer": true, "engines": { "node": ">=10" }, @@ -17998,6 +18073,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "peer": true, "engines": { "node": ">=8" }, @@ -18009,6 +18085,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/graceful-fs": "^4.1.3", @@ -18033,6 +18110,7 @@ "version": "28.0.2", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "peer": true, "engines": { "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } @@ -18041,6 +18119,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", + "peer": true, "dependencies": { "@jest/environment": "^28.1.3", "@jest/fake-timers": "^28.1.3", @@ -18073,6 +18152,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/node": "*", @@ -18089,6 +18169,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "peer": true, "dependencies": { "path-key": "^3.0.0" }, @@ -18100,6 +18181,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", @@ -18113,12 +18195,14 @@ "node_modules/jest-circus/node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "peer": true }, "node_modules/jest-cli": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.3.tgz", "integrity": "sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==", + "peer": true, "dependencies": { "@jest/core": "^28.1.3", "@jest/test-result": "^28.1.3", @@ -18152,6 +18236,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -18163,6 +18248,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -18178,12 +18264,14 @@ "node_modules/jest-cli/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/jest-cli/node_modules/jest-util": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/node": "*", @@ -18200,6 +18288,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz", "integrity": "sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==", + "peer": true, "dependencies": { "@babel/core": "^7.11.6", "@jest/test-sequencer": "^28.1.3", @@ -18244,6 +18333,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -18255,6 +18345,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -18270,12 +18361,14 @@ "node_modules/jest-config/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/jest-config/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "peer": true, "engines": { "node": ">=10" }, @@ -18287,6 +18380,7 @@ "version": "28.0.2", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "peer": true, "engines": { "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } @@ -18295,6 +18389,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/node": "*", @@ -18311,6 +18406,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", @@ -18324,7 +18420,8 @@ "node_modules/jest-config/node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "peer": true }, "node_modules/jest-diff": { "version": "28.1.3", @@ -18390,6 +18487,7 @@ "version": "28.1.1", "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", + "peer": true, "dependencies": { "detect-newline": "^3.0.0" }, @@ -18401,6 +18499,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.3.tgz", "integrity": "sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "chalk": "^4.0.0", @@ -18416,6 +18515,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -18427,6 +18527,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -18442,12 +18543,14 @@ "node_modules/jest-each/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/jest-each/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "peer": true, "engines": { "node": ">=10" }, @@ -18459,6 +18562,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/node": "*", @@ -18475,6 +18579,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", @@ -18488,7 +18593,8 @@ "node_modules/jest-each/node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "peer": true }, "node_modules/jest-environment-jsdom": { "version": "28.1.3", @@ -18767,6 +18873,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.3.tgz", "integrity": "sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==", + "peer": true, "dependencies": { "@jest/environment": "^28.1.3", "@jest/fake-timers": "^28.1.3", @@ -18783,6 +18890,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -18794,6 +18902,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -18809,12 +18918,14 @@ "node_modules/jest-environment-node/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/jest-environment-node/node_modules/jest-util": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/node": "*", @@ -18891,6 +19002,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", "integrity": "sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==", + "peer": true, "dependencies": { "jest-get-type": "^28.0.2", "pretty-format": "^28.1.3" @@ -18903,6 +19015,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -18913,12 +19026,14 @@ "node_modules/jest-leak-detector/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/jest-leak-detector/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "peer": true, "engines": { "node": ">=10" }, @@ -18930,6 +19045,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", @@ -18943,7 +19059,8 @@ "node_modules/jest-leak-detector/node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "peer": true }, "node_modules/jest-matcher-utils": { "version": "28.1.3", @@ -19171,6 +19288,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.3.tgz", "integrity": "sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==", + "peer": true, "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", @@ -19190,6 +19308,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz", "integrity": "sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==", + "peer": true, "dependencies": { "jest-regex-util": "^28.0.2", "jest-snapshot": "^28.1.3" @@ -19202,6 +19321,7 @@ "version": "28.0.2", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "peer": true, "engines": { "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } @@ -19210,6 +19330,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -19221,6 +19342,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -19236,12 +19358,14 @@ "node_modules/jest-resolve/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/jest-resolve/node_modules/jest-haste-map": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/graceful-fs": "^4.1.3", @@ -19266,6 +19390,7 @@ "version": "28.0.2", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "peer": true, "engines": { "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } @@ -19274,6 +19399,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/node": "*", @@ -19290,6 +19416,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz", "integrity": "sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==", + "peer": true, "dependencies": { "@jest/console": "^28.1.3", "@jest/environment": "^28.1.3", @@ -19321,6 +19448,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", + "peer": true, "dependencies": { "@jest/environment": "^28.1.3", "@jest/expect": "^28.1.3", @@ -19334,6 +19462,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -19345,6 +19474,7 @@ "version": "28.1.2", "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", + "peer": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.13", "callsites": "^3.0.0", @@ -19358,6 +19488,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "peer": true, "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^28.1.3", @@ -19383,6 +19514,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -19398,17 +19530,20 @@ "node_modules/jest-runner/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/jest-runner/node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "peer": true }, "node_modules/jest-runner/node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "peer": true, "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -19431,6 +19566,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "peer": true, "engines": { "node": ">=10" }, @@ -19442,6 +19578,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "peer": true, "engines": { "node": ">=8" }, @@ -19453,6 +19590,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/graceful-fs": "^4.1.3", @@ -19477,6 +19615,7 @@ "version": "28.0.2", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "peer": true, "engines": { "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } @@ -19485,6 +19624,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", + "peer": true, "dependencies": { "@jest/environment": "^28.1.3", "@jest/fake-timers": "^28.1.3", @@ -19517,6 +19657,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/node": "*", @@ -19533,6 +19674,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "peer": true, "dependencies": { "path-key": "^3.0.0" }, @@ -19544,6 +19686,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -19552,6 +19695,7 @@ "version": "0.5.13", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "peer": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -19887,6 +20031,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", + "peer": true, "dependencies": { "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", @@ -19920,6 +20065,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -19931,6 +20077,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "peer": true, "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^28.1.3", @@ -19956,6 +20103,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -19971,12 +20119,14 @@ "node_modules/jest-snapshot/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/jest-snapshot/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "peer": true, "engines": { "node": ">=10" }, @@ -19987,12 +20137,14 @@ "node_modules/jest-snapshot/node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "peer": true }, "node_modules/jest-snapshot/node_modules/jest-haste-map": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/graceful-fs": "^4.1.3", @@ -20017,6 +20169,7 @@ "version": "28.0.2", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "peer": true, "engines": { "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } @@ -20025,6 +20178,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/node": "*", @@ -20041,6 +20195,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", @@ -20054,7 +20209,8 @@ "node_modules/jest-snapshot/node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "peer": true }, "node_modules/jest-util": { "version": "29.5.0", @@ -20076,6 +20232,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz", "integrity": "sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "camelcase": "^6.2.0", @@ -20092,6 +20249,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -20103,6 +20261,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -20118,12 +20277,14 @@ "node_modules/jest-validate/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/jest-validate/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "peer": true, "engines": { "node": ">=10" }, @@ -20135,6 +20296,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "peer": true, "engines": { "node": ">=10" }, @@ -20146,6 +20308,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", @@ -20159,7 +20322,8 @@ "node_modules/jest-validate/node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "peer": true }, "node_modules/jest-watch-select-projects": { "version": "2.0.0", @@ -20526,6 +20690,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "peer": true, "dependencies": { "@jest/test-result": "^28.1.3", "@jest/types": "^28.1.3", @@ -20544,6 +20709,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -20555,6 +20721,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -20570,12 +20737,14 @@ "node_modules/jest-watcher/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/jest-watcher/node_modules/jest-util": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "peer": true, "dependencies": { "@jest/types": "^28.1.3", "@types/node": "*", @@ -20592,6 +20761,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "peer": true, "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -20605,6 +20775,7 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -20619,6 +20790,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "peer": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -20630,6 +20802,7 @@ "version": "28.1.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "peer": true, "dependencies": { "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -20645,7 +20818,8 @@ "node_modules/jest/node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "peer": true }, "node_modules/joi": { "version": "17.8.4", @@ -29856,6 +30030,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", + "peer": true, "engines": { "node": ">=10" } @@ -31513,6 +31688,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "peer": true, "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" @@ -31966,6 +32142,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "peer": true, "dependencies": { "ansi-escapes": "^4.2.1", "supports-hyperlinks": "^2.0.0" @@ -34197,7 +34374,6 @@ "filehound": "^1.17.6", "fs-extra": "^9.0.1", "glob-to-regexp": "^0.4.1", - "got": "^11.8.6", "grapheme-splitter": "^1.0.4", "handlebars": "^4.7.7", "history": "^4.10.1", @@ -34268,7 +34444,7 @@ "@types/hapi__call": "^9.0.0", "@types/hapi__subtext": "^7.0.0", "@types/http-proxy": "^1.17.9", - "@types/jest": "^28.1.6", + "@types/jest": "^29.5.0", "@types/js-yaml": "^4.0.5", "@types/lodash": "^4.14.191", "@types/marked": "^4.0.8", @@ -34326,7 +34502,7 @@ "identity-obj-proxy": "^3.0.0", "ignore-loader": "^0.1.2", "include-media": "^1.4.9", - "jest": "^28.1.3", + "jest": "^29.5.0", "jest-canvas-mock": "^2.3.1", "jest-environment-jsdom": "^28.1.3", "jest-mock-extended": "^2.0.9", @@ -34407,12 +34583,944 @@ "xterm-addon-fit": "^0.5.0" } }, + "packages/core/node_modules/@jest/console": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", + "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/@jest/core": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", + "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.5.0", + "@jest/reporters": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.5.0", + "jest-config": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-resolve-dependencies": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "jest-watcher": "^29.5.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "packages/core/node_modules/@jest/core/node_modules/jest-config": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.5.0", + "@jest/types": "^29.5.0", + "babel-jest": "^29.5.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.5.0", + "jest-environment-node": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "packages/core/node_modules/@jest/environment": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", + "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-mock": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/@jest/expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", + "dev": true, + "dependencies": { + "expect": "^29.5.0", + "jest-snapshot": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/@jest/expect-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.4.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/@jest/fake-timers": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", + "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/@jest/reporters": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", + "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@jridgewell/trace-mapping": "^0.3.15", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "packages/core/node_modules/@jest/test-result": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", + "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/@jest/test-sequencer": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", + "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.5.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "packages/core/node_modules/@sinonjs/fake-timers": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", + "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0" + } + }, + "packages/core/node_modules/@types/jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, "packages/core/node_modules/@types/node": { "version": "16.18.16", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.16.tgz", "integrity": "sha512-ZOzvDRWp8dCVBmgnkIqYCArgdFOO9YzocZp8Ra25N/RStKiWvMOXHMz+GjSeVNe5TstaTmTWPucGJkDw0XXJWA==", "dev": true }, + "packages/core/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "packages/core/node_modules/babel-jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", + "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.5.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.5.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "packages/core/node_modules/babel-plugin-jest-hoist": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", + "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/babel-preset-jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", + "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.5.0", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "packages/core/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/core/node_modules/diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "packages/core/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "packages/core/node_modules/expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/core/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/core/node_modules/jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", + "dev": true, + "dependencies": { + "@jest/core": "^29.5.0", + "@jest/types": "^29.5.0", + "import-local": "^3.0.2", + "jest-cli": "^29.5.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "packages/core/node_modules/jest-changed-files": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", + "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/jest-circus": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", + "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.5.0", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.5.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/jest-cli": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", + "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", + "dev": true, + "dependencies": { + "@jest/core": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "packages/core/node_modules/jest-cli/node_modules/jest-config": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.5.0", + "@jest/types": "^29.5.0", + "babel-jest": "^29.5.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.5.0", + "jest-environment-node": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "packages/core/node_modules/jest-diff": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/jest-docblock": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", + "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/jest-each": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", + "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.4.3", + "jest-util": "^29.5.0", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/jest-environment-node": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/jest-leak-detector": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", + "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/jest-matcher-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/jest-message-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.5.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/jest-mock": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", + "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/jest-resolve": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", + "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/jest-resolve-dependencies": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", + "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.4.3", + "jest-snapshot": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/jest-runner": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", + "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.5.0", + "@jest/environment": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.4.3", + "jest-environment-node": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-leak-detector": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-resolve": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-util": "^29.5.0", + "jest-watcher": "^29.5.0", + "jest-worker": "^29.5.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/jest-snapshot": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", + "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.5.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.5.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/jest-validate": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", + "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.4.3", + "leven": "^3.1.0", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/jest-watcher": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", + "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.5.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/jest-worker": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", + "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.5.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/core/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/core/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "packages/core/node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "packages/core/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "packages/core/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "packages/core/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "packages/ensure-binaries": { "name": "@k8slens/ensure-binaries", "version": "6.5.0-alpha.1", @@ -36504,7 +37612,7 @@ "esbuild-loader": "^2.20.0", "fork-ts-checker-webpack-plugin": "^7.3.0", "html-webpack-plugin": "^5.5.0", - "jest": "^28.1.3", + "jest": "^29.5.0", "jest-environment-jsdom": "^28.1.3", "jsonfile": "^6.1.0", "mini-css-extract-plugin": "^2.7.1", @@ -36536,12 +37644,354 @@ "node": ">=16 <17" } }, + "packages/open-lens/node_modules/@jest/console": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", + "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/@jest/core": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", + "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.5.0", + "@jest/reporters": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.5.0", + "jest-config": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-resolve-dependencies": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "jest-watcher": "^29.5.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "packages/open-lens/node_modules/@jest/core/node_modules/jest-config": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.5.0", + "@jest/types": "^29.5.0", + "babel-jest": "^29.5.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.5.0", + "jest-environment-node": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "packages/open-lens/node_modules/@jest/environment": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", + "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-mock": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/@jest/expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", + "dev": true, + "dependencies": { + "expect": "^29.5.0", + "jest-snapshot": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/@jest/expect-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.4.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/@jest/fake-timers": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", + "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/@jest/reporters": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", + "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@jridgewell/trace-mapping": "^0.3.15", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "packages/open-lens/node_modules/@jest/test-result": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", + "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/@jest/test-sequencer": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", + "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.5.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "packages/open-lens/node_modules/@sinonjs/fake-timers": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", + "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0" + } + }, "packages/open-lens/node_modules/@types/node": { "version": "16.18.16", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.16.tgz", "integrity": "sha512-ZOzvDRWp8dCVBmgnkIqYCArgdFOO9YzocZp8Ra25N/RStKiWvMOXHMz+GjSeVNe5TstaTmTWPucGJkDw0XXJWA==", "dev": true }, + "packages/open-lens/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "packages/open-lens/node_modules/babel-jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", + "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.5.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.5.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "packages/open-lens/node_modules/babel-plugin-jest-hoist": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", + "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/babel-preset-jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", + "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.5.0", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "packages/open-lens/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/open-lens/node_modules/diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "packages/open-lens/node_modules/dotenv": { "version": "16.0.3", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", @@ -36551,6 +38001,571 @@ "node": ">=12" } }, + "packages/open-lens/node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "packages/open-lens/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "packages/open-lens/node_modules/expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/open-lens/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/open-lens/node_modules/jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", + "dev": true, + "dependencies": { + "@jest/core": "^29.5.0", + "@jest/types": "^29.5.0", + "import-local": "^3.0.2", + "jest-cli": "^29.5.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "packages/open-lens/node_modules/jest-changed-files": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", + "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/jest-circus": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", + "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.5.0", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.5.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/jest-cli": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", + "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", + "dev": true, + "dependencies": { + "@jest/core": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "packages/open-lens/node_modules/jest-cli/node_modules/jest-config": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.5.0", + "@jest/types": "^29.5.0", + "babel-jest": "^29.5.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.5.0", + "jest-environment-node": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "packages/open-lens/node_modules/jest-diff": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/jest-docblock": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", + "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/jest-each": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", + "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.4.3", + "jest-util": "^29.5.0", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/jest-environment-node": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/jest-leak-detector": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", + "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/jest-matcher-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/jest-message-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.5.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/jest-mock": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", + "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/jest-resolve": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", + "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/jest-resolve-dependencies": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", + "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.4.3", + "jest-snapshot": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/jest-runner": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", + "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.5.0", + "@jest/environment": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.4.3", + "jest-environment-node": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-leak-detector": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-resolve": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-util": "^29.5.0", + "jest-watcher": "^29.5.0", + "jest-worker": "^29.5.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/jest-snapshot": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", + "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.5.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.5.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/jest-validate": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", + "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.4.3", + "leven": "^3.1.0", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/jest-watcher": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", + "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.5.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/jest-worker": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", + "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.5.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/open-lens/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/open-lens/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "packages/open-lens/node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "packages/open-lens/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "packages/open-lens/node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "packages/open-lens/node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -36582,6 +38597,21 @@ "url": "https://opencollective.com/stylus" } }, + "packages/open-lens/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "packages/open-lens/node_modules/tsconfig-paths": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.1.2.tgz", diff --git a/packages/core/package.json b/packages/core/package.json index ad6e7e45ae..b608493c38 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -144,7 +144,6 @@ "filehound": "^1.17.6", "fs-extra": "^9.0.1", "glob-to-regexp": "^0.4.1", - "got": "^11.8.6", "grapheme-splitter": "^1.0.4", "handlebars": "^4.7.7", "history": "^4.10.1", @@ -215,7 +214,7 @@ "@types/hapi__call": "^9.0.0", "@types/hapi__subtext": "^7.0.0", "@types/http-proxy": "^1.17.9", - "@types/jest": "^28.1.6", + "@types/jest": "^29.5.0", "@types/js-yaml": "^4.0.5", "@types/lodash": "^4.14.191", "@types/marked": "^4.0.8", @@ -273,7 +272,7 @@ "identity-obj-proxy": "^3.0.0", "ignore-loader": "^0.1.2", "include-media": "^1.4.9", - "jest": "^28.1.3", + "jest": "^29.5.0", "jest-canvas-mock": "^2.3.1", "jest-environment-jsdom": "^28.1.3", "jest-mock-extended": "^2.0.9", diff --git a/packages/core/src/common/__tests__/hotbar-store.test.ts b/packages/core/src/common/__tests__/hotbar-store.test.ts deleted file mode 100644 index 474ebc1618..0000000000 --- a/packages/core/src/common/__tests__/hotbar-store.test.ts +++ /dev/null @@ -1,356 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { anyObject } from "jest-mock-extended"; -import type { CatalogEntity, CatalogEntityData, CatalogEntityKindData } from "../catalog"; -import { getDiForUnitTesting } from "../../main/getDiForUnitTesting"; -import type { DiContainer } from "@ogre-tools/injectable"; -import hotbarStoreInjectable from "../hotbars/store.injectable"; -import type { HotbarStore } from "../hotbars/store"; -import catalogEntityRegistryInjectable from "../../main/catalog/entity-registry.injectable"; -import { computed } from "mobx"; -import hasCategoryForEntityInjectable from "../catalog/has-category-for-entity.injectable"; -import catalogCatalogEntityInjectable from "../catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable"; -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"; -import writeJsonSyncInjectable from "../fs/write-json-sync.injectable"; - -function getMockCatalogEntity(data: Partial & CatalogEntityKindData): CatalogEntity { - return { - getName: jest.fn(() => data.metadata?.name), - getId: jest.fn(() => data.metadata?.uid), - getSource: jest.fn(() => data.metadata?.source ?? "unknown"), - isEnabled: jest.fn(() => data.status?.enabled ?? true), - onContextMenuOpen: jest.fn(), - onSettingsOpen: jest.fn(), - metadata: {}, - spec: {}, - status: {}, - ...data, - } as CatalogEntity; -} - -describe("HotbarStore", () => { - let di: DiContainer; - let hotbarStore: HotbarStore; - let testCluster: CatalogEntity; - let minikubeCluster: CatalogEntity; - let awsCluster: CatalogEntity; - let loggerMock: jest.Mocked; - - beforeEach(async () => { - di = getDiForUnitTesting(); - - testCluster = getMockCatalogEntity({ - apiVersion: "v1", - kind: "Cluster", - status: { - phase: "Running", - }, - metadata: { - uid: "some-test-id", - name: "my-test-cluster", - source: "local", - labels: {}, - }, - }); - minikubeCluster = getMockCatalogEntity({ - apiVersion: "v1", - kind: "Cluster", - status: { - phase: "Running", - }, - metadata: { - uid: "some-minikube-id", - name: "my-minikube-cluster", - source: "local", - labels: {}, - }, - }); - awsCluster = getMockCatalogEntity({ - apiVersion: "v1", - kind: "Cluster", - status: { - phase: "Running", - }, - metadata: { - uid: "some-aws-id", - name: "my-aws-cluster", - source: "local", - labels: {}, - }, - }); - - di.override(hasCategoryForEntityInjectable, () => () => true); - - loggerMock = { - warn: jest.fn(), - debug: jest.fn(), - error: jest.fn(), - info: jest.fn(), - silly: jest.fn(), - }; - - di.override(loggerInjectable, () => loggerMock); - - di.override(directoryForUserDataInjectable, () => "/some-directory-for-user-data"); - - const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable); - const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable); - - catalogEntityRegistry.addComputedSource("some-id", computed(() => [ - testCluster, - minikubeCluster, - awsCluster, - catalogCatalogEntity, - ])); - }); - - describe("given no previous data in store, running all migrations", () => { - beforeEach(() => { - hotbarStore = di.inject(hotbarStoreInjectable); - - hotbarStore.load(); - }); - - describe("load", () => { - it("loads one hotbar by default", () => { - expect(hotbarStore.hotbars.length).toEqual(1); - }); - }); - - describe("add", () => { - it("adds a hotbar", () => { - hotbarStore.add({ name: "hottest" }); - expect(hotbarStore.hotbars.length).toEqual(2); - }); - }); - - describe("hotbar items", () => { - it("initially creates 12 empty cells", () => { - expect(hotbarStore.getActive().items.length).toEqual(12); - }); - - it("initially adds catalog entity as first item", () => { - expect(hotbarStore.getActive().items[0]?.entity.name).toEqual("Catalog"); - }); - - it("adds items", () => { - hotbarStore.addToHotbar(testCluster); - const items = hotbarStore.getActive().items.filter(Boolean); - - expect(items.length).toEqual(2); - }); - - it("removes items", () => { - hotbarStore.addToHotbar(testCluster); - hotbarStore.removeFromHotbar("some-test-id"); - hotbarStore.removeFromHotbar("catalog-entity"); - const items = hotbarStore.getActive().items.filter(Boolean); - - expect(items).toStrictEqual([]); - }); - - it("does nothing if removing with invalid uid", () => { - hotbarStore.addToHotbar(testCluster); - hotbarStore.removeFromHotbar("invalid uid"); - const items = hotbarStore.getActive().items.filter(Boolean); - - expect(items.length).toEqual(2); - }); - - it("moves item to empty cell", () => { - hotbarStore.addToHotbar(testCluster); - hotbarStore.addToHotbar(minikubeCluster); - hotbarStore.addToHotbar(awsCluster); - - expect(hotbarStore.getActive().items[6]).toBeNull(); - - hotbarStore.restackItems(1, 5); - - expect(hotbarStore.getActive().items[5]).toBeTruthy(); - expect(hotbarStore.getActive().items[5]?.entity.uid).toEqual("some-test-id"); - }); - - it("moves items down", () => { - hotbarStore.addToHotbar(testCluster); - hotbarStore.addToHotbar(minikubeCluster); - hotbarStore.addToHotbar(awsCluster); - - // aws -> catalog - hotbarStore.restackItems(3, 0); - - const items = hotbarStore.getActive().items.map(item => item?.entity.uid || null); - - expect(items.slice(0, 4)).toEqual(["some-aws-id", "catalog-entity", "some-test-id", "some-minikube-id"]); - }); - - it("moves items up", () => { - hotbarStore.addToHotbar(testCluster); - hotbarStore.addToHotbar(minikubeCluster); - hotbarStore.addToHotbar(awsCluster); - - // test -> aws - hotbarStore.restackItems(1, 3); - - const items = hotbarStore.getActive().items.map(item => item?.entity.uid || null); - - expect(items.slice(0, 4)).toEqual(["catalog-entity", "some-minikube-id", "some-aws-id", "some-test-id"]); - }); - - it("logs an error if cellIndex is out of bounds", () => { - hotbarStore.add({ name: "hottest", id: "hottest" }); - hotbarStore.setActiveHotbar("hottest"); - - hotbarStore.addToHotbar(testCluster, -1); - expect(loggerMock.error).toBeCalledWith("[HOTBAR-STORE]: cannot pin entity to hotbar outside of index range", anyObject()); - - hotbarStore.addToHotbar(testCluster, 12); - expect(loggerMock.error).toBeCalledWith("[HOTBAR-STORE]: cannot pin entity to hotbar outside of index range", anyObject()); - - hotbarStore.addToHotbar(testCluster, 13); - expect(loggerMock.error).toBeCalledWith("[HOTBAR-STORE]: cannot pin entity to hotbar outside of index range", anyObject()); - }); - - it("throws an error if getId is invalid or returns not a string", () => { - expect(() => hotbarStore.addToHotbar({} as any)).toThrowError(TypeError); - expect(() => hotbarStore.addToHotbar({ getId: () => true } as any)).toThrowError(TypeError); - }); - - it("throws an error if getName is invalid or returns not a string", () => { - expect(() => hotbarStore.addToHotbar({ getId: () => "" } as any)).toThrowError(TypeError); - expect(() => hotbarStore.addToHotbar({ getId: () => "", getName: () => 4 } as any)).toThrowError(TypeError); - }); - - it("does nothing when item moved to same cell", () => { - hotbarStore.addToHotbar(testCluster); - hotbarStore.restackItems(1, 1); - - expect(hotbarStore.getActive().items[1]?.entity.uid).toEqual("some-test-id"); - }); - - it("new items takes first empty cell", () => { - hotbarStore.addToHotbar(testCluster); - hotbarStore.addToHotbar(awsCluster); - hotbarStore.restackItems(0, 3); - hotbarStore.addToHotbar(minikubeCluster); - - expect(hotbarStore.getActive().items[0]?.entity.uid).toEqual("some-minikube-id"); - }); - - it("throws if invalid arguments provided", () => { - hotbarStore.addToHotbar(testCluster); - - expect(() => hotbarStore.restackItems(-5, 0)).toThrow(); - expect(() => hotbarStore.restackItems(2, -1)).toThrow(); - expect(() => hotbarStore.restackItems(14, 1)).toThrow(); - expect(() => hotbarStore.restackItems(11, 112)).toThrow(); - }); - - it("checks if entity already pinned to hotbar", () => { - hotbarStore.addToHotbar(testCluster); - - expect(hotbarStore.isAddedToActive(testCluster)).toBeTruthy(); - expect(hotbarStore.isAddedToActive(awsCluster)).toBeFalsy(); - }); - }); - }); - - describe("given data from 5.0.0-beta.3 and version being 5.0.0-beta.10", () => { - beforeEach(() => { - const writeJsonSync = di.inject(writeJsonSyncInjectable); - - writeJsonSync("/some-directory-for-user-data/lens-hotbar-store.json", { - __internal__: { - migrations: { - version: "5.0.0-beta.3", - }, - }, - hotbars: [ - { - id: "3caac17f-aec2-4723-9694-ad204465d935", - name: "myhotbar", - items: [ - { - entity: { - uid: "some-aws-id", - }, - }, - { - entity: { - uid: "55b42c3c7ba3b04193416cda405269a5", - }, - }, - { - entity: { - uid: "176fd331968660832f62283219d7eb6e", - }, - }, - { - entity: { - uid: "61c4fb45528840ebad1badc25da41d14", - name: "user1-context", - source: "local", - }, - }, - { - entity: { - uid: "27d6f99fe9e7548a6e306760bfe19969", - name: "foo2", - source: "local", - }, - }, - null, - { - entity: { - uid: "c0b20040646849bb4dcf773e43a0bf27", - name: "multinode-demo", - source: "local", - }, - }, - null, - null, - null, - null, - null, - ], - }, - ], - }); - - di.override(storeMigrationVersionInjectable, () => "5.0.0-beta.10"); - - hotbarStore = di.inject(hotbarStoreInjectable); - - hotbarStore.load(); - }); - - it("allows to retrieve a hotbar", () => { - const hotbar = hotbarStore.findById("3caac17f-aec2-4723-9694-ad204465d935"); - - expect(hotbar?.id).toBe("3caac17f-aec2-4723-9694-ad204465d935"); - }); - - it("clears cells without entity", () => { - const items = hotbarStore.hotbars[0].items; - - expect(items[2]).toBeNull(); - }); - - it("adds extra data to cells with according entity", () => { - const items = hotbarStore.hotbars[0].items; - - expect(items[0]).toEqual({ - entity: { - name: "my-aws-cluster", - source: "local", - uid: "some-aws-id", - }, - }); - }); - }); -}); diff --git a/packages/core/src/common/__tests__/user-store.test.ts b/packages/core/src/common/__tests__/user-store.test.ts index fb8d020fb0..eee46fa9a4 100644 --- a/packages/core/src/common/__tests__/user-store.test.ts +++ b/packages/core/src/common/__tests__/user-store.test.ts @@ -2,11 +2,8 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { UserStore } from "../user-store"; -import userStoreInjectable from "../user-store/user-store.injectable"; import type { DiContainer } from "@ogre-tools/injectable"; import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable"; -import type { ClusterStoreModel } from "../cluster-store/cluster-store"; import { defaultThemeId } from "../vars"; import writeFileInjectable from "../fs/write-file.injectable"; import { getDiForUnitTesting } from "../../main/getDiForUnitTesting"; @@ -15,9 +12,16 @@ import releaseChannelInjectable from "../vars/release-channel.injectable"; import defaultUpdateChannelInjectable from "../../features/application-update/common/selected-update-channel/default-update-channel.injectable"; import writeJsonSyncInjectable from "../fs/write-json-sync.injectable"; import writeFileSyncInjectable from "../fs/write-file-sync.injectable"; +import type { UserPreferencesState } from "../../features/user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../features/user-preferences/common/state.injectable"; +import userPreferencesPersistentStorageInjectable from "../../features/user-preferences/common/storage.injectable"; +import type { ResetTheme } from "../../features/user-preferences/common/reset-theme.injectable"; +import resetThemeInjectable from "../../features/user-preferences/common/reset-theme.injectable"; +import type { ClusterStoreModel } from "../../features/cluster/storage/common/storage.injectable"; describe("user store tests", () => { - let userStore: UserStore; + let state: UserPreferencesState; + let resetTheme: ResetTheme; let di: DiContainer; beforeEach(async () => { @@ -33,6 +37,8 @@ describe("user store tests", () => { await di.inject(defaultUpdateChannelInjectable).init(); + state = di.inject(userPreferencesStateInjectable); + resetTheme = di.inject(resetThemeInjectable); }); describe("for an empty config", () => { @@ -42,25 +48,23 @@ describe("user store tests", () => { writeJsonSync("/some-directory-for-user-data/lens-user-store.json", {}); writeJsonSync("/some-directory-for-user-data/kube_config", {}); - userStore = di.inject(userStoreInjectable); - - userStore.load(); + di.inject(userPreferencesPersistentStorageInjectable).loadAndStartSyncing(); }); it("allows setting and getting preferences", () => { - userStore.httpsProxy = "abcd://defg"; + state.httpsProxy = "abcd://defg"; - expect(userStore.httpsProxy).toBe("abcd://defg"); - expect(userStore.colorTheme).toBe(defaultThemeId); + expect(state.httpsProxy).toBe("abcd://defg"); + expect(state.colorTheme).toBe(defaultThemeId); - userStore.colorTheme = "light"; - expect(userStore.colorTheme).toBe("light"); + state.colorTheme = "light"; + expect(state.colorTheme).toBe("light"); }); it("correctly resets theme to default value", async () => { - userStore.colorTheme = "some other theme"; - userStore.resetTheme(); - expect(userStore.colorTheme).toBe(defaultThemeId); + state.colorTheme = "some other theme"; + resetTheme(); + expect(state.colorTheme).toBe(defaultThemeId); }); }); @@ -92,18 +96,16 @@ describe("user store tests", () => { di.override(storeMigrationVersionInjectable, () => "10.0.0"); - userStore = di.inject(userStoreInjectable); - - userStore.load(); + di.inject(userPreferencesPersistentStorageInjectable).loadAndStartSyncing(); }); it("skips clusters for adding to kube-sync with files under extension_data/", () => { - expect(userStore.syncKubeconfigEntries.has("/some-directory-for-user-data/extension_data/foo/bar")).toBe(false); - expect(userStore.syncKubeconfigEntries.has("/some/other/path")).toBe(true); + expect(state.syncKubeconfigEntries.has("/some-directory-for-user-data/extension_data/foo/bar")).toBe(false); + expect(state.syncKubeconfigEntries.has("/some/other/path")).toBe(true); }); it("allows access to the colorTheme preference", () => { - expect(userStore.colorTheme).toBe("light"); + expect(state.colorTheme).toBe("light"); }); }); }); diff --git a/packages/core/src/common/base-store/base-store.ts b/packages/core/src/common/base-store/base-store.ts deleted file mode 100644 index a1dd26f0f7..0000000000 --- a/packages/core/src/common/base-store/base-store.ts +++ /dev/null @@ -1,156 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type Config from "conf"; -import type { Migrations, Options as ConfOptions } from "conf/dist/source/types"; -import type { IEqualsComparer } from "mobx"; -import { makeObservable, reaction } from "mobx"; -import { disposer, isPromiseLike } from "@k8slens/utilities"; -import { broadcastMessage } from "../ipc"; -import isEqual from "lodash/isEqual"; -import { kebabCase } from "lodash"; -import type { GetConfigurationFileModel } from "../get-configuration-file-model/get-configuration-file-model.injectable"; -import type { Logger } from "../logger"; -import type { PersistStateToConfig } from "./save-to-file"; -import type { GetBasenameOfPath } from "../path/get-basename.injectable"; -import type { EnlistMessageChannelListener } from "@k8slens/messaging"; -import { toJS } from "../utils"; - -export interface BaseStoreParams extends Omit, "migrations"> { - syncOptions?: { - fireImmediately?: boolean; - equals?: IEqualsComparer; - }; - configName: string; -} - -export interface IpcChannelPrefixes { - local: string; - remote: string; -} - -export interface BaseStoreDependencies { - readonly logger: Logger; - readonly storeMigrationVersion: string; - readonly directoryForUserData: string; - readonly migrations: Migrations>; - readonly ipcChannelPrefixes: IpcChannelPrefixes; - readonly shouldDisableSyncInListener: boolean; - getConfigurationFileModel: GetConfigurationFileModel; - persistStateToConfig: PersistStateToConfig; - getBasenameOfPath: GetBasenameOfPath; - enlistMessageChannelListener: EnlistMessageChannelListener; -} - -/** - * Note: T should only contain base JSON serializable types. - */ -export abstract class BaseStore { - private readonly syncDisposers = disposer(); - - readonly displayName = kebabCase(this.params.configName).toUpperCase(); - - /** - * @ignore - */ - protected readonly dependencies: BaseStoreDependencies; - - protected constructor( - dependencies: BaseStoreDependencies, - protected readonly params: BaseStoreParams, - ) { - this.dependencies = dependencies; - makeObservable(this); - } - - /** - * This must be called after the last child's constructor is finished (or just before it finishes) - */ - load() { - this.dependencies.logger.info(`[${this.displayName}]: LOADING ...`); - - const config = this.dependencies.getConfigurationFileModel({ - projectName: "lens", - projectVersion: this.dependencies.storeMigrationVersion, - cwd: this.cwd(), - ...this.params, - migrations: this.dependencies.migrations as Migrations, - }); - - const res = this.fromStore(config.store); - - if (isPromiseLike(res)) { - this.dependencies.logger.error(`${this.displayName} extends BaseStore's fromStore method returns a Promise or promise-like object. This is an error and must be fixed.`); - } - - this.startSyncing(config); - this.dependencies.logger.info(`[${this.displayName}]: LOADED from ${config.path}`); - } - - protected cwd() { - return this.dependencies.directoryForUserData; - } - - private startSyncing(config: Config) { - const name = this.dependencies.getBasenameOfPath(config.path); - - const disableSync = () => this.syncDisposers(); - const enableSync = () => { - this.syncDisposers.push( - reaction( - () => toJS(this.toJSON()), // unwrap possible observables and react to everything - model => { - this.dependencies.persistStateToConfig(config, model); - broadcastMessage(`${this.dependencies.ipcChannelPrefixes.remote}:${config.path}`, model); - }, - this.params.syncOptions, - ), - this.dependencies.enlistMessageChannelListener({ - id: this.displayName, - channel: { - id: `${this.dependencies.ipcChannelPrefixes.local}:${config.path}`, - }, - handler: (model) => { - this.dependencies.logger.silly(`[${this.displayName}]: syncing ${name}`, { model }); - - if (this.dependencies.shouldDisableSyncInListener) { - disableSync(); - } - - // todo: use "resourceVersion" if merge required (to avoid equality checks => better performance) - if (!isEqual(this.toJSON(), model)) { - this.fromStore(model as T); - } - - if (this.dependencies.shouldDisableSyncInListener) { - enableSync(); - } - }, - }), - ); - }; - - enableSync(); - } - - /** - * fromStore is called internally when a child class syncs with the file - * system. - * - * Note: This function **must** be synchronous. - * - * @param data the parsed information read from the stored JSON file - */ - protected abstract fromStore(data: T): void; - - /** - * toJSON is called when syncing the store to the filesystem. It should - * produce a JSON serializable object representation of the current state. - * - * It is recommended that a round trip is valid. Namely, calling - * `this.fromStore(this.toJSON())` shouldn't change the state. - */ - abstract toJSON(): T; -} diff --git a/packages/core/src/common/base-store/channel-prefix.ts b/packages/core/src/common/base-store/channel-prefix.ts deleted file mode 100644 index f2662c65e0..0000000000 --- a/packages/core/src/common/base-store/channel-prefix.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * 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 type { IpcChannelPrefixes } from "./base-store"; - -export const baseStoreIpcChannelPrefixesInjectionToken = getInjectionToken({ - id: "base-store-ipc-channel-prefix-token", -}); diff --git a/packages/core/src/common/base-store/migrations.injectable.ts b/packages/core/src/common/base-store/migrations.injectable.ts deleted file mode 100644 index d97abee1ec..0000000000 --- a/packages/core/src/common/base-store/migrations.injectable.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import type { InjectionToken } from "@ogre-tools/injectable"; -import { lifecycleEnum, getInjectable } from "@ogre-tools/injectable"; -import type Conf from "conf/dist/source"; -import type { Migrations } from "conf/dist/source/types"; -import loggerInjectable from "../logger.injectable"; -import { getOrInsert, iter } from "@k8slens/utilities"; - -export interface MigrationDeclaration { - version: string; - run(store: Conf>>): void; -} - -const storeMigrationsInjectable = getInjectable({ - id: "store-migrations", - instantiate: (di, token): Migrations> => { - const logger = di.inject(loggerInjectable); - const declarations = di.injectMany(token); - const migrations = new Map(); - - for (const decl of declarations) { - getOrInsert(migrations, decl.version, []).push(decl.run); - } - - return Object.fromEntries( - iter.map( - migrations, - ([v, fns]) => [v, (store) => { - logger.info(`Running ${v} migration for ${store.path}`); - - for (const fn of fns) { - fn(store); - } - }], - ), - ); - }, - lifecycle: lifecycleEnum.keyedSingleton({ - getInstanceKey: (di, token: InjectionToken) => token.id, - }), -}); - -export default storeMigrationsInjectable; diff --git a/packages/core/src/common/catalog-entities/web-link.ts b/packages/core/src/common/catalog-entities/web-link.ts index 833f05d65b..4b18ac7f73 100644 --- a/packages/core/src/common/catalog-entities/web-link.ts +++ b/packages/core/src/common/catalog-entities/web-link.ts @@ -4,10 +4,10 @@ */ import { getEnvironmentSpecificLegacyGlobalDiForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; +import removeWeblinkInjectable from "../../features/weblinks/common/remove.injectable"; import type { CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog"; import { CatalogCategory, CatalogEntity, categoryVersion } from "../catalog/catalog-entity"; import productNameInjectable from "../vars/product-name.injectable"; -import weblinkStoreInjectable from "../weblinks-store/weblink-store.injectable"; export type WebLinkStatusPhase = "available" | "unavailable"; @@ -34,13 +34,13 @@ export class WebLink extends CatalogEntity weblinkStore.removeById(this.getId()), + onClick: () => removeWeblink(this.getId()), confirm: { message: `Remove Web Link "${this.getName()}" from ${productName}?`, }, diff --git a/packages/core/src/common/catalog/helpers.ts b/packages/core/src/common/catalog/helpers.ts new file mode 100644 index 0000000000..75cdf726aa --- /dev/null +++ b/packages/core/src/common/catalog/helpers.ts @@ -0,0 +1,83 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import type { CatalogEntity } from "./catalog-entity"; +import GraphemeSplitter from "grapheme-splitter"; +import { hasOwnProperty, hasTypedProperty, isObject, isString, iter } from "@k8slens/utilities"; + +function getNameParts(name: string): string[] { + const byWhitespace = name.split(/\s+/); + + if (byWhitespace.length > 1) { + return byWhitespace; + } + + const byDashes = name.split(/[-_]+/); + + if (byDashes.length > 1) { + return byDashes; + } + + return name.split(/@+/); +} + +export function limitGraphemeLengthOf(src: string, count: number): string { + const splitter = new GraphemeSplitter(); + + return iter + .chain(splitter.iterateGraphemes(src)) + .take(count) + .join(""); +} + +export function computeDefaultShortName(name: string) { + if (!name || typeof name !== "string") { + return "??"; + } + + const [rawFirst, rawSecond, rawThird] = getNameParts(name); + const splitter = new GraphemeSplitter(); + const first = splitter.iterateGraphemes(rawFirst); + const second = rawSecond ? splitter.iterateGraphemes(rawSecond): first; + const third = rawThird ? splitter.iterateGraphemes(rawThird) : iter.newEmpty(); + + return iter.chain(iter.take(first, 1)) + .concat(iter.take(second, 1)) + .concat(iter.take(third, 1)) + .join(""); +} + +export function getShortName(entity: CatalogEntity): string { + return entity.metadata.shortName || computeDefaultShortName(entity.getName()); +} + +export function getIconColourHash(entity: CatalogEntity): string { + return `${entity.metadata.name}-${entity.metadata.source}`; +} + +export function getIconBackground(entity: CatalogEntity): string | undefined { + if (isObject(entity.spec.icon)) { + if (hasTypedProperty(entity.spec.icon, "background", isString)) { + return entity.spec.icon.background; + } + + return hasOwnProperty(entity.spec.icon, "src") + ? "transparent" + : undefined; + } + + return undefined; +} + +export function getIconMaterial(entity: CatalogEntity): string | undefined { + if ( + isObject(entity.spec.icon) + && hasTypedProperty(entity.spec.icon, "material", isString) + ) { + return entity.spec.icon.material; + } + + return undefined; +} diff --git a/packages/core/src/common/cluster-store/cluster-store.injectable.ts b/packages/core/src/common/cluster-store/cluster-store.injectable.ts deleted file mode 100644 index 79eb02e36c..0000000000 --- a/packages/core/src/common/cluster-store/cluster-store.injectable.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 { getInjectable } from "@ogre-tools/injectable"; -import { ClusterStore } from "./cluster-store"; -import readClusterConfigSyncInjectable from "./read-cluster-config.injectable"; -import emitAppEventInjectable from "../app-event-bus/emit-event.injectable"; -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 loggerInjectable from "../logger.injectable"; -import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable"; -import storeMigrationsInjectable from "../base-store/migrations.injectable"; -import { clusterStoreMigrationInjectionToken } from "./migration-token"; -import { baseStoreIpcChannelPrefixesInjectionToken } from "../base-store/channel-prefix"; -import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../base-store/disable-sync"; -import { persistStateToConfigInjectionToken } from "../base-store/save-to-file"; -import getBasenameOfPathInjectable from "../path/get-basename.injectable"; -import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging"; - -const clusterStoreInjectable = getInjectable({ - id: "cluster-store", - - instantiate: (di) => new ClusterStore({ - readClusterConfigSync: di.inject(readClusterConfigSyncInjectable), - emitAppEvent: di.inject(emitAppEventInjectable), - directoryForUserData: di.inject(directoryForUserDataInjectable), - getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable), - logger: di.inject(loggerInjectable), - storeMigrationVersion: di.inject(storeMigrationVersionInjectable), - migrations: di.inject(storeMigrationsInjectable, clusterStoreMigrationInjectionToken), - getBasenameOfPath: di.inject(getBasenameOfPathInjectable), - ipcChannelPrefixes: di.inject(baseStoreIpcChannelPrefixesInjectionToken), - persistStateToConfig: di.inject(persistStateToConfigInjectionToken), - enlistMessageChannelListener: di.inject(enlistMessageChannelListenerInjectionToken), - shouldDisableSyncInListener: di.inject(shouldBaseStoreDisableSyncInIpcListenerInjectionToken), - }), -}); - -export default clusterStoreInjectable; diff --git a/packages/core/src/common/cluster-store/cluster-store.ts b/packages/core/src/common/cluster-store/cluster-store.ts deleted file mode 100644 index 8d283411c9..0000000000 --- a/packages/core/src/common/cluster-store/cluster-store.ts +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - - -import { action, comparer, computed, makeObservable, observable } from "mobx"; -import type { BaseStoreDependencies } from "../base-store/base-store"; -import { BaseStore } from "../base-store/base-store"; -import { Cluster } from "../cluster/cluster"; -import { toJS } from "../utils"; -import type { ClusterModel, ClusterId } from "../cluster-types"; -import type { ReadClusterConfigSync } from "./read-cluster-config.injectable"; -import type { EmitAppEvent } from "../app-event-bus/emit-event.injectable"; - -export interface ClusterStoreModel { - clusters?: ClusterModel[]; -} - -interface Dependencies extends BaseStoreDependencies { - readClusterConfigSync: ReadClusterConfigSync; - emitAppEvent: EmitAppEvent; -} - -export class ClusterStore extends BaseStore { - readonly clusters = observable.map(); - - constructor(protected readonly dependencies: Dependencies) { - super(dependencies, { - configName: "lens-cluster-store", - accessPropertiesByDotNotation: false, // To make dots safe in cluster context names - syncOptions: { - equals: comparer.structural, - }, - }); - - makeObservable(this); - } - - @computed get clustersList(): Cluster[] { - return Array.from(this.clusters.values()); - } - - @computed get connectedClustersList(): Cluster[] { - return this.clustersList.filter((c) => !c.disconnected); - } - - hasClusters() { - return this.clusters.size > 0; - } - - getById(id: ClusterId | undefined): Cluster | undefined { - if (id) { - return this.clusters.get(id); - } - - return undefined; - } - - addCluster(clusterOrModel: ClusterModel | Cluster): Cluster { - this.dependencies.emitAppEvent({ name: "cluster", action: "add" }); - - const cluster = clusterOrModel instanceof Cluster - ? clusterOrModel - : new Cluster( - clusterOrModel, - this.dependencies.readClusterConfigSync(clusterOrModel), - ); - - this.clusters.set(cluster.id, cluster); - - return cluster; - } - - @action - protected fromStore({ clusters = [] }: ClusterStoreModel = {}) { - const currentClusters = new Map(this.clusters); - const newClusters = new Map(); - - // update new clusters - for (const clusterModel of clusters) { - try { - let cluster = currentClusters.get(clusterModel.id); - - if (cluster) { - cluster.updateModel(clusterModel); - } else { - cluster = new Cluster( - clusterModel, - this.dependencies.readClusterConfigSync(clusterModel), - ); - } - newClusters.set(clusterModel.id, cluster); - } catch (error) { - this.dependencies.logger.warn(`[CLUSTER-STORE]: Failed to update/create a cluster: ${error}`); - } - } - - this.clusters.replace(newClusters); - } - - toJSON(): ClusterStoreModel { - return toJS({ - clusters: this.clustersList.map(cluster => cluster.toJSON()), - }); - } -} diff --git a/packages/core/src/common/error-reporting/initialize-sentry-reporting.injectable.ts b/packages/core/src/common/error-reporting/initialize-sentry-reporting.injectable.ts index 677c18a586..3a72ef7b12 100644 --- a/packages/core/src/common/error-reporting/initialize-sentry-reporting.injectable.ts +++ b/packages/core/src/common/error-reporting/initialize-sentry-reporting.injectable.ts @@ -9,7 +9,7 @@ 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"; +import userPreferencesStateInjectable from "../../features/user-preferences/common/state.injectable"; export type InitializeSentryReportingWith = (initSentry: (opts: BrowserOptions | ElectronMainOptions) => void) => void; @@ -20,7 +20,7 @@ const initializeSentryReportingWithInjectable = getInjectable({ instantiate: (di): InitializeSentryReportingWith => { const sentryDataSourceName = di.inject(sentryDataSourceNameInjectable); const isProduction = di.inject(isProductionInjectable); - const userStore = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); if (!sentryDataSourceName) { return () => {}; @@ -28,7 +28,7 @@ const initializeSentryReportingWithInjectable = getInjectable({ return (initSentry) => initSentry({ beforeSend: (event) => { - if (userStore.allowErrorReporting) { + if (state.allowErrorReporting) { return event; } diff --git a/packages/core/src/common/fetch/proxy-fetch.injectable.ts b/packages/core/src/common/fetch/proxy-fetch.injectable.ts index f13842c410..433670e003 100644 --- a/packages/core/src/common/fetch/proxy-fetch.injectable.ts +++ b/packages/core/src/common/fetch/proxy-fetch.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { HttpsProxyAgent } from "hpagent"; -import userStoreInjectable from "../user-store/user-store.injectable"; +import userPreferencesStateInjectable from "../../features/user-preferences/common/state.injectable"; import type { Fetch } from "./fetch.injectable"; import fetchInjectable from "./fetch.injectable"; @@ -12,7 +12,7 @@ const proxyFetchInjectable = getInjectable({ id: "proxy-fetch", instantiate: (di): Fetch => { const fetch = di.inject(fetchInjectable); - const { httpsProxy, allowUntrustedCAs } = di.inject(userStoreInjectable); + const { httpsProxy, allowUntrustedCAs } = di.inject(userPreferencesStateInjectable); const agent = httpsProxy ? new HttpsProxyAgent({ proxy: httpsProxy, diff --git a/packages/core/src/common/front-end-routing/routes/cluster/config/config-maps/config-maps-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/config/config-maps/config-maps-route.injectable.ts index 0ad7ed3d88..c6a525269c 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/config/config-maps/config-maps-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/config/config-maps/config-maps-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const configMapsRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/config/horizontal-pod-autoscalers/horizontal-pod-autoscalers-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/config/horizontal-pod-autoscalers/horizontal-pod-autoscalers-route.injectable.ts index 00002620ee..cef3bdcb5a 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/config/horizontal-pod-autoscalers/horizontal-pod-autoscalers-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/config/horizontal-pod-autoscalers/horizontal-pod-autoscalers-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const horizontalPodAutoscalersRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/config/leases/leases-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/config/leases/leases-route.injectable.ts index ea4eb2ae59..6da3564c8f 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/config/leases/leases-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/config/leases/leases-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const leasesRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/config/limit-ranges/limit-ranges-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/config/limit-ranges/limit-ranges-route.injectable.ts index 0536e76004..a80a9e8ef4 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/config/limit-ranges/limit-ranges-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/config/limit-ranges/limit-ranges-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const limitRangesRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/config/pod-disruption-budgets/pod-disruption-budgets-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/config/pod-disruption-budgets/pod-disruption-budgets-route.injectable.ts index 12ce0a2138..e297c7396e 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/config/pod-disruption-budgets/pod-disruption-budgets-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/config/pod-disruption-budgets/pod-disruption-budgets-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const podDisruptionBudgetsRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/config/priority-classes/priority-classes-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/config/priority-classes/priority-classes-route.injectable.ts index 75194b0541..ea424ec86d 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/config/priority-classes/priority-classes-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/config/priority-classes/priority-classes-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const priorityClassesRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/config/resource-quotas/resource-quotas-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/config/resource-quotas/resource-quotas-route.injectable.ts index 4905b70890..96704bbc80 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/config/resource-quotas/resource-quotas-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/config/resource-quotas/resource-quotas-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const resourceQuotasRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/config/runtime-classes/runtime-classes-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/config/runtime-classes/runtime-classes-route.injectable.ts index beab83754f..a088ee2ba4 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/config/runtime-classes/runtime-classes-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/config/runtime-classes/runtime-classes-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const runtimeClassesRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/config/secrets/secrets-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/config/secrets/secrets-route.injectable.ts index 7442de14b1..38343e4729 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/config/secrets/secrets-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/config/secrets/secrets-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const secretsRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/config/vertical-pod-autoscalers/vertical-pod-autoscalers-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/config/vertical-pod-autoscalers/vertical-pod-autoscalers-route.injectable.ts index 57776c8237..07559a8d2a 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/config/vertical-pod-autoscalers/vertical-pod-autoscalers-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/config/vertical-pod-autoscalers/vertical-pod-autoscalers-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const verticalPodAutoscalersRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/events/events-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/events/events-route.injectable.ts index 728f80c21d..fd4dfef75d 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/events/events-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/events/events-route.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 { shouldShowResourceInjectionToken } from "../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../front-end-route-injection-token"; const eventsRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/namespaces/namespaces-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/namespaces/namespaces-route.injectable.ts index 0b57c8d573..6fb569fc11 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/namespaces/namespaces-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/namespaces/namespaces-route.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 { shouldShowResourceInjectionToken } from "../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../front-end-route-injection-token"; const namespacesRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/network/endpoints/endpoints-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/network/endpoints/endpoints-route.injectable.ts index 50b3c72e4c..d8dcf8aa8f 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/network/endpoints/endpoints-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/network/endpoints/endpoints-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const endpointsRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/network/ingress-class/ingress-classeses-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/network/ingress-class/ingress-classeses-route.injectable.ts index e036d4b6a6..efde1d8d7a 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/network/ingress-class/ingress-classeses-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/network/ingress-class/ingress-classeses-route.injectable.ts @@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { shouldShowResourceInjectionToken, -} from "../../../../../cluster-store/allowed-resources-injection-token"; +} from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; const ingressClassesesRouteInjectable = getInjectable({ id: "ingress-classes-route", diff --git a/packages/core/src/common/front-end-routing/routes/cluster/network/ingresses/ingresses-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/network/ingresses/ingresses-route.injectable.ts index 3a6669d99f..c2a6fe33cc 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/network/ingresses/ingresses-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/network/ingresses/ingresses-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { computedOr } from "@k8slens/utilities"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; diff --git a/packages/core/src/common/front-end-routing/routes/cluster/network/network-policies/network-policies-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/network/network-policies/network-policies-route.injectable.ts index 38a1b8a7e2..664eefa9f1 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/network/network-policies/network-policies-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/network/network-policies/network-policies-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const networkPoliciesRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/network/services/services-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/network/services/services-route.injectable.ts index 223ded1e65..e9b130b318 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/network/services/services-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/network/services/services-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const servicesRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/nodes/nodes-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/nodes/nodes-route.injectable.ts index e6ca61346e..1fe80a799b 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/nodes/nodes-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/nodes/nodes-route.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 { shouldShowResourceInjectionToken } from "../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../front-end-route-injection-token"; const nodesRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/overview/cluster-overview-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/overview/cluster-overview-route.injectable.ts index e559c35079..bf9c3961ed 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/overview/cluster-overview-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/overview/cluster-overview-route.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 { shouldShowResourceInjectionToken } from "../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../front-end-route-injection-token"; const clusterOverviewRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/storage/persistent-volume-claims/persistent-volume-claims-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/storage/persistent-volume-claims/persistent-volume-claims-route.injectable.ts index dbda527555..c8d7b64f8d 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/storage/persistent-volume-claims/persistent-volume-claims-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/storage/persistent-volume-claims/persistent-volume-claims-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const persistentVolumeClaimsRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/storage/persistent-volumes/persistent-volumes-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/storage/persistent-volumes/persistent-volumes-route.injectable.ts index 7a06d9df58..a93ac0a3c8 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/storage/persistent-volumes/persistent-volumes-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/storage/persistent-volumes/persistent-volumes-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const persistentVolumesRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/storage/storage-classes/storage-classes-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/storage/storage-classes/storage-classes-route.injectable.ts index 8702ab1602..0645c0f4eb 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/storage/storage-classes/storage-classes-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/storage/storage-classes/storage-classes-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const storageClassesRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/user-management/cluster-role-bindings/cluster-role-bindings-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/user-management/cluster-role-bindings/cluster-role-bindings-route.injectable.ts index 0903d5fced..158563f8d5 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/user-management/cluster-role-bindings/cluster-role-bindings-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/user-management/cluster-role-bindings/cluster-role-bindings-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const clusterRoleBindingsRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/user-management/cluster-roles/cluster-roles-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/user-management/cluster-roles/cluster-roles-route.injectable.ts index 9fce206667..db28d8dfff 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/user-management/cluster-roles/cluster-roles-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/user-management/cluster-roles/cluster-roles-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const clusterRolesRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/user-management/pod-security-policies/pod-security-policies-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/user-management/pod-security-policies/pod-security-policies-route.injectable.ts index 2f35986916..27f9165be8 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/user-management/pod-security-policies/pod-security-policies-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/user-management/pod-security-policies/pod-security-policies-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const podSecurityPoliciesRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/user-management/role-bindings/role-bindings-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/user-management/role-bindings/role-bindings-route.injectable.ts index 759c1b8eda..195210df23 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/user-management/role-bindings/role-bindings-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/user-management/role-bindings/role-bindings-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const roleBindingsRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/user-management/roles/roles-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/user-management/roles/roles-route.injectable.ts index efe4cad810..807a12177c 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/user-management/roles/roles-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/user-management/roles/roles-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const rolesRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/user-management/service-accounts/service-accounts-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/user-management/service-accounts/service-accounts-route.injectable.ts index 65d02135c7..aecc5a3640 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/user-management/service-accounts/service-accounts-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/user-management/service-accounts/service-accounts-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const serviceAccountsRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/workloads/cron-jobs/cron-jobs-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/workloads/cron-jobs/cron-jobs-route.injectable.ts index 33453a2247..0899486298 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/workloads/cron-jobs/cron-jobs-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/workloads/cron-jobs/cron-jobs-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const cronJobsRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/workloads/daemonsets/daemonsets-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/workloads/daemonsets/daemonsets-route.injectable.ts index f1ec2008fa..42f1329551 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/workloads/daemonsets/daemonsets-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/workloads/daemonsets/daemonsets-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const daemonsetsRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/workloads/deployments/deployments-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/workloads/deployments/deployments-route.injectable.ts index 84c059780f..222f842981 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/workloads/deployments/deployments-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/workloads/deployments/deployments-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const deploymentsRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/workloads/jobs/jobs-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/workloads/jobs/jobs-route.injectable.ts index 39cc89e88f..4933c69531 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/workloads/jobs/jobs-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/workloads/jobs/jobs-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const jobsRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/workloads/pods/pods-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/workloads/pods/pods-route.injectable.ts index d013f872f0..6563896893 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/workloads/pods/pods-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/workloads/pods/pods-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const podsRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/workloads/replicasets/replicasets-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/workloads/replicasets/replicasets-route.injectable.ts index b790ce13ec..bff60b2b8d 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/workloads/replicasets/replicasets-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/workloads/replicasets/replicasets-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const replicasetsRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/workloads/replicationcontrollers/replicationcontrollers-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/workloads/replicationcontrollers/replicationcontrollers-route.injectable.ts index 77d87abc96..c6ce4afafe 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/workloads/replicationcontrollers/replicationcontrollers-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/workloads/replicationcontrollers/replicationcontrollers-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const replicationControllersRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/routes/cluster/workloads/statefulsets/statefulsets-route.injectable.ts b/packages/core/src/common/front-end-routing/routes/cluster/workloads/statefulsets/statefulsets-route.injectable.ts index 72c81b3bee..0a0160ccd9 100644 --- a/packages/core/src/common/front-end-routing/routes/cluster/workloads/statefulsets/statefulsets-route.injectable.ts +++ b/packages/core/src/common/front-end-routing/routes/cluster/workloads/statefulsets/statefulsets-route.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 { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; const statefulsetsRouteInjectable = getInjectable({ diff --git a/packages/core/src/common/front-end-routing/verify-that-all-routes-have-route-component.test.ts b/packages/core/src/common/front-end-routing/verify-that-all-routes-have-route-component.test.ts index 44f86f270d..a13a3f8929 100644 --- a/packages/core/src/common/front-end-routing/verify-that-all-routes-have-route-component.test.ts +++ b/packages/core/src/common/front-end-routing/verify-that-all-routes-have-route-component.test.ts @@ -6,22 +6,14 @@ import { getDiForUnitTesting } from "../../renderer/getDiForUnitTesting"; import { routeSpecificComponentInjectionToken } from "../../renderer/routes/route-specific-component-injection-token"; import { frontEndRouteInjectionToken } from "./front-end-route-injection-token"; import { filter, map } from "lodash/fp"; -import clusterStoreInjectable from "../cluster-store/cluster-store.injectable"; -import type { ClusterStore } from "../cluster-store/cluster-store"; import { pipeline } from "@ogre-tools/fp"; describe("verify-that-all-routes-have-component", () => { it("verify that routes have route component", () => { const rendererDi = getDiForUnitTesting(); - rendererDi.override(clusterStoreInjectable, () => ({ - getById: () => null, - } as unknown as ClusterStore)); - const routes = rendererDi.injectMany(frontEndRouteInjectionToken); - const routeComponents = rendererDi.injectMany( - routeSpecificComponentInjectionToken, - ); + const routeComponents = rendererDi.injectMany(routeSpecificComponentInjectionToken); const routesMissingComponent = pipeline( routes, diff --git a/packages/core/src/common/fs/fs.injectable.ts b/packages/core/src/common/fs/fs.injectable.ts index b42a51aad7..16fbbd73aa 100644 --- a/packages/core/src/common/fs/fs.injectable.ts +++ b/packages/core/src/common/fs/fs.injectable.ts @@ -22,6 +22,7 @@ const fsInjectable = getInjectable({ access, stat, unlink, + rename, }, ensureDir, ensureDirSync, @@ -58,6 +59,7 @@ const fsInjectable = getInjectable({ createReadStream, stat, unlink, + rename, }; }, causesSideEffects: true, diff --git a/packages/core/src/common/get-configuration-file-model/get-configuration-file-model.global-override-for-injectable.ts b/packages/core/src/common/get-configuration-file-model/get-configuration-file-model.global-override-for-injectable.ts index 95e2845825..5b83b7b573 100644 --- a/packages/core/src/common/get-configuration-file-model/get-configuration-file-model.global-override-for-injectable.ts +++ b/packages/core/src/common/get-configuration-file-model/get-configuration-file-model.global-override-for-injectable.ts @@ -10,7 +10,7 @@ import getConfigurationFileModelInjectable from "./get-configuration-file-model. import type Config from "conf"; import readJsonSyncInjectable from "../fs/read-json-sync.injectable"; import writeJsonSyncInjectable from "../fs/write-json-sync.injectable"; -import { get, set } from "lodash"; +import { get, has, set } from "lodash"; import semver from "semver"; const MIGRATION_KEY = `__internal__.migrations.version`; @@ -64,7 +64,7 @@ export default getGlobalOverride(getConfigurationFileModelInjectable, (di) => { path: configFilePath, get: (key: string) => get(store, key), set: (key: string, value: unknown) => { - let currentState: object; + let currentState: Partial>; try { currentState = readJsonSync(configFilePath); @@ -78,6 +78,25 @@ export default getGlobalOverride(getConfigurationFileModelInjectable, (di) => { }); store = readJsonSync(configFilePath); }, + delete: (key: string) => { + let currentState: Partial>; + + try { + currentState = readJsonSync(configFilePath); + } catch { + currentState = {}; + } + + delete currentState[key]; + + writeJsonSync(configFilePath, currentState); + store = readJsonSync(configFilePath); + }, + has: (key: string) => has(store, key), + clear: () => { + writeJsonSync(configFilePath, {}); + store = readJsonSync(configFilePath); + }, } as Partial as Config; // Migrate diff --git a/packages/core/src/common/hotbars/add-hotbar.injectable.ts b/packages/core/src/common/hotbars/add-hotbar.injectable.ts deleted file mode 100644 index 25ee0f588a..0000000000 --- a/packages/core/src/common/hotbars/add-hotbar.injectable.ts +++ /dev/null @@ -1,20 +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 hotbarStoreInjectable from "./store.injectable"; -import type { CreateHotbarData, CreateHotbarOptions } from "./types"; - -export type AddHotbar = (data: CreateHotbarData, opts?: CreateHotbarOptions) => void; - -const addHotbarInjectable = getInjectable({ - id: "add-hotbar", - instantiate: (di): AddHotbar => { - const store = di.inject(hotbarStoreInjectable); - - return (data, opts) => store.add(data, opts); - }, -}); - -export default addHotbarInjectable; diff --git a/packages/core/src/common/hotbars/store.injectable.ts b/packages/core/src/common/hotbars/store.injectable.ts deleted file mode 100644 index ea25840e11..0000000000 --- a/packages/core/src/common/hotbars/store.injectable.ts +++ /dev/null @@ -1,38 +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 catalogCatalogEntityInjectable from "../catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable"; -import { HotbarStore } from "./store"; -import loggerInjectable from "../logger.injectable"; -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 storeMigrationVersionInjectable from "../vars/store-migration-version.injectable"; -import storeMigrationsInjectable from "../base-store/migrations.injectable"; -import { hotbarStoreMigrationInjectionToken } from "./migrations-token"; -import getBasenameOfPathInjectable from "../path/get-basename.injectable"; -import { baseStoreIpcChannelPrefixesInjectionToken } from "../base-store/channel-prefix"; -import { persistStateToConfigInjectionToken } from "../base-store/save-to-file"; -import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging"; -import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../base-store/disable-sync"; - -const hotbarStoreInjectable = getInjectable({ - id: "hotbar-store", - - instantiate: (di) => new HotbarStore({ - catalogCatalogEntity: di.inject(catalogCatalogEntityInjectable), - logger: di.inject(loggerInjectable), - directoryForUserData: di.inject(directoryForUserDataInjectable), - getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable), - storeMigrationVersion: di.inject(storeMigrationVersionInjectable), - migrations: di.inject(storeMigrationsInjectable, hotbarStoreMigrationInjectionToken), - getBasenameOfPath: di.inject(getBasenameOfPathInjectable), - ipcChannelPrefixes: di.inject(baseStoreIpcChannelPrefixesInjectionToken), - persistStateToConfig: di.inject(persistStateToConfigInjectionToken), - enlistMessageChannelListener: di.inject(enlistMessageChannelListenerInjectionToken), - shouldDisableSyncInListener: di.inject(shouldBaseStoreDisableSyncInIpcListenerInjectionToken), - }), -}); - -export default hotbarStoreInjectable; diff --git a/packages/core/src/common/hotbars/store.ts b/packages/core/src/common/hotbars/store.ts deleted file mode 100644 index 709242f20e..0000000000 --- a/packages/core/src/common/hotbars/store.ts +++ /dev/null @@ -1,351 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { action, comparer, observable, makeObservable, computed } from "mobx"; -import type { BaseStoreDependencies } from "../base-store/base-store"; -import { BaseStore } from "../base-store/base-store"; -import { toJS } from "../utils"; -import type { CatalogEntity } from "../catalog"; -import { broadcastMessage } from "../ipc"; -import type { Hotbar, CreateHotbarData, CreateHotbarOptions } from "./types"; -import { defaultHotbarCells, getEmptyHotbar } from "./types"; -import { hotbarTooManyItemsChannel } from "../ipc/hotbar"; -import type { GeneralEntity } from "../catalog-entities"; -import type { Logger } from "../logger"; -import assert from "assert"; - -export interface HotbarStoreModel { - hotbars: Hotbar[]; - activeHotbarId: string; -} - -interface Dependencies extends BaseStoreDependencies { - readonly catalogCatalogEntity: GeneralEntity; - readonly logger: Logger; -} - -export class HotbarStore extends BaseStore { - @observable hotbars: Hotbar[] = []; - @observable private _activeHotbarId!: string; - - constructor(protected readonly dependencies: Dependencies) { - super(dependencies, { - configName: "lens-hotbar-store", - accessPropertiesByDotNotation: false, // To make dots safe in cluster context names - syncOptions: { - equals: comparer.structural, - }, - }); - makeObservable(this); - } - - @computed get activeHotbarId() { - return this._activeHotbarId; - } - - /** - * If `hotbar` points to a known hotbar, make it active. Otherwise, ignore - * @param hotbar The hotbar instance, or the index, or its ID - */ - setActiveHotbar(hotbar: Hotbar | number | string) { - if (typeof hotbar === "number") { - if (hotbar >= 0 && hotbar < this.hotbars.length) { - this._activeHotbarId = this.hotbars[hotbar].id; - } - } else if (typeof hotbar === "string") { - if (this.findById(hotbar)) { - this._activeHotbarId = hotbar; - } - } else { - if (this.hotbars.indexOf(hotbar) >= 0) { - this._activeHotbarId = hotbar.id; - } - } - } - - private hotbarIndexById(id: string) { - return this.hotbars.findIndex((hotbar) => hotbar.id === id); - } - - private hotbarIndex(hotbar: Hotbar) { - return this.hotbars.indexOf(hotbar); - } - - @computed get activeHotbarIndex() { - return this.hotbarIndexById(this.activeHotbarId); - } - - @action - protected fromStore(data: Partial = {}) { - if (!data.hotbars || !data.hotbars.length) { - const hotbar = getEmptyHotbar("Default"); - const { - metadata: { uid, name, source }, - } = this.dependencies.catalogCatalogEntity; - const initialItem = { entity: { uid, name, source }}; - - hotbar.items[0] = initialItem; - - this.hotbars = [hotbar]; - } else { - this.hotbars = data.hotbars; - } - - this.hotbars.forEach(ensureExactHotbarItemLength); - - if (data.activeHotbarId) { - this._activeHotbarId = data.activeHotbarId; - } - - if (!this._activeHotbarId) { - this._activeHotbarId = this.hotbars[0].id; - } - } - - toJSON(): HotbarStoreModel { - return toJS({ - hotbars: this.hotbars, - activeHotbarId: this.activeHotbarId, - }); - } - - getActive(): Hotbar { - const hotbar = this.findById(this.activeHotbarId); - - assert(hotbar, "There MUST always be an active hotbar"); - - return hotbar; - } - - findByName(name: string) { - return this.hotbars.find((hotbar) => hotbar.name === name); - } - - findById(id: string) { - return this.hotbars.find((hotbar) => hotbar.id === id); - } - - @action - add(data: CreateHotbarData, { setActive = false }: CreateHotbarOptions = {}) { - const hotbar = getEmptyHotbar(data.name, data.id); - - this.hotbars.push(hotbar); - - if (setActive) { - this._activeHotbarId = hotbar.id; - } - } - - @action - setHotbarName(id: string, name: string): void { - const index = this.hotbars.findIndex((hotbar) => hotbar.id === id); - - if (index < 0) { - return this.dependencies.logger.warn( - `[HOTBAR-STORE]: cannot setHotbarName: unknown id`, - { id }, - ); - } - - this.hotbars[index].name = name; - } - - @action - remove(hotbar: Hotbar) { - assert(this.hotbars.length >= 2, "Cannot remove the last hotbar"); - - this.hotbars = this.hotbars.filter((h) => h !== hotbar); - - if (this.activeHotbarId === hotbar.id) { - this.setActiveHotbar(0); - } - } - - @action - addToHotbar(item: CatalogEntity, cellIndex?: number) { - const hotbar = this.getActive(); - const uid = item.getId(); - const name = item.getName(); - - if (typeof uid !== "string") { - throw new TypeError("CatalogEntity's ID must be a string"); - } - - if (typeof name !== "string") { - throw new TypeError("CatalogEntity's NAME must be a string"); - } - - if (this.isAddedToActive(item)) { - return; - } - - const entity = { - uid, - name, - source: item.metadata.source, - }; - const newItem = { entity }; - - if (cellIndex === undefined) { - // Add item to empty cell - const emptyCellIndex = hotbar.items.indexOf(null); - - if (emptyCellIndex != -1) { - hotbar.items[emptyCellIndex] = newItem; - } else { - broadcastMessage(hotbarTooManyItemsChannel); - } - } else if (0 <= cellIndex && cellIndex < hotbar.items.length) { - hotbar.items[cellIndex] = newItem; - } else { - this.dependencies.logger.error( - `[HOTBAR-STORE]: cannot pin entity to hotbar outside of index range`, - { entityId: uid, hotbarId: hotbar.id, cellIndex }, - ); - } - } - - @action - removeFromHotbar(uid: string): void { - const hotbar = this.getActive(); - const index = hotbar.items.findIndex((item) => item?.entity.uid === uid); - - if (index < 0) { - return; - } - - hotbar.items[index] = null; - } - - /** - * Remove all hotbar items that reference the `uid`. - * @param uid The `EntityId` that each hotbar item refers to - * @returns A function that will (in an action) undo the removing of the hotbar items. This function will not complete if the hotbar has changed. - */ - @action - removeAllHotbarItems(uid: string) { - for (const hotbar of this.hotbars) { - const index = hotbar.items.findIndex((i) => i?.entity.uid === uid); - - if (index >= 0) { - hotbar.items[index] = null; - } - } - } - - findClosestEmptyIndex(from: number, direction = 1) { - let index = from; - const hotbar = this.getActive(); - - while (hotbar.items[index] != null) { - index += direction; - } - - return index; - } - - @action - restackItems(from: number, to: number): void { - const { items } = this.getActive(); - const source = items[from]; - const moveDown = from < to; - - if ( - from < 0 || - to < 0 || - from >= items.length || - to >= items.length || - isNaN(from) || - isNaN(to) - ) { - throw new Error("Invalid 'from' or 'to' arguments"); - } - - if (from == to) { - return; - } - - items.splice(from, 1, null); - - if (items[to] == null) { - items.splice(to, 1, source); - } else { - // Move cells up or down to closes empty cell - items.splice(this.findClosestEmptyIndex(to, moveDown ? -1 : 1), 1); - items.splice(to, 0, source); - } - } - - switchToPrevious() { - let index = this.activeHotbarIndex - 1; - - if (index < 0) { - index = this.hotbars.length - 1; - } - - this.setActiveHotbar(index); - } - - switchToNext() { - let index = this.activeHotbarIndex + 1; - - if (index >= this.hotbars.length) { - index = 0; - } - - this.setActiveHotbar(index); - } - - /** - * Checks if entity already pinned to the active hotbar - */ - isAddedToActive(entity: CatalogEntity | null | undefined): boolean { - if (!entity) { - return false; - } - - const indexInActiveHotbar = this.getActive().items.findIndex(item => item?.entity.uid === entity.getId()); - - return indexInActiveHotbar >= 0; - } - - getDisplayLabel(hotbar: Hotbar): string { - return `${this.getDisplayIndex(hotbar)}: ${hotbar.name}`; - } - - getDisplayIndex(hotbar: Hotbar): string { - const index = this.hotbarIndex(hotbar); - - if (index < 0) { - return "??"; - } - - return `${index + 1}`; - } -} - -/** - * This function ensures that there are always exactly `defaultHotbarCells` - * worth of items in the hotbar. - * @param hotbar The hotbar to modify - */ -function ensureExactHotbarItemLength(hotbar: Hotbar) { - // if there are not enough items - while (hotbar.items.length < defaultHotbarCells) { - hotbar.items.push(null); - } - - // if for some reason the hotbar was overfilled before, remove as many entries - // as needed, but prefer empty slots and items at the end first. - while (hotbar.items.length > defaultHotbarCells) { - const lastNull = hotbar.items.lastIndexOf(null); - - if (lastNull >= 0) { - hotbar.items.splice(lastNull, 1); - } else { - hotbar.items.length = defaultHotbarCells; - } - } -} diff --git a/packages/core/src/common/os/home-directory-path.injectable.ts b/packages/core/src/common/os/home-directory-path.injectable.ts index 83b4b0cdff..c8831eebab 100644 --- a/packages/core/src/common/os/home-directory-path.injectable.ts +++ b/packages/core/src/common/os/home-directory-path.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 userInfoInjectable from "../user-store/user-info.injectable"; +import userInfoInjectable from "../vars/user-info.injectable"; const homeDirectoryPathInjectable = getInjectable({ id: "home-directory-path", diff --git a/packages/core/src/common/persistent-storage/channel-prefix.ts b/packages/core/src/common/persistent-storage/channel-prefix.ts new file mode 100644 index 0000000000..aeb7da7a72 --- /dev/null +++ b/packages/core/src/common/persistent-storage/channel-prefix.ts @@ -0,0 +1,15 @@ +/** + * 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"; + +export interface IpcChannelPrefixes { + readonly local: string; + readonly remote: string; +} + +export const persistentStorageIpcChannelPrefixesInjectionToken = getInjectionToken({ + id: "persistent-storage-ipc-channel-prefix-token", +}); diff --git a/packages/core/src/common/persistent-storage/create.injectable.ts b/packages/core/src/common/persistent-storage/create.injectable.ts new file mode 100644 index 0000000000..da54076a5a --- /dev/null +++ b/packages/core/src/common/persistent-storage/create.injectable.ts @@ -0,0 +1,158 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { disposer, isPromiseLike } from "@k8slens/utilities"; +import { getInjectable } from "@ogre-tools/injectable"; +import type { Options } from "conf/dist/source"; +import { isEqual, kebabCase } from "lodash"; +import type { IEqualsComparer } from "mobx"; +import { reaction } from "mobx"; +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 loggerInjectable from "../logger.injectable"; +import getBasenameOfPathInjectable from "../path/get-basename.injectable"; +import { enlistMessageChannelListenerInjectionToken, sendMessageToChannelInjectionToken } from "@k8slens/messaging"; +import type { MessageChannel } from "@k8slens/messaging"; +import { persistentStorageIpcChannelPrefixesInjectionToken } from "./channel-prefix"; +import { shouldPersistentStorageDisableSyncInIpcListenerInjectionToken } from "./disable-sync"; +import { persistStateToConfigInjectionToken } from "./save-to-file"; +import type { Migrations } from "./migrations.injectable"; +import { nextTick } from "process"; + +export interface PersistentStorage { + /** + * This method does the initial synchronous load from disk and then starts writing the state + * back to disk whenever it changes. + */ + loadAndStartSyncing: () => void; +} + +export interface PersistentStorageParams extends Omit, "migrations"> { + readonly syncOptions?: { + readonly fireImmediately?: boolean; + equals?: IEqualsComparer; + }; + readonly configName: string; + readonly migrations?: Migrations; + + /** + * fromStore is called internally when a child class syncs with the file + * system. + * + * Note: This function **must** be synchronous. + * + * @param data the parsed information read from the stored JSON file + */ + fromStore(data: Partial): void; + + /** + * toJSON is called when syncing the store to the filesystem. It should + * produce a JSON serializable object representation of the current state. + * + * It is recommended that a round trip is valid. Namely, calling + * `this.fromStore(this.toJSON())` shouldn't change the state. + */ + toJSON(): T; +} + +export type CreatePersistentStorage = (params: PersistentStorageParams) => PersistentStorage; + +const createPersistentStorageInjectable = getInjectable({ + id: "create-persistent-storage", + instantiate: (di): CreatePersistentStorage => { + const directoryForUserData = di.inject(directoryForUserDataInjectable); + const getConfigurationFileModel = di.inject(getConfigurationFileModelInjectable); + const logger = di.inject(loggerInjectable); + const getBasenameOfPath = di.inject(getBasenameOfPathInjectable); + const ipcChannelPrefixes = di.inject(persistentStorageIpcChannelPrefixesInjectionToken); + const persistStateToConfig = di.inject(persistStateToConfigInjectionToken); + const enlistMessageChannelListener = di.inject(enlistMessageChannelListenerInjectionToken); + const shouldDisableSyncInListener = di.inject(shouldPersistentStorageDisableSyncInIpcListenerInjectionToken); + const sendMessageToChannel = di.inject(sendMessageToChannelInjectionToken); + + return (rawParams: PersistentStorageParams) => { + const { + fromStore, + toJSON, + syncOptions, + migrations, + cwd = directoryForUserData, + ...params + } = rawParams; + const displayName = kebabCase(params.configName).toUpperCase(); + + const loadAndStartSyncing = () => { + logger.info(`[${displayName}]: LOADING ...`); + + const config = getConfigurationFileModel({ + projectName: "lens", + cwd, + migrations: migrations as Options["migrations"], + ...params, + }); + + const res = fromStore(config.store); + + if (isPromiseLike(res)) { + logger.error(`${displayName} extends BaseStore's fromStore method returns a Promise or promise-like object. This is an error and must be fixed.`); + } + + logger.info(`[${displayName}]: LOADED from ${config.path}`); + + const syncDisposers = disposer(); + const sendChannel: MessageChannel = { + id: `${ipcChannelPrefixes.remote}:${config.path}`, + }; + const receiveChannel: MessageChannel = { + id: `${ipcChannelPrefixes.local}:${config.path}`, + }; + const name = getBasenameOfPath(config.path); + + const disableSync = () => syncDisposers(); + const enableSync = () => { + syncDisposers.push( + reaction( + () => toJSON(), + model => { + persistStateToConfig(config, model); + sendMessageToChannel(sendChannel, model); + }, + syncOptions, + ), + enlistMessageChannelListener({ + id: "persistent-storage-sync", + channel: receiveChannel, + handler: (model) => { + logger.silly(`[${displayName}]: syncing ${name}`, { model }); + + if (shouldDisableSyncInListener) { + disableSync(); + } + + // todo: use "resourceVersion" if merge required (to avoid equality checks => better performance) + if (!isEqual(toJSON(), model)) { + fromStore(model); + } + + if (shouldDisableSyncInListener) { + nextTick(() => { + enableSync(); + }); + } + }, + }), + ); + }; + + enableSync(); + }; + + return { + loadAndStartSyncing, + }; + }; + }, +}); + +export default createPersistentStorageInjectable; diff --git a/packages/core/src/common/base-store/disable-sync.ts b/packages/core/src/common/persistent-storage/disable-sync.ts similarity index 54% rename from packages/core/src/common/base-store/disable-sync.ts rename to packages/core/src/common/persistent-storage/disable-sync.ts index ce7abd16a1..db24561936 100644 --- a/packages/core/src/common/base-store/disable-sync.ts +++ b/packages/core/src/common/persistent-storage/disable-sync.ts @@ -5,6 +5,6 @@ import { getInjectionToken } from "@ogre-tools/injectable"; -export const shouldBaseStoreDisableSyncInIpcListenerInjectionToken = getInjectionToken({ - id: "should-base-store-disable-sync-in-ipc-listener-token", +export const shouldPersistentStorageDisableSyncInIpcListenerInjectionToken = getInjectionToken({ + id: "should-persistent-storage-disable-sync-in-ipc-listener-token", }); diff --git a/packages/core/src/common/persistent-storage/migrations.injectable.ts b/packages/core/src/common/persistent-storage/migrations.injectable.ts new file mode 100644 index 0000000000..e4bd43d1de --- /dev/null +++ b/packages/core/src/common/persistent-storage/migrations.injectable.ts @@ -0,0 +1,58 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import type { InjectionToken } from "@ogre-tools/injectable"; +import { lifecycleEnum, getInjectable } from "@ogre-tools/injectable"; +import loggerInjectable from "../logger.injectable"; +import { getOrInsert, iter, object } from "@k8slens/utilities"; + +export type AllowedSetValue = T extends (...args: any[]) => any + ? never + : T extends undefined | symbol + ? never + : T; + +export interface MigrationStore { + readonly path: string; + get(key: string): unknown; + delete(key: string): void; + has(key: string): boolean; + clear(): void; + set(key: string, value: AllowedSetValue): void; +} + +export type Migrations = Partial void>>; + +export interface MigrationDeclaration { + version: string; + run(store: MigrationStore): void; +} + +const persistentStorageMigrationsInjectable = getInjectable({ + id: "persistent-storage-migrations", + instantiate: (di, token) => { + const logger = di.inject(loggerInjectable); + const declarations = di.injectMany(token); + const migrations = new Map(); + + for (const decl of declarations) { + getOrInsert(migrations, decl.version, []).push(decl.run); + } + + return iter.chain(migrations.entries()) + .map(([v, fns]) => [v, (store: MigrationStore) => { + logger.info(`Running ${v} migration for ${store.path}`); + + for (const fn of fns) { + fn(store); + } + }] as const) + .collect(object.fromEntries); + }, + lifecycle: lifecycleEnum.keyedSingleton({ + getInstanceKey: (di, token: InjectionToken) => token.id, + }), +}); + +export default persistentStorageMigrationsInjectable; diff --git a/packages/core/src/common/base-store/save-to-file.ts b/packages/core/src/common/persistent-storage/save-to-file.ts similarity index 100% rename from packages/core/src/common/base-store/save-to-file.ts rename to packages/core/src/common/persistent-storage/save-to-file.ts diff --git a/packages/core/src/common/persistent-storage/storage-migration-version.injectable.ts b/packages/core/src/common/persistent-storage/storage-migration-version.injectable.ts new file mode 100644 index 0000000000..6568e8f983 --- /dev/null +++ b/packages/core/src/common/persistent-storage/storage-migration-version.injectable.ts @@ -0,0 +1,32 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import type { InjectionToken } from "@ogre-tools/injectable"; +import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable"; +import * as semver from "semver"; +import type { MigrationDeclaration } from "./migrations.injectable"; + +/** + * NOTE: not all stores can use this computed version, namely if any migration uses a range for + * the version selector. + */ +const storageMigrationVersionInjectable = getInjectable({ + id: "storage-migration-version", + instantiate: (di, token) => { + const declarations = di.injectMany(token); + + return declarations.reduce((version, decl) => { + if (semver.gte(decl.version, version)) { + return decl.version; + } + + return version; + }, "1.0.0"); + }, + lifecycle: lifecycleEnum.keyedSingleton({ + getInstanceKey: (di, token: InjectionToken) => token.id, + }), +}); + +export default storageMigrationVersionInjectable; diff --git a/packages/core/src/common/protocol-handler/router.ts b/packages/core/src/common/protocol-handler/router.ts index 0018c385c2..7a48dbb343 100644 --- a/packages/core/src/common/protocol-handler/router.ts +++ b/packages/core/src/common/protocol-handler/router.ts @@ -10,13 +10,13 @@ import { isDefined, iter } from "@k8slens/utilities"; import { pathToRegexp } from "path-to-regexp"; import type Url from "url-parse"; import { RoutingError, RoutingErrorType } from "./error"; -import type { ExtensionsStore } from "../../extensions/extensions-store/extensions-store"; import type { ExtensionLoader } from "../../extensions/extension-loader"; import type { LensExtension } from "../../extensions/lens-extension"; import type { RouteHandler, RouteParams } from "./registration"; import { when } from "mobx"; import { ipcRenderer } from "electron"; import type { Logger } from "../logger"; +import type { IsExtensionEnabled } from "../../features/extensions/enabled/common/is-enabled.injectable"; // IPC channel for protocol actions. Main broadcasts the open-url events to this channel. export const ProtocolHandlerIpcPrefix = "protocol-handler"; @@ -65,8 +65,8 @@ export function foldAttemptResults(mainAttempt: RouteAttempt, rendererAttempt: R export interface LensProtocolRouterDependencies { readonly extensionLoader: ExtensionLoader; - readonly extensionsStore: ExtensionsStore; readonly logger: Logger; + isExtensionEnabled: IsExtensionEnabled; } export abstract class LensProtocolRouter { @@ -209,7 +209,7 @@ export abstract class LensProtocolRouter { return name; } - if (!this.dependencies.extensionsStore.isEnabled(extension)) { + if (!this.dependencies.isExtensionEnabled(extension)) { this.dependencies.logger.info(`${LensProtocolRouter.LoggingPrefix}: Extension ${name} matched, but not enabled`); return name; diff --git a/packages/core/src/common/user-store/index.ts b/packages/core/src/common/user-store/index.ts deleted file mode 100644 index 026167519b..0000000000 --- a/packages/core/src/common/user-store/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -export * from "./user-store"; -export type { KubeconfigSyncEntry, KubeconfigSyncValue, UserPreferencesModel } from "./preferences-helpers"; diff --git a/packages/core/src/common/user-store/migrations-token.ts b/packages/core/src/common/user-store/migrations-token.ts deleted file mode 100644 index f3959beb3a..0000000000 --- a/packages/core/src/common/user-store/migrations-token.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * 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 type { MigrationDeclaration } from "../base-store/migrations.injectable"; - -export const userStoreMigrationInjectionToken = getInjectionToken({ - id: "user-store-migration-token", -}); diff --git a/packages/core/src/common/user-store/user-store.injectable.ts b/packages/core/src/common/user-store/user-store.injectable.ts deleted file mode 100644 index 10806007a2..0000000000 --- a/packages/core/src/common/user-store/user-store.injectable.ts +++ /dev/null @@ -1,42 +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 { UserStore } from "./user-store"; -import selectedUpdateChannelInjectable from "../../features/application-update/common/selected-update-channel/selected-update-channel.injectable"; -import emitAppEventInjectable from "../app-event-bus/emit-event.injectable"; -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 loggerInjectable from "../logger.injectable"; -import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable"; -import storeMigrationsInjectable from "../base-store/migrations.injectable"; -import { userStoreMigrationInjectionToken } from "./migrations-token"; -import { baseStoreIpcChannelPrefixesInjectionToken } from "../base-store/channel-prefix"; -import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../base-store/disable-sync"; -import { persistStateToConfigInjectionToken } from "../base-store/save-to-file"; -import getBasenameOfPathInjectable from "../path/get-basename.injectable"; -import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging"; -import userStorePreferenceDescriptorsInjectable from "./preference-descriptors.injectable"; - -const userStoreInjectable = getInjectable({ - id: "user-store", - - instantiate: (di) => new UserStore({ - selectedUpdateChannel: di.inject(selectedUpdateChannelInjectable), - emitAppEvent: di.inject(emitAppEventInjectable), - directoryForUserData: di.inject(directoryForUserDataInjectable), - getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable), - logger: di.inject(loggerInjectable), - storeMigrationVersion: di.inject(storeMigrationVersionInjectable), - migrations: di.inject(storeMigrationsInjectable, userStoreMigrationInjectionToken), - getBasenameOfPath: di.inject(getBasenameOfPathInjectable), - ipcChannelPrefixes: di.inject(baseStoreIpcChannelPrefixesInjectionToken), - persistStateToConfig: di.inject(persistStateToConfigInjectionToken), - enlistMessageChannelListener: di.inject(enlistMessageChannelListenerInjectionToken), - shouldDisableSyncInListener: di.inject(shouldBaseStoreDisableSyncInIpcListenerInjectionToken), - preferenceDescriptors: di.inject(userStorePreferenceDescriptorsInjectable), - }), -}); - -export default userStoreInjectable; diff --git a/packages/core/src/common/user-store/user-store.ts b/packages/core/src/common/user-store/user-store.ts deleted file mode 100644 index 4ffa31fac1..0000000000 --- a/packages/core/src/common/user-store/user-store.ts +++ /dev/null @@ -1,156 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { action, observable, makeObservable, isObservableArray, isObservableSet, isObservableMap } from "mobx"; -import type { BaseStoreDependencies } from "../base-store/base-store"; -import { BaseStore } from "../base-store/base-store"; -import { getOrInsertSet, toggle, object } from "@k8slens/utilities"; -import type { UserPreferencesModel, StoreType } from "./preferences-helpers"; -import type { EmitAppEvent } from "../app-event-bus/emit-event.injectable"; - -// TODO: Remove coupling with Feature -import type { SelectedUpdateChannel } from "../../features/application-update/common/selected-update-channel/selected-update-channel.injectable"; -import type { ReleaseChannel } from "../../features/application-update/common/update-channels"; -import type { PreferenceDescriptors } from "./preference-descriptors.injectable"; -import { toJS } from "../utils"; - -export interface UserStoreModel { - preferences: UserPreferencesModel; -} - -interface Dependencies extends BaseStoreDependencies { - readonly selectedUpdateChannel: SelectedUpdateChannel; - readonly preferenceDescriptors: PreferenceDescriptors; - emitAppEvent: EmitAppEvent; -} - -export class UserStore extends BaseStore /* implements UserStoreFlatModel (when strict null is enabled) */ { - constructor(protected readonly dependencies: Dependencies) { - super(dependencies, { - configName: "lens-user-store", - }); - - makeObservable(this); - } - - /** - * @deprecated No longer used - */ - @observable seenContexts = observable.set(); - - /** - * @deprecated No longer used - */ - @observable newContexts = observable.set(); - - @observable allowErrorReporting!: StoreType; - @observable allowUntrustedCAs!: StoreType; - @observable colorTheme!: StoreType; - @observable terminalTheme!: StoreType; - @observable localeTimezone!: StoreType; - @observable downloadMirror!: StoreType; - @observable httpsProxy!: StoreType; - @observable shell!: StoreType; - @observable downloadBinariesPath!: StoreType; - @observable kubectlBinariesPath!: StoreType; - @observable terminalCopyOnSelect!: StoreType; - @observable terminalConfig!: StoreType; - @observable extensionRegistryUrl!: StoreType; - - /** - * Download kubectl binaries matching cluster version - */ - @observable downloadKubectlBinaries!: StoreType; - - /** - * Whether the application should open itself at login. - */ - @observable openAtLogin!: StoreType; - - /** - * The column IDs under each configurable table ID that have been configured - * to not be shown - */ - @observable hiddenTableColumns!: StoreType; - - /** - * Monaco editor configs - */ - @observable editorConfiguration!: StoreType; - - /** - * The set of file/folder paths to be synced - */ - @observable syncKubeconfigEntries!: StoreType; - - /** - * Checks if a column (by ID) for a table (by ID) is configured to be hidden - * @param tableId The ID of the table to be checked against - * @param columnIds The list of IDs the check if one is hidden - * @returns true if at least one column under the table is set to hidden - */ - isTableColumnHidden(tableId: string, ...columnIds: (string | undefined)[]): boolean { - if (columnIds.length === 0) { - return false; - } - - const config = this.hiddenTableColumns.get(tableId); - - if (!config) { - return false; - } - - return columnIds.some(columnId => columnId && config.has(columnId)); - } - - /** - * Toggles the hidden configuration of a table's column - */ - toggleTableColumnVisibility(tableId: string, columnId: string) { - toggle(getOrInsertSet(this.hiddenTableColumns, tableId), columnId); - } - - @action - resetTheme() { - this.colorTheme = this.dependencies.preferenceDescriptors.colorTheme.fromStore(undefined); - } - - @action - protected fromStore({ preferences }: Partial = {}) { - this.dependencies.logger.debug("UserStore.fromStore()", { preferences }); - - for (const [key, { fromStore }] of object.entries(this.dependencies.preferenceDescriptors)) { - const curVal = this[key]; - const newVal = fromStore((preferences)?.[key] as never) as never; - - if (isObservableArray(curVal)) { - curVal.replace(newVal); - } else if (isObservableSet(curVal) || isObservableMap(curVal)) { - curVal.replace(newVal); - } else { - this[key] = newVal; - } - } - - // TODO: Switch to action-based saving instead saving stores by reaction - if (preferences?.updateChannel) { - this.dependencies.selectedUpdateChannel.setValue(preferences?.updateChannel as ReleaseChannel); - } - } - - toJSON(): UserStoreModel { - const preferences = object.fromEntries( - object.entries(this.dependencies.preferenceDescriptors) - .map(([key, { toStore }]) => [key, toStore(this[key] as never)]), - ) as UserPreferencesModel; - - return toJS({ - preferences: { - ...preferences, - updateChannel: this.dependencies.selectedUpdateChannel.value.get().id, - }, - }); - } -} diff --git a/packages/core/src/common/user-store/current-timezone.global-override-for-injectable.ts b/packages/core/src/common/vars/current-timezone.global-override-for-injectable.ts similarity index 100% rename from packages/core/src/common/user-store/current-timezone.global-override-for-injectable.ts rename to packages/core/src/common/vars/current-timezone.global-override-for-injectable.ts diff --git a/packages/core/src/common/user-store/current-timezone.injectable.ts b/packages/core/src/common/vars/current-timezone.injectable.ts similarity index 100% rename from packages/core/src/common/user-store/current-timezone.injectable.ts rename to packages/core/src/common/vars/current-timezone.injectable.ts diff --git a/packages/core/src/common/user-store/user-info.global-override-for-injectable.ts b/packages/core/src/common/vars/user-info.global-override-for-injectable.ts similarity index 100% rename from packages/core/src/common/user-store/user-info.global-override-for-injectable.ts rename to packages/core/src/common/vars/user-info.global-override-for-injectable.ts diff --git a/packages/core/src/common/user-store/user-info.injectable.ts b/packages/core/src/common/vars/user-info.injectable.ts similarity index 100% rename from packages/core/src/common/user-store/user-info.injectable.ts rename to packages/core/src/common/vars/user-info.injectable.ts diff --git a/packages/core/src/common/weblinks-store/weblink-store.injectable.ts b/packages/core/src/common/weblinks-store/weblink-store.injectable.ts deleted file mode 100644 index 843c8716e5..0000000000 --- a/packages/core/src/common/weblinks-store/weblink-store.injectable.ts +++ /dev/null @@ -1,35 +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 directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable"; -import { baseStoreIpcChannelPrefixesInjectionToken } from "../base-store/channel-prefix"; -import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../base-store/disable-sync"; -import storeMigrationsInjectable from "../base-store/migrations.injectable"; -import { persistStateToConfigInjectionToken } from "../base-store/save-to-file"; -import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable"; -import loggerInjectable from "../logger.injectable"; -import getBasenameOfPathInjectable from "../path/get-basename.injectable"; -import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging"; -import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable"; -import { weblinkStoreMigrationInjectionToken } from "./migration-token"; -import { WeblinkStore } from "./weblink-store"; - -const weblinkStoreInjectable = getInjectable({ - id: "weblink-store", - instantiate: (di) => new WeblinkStore({ - directoryForUserData: di.inject(directoryForUserDataInjectable), - getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable), - logger: di.inject(loggerInjectable), - storeMigrationVersion: di.inject(storeMigrationVersionInjectable), - migrations: di.inject(storeMigrationsInjectable, weblinkStoreMigrationInjectionToken), - getBasenameOfPath: di.inject(getBasenameOfPathInjectable), - ipcChannelPrefixes: di.inject(baseStoreIpcChannelPrefixesInjectionToken), - persistStateToConfig: di.inject(persistStateToConfigInjectionToken), - enlistMessageChannelListener: di.inject(enlistMessageChannelListenerInjectionToken), - shouldDisableSyncInListener: di.inject(shouldBaseStoreDisableSyncInIpcListenerInjectionToken), - }), -}); - -export default weblinkStoreInjectable; diff --git a/packages/core/src/common/weblinks-store/weblink-store.ts b/packages/core/src/common/weblinks-store/weblink-store.ts deleted file mode 100644 index 2044ca08c1..0000000000 --- a/packages/core/src/common/weblinks-store/weblink-store.ts +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { action, comparer, observable, makeObservable } from "mobx"; -import type { BaseStoreDependencies } from "../base-store/base-store"; -import { BaseStore } from "../base-store/base-store"; -import * as uuid from "uuid"; -import { toJS } from "../utils"; - -export interface WeblinkData { - id: string; - name: string; - url: string; -} - -export interface WeblinkCreateOptions { - id?: string; - name: string; - url: string; -} - - -export interface WeblinkStoreModel { - weblinks: WeblinkData[]; -} - -export class WeblinkStore extends BaseStore { - @observable weblinks: WeblinkData[] = []; - - constructor(deps: BaseStoreDependencies) { - super(deps, { - configName: "lens-weblink-store", - accessPropertiesByDotNotation: false, // To make dots safe in cluster context names - syncOptions: { - equals: comparer.structural, - }, - }); - makeObservable(this); - this.load(); - } - - @action - protected fromStore(data: Partial = {}) { - this.weblinks = data.weblinks || []; - } - - add(data: WeblinkCreateOptions) { - const { - id = uuid.v4(), - name, - url, - } = data; - const weblink: WeblinkData = { id, name, url }; - - this.weblinks.push(weblink); - - return weblink; - } - - @action - removeById(id: string) { - this.weblinks = this.weblinks.filter((w) => w.id !== id); - } - - toJSON(): WeblinkStoreModel { - const model: WeblinkStoreModel = { - weblinks: this.weblinks, - }; - - return toJS(model); - } -} diff --git a/packages/core/src/extensions/__tests__/extension-loader.test.ts b/packages/core/src/extensions/__tests__/extension-loader.test.ts index 4ded8cdbb9..9be0507f6d 100644 --- a/packages/core/src/extensions/__tests__/extension-loader.test.ts +++ b/packages/core/src/extensions/__tests__/extension-loader.test.ts @@ -5,14 +5,16 @@ import type { ExtensionLoader } from "../extension-loader"; import extensionLoaderInjectable from "../extension-loader/extension-loader.injectable"; +import type { ObservableMap } from "mobx"; import { runInAction } from "mobx"; -import updateExtensionsStateInjectable from "../extension-loader/update-extensions-state/update-extensions-state.injectable"; import { delay } from "@k8slens/utilities"; import { getDiForUnitTesting } from "../../renderer/getDiForUnitTesting"; import ipcRendererInjectable from "../../renderer/utils/channel/ipc-renderer.injectable"; import type { IpcRenderer } from "electron"; import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; import currentlyInClusterFrameInjectable from "../../renderer/routes/currently-in-cluster-frame.injectable"; +import type { LensExtensionState } from "../../features/extensions/enabled/common/state.injectable"; +import enabledExtensionsStateInjectable from "../../features/extensions/enabled/common/state.injectable"; const manifestPath = "manifest/path"; const manifestPath2 = "manifest/path2"; @@ -20,7 +22,7 @@ const manifestPath3 = "manifest/path3"; describe("ExtensionLoader", () => { let extensionLoader: ExtensionLoader; - let updateExtensionStateMock: jest.Mock; + let enabledExtensionsState: ObservableMap; beforeEach(() => { const di = getDiForUnitTesting(); @@ -106,69 +108,60 @@ describe("ExtensionLoader", () => { }, }) as unknown as IpcRenderer); - updateExtensionStateMock = jest.fn(); - - di.override(updateExtensionsStateInjectable, () => updateExtensionStateMock); - extensionLoader = di.inject(extensionLoaderInjectable); + enabledExtensionsState = di.inject(enabledExtensionsStateInjectable); }); it("renderer updates extension after ipc broadcast", async () => { - expect(extensionLoader.userExtensions).toMatchInlineSnapshot(`Map {}`); + expect(extensionLoader.userExtensions).toEqual(new Map()); await extensionLoader.init(); await delay(10); // Assert the extensions after the extension broadcast event - expect(extensionLoader.userExtensions).toMatchInlineSnapshot(` - Map { - "manifest/path" => Object { - "absolutePath": "/test/1", - "id": "manifest/path", - "isBundled": false, - "isEnabled": true, - "manifest": Object { - "name": "TestExtension", - "version": "1.0.0", + expect(extensionLoader.userExtensions).toEqual( + new Map([ + ["manifest/path", { + absolutePath: "/test/1", + id: "manifest/path", + isBundled: false, + isEnabled: true, + manifest: { + name: "TestExtension", + version: "1.0.0", }, - "manifestPath": "manifest/path", - }, - "manifest/path3" => Object { - "absolutePath": "/test/3", - "id": "manifest/path3", - "isBundled": false, - "isEnabled": true, - "manifest": Object { - "name": "TestExtension3", - "version": "3.0.0", + manifestPath: "manifest/path", + }], + ["manifest/path3", { + absolutePath: "/test/3", + id: "manifest/path3", + isBundled: false, + isEnabled: true, + manifest: { + name: "TestExtension3", + version: "3.0.0", }, - "manifestPath": "manifest/path3", - }, - } - `); + manifestPath: "manifest/path3", + }], + ]), + ); }); it("updates ExtensionsStore after isEnabled is changed", async () => { await extensionLoader.init(); - expect(updateExtensionStateMock).not.toHaveBeenCalled(); - runInAction(() => { extensionLoader.setIsEnabled("manifest/path", false); }); - expect(updateExtensionStateMock).toHaveBeenCalledWith( - expect.objectContaining({ - "manifest/path": { - enabled: false, - name: "TestExtension", - }, - - "manifest/path2": { - enabled: true, - name: "TestExtension2", - }, - }), - ); + expect(enabledExtensionsState.size).toBe(2); + expect(enabledExtensionsState.get("manifest/path")).toMatchObject({ + enabled: false, + name: "TestExtension", + }); + expect(enabledExtensionsState.get("manifest/path2")).toMatchObject({ + enabled: true, + name: "TestExtension2", + }); }); }); diff --git a/packages/core/src/extensions/base-extension-store.ts b/packages/core/src/extensions/base-extension-store.ts new file mode 100644 index 0000000000..703edfafd0 --- /dev/null +++ b/packages/core/src/extensions/base-extension-store.ts @@ -0,0 +1,103 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import * as path from "path"; +import type { LensExtension } from "./lens-extension"; +import type { StaticThis } from "../common/utils/singleton"; +import { getOrInsertWith } from "@k8slens/utilities"; +import { getLegacyGlobalDiForExtensionApi } from "./as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; +import type { PersistentStorage, PersistentStorageParams } from "../common/persistent-storage/create.injectable"; +import createPersistentStorageInjectable from "../common/persistent-storage/create.injectable"; +import directoryForUserDataInjectable from "../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; +import assert from "assert"; +import type { Options } from "conf"; +import type { Migrations } from "../common/persistent-storage/migrations.injectable"; + +export interface ExtensionStoreParams extends Omit, "migrations" | "cwd" | "fromStore" | "toJSON"> { + migrations?: Options["migrations"]; + cwd?: string; +} + +export abstract class BaseExtensionStore { + private static readonly instances = new WeakMap(); + + /** + * @deprecated This is a form of global shared state. Just call `new Store(...)` + */ + static createInstance(this: StaticThis, ...args: R): T { + return getOrInsertWith(BaseExtensionStore.instances, this, () => new this(...args)) as T; + } + + /** + * @deprecated This is a form of global shared state. Just call `new Store(...)` + */ + static getInstance(this: StaticThis, strict?: true): T; + static getInstance(this: StaticThis, strict: false): T | undefined; + static getInstance(this: StaticThis, strict = true): T | undefined { + if (!BaseExtensionStore.instances.has(this) && strict) { + throw new TypeError(`instance of ${this.name} is not created`); + } + + return BaseExtensionStore.instances.get(this) as (T | undefined); + } + + protected persistentStorage?: PersistentStorage; + private readonly dependencies = (() => { + const di = getLegacyGlobalDiForExtensionApi(); + + return { + createPersistentStorage: di.inject(createPersistentStorageInjectable), + directoryForUserData: di.inject(directoryForUserDataInjectable), + } as const; + })(); + + constructor(protected readonly rawParams: ExtensionStoreParams) { } + + /** + * @deprecated This is a form of global shared state. Just call `new Store(...)` + */ + static resetInstance() { + BaseExtensionStore.instances.delete(this); + } + + protected extension?: LensExtension; + + loadExtension(extension: LensExtension) { + this.extension = extension; + const { + projectVersion = this.extension.version, + cwd: _cwd, // This is ignored to maintain backwards compatibility + migrations = {}, + ...params + } = this.rawParams; + + this.persistentStorage = this.dependencies.createPersistentStorage({ + ...params, + cwd: this.cwd(), + projectVersion, + migrations: migrations as Migrations, + fromStore: (data) => this.fromStore(data), + toJSON: () => this.toJSON(), + }); + + this.persistentStorage.loadAndStartSyncing(); + } + + /** + * @deprecated Never use this method. Instead call {@link BaseExtensionStore.loadExtension} + */ + load() { + this.persistentStorage?.loadAndStartSyncing(); + } + + protected cwd() { + assert(this.extension, "cwd can only be called in loadExtension"); + + return this.rawParams.cwd ?? path.join(this.dependencies.directoryForUserData, "extension-store", this.extension.storeName); + } + + abstract fromStore(data: Partial): void; + abstract toJSON(): T; +} diff --git a/packages/core/src/extensions/common-api/app.ts b/packages/core/src/extensions/common-api/app.ts index 8c190b984b..9e0c84f4e0 100644 --- a/packages/core/src/extensions/common-api/app.ts +++ b/packages/core/src/extensions/common-api/app.ts @@ -8,21 +8,21 @@ 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 { issuesTrackerUrl } from "../../common/vars"; import { buildVersionInjectionToken } from "../../common/vars/build-semantic-version.injectable"; import { asLegacyGlobalForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import userStoreInjectable from "../../common/user-store/user-store.injectable"; +import enabledExtensionsInjectable from "../../features/extensions/enabled/common/enabled-extensions.injectable"; +import userPreferencesStateInjectable from "../../features/user-preferences/common/state.injectable"; -const userStore = asLegacyGlobalForExtensionApi(userStoreInjectable); +const userStore = asLegacyGlobalForExtensionApi(userPreferencesStateInjectable); +const enabledExtensions = asLegacyGlobalForExtensionApi(enabledExtensionsInjectable); export const App = { Preferences: { getKubectlPath: () => userStore.kubectlBinariesPath, }, - getEnabledExtensions: asLegacyGlobalFunctionForExtensionApi(getEnabledExtensionsInjectable), + getEnabledExtensions: () => enabledExtensions.get(), get version() { const di = getLegacyGlobalDiForExtensionApi(); @@ -54,7 +54,7 @@ export const App = { return di.inject(isLinuxInjectable); }, /** - * @deprecated This value is now `""` and is left here for backwards compatability. + * @deprecated This value is now `""` and is left here for backwards compatibility. */ slackUrl: "", issuesTrackerUrl, diff --git a/packages/core/src/extensions/common-api/get-enabled-extensions/get-enabled-extensions.injectable.ts b/packages/core/src/extensions/common-api/get-enabled-extensions/get-enabled-extensions.injectable.ts deleted file mode 100644 index 747dfa4f42..0000000000 --- a/packages/core/src/extensions/common-api/get-enabled-extensions/get-enabled-extensions.injectable.ts +++ /dev/null @@ -1,15 +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 extensionsStoreInjectable from "../../extensions-store/extensions-store.injectable"; - -const getEnabledExtensionsInjectable = getInjectable({ - id: "get-enabled-extensions", - - instantiate: (di) => () => - di.inject(extensionsStoreInjectable).enabledExtensions, -}); - -export default getEnabledExtensionsInjectable; diff --git a/packages/core/src/extensions/common-api/stores.ts b/packages/core/src/extensions/common-api/stores.ts index 023fc5c7a4..4585a1661d 100644 --- a/packages/core/src/extensions/common-api/stores.ts +++ b/packages/core/src/extensions/common-api/stores.ts @@ -3,10 +3,13 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { BaseStoreParams } from "../../common/base-store/base-store"; -import { ExtensionStore } from "../extension-store"; +import type { PersistentStorageParams } from "../../common/persistent-storage/create.injectable"; +import type { ExtensionStoreParams } from "../base-extension-store"; +import { BaseExtensionStore as ExtensionStore } from "../base-extension-store"; -export { - BaseStoreParams, - ExtensionStore, +export type { + ExtensionStoreParams, + PersistentStorageParams, }; + +export { ExtensionStore }; diff --git a/packages/core/src/extensions/extension-discovery/extension-discovery.injectable.ts b/packages/core/src/extensions/extension-discovery/extension-discovery.injectable.ts index 5e2a4cd84d..92b1c8cf77 100644 --- a/packages/core/src/extensions/extension-discovery/extension-discovery.injectable.ts +++ b/packages/core/src/extensions/extension-discovery/extension-discovery.injectable.ts @@ -6,7 +6,6 @@ import { getInjectable } from "@ogre-tools/injectable"; import { ExtensionDiscovery } from "./extension-discovery"; import extensionLoaderInjectable from "../extension-loader/extension-loader.injectable"; import isCompatibleExtensionInjectable from "./is-compatible-extension/is-compatible-extension.injectable"; -import extensionsStoreInjectable from "../extensions-store/extensions-store.injectable"; import extensionInstallationStateStoreInjectable from "../extension-installation-state-store/extension-installation-state-store.injectable"; import installExtensionInjectable from "../install-extension/install-extension.injectable"; import extensionPackageRootDirectoryInjectable from "../install-extension/extension-package-root-directory.injectable"; @@ -28,13 +27,14 @@ import joinPathsInjectable from "../../common/path/join-paths.injectable"; import removePathInjectable from "../../common/fs/remove.injectable"; import homeDirectoryPathInjectable from "../../common/os/home-directory-path.injectable"; import lensResourcesDirInjectable from "../../common/vars/lens-resources-dir.injectable"; +import isExtensionEnabledInjectable from "../../features/extensions/enabled/common/is-enabled.injectable"; const extensionDiscoveryInjectable = getInjectable({ id: "extension-discovery", instantiate: (di) => new ExtensionDiscovery({ extensionLoader: di.inject(extensionLoaderInjectable), - extensionsStore: di.inject(extensionsStoreInjectable), + isExtensionEnabled: di.inject(isExtensionEnabledInjectable), extensionInstallationStateStore: di.inject(extensionInstallationStateStoreInjectable), isCompatibleExtension: di.inject(isCompatibleExtensionInjectable), installExtension: di.inject(installExtensionInjectable), diff --git a/packages/core/src/extensions/extension-discovery/extension-discovery.ts b/packages/core/src/extensions/extension-discovery/extension-discovery.ts index 88864d8663..7a39fa7467 100644 --- a/packages/core/src/extensions/extension-discovery/extension-discovery.ts +++ b/packages/core/src/extensions/extension-discovery/extension-discovery.ts @@ -9,7 +9,6 @@ import { makeObservable, observable, reaction, when } from "mobx"; import { broadcastMessage, ipcMainHandle, ipcRendererOn } from "../../common/ipc"; import { toJS } from "../../common/utils"; import { isErrnoException } from "@k8slens/utilities"; -import type { ExtensionsStore } from "../extensions-store/extensions-store"; import type { ExtensionLoader } from "../extension-loader"; import type { InstalledExtension, LensExtensionId, LensExtensionManifest } from "@k8slens/legacy-extensions"; import type { ExtensionInstallationStateStore } from "../extension-installation-state-store/extension-installation-state-store"; @@ -31,10 +30,10 @@ import type { GetDirnameOfPath } from "../../common/path/get-dirname.injectable" import type { GetRelativePath } from "../../common/path/get-relative-path.injectable"; import type { RemovePath } from "../../common/fs/remove.injectable"; import type TypedEventEmitter from "typed-emitter"; +import type { IsExtensionEnabled } from "../../features/extensions/enabled/common/is-enabled.injectable"; interface Dependencies { readonly extensionLoader: ExtensionLoader; - readonly extensionsStore: ExtensionsStore; readonly extensionInstallationStateStore: ExtensionInstallationStateStore; readonly extensionPackageRootDirectory: string; readonly resourcesDirectory: string; @@ -42,6 +41,7 @@ interface Dependencies { readonly isProduction: boolean; readonly fileSystemSeparator: string; readonly homeDirectoryPath: string; + isExtensionEnabled: IsExtensionEnabled; isCompatibleExtension: (manifest: LensExtensionManifest) => boolean; installExtension: (name: string) => Promise; readJsonFile: ReadJson; @@ -334,7 +334,7 @@ export class ExtensionDiscovery { try { const manifest = await this.dependencies.readJsonFile(manifestPath) as unknown as LensExtensionManifest; const id = isBundled ? manifestPath : this.getInstalledManifestPath(manifest.name); - const isEnabled = this.dependencies.extensionsStore.isEnabled({ id, isBundled }); + const isEnabled = this.dependencies.isExtensionEnabled({ id, isBundled }); const extensionDir = this.dependencies.getDirnameOfPath(manifestPath); const npmPackage = this.dependencies.joinPaths(extensionDir, `${manifest.name}-${manifest.version}.tgz`); const absolutePath = this.dependencies.isProduction && await this.dependencies.pathExists(npmPackage) diff --git a/packages/core/src/extensions/extension-loader/extension-loader.injectable.ts b/packages/core/src/extensions/extension-loader/extension-loader.injectable.ts index e635a6cca1..12187c38c0 100644 --- a/packages/core/src/extensions/extension-loader/extension-loader.injectable.ts +++ b/packages/core/src/extensions/extension-loader/extension-loader.injectable.ts @@ -4,7 +4,6 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { ExtensionLoader } from "./extension-loader"; -import updateExtensionsStateInjectable from "./update-extensions-state/update-extensions-state.injectable"; import { createExtensionInstanceInjectionToken } from "./create-extension-instance.token"; import extensionInstancesInjectable from "./extension-instances.injectable"; import type { LensExtension } from "../lens-extension"; @@ -14,6 +13,7 @@ import joinPathsInjectable from "../../common/path/join-paths.injectable"; import getDirnameOfPathInjectable from "../../common/path/get-dirname.injectable"; import { bundledExtensionInjectionToken } from "@k8slens/legacy-extensions"; import { extensionEntryPointNameInjectionToken } from "./entry-point-name"; +import updateExtensionsStateInjectable from "../../features/extensions/enabled/common/update-state.injectable"; const extensionLoaderInjectable = getInjectable({ id: "extension-loader", diff --git a/packages/core/src/extensions/extension-loader/extension-loader.ts b/packages/core/src/extensions/extension-loader/extension-loader.ts index 7d41ec1fda..4a24ad23a1 100644 --- a/packages/core/src/extensions/extension-loader/extension-loader.ts +++ b/packages/core/src/extensions/extension-loader/extension-loader.ts @@ -10,7 +10,6 @@ import { action, computed, makeObservable, toJS, observable, observe, reaction, import { broadcastMessage, ipcMainOn, ipcRendererOn, ipcMainHandle } from "../../common/ipc"; import { isDefined } from "@k8slens/utilities"; import type { LensExtension } from "../lens-extension"; -import type { LensExtensionState } from "../extensions-store/extensions-store"; import { extensionLoaderFromMainChannel, extensionLoaderFromRendererChannel } from "../../common/ipc/extension-handling"; import { requestExtensionLoaderInitialState } from "../../renderer/ipc"; import assert from "assert"; @@ -21,6 +20,7 @@ import type { Logger } from "../../common/logger"; import type { JoinPaths } from "../../common/path/join-paths.injectable"; import type { GetDirnameOfPath } from "../../common/path/get-dirname.injectable"; import type { LensExtensionId, BundledExtension, InstalledExtension, LensExtensionConstructor } from "@k8slens/legacy-extensions"; +import type { UpdateExtensionsState } from "../../features/extensions/enabled/common/update-state.injectable"; const logModule = "[EXTENSIONS-LOADER]"; @@ -29,7 +29,7 @@ interface Dependencies { readonly bundledExtensions: BundledExtension[]; readonly logger: Logger; readonly extensionEntryPointName: "main" | "renderer"; - updateExtensionsState: (extensionsState: Record) => void; + updateExtensionsState: UpdateExtensionsState; createExtensionInstance: CreateExtensionInstance; getExtension: (instance: LensExtension) => Extension; joinPaths: JoinPaths; @@ -125,13 +125,11 @@ export class ExtensionLoader { // Transform userExtensions to a state object for storing into ExtensionsStore @computed get storeState() { - return Object.fromEntries( - Array.from(this.userExtensions) - .map(([extId, extension]) => [extId, { - enabled: extension.isEnabled, - name: extension.manifest.name, - }]), - ); + return Array.from(this.userExtensions) + .map(([extId, extension]) => [extId, { + enabled: extension.isEnabled, + name: extension.manifest.name, + }] as const); } @action diff --git a/packages/core/src/extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store-injection-token.ts b/packages/core/src/extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store-injection-token.ts index d7635a71b2..297238787e 100644 --- a/packages/core/src/extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store-injection-token.ts +++ b/packages/core/src/extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store-injection-token.ts @@ -3,8 +3,8 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectionToken } from "@ogre-tools/injectable"; -import type { MigrationDeclaration } from "../../../common/base-store/migrations.injectable"; +import type { MigrationDeclaration } from "../../../common/persistent-storage/migrations.injectable"; -export const fileSystemProvisionerStoreInjectionToken = getInjectionToken({ - id: "file-system-provisioner-store-injection-token", +export const fileSystemProvisionerStoreMigrationDeclarationInjectionToken = getInjectionToken({ + id: "file-system-provisioner-store-migration-declaration", }); diff --git a/packages/core/src/extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable.ts b/packages/core/src/extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable.ts index 2295608520..fe78674d11 100644 --- a/packages/core/src/extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable.ts +++ b/packages/core/src/extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable.ts @@ -3,36 +3,36 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { FileSystemProvisionerStore } from "./file-system-provisioner-store"; -import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; -import getConfigurationFileModelInjectable from "../../../common/get-configuration-file-model/get-configuration-file-model.injectable"; -import loggerInjectable from "../../../common/logger.injectable"; -import storeMigrationVersionInjectable from "../../../common/vars/store-migration-version.injectable"; -import { baseStoreIpcChannelPrefixesInjectionToken } from "../../../common/base-store/channel-prefix"; -import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../../../common/base-store/disable-sync"; -import { persistStateToConfigInjectionToken } from "../../../common/base-store/save-to-file"; -import getBasenameOfPathInjectable from "../../../common/path/get-basename.injectable"; -import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging"; -import ensureHashedDirectoryForExtensionInjectable from "./ensure-hashed-directory-for-extension.injectable"; import { registeredExtensionsInjectable } from "./registered-extensions.injectable"; +import createPersistentStorageInjectable from "../../../common/persistent-storage/create.injectable"; +import { action } from "mobx"; +import { object } from "@k8slens/utilities"; +import storeMigrationVersionInjectable from "../../../common/vars/store-migration-version.injectable"; const fileSystemProvisionerStoreInjectable = getInjectable({ id: "file-system-provisioner-store", - instantiate: (di) => new FileSystemProvisionerStore({ - directoryForUserData: di.inject(directoryForUserDataInjectable), - getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable), - logger: di.inject(loggerInjectable), - storeMigrationVersion: di.inject(storeMigrationVersionInjectable), - migrations: {}, - getBasenameOfPath: di.inject(getBasenameOfPathInjectable), - ipcChannelPrefixes: di.inject(baseStoreIpcChannelPrefixesInjectionToken), - persistStateToConfig: di.inject(persistStateToConfigInjectionToken), - enlistMessageChannelListener: di.inject(enlistMessageChannelListenerInjectionToken), - shouldDisableSyncInListener: di.inject(shouldBaseStoreDisableSyncInIpcListenerInjectionToken), - ensureHashedDirectoryForExtension: di.inject(ensureHashedDirectoryForExtensionInjectable), - registeredExtensions: di.inject(registeredExtensionsInjectable), - }), + instantiate: (di) => { + const registeredExtensions = di.inject(registeredExtensionsInjectable); + const createPersistentStorage = di.inject(createPersistentStorageInjectable); + const storeMigrationVersion = di.inject(storeMigrationVersionInjectable); + + const store = createPersistentStorage({ + configName: "lens-filesystem-provisioner-store", + accessPropertiesByDotNotation: false, // To make dots safe in cluster context names + projectVersion: storeMigrationVersion, + fromStore: action(({ extensions = {}}) => { + registeredExtensions.replace(object.entries(extensions)); + }), + toJSON: () => ({ + extensions: Object.fromEntries(registeredExtensions), + }), + }); + + return { + load: () => store.loadAndStartSyncing(), + }; + }, }); export default fileSystemProvisionerStoreInjectable; diff --git a/packages/core/src/extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.ts b/packages/core/src/extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.ts deleted file mode 100644 index 6c48210479..0000000000 --- a/packages/core/src/extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.ts +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { LensExtensionId } from "@k8slens/legacy-extensions"; -import type { ObservableMap } from "mobx"; -import { action, makeObservable } from "mobx"; -import type { BaseStoreDependencies } from "../../../common/base-store/base-store"; -import { BaseStore } from "../../../common/base-store/base-store"; -import type { EnsureHashedDirectoryForExtension } from "./ensure-hashed-directory-for-extension.injectable"; - -interface FSProvisionModel { - extensions: Record; // extension names to paths -} - -interface Dependencies extends BaseStoreDependencies { - ensureHashedDirectoryForExtension: EnsureHashedDirectoryForExtension; - registeredExtensions: ObservableMap; -} - -export class FileSystemProvisionerStore extends BaseStore { - constructor(protected readonly dependencies: Dependencies) { - super(dependencies, { - configName: "lens-filesystem-provisioner-store", - accessPropertiesByDotNotation: false, // To make dots safe in cluster context names - }); - - makeObservable(this); - } - - /** - * This function retrieves the saved path to the folder which the extension - * can saves files to. If the folder is not present then it is created. - * @param extensionName the name of the extension requesting the path - * @returns path to the folder that the extension can safely write files to. - */ - async requestDirectory(extensionName: string): Promise { - return this.dependencies.ensureHashedDirectoryForExtension(extensionName); - } - - @action - protected fromStore({ extensions }: FSProvisionModel = { extensions: {}}): void { - this.dependencies.registeredExtensions.merge(extensions); - } - - toJSON(): FSProvisionModel { - return { - extensions: Object.fromEntries(this.dependencies.registeredExtensions.toJSON()), - }; - } -} diff --git a/packages/core/src/extensions/extension-loader/update-extensions-state/update-extensions-state.injectable.ts b/packages/core/src/extensions/extension-loader/update-extensions-state/update-extensions-state.injectable.ts deleted file mode 100644 index 754375dd5a..0000000000 --- a/packages/core/src/extensions/extension-loader/update-extensions-state/update-extensions-state.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 extensionsStoreInjectable from "../../extensions-store/extensions-store.injectable"; - -const updateExtensionsStateInjectable = getInjectable({ - id: "update-extensions-state", - instantiate: (di) => di.inject(extensionsStoreInjectable).mergeState, -}); - -export default updateExtensionsStateInjectable; diff --git a/packages/core/src/extensions/extension-store.ts b/packages/core/src/extensions/extension-store.ts deleted file mode 100644 index fe9cff2a02..0000000000 --- a/packages/core/src/extensions/extension-store.ts +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { BaseStoreParams } from "../common/base-store/base-store"; -import { BaseStore } from "../common/base-store/base-store"; -import * as path from "path"; -import type { LensExtension } from "./lens-extension"; -import assert from "assert"; -import type { StaticThis } from "../common/utils/singleton"; -import { getOrInsertWith } from "@k8slens/utilities"; -import { getLegacyGlobalDiForExtensionApi } from "./as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; -import directoryForUserDataInjectable from "../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; -import getConfigurationFileModelInjectable from "../common/get-configuration-file-model/get-configuration-file-model.injectable"; -import loggerInjectable from "../common/logger.injectable"; -import storeMigrationVersionInjectable from "../common/vars/store-migration-version.injectable"; -import type { Migrations } from "conf/dist/source/types"; -import { baseStoreIpcChannelPrefixesInjectionToken } from "../common/base-store/channel-prefix"; -import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../common/base-store/disable-sync"; -import { persistStateToConfigInjectionToken } from "../common/base-store/save-to-file"; -import getBasenameOfPathInjectable from "../common/path/get-basename.injectable"; -import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging"; - -export interface ExtensionStoreParams extends BaseStoreParams { - migrations?: Migrations; -} - -export abstract class ExtensionStore extends BaseStore { - private static readonly instances = new WeakMap(); - - /** - * @deprecated This is a form of global shared state. Just call `new Store(...)` - */ - static createInstance(this: StaticThis, ...args: R): T { - return getOrInsertWith(ExtensionStore.instances, this, () => new this(...args)) as T; - } - - /** - * @deprecated This is a form of global shared state. Just call `new Store(...)` - */ - static getInstance(this: StaticThis, strict?: true): T; - static getInstance(this: StaticThis, strict: false): T | undefined; - static getInstance(this: StaticThis, strict = true): T | undefined { - if (!ExtensionStore.instances.has(this) && strict) { - throw new TypeError(`instance of ${this.name} is not created`); - } - - return ExtensionStore.instances.get(this) as (T | undefined); - } - - constructor({ migrations, ...params }: ExtensionStoreParams) { - const di = getLegacyGlobalDiForExtensionApi(); - - super({ - directoryForUserData: di.inject(directoryForUserDataInjectable), - getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable), - logger: di.inject(loggerInjectable), - storeMigrationVersion: di.inject(storeMigrationVersionInjectable), - migrations: migrations as Migrations>, - getBasenameOfPath: di.inject(getBasenameOfPathInjectable), - ipcChannelPrefixes: di.inject(baseStoreIpcChannelPrefixesInjectionToken), - persistStateToConfig: di.inject(persistStateToConfigInjectionToken), - enlistMessageChannelListener: di.inject(enlistMessageChannelListenerInjectionToken), - shouldDisableSyncInListener: di.inject(shouldBaseStoreDisableSyncInIpcListenerInjectionToken), - }, params); - } - - /** - * @deprecated This is a form of global shared state. Just call `new Store(...)` - */ - static resetInstance() { - ExtensionStore.instances.delete(this); - } - - protected extension?: LensExtension; - - loadExtension(extension: LensExtension) { - this.extension = extension; - - this.params.projectVersion ??= this.extension.version; - - return super.load(); - } - - load() { - if (!this.extension) { return; } - - return super.load(); - } - - protected cwd() { - assert(this.extension, "must call this.load() first"); - - return path.join(super.cwd(), "extension-store", this.extension.storeName); - } -} diff --git a/packages/core/src/extensions/extensions-store/extensions-store.injectable.ts b/packages/core/src/extensions/extensions-store/extensions-store.injectable.ts deleted file mode 100644 index 9e08a96aac..0000000000 --- a/packages/core/src/extensions/extensions-store/extensions-store.injectable.ts +++ /dev/null @@ -1,33 +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 directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; -import { baseStoreIpcChannelPrefixesInjectionToken } from "../../common/base-store/channel-prefix"; -import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../../common/base-store/disable-sync"; -import { persistStateToConfigInjectionToken } from "../../common/base-store/save-to-file"; -import getConfigurationFileModelInjectable from "../../common/get-configuration-file-model/get-configuration-file-model.injectable"; -import loggerInjectable from "../../common/logger.injectable"; -import getBasenameOfPathInjectable from "../../common/path/get-basename.injectable"; -import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging"; -import storeMigrationVersionInjectable from "../../common/vars/store-migration-version.injectable"; -import { ExtensionsStore } from "./extensions-store"; - -const extensionsStoreInjectable = getInjectable({ - id: "extensions-store", - instantiate: (di) => new ExtensionsStore({ - directoryForUserData: di.inject(directoryForUserDataInjectable), - getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable), - logger: di.inject(loggerInjectable), - storeMigrationVersion: di.inject(storeMigrationVersionInjectable), - migrations: {}, - getBasenameOfPath: di.inject(getBasenameOfPathInjectable), - ipcChannelPrefixes: di.inject(baseStoreIpcChannelPrefixesInjectionToken), - persistStateToConfig: di.inject(persistStateToConfigInjectionToken), - enlistMessageChannelListener: di.inject(enlistMessageChannelListenerInjectionToken), - shouldDisableSyncInListener: di.inject(shouldBaseStoreDisableSyncInIpcListenerInjectionToken), - }), -}); - -export default extensionsStoreInjectable; diff --git a/packages/core/src/extensions/extensions-store/extensions-store.ts b/packages/core/src/extensions/extensions-store/extensions-store.ts deleted file mode 100644 index 17766d26d7..0000000000 --- a/packages/core/src/extensions/extensions-store/extensions-store.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { LensExtensionId } from "@k8slens/legacy-extensions"; -import { action, computed, makeObservable, observable } from "mobx"; -import type { BaseStoreDependencies } from "../../common/base-store/base-store"; -import { BaseStore } from "../../common/base-store/base-store"; - -export interface LensExtensionsStoreModel { - extensions: Record; -} - -export interface LensExtensionState { - enabled?: boolean; - name: string; -} - -export interface IsEnabledExtensionDescriptor { - id: string; - isBundled: boolean; -} - -export class ExtensionsStore extends BaseStore { - constructor(deps: BaseStoreDependencies) { - super(deps, { - configName: "lens-extensions", - }); - makeObservable(this); - this.load(); - } - - @computed - get enabledExtensions() { - return Array.from(this.state.values()) - .filter(({ enabled }) => enabled) - .map(({ name }) => name); - } - - protected state = observable.map(); - - isEnabled({ id, isBundled }: IsEnabledExtensionDescriptor): boolean { - // By default false, so that copied extensions are disabled by default. - // If user installs the extension from the UI, the Extensions component will specifically enable it. - return isBundled || Boolean(this.state.get(id)?.enabled); - } - - mergeState = action((extensionsState: Record | [LensExtensionId, LensExtensionState][]) => { - this.state.merge(extensionsState); - }); - - @action - protected fromStore({ extensions }: LensExtensionsStoreModel) { - this.state.merge(extensions); - } - - toJSON(): LensExtensionsStoreModel { - return { - extensions: Object.fromEntries(this.state.toJSON()), - }; - } -} diff --git a/packages/core/src/extensions/lens-extension-set-dependencies.ts b/packages/core/src/extensions/lens-extension-set-dependencies.ts index 7b7c62597a..aa22b7a1a1 100644 --- a/packages/core/src/extensions/lens-extension-set-dependencies.ts +++ b/packages/core/src/extensions/lens-extension-set-dependencies.ts @@ -10,13 +10,13 @@ import type { Route } from "../common/front-end-routing/front-end-route-injectio import type { CatalogEntityRegistry as MainCatalogEntityRegistry } from "../main/catalog"; import type { CatalogEntityRegistry as RendererCatalogEntityRegistry } from "../renderer/api/catalog/entity/registry"; import type { GetExtensionPageParameters } from "../renderer/routes/get-extension-page-parameters.injectable"; -import type { FileSystemProvisionerStore } from "./extension-loader/file-system-provisioner-store/file-system-provisioner-store"; import type { NavigateForExtension } from "../main/start-main-application/lens-window/navigate-for-extension.injectable"; import type { Logger } from "../common/logger"; +import type { EnsureHashedDirectoryForExtension } from "./extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.injectable"; export interface LensExtensionDependencies { - readonly fileSystemProvisionerStore: FileSystemProvisionerStore; readonly logger: Logger; + ensureHashedDirectoryForExtension: EnsureHashedDirectoryForExtension; } export interface LensMainExtensionDependencies extends LensExtensionDependencies { diff --git a/packages/core/src/extensions/lens-extension.ts b/packages/core/src/extensions/lens-extension.ts index 83ba4ebaec..ec5eca0cd9 100644 --- a/packages/core/src/extensions/lens-extension.ts +++ b/packages/core/src/extensions/lens-extension.ts @@ -83,7 +83,7 @@ export class LensExtension< */ async getExtensionFileFolder(): Promise { // storeName is read from the manifest and has a fallback to the manifest name, which equals id - return this[lensExtensionDependencies].fileSystemProvisionerStore.requestDirectory(this.storeName); + return this[lensExtensionDependencies].ensureHashedDirectoryForExtension(this.storeName); } @action diff --git a/packages/core/src/extensions/renderer-api/k8s-api.ts b/packages/core/src/extensions/renderer-api/k8s-api.ts index 1dfdc0e075..98e2cfcdfb 100644 --- a/packages/core/src/extensions/renderer-api/k8s-api.ts +++ b/packages/core/src/extensions/renderer-api/k8s-api.ts @@ -37,7 +37,7 @@ import namespaceApiInjectable from "../../common/k8s-api/endpoints/namespace.api import kubeEventApiInjectable from "../../common/k8s-api/endpoints/events.api.injectable"; import roleBindingApiInjectable from "../../common/k8s-api/endpoints/role-binding.api.injectable"; import customResourceDefinitionApiInjectable from "../../common/k8s-api/endpoints/custom-resource-definition.api.injectable"; -import { shouldShowResourceInjectionToken } from "../../common/cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { asLegacyGlobalFunctionForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api"; import requestMetricsInjectable from "../../common/k8s-api/endpoints/metrics.api/request-metrics.injectable"; diff --git a/packages/core/src/features/__snapshots__/extension-special-characters-in-page-registrations.test.tsx.snap b/packages/core/src/features/__snapshots__/extension-special-characters-in-page-registrations.test.tsx.snap index 03e2a2cd8a..a63146ddcc 100644 --- a/packages/core/src/features/__snapshots__/extension-special-characters-in-page-registrations.test.tsx.snap +++ b/packages/core/src/features/__snapshots__/extension-special-characters-in-page-registrations.test.tsx.snap @@ -230,7 +230,7 @@ exports[`extension special characters in page registrations renders 1`] = ` class="HotbarSelector" > mac", - "root -> mac -> about", - "root -> mac -> separator-1", - "root -> mac -> navigate-to-preferences", - "root -> mac -> navigate-to-extensions", - "root -> mac -> separator-2", - "root -> mac -> services", - "root -> mac -> separator-3", - "root -> mac -> hide", - "root -> mac -> hide-others", - "root -> mac -> unhide", - "root -> mac -> separator-4", - "root -> mac -> quit", - "root -> file", - "root -> file -> add-cluster", - "root -> file -> separator-1-for-file", - "root -> file -> close-window", - "root -> edit", - "root -> edit -> undo", - "root -> edit -> redo", - "root -> edit -> separator-1-in-edit", - "root -> edit -> cut", - "root -> edit -> copy", - "root -> edit -> paste", - "root -> edit -> delete", - "root -> edit -> separator-2-in-edit", - "root -> edit -> selectAll", - "root -> view", - "root -> view -> navigate-to-catalog", - "root -> view -> open-command-palette", - "root -> view -> separator-1-for-view", - "root -> view -> go-back", - "root -> view -> go-forward", - "root -> view -> reload", - "root -> view -> toggle-dev-tools", - "root -> view -> separator-2-for-view", - "root -> view -> reset-zoom", - "root -> view -> zoom-in", - "root -> view -> zoom-out", - "root -> view -> separator-3-for-view", - "root -> view -> toggle-full-screen", - "root -> help", - "root -> help -> navigate-to-welcome", - "root -> help -> open-documentation", - "root -> help -> open-support", -] +"[ + 'root', + 'root -> mac', + 'root -> mac -> about', + 'root -> mac -> separator-1', + 'root -> mac -> navigate-to-preferences', + 'root -> mac -> navigate-to-extensions', + 'root -> mac -> separator-2', + 'root -> mac -> services', + 'root -> mac -> separator-3', + 'root -> mac -> hide', + 'root -> mac -> hide-others', + 'root -> mac -> unhide', + 'root -> mac -> separator-4', + 'root -> mac -> quit', + 'root -> file', + 'root -> file -> add-cluster', + 'root -> file -> separator-1-for-file', + 'root -> file -> close-window', + 'root -> edit', + 'root -> edit -> undo', + 'root -> edit -> redo', + 'root -> edit -> separator-1-in-edit', + 'root -> edit -> cut', + 'root -> edit -> copy', + 'root -> edit -> paste', + 'root -> edit -> delete', + 'root -> edit -> separator-2-in-edit', + 'root -> edit -> selectAll', + 'root -> view', + 'root -> view -> navigate-to-catalog', + 'root -> view -> open-command-palette', + 'root -> view -> separator-1-for-view', + 'root -> view -> go-back', + 'root -> view -> go-forward', + 'root -> view -> reload', + 'root -> view -> toggle-dev-tools', + 'root -> view -> separator-2-for-view', + 'root -> view -> reset-zoom', + 'root -> view -> zoom-in', + 'root -> view -> zoom-out', + 'root -> view -> separator-3-for-view', + 'root -> view -> toggle-full-screen', + 'root -> help', + 'root -> help -> navigate-to-welcome', + 'root -> help -> open-documentation', + 'root -> help -> open-support' +]" `; exports[`application-menu, given platform is 'linux' given enough time passes populates application menu 1`] = ` -Array [ - "root", - "root -> file", - "root -> file -> add-cluster", - "root -> file -> navigate-to-preferences", - "root -> file -> navigate-to-extensions", - "root -> file -> quit", - "root -> edit", - "root -> edit -> undo", - "root -> edit -> redo", - "root -> edit -> separator-1-in-edit", - "root -> edit -> cut", - "root -> edit -> copy", - "root -> edit -> paste", - "root -> edit -> delete", - "root -> edit -> separator-2-in-edit", - "root -> edit -> selectAll", - "root -> view", - "root -> view -> navigate-to-catalog", - "root -> view -> open-command-palette", - "root -> view -> separator-1-for-view", - "root -> view -> go-back", - "root -> view -> go-forward", - "root -> view -> reload", - "root -> view -> toggle-dev-tools", - "root -> view -> separator-2-for-view", - "root -> view -> reset-zoom", - "root -> view -> zoom-in", - "root -> view -> zoom-out", - "root -> view -> separator-3-for-view", - "root -> view -> toggle-full-screen", - "root -> help", - "root -> help -> navigate-to-welcome", - "root -> help -> open-documentation", - "root -> help -> open-support", - "root -> help -> about", -] +"[ + 'root', + 'root -> file', + 'root -> file -> add-cluster', + 'root -> file -> navigate-to-preferences', + 'root -> file -> navigate-to-extensions', + 'root -> file -> quit', + 'root -> edit', + 'root -> edit -> undo', + 'root -> edit -> redo', + 'root -> edit -> separator-1-in-edit', + 'root -> edit -> cut', + 'root -> edit -> copy', + 'root -> edit -> paste', + 'root -> edit -> delete', + 'root -> edit -> separator-2-in-edit', + 'root -> edit -> selectAll', + 'root -> view', + 'root -> view -> navigate-to-catalog', + 'root -> view -> open-command-palette', + 'root -> view -> separator-1-for-view', + 'root -> view -> go-back', + 'root -> view -> go-forward', + 'root -> view -> reload', + 'root -> view -> toggle-dev-tools', + 'root -> view -> separator-2-for-view', + 'root -> view -> reset-zoom', + 'root -> view -> zoom-in', + 'root -> view -> zoom-out', + 'root -> view -> separator-3-for-view', + 'root -> view -> toggle-full-screen', + 'root -> help', + 'root -> help -> navigate-to-welcome', + 'root -> help -> open-documentation', + 'root -> help -> open-support', + 'root -> help -> about' +]" `; exports[`application-menu, given platform is 'win32' given enough time passes populates application menu 1`] = ` -Array [ - "root", - "root -> file", - "root -> file -> add-cluster", - "root -> file -> navigate-to-preferences", - "root -> file -> navigate-to-extensions", - "root -> file -> quit", - "root -> edit", - "root -> edit -> undo", - "root -> edit -> redo", - "root -> edit -> separator-1-in-edit", - "root -> edit -> cut", - "root -> edit -> copy", - "root -> edit -> paste", - "root -> edit -> delete", - "root -> edit -> separator-2-in-edit", - "root -> edit -> selectAll", - "root -> view", - "root -> view -> navigate-to-catalog", - "root -> view -> open-command-palette", - "root -> view -> separator-1-for-view", - "root -> view -> go-back", - "root -> view -> go-forward", - "root -> view -> reload", - "root -> view -> toggle-dev-tools", - "root -> view -> separator-2-for-view", - "root -> view -> reset-zoom", - "root -> view -> zoom-in", - "root -> view -> zoom-out", - "root -> view -> separator-3-for-view", - "root -> view -> toggle-full-screen", - "root -> help", - "root -> help -> navigate-to-welcome", - "root -> help -> open-documentation", - "root -> help -> open-support", - "root -> help -> about", -] +"[ + 'root', + 'root -> file', + 'root -> file -> add-cluster', + 'root -> file -> navigate-to-preferences', + 'root -> file -> navigate-to-extensions', + 'root -> file -> quit', + 'root -> edit', + 'root -> edit -> undo', + 'root -> edit -> redo', + 'root -> edit -> separator-1-in-edit', + 'root -> edit -> cut', + 'root -> edit -> copy', + 'root -> edit -> paste', + 'root -> edit -> delete', + 'root -> edit -> separator-2-in-edit', + 'root -> edit -> selectAll', + 'root -> view', + 'root -> view -> navigate-to-catalog', + 'root -> view -> open-command-palette', + 'root -> view -> separator-1-for-view', + 'root -> view -> go-back', + 'root -> view -> go-forward', + 'root -> view -> reload', + 'root -> view -> toggle-dev-tools', + 'root -> view -> separator-2-for-view', + 'root -> view -> reset-zoom', + 'root -> view -> zoom-in', + 'root -> view -> zoom-out', + 'root -> view -> separator-3-for-view', + 'root -> view -> toggle-full-screen', + 'root -> help', + 'root -> help -> navigate-to-welcome', + 'root -> help -> open-documentation', + 'root -> help -> open-support', + 'root -> help -> about' +]" `; diff --git a/packages/core/src/features/application-menu/application-menu.test.ts b/packages/core/src/features/application-menu/application-menu.test.ts index 84dddb2531..7f17c9eceb 100644 --- a/packages/core/src/features/application-menu/application-menu.test.ts +++ b/packages/core/src/features/application-menu/application-menu.test.ts @@ -8,6 +8,7 @@ import populateApplicationMenuInjectable from "./main/populate-application-menu. import { advanceFakeTime, testUsingFakeTime } from "../../test-utils/use-fake-time"; import { getCompositePaths } from "../../common/utils/composite/get-composite-paths/get-composite-paths"; import platformInjectable, { allPlatforms } from "../../common/vars/platform.injectable"; +import { inspect } from "util"; describe.each(allPlatforms)("application-menu, given platform is '%s'", (platform) => { let builder: ApplicationBuilder; @@ -53,7 +54,14 @@ describe.each(allPlatforms)("application-menu, given platform is '%s'", (platfor }); it("populates application menu", () => { - expect(applicationMenuPaths.map(x => x.join(" -> "))).toMatchSnapshot(); + expect(inspect(applicationMenuPaths.map(x => x.join(" -> ")), { + compact: false, + breakLength: Infinity, + colors: false, + depth: Infinity, + maxArrayLength: Infinity, + maxStringLength: Infinity, + })).toMatchSnapshot(); }); }); }); diff --git a/packages/core/src/features/application-update/__snapshots__/installing-update.test.ts.snap b/packages/core/src/features/application-update/__snapshots__/installing-update.test.ts.snap index cd0d55e25f..30b66e8970 100644 --- a/packages/core/src/features/application-update/__snapshots__/installing-update.test.ts.snap +++ b/packages/core/src/features/application-update/__snapshots__/installing-update.test.ts.snap @@ -231,7 +231,7 @@ exports[`installing update when started renders 1`] = ` class="HotbarSelector" > { let builder: ApplicationBuilder; let rendered: RenderResult; let windowDi: DiContainer; - let cluster: Cluster; let clusterEntity: KubernetesCluster; let localClusterEntity: KubernetesCluster; let otherEntity: WebLink; @@ -26,20 +25,7 @@ describe("opening catalog entity details panel", () => { beforeEach(async () => { builder = getApplicationBuilder(); - builder.beforeWindowStart(({ windowDi }) => { - // TODO: remove once ClusterStore can be used without overriding it - windowDi.override(getClusterByIdInjectable, () => (clusterId) => { - if (clusterId === cluster?.id) { - return cluster; - } - - return undefined; - }); - }); - - testUsingFakeTime(); - - builder.afterWindowStart(({ windowDi }) => { + builder.afterWindowStart(async ({ windowDi }) => { clusterEntity = new KubernetesCluster({ metadata: { labels: {}, @@ -82,12 +68,33 @@ describe("opening catalog entity details panel", () => { phase: "available", }, }); - cluster = new Cluster({ - contextName: clusterEntity.spec.kubeconfigContext, + + const writeJsonFile = windowDi.inject(writeJsonFileInjectable); + const addCluster = windowDi.inject(addClusterInjectable); + + await writeJsonFile(clusterEntity.spec.kubeconfigPath, { + contexts: [{ + name: clusterEntity.spec.kubeconfigContext, + context: { + cluster: "some-cluster", + user: "some-user", + }, + }], + clusters: [{ + name: "some-cluster", + cluster: { + server: "https://localhost:9999", + }, + }], + users: [{ + name: "some-user", + }], + }); + + addCluster({ id: clusterEntity.getId(), kubeConfigPath: clusterEntity.spec.kubeconfigPath, - }, { - clusterServerUrl: "https://localhost:9999", + contextName: clusterEntity.spec.kubeconfigContext, }); // TODO: replace with proper entity source once syncing entities between main and windows is injectable diff --git a/packages/core/src/features/cluster/activation/main/request-activation.injectable.ts b/packages/core/src/features/cluster/activation/main/request-activation.injectable.ts index c498040fc0..0bc51a6f6f 100644 --- a/packages/core/src/features/cluster/activation/main/request-activation.injectable.ts +++ b/packages/core/src/features/cluster/activation/main/request-activation.injectable.ts @@ -3,8 +3,8 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable"; import clusterConnectionInjectable from "../../../../main/cluster/cluster-connection.injectable"; +import getClusterByIdInjectable from "../../storage/common/get-by-id.injectable"; import { requestClusterActivationInjectionToken } from "../common/request-token"; const requestClusterActivationInjectable = getInjectable({ diff --git a/packages/core/src/features/cluster/activation/main/request-deactivation.injectable.ts b/packages/core/src/features/cluster/activation/main/request-deactivation.injectable.ts index 05fc00911c..45585419dc 100644 --- a/packages/core/src/features/cluster/activation/main/request-deactivation.injectable.ts +++ b/packages/core/src/features/cluster/activation/main/request-deactivation.injectable.ts @@ -5,8 +5,8 @@ import { getInjectable } from "@ogre-tools/injectable"; import emitAppEventInjectable from "../../../../common/app-event-bus/emit-event.injectable"; import clusterFramesInjectable from "../../../../common/cluster-frames.injectable"; -import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable"; import clusterConnectionInjectable from "../../../../main/cluster/cluster-connection.injectable"; +import getClusterByIdInjectable from "../../storage/common/get-by-id.injectable"; import { requestClusterDeactivationInjectionToken } from "../common/request-token"; const requestClusterDeactivationInjectable = getInjectable({ diff --git a/packages/core/src/features/cluster/delete-dialog/__snapshots__/delete-cluster-dialog.test.tsx.snap b/packages/core/src/features/cluster/delete-dialog/__snapshots__/delete-cluster-dialog.test.tsx.snap index 980e1a5461..41695a2f1f 100644 --- a/packages/core/src/features/cluster/delete-dialog/__snapshots__/delete-cluster-dialog.test.tsx.snap +++ b/packages/core/src/features/cluster/delete-dialog/__snapshots__/delete-cluster-dialog.test.tsx.snap @@ -542,7 +542,7 @@ exports[`Deleting a cluster when an internal kubeconfig cluster is used when the class="HotbarSelector" > { const emitAppEvent = di.inject(emitAppEventInjectable); - const clusterStore = di.inject(clusterStoreInjectable); const clusterFrames = di.inject(clusterFramesInjectable); const joinPaths = di.inject(joinPathsInjectable); const directoryForLensLocalStorage = di.inject(directoryForLensLocalStorageInjectable); const deleteFile = di.inject(removePathInjectable); + const clustersState = di.inject(clustersStateInjectable); return async (clusterId) => { emitAppEvent({ name: "cluster", action: "remove" }); - const cluster = clusterStore.getById(clusterId); + const cluster = clustersState.get(clusterId); if (!cluster) { return; @@ -37,9 +37,7 @@ const deleteClusterChannelListenerInjectable = getRequestChannelListenerInjectab clusterConnection.disconnect(); clusterFrames.delete(cluster.id); - - // Remove from the cluster store as well, this should clear any old settings - clusterStore.clusters.delete(cluster.id); + clustersState.delete(cluster.id); // remove the local storage file const localStorageFilePath = joinPaths(directoryForLensLocalStorage, `${cluster.id}.json`); diff --git a/packages/core/src/features/cluster/refresh-accessibility-technical.test.ts b/packages/core/src/features/cluster/refresh-accessibility-technical.test.ts index 73ff6151b9..4851cca084 100644 --- a/packages/core/src/features/cluster/refresh-accessibility-technical.test.ts +++ b/packages/core/src/features/cluster/refresh-accessibility-technical.test.ts @@ -6,7 +6,6 @@ import type { AsyncFnMock } from "@async-fn/jest"; import asyncFn from "@async-fn/jest"; import type { AuthorizationV1Api, CoreV1Api, V1APIGroupList, V1APIVersions, V1NamespaceList, V1SelfSubjectAccessReview, V1SelfSubjectRulesReview } from "@kubernetes/client-node"; -import clusterStoreInjectable from "../../common/cluster-store/cluster-store.injectable"; import type { Cluster } from "../../common/cluster/cluster"; import createAuthorizationApiInjectable from "../../common/cluster/create-authorization-api.injectable"; import writeJsonFileInjectable from "../../common/fs/write-json-file.injectable"; @@ -26,6 +25,7 @@ import type { KubeAuthProxy } from "../../main/kube-auth-proxy/create-kube-auth- import createKubeAuthProxyInjectable from "../../main/kube-auth-proxy/create-kube-auth-proxy.injectable"; import type { Mocked } from "../../test-utils/mock-interface"; import { flushPromises } from "@k8slens/test-utils"; +import addClusterInjectable from "./storage/common/add.injectable"; describe("Refresh Cluster Accessibility Technical Tests", () => { let builder: ApplicationBuilder; @@ -79,7 +79,7 @@ describe("Refresh Cluster Accessibility Technical Tests", () => { beforeEach(async () => { const mainDi = builder.mainDi; - const clusterStore = mainDi.inject(clusterStoreInjectable); + const addCluster = mainDi.inject(addClusterInjectable); const writeJsonFile = mainDi.inject(writeJsonFileInjectable); await writeJsonFile("/some-kube-config-path", { @@ -103,13 +103,11 @@ describe("Refresh Cluster Accessibility Technical Tests", () => { }], }); - clusterStore.addCluster({ + cluster = addCluster({ contextName: "some-cluster-context", id: "some-cluster-id", kubeConfigPath: "/some-kube-config-path", }); - - cluster = clusterStore.getById("some-cluster-id") ?? (() => { throw new Error("missing cluster"); })(); clusterConnection = mainDi.inject(clusterConnectionInjectable, cluster); refreshPromise = clusterConnection.refreshAccessibilityAndMetadata(); }); diff --git a/packages/core/src/common/cluster-store/allowed-resources-injection-token.ts b/packages/core/src/features/cluster/showing-kube-resources/common/allowed-resources-injection-token.ts similarity index 84% rename from packages/core/src/common/cluster-store/allowed-resources-injection-token.ts rename to packages/core/src/features/cluster/showing-kube-resources/common/allowed-resources-injection-token.ts index 5b71038d04..317ed5a0ec 100644 --- a/packages/core/src/common/cluster-store/allowed-resources-injection-token.ts +++ b/packages/core/src/features/cluster/showing-kube-resources/common/allowed-resources-injection-token.ts @@ -5,7 +5,7 @@ import { getInjectionToken } from "@ogre-tools/injectable"; import type { IComputedValue } from "mobx"; -import type { KubeApiResourceDescriptor } from "../rbac"; +import type { KubeApiResourceDescriptor } from "../../../../common/rbac"; export const shouldShowResourceInjectionToken = getInjectionToken, KubeApiResourceDescriptor>({ id: "should-show-resource", diff --git a/packages/core/src/features/cluster/state-sync/main/handle-initial.injectable.ts b/packages/core/src/features/cluster/state-sync/main/handle-initial.injectable.ts index db65024973..75a68273a0 100644 --- a/packages/core/src/features/cluster/state-sync/main/handle-initial.injectable.ts +++ b/packages/core/src/features/cluster/state-sync/main/handle-initial.injectable.ts @@ -2,17 +2,17 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable"; import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; +import clustersInjectable from "../../storage/common/clusters.injectable"; import { initialClusterStatesChannel } from "../common/channels"; const handleInitialClusterStateSyncInjectable = getRequestChannelListenerInjectable({ id: "handle-initial-cluster-state-sync", channel: initialClusterStatesChannel, getHandler: (di) => { - const clusterStore = di.inject(clusterStoreInjectable); + const clusters = di.inject(clustersInjectable); - return () => clusterStore.clustersList.map(cluster => ({ + return () => clusters.get().map(cluster => ({ clusterId: cluster.id, state: cluster.getState(), })); diff --git a/packages/core/src/features/cluster/state-sync/main/setup-sync.injectable.ts b/packages/core/src/features/cluster/state-sync/main/setup-sync.injectable.ts index 348450958d..927c93c148 100644 --- a/packages/core/src/features/cluster/state-sync/main/setup-sync.injectable.ts +++ b/packages/core/src/features/cluster/state-sync/main/setup-sync.injectable.ts @@ -5,22 +5,22 @@ import { getInjectable } from "@ogre-tools/injectable"; import { isEqual } from "lodash"; import { autorun } from "mobx"; -import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable"; import type { ClusterId, ClusterState } from "../../../../common/cluster-types"; import { beforeApplicationIsLoadingInjectionToken } from "@k8slens/application"; -import initClusterStoreInjectable from "../../store/main/init.injectable"; +import initClusterStoreInjectable from "../../storage/main/init.injectable"; import emitClusterStateUpdateInjectable from "./emit-update.injectable"; +import clustersInjectable from "../../storage/common/clusters.injectable"; const setupClusterStateBroadcastingInjectable = getInjectable({ id: "setup-cluster-state-broadcasting", instantiate: (di) => ({ run: () => { const emitClusterStateUpdate = di.inject(emitClusterStateUpdateInjectable); - const clusterStore = di.inject(clusterStoreInjectable); + const clusters = di.inject(clustersInjectable); const prevStates = new Map(); autorun(() => { - for (const cluster of clusterStore.clusters.values()) { + for (const cluster of clusters.get()) { const prevState = prevStates.get(cluster.id); const curState = cluster.getState(); diff --git a/packages/core/src/features/cluster/state-sync/renderer/listener.injectable.ts b/packages/core/src/features/cluster/state-sync/renderer/listener.injectable.ts index a3778d096e..ec329f2c9d 100644 --- a/packages/core/src/features/cluster/state-sync/renderer/listener.injectable.ts +++ b/packages/core/src/features/cluster/state-sync/renderer/listener.injectable.ts @@ -2,8 +2,8 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable"; import { getMessageChannelListenerInjectable } from "@k8slens/messaging"; +import getClusterByIdInjectable from "../../storage/common/get-by-id.injectable"; import { clusterStateSyncChannel } from "../common/channels"; const clusterStateListenerInjectable = getMessageChannelListenerInjectable({ diff --git a/packages/core/src/features/cluster/state-sync/renderer/setup-sync.injectable.ts b/packages/core/src/features/cluster/state-sync/renderer/setup-sync.injectable.ts index da43ace234..43e1025f0a 100644 --- a/packages/core/src/features/cluster/state-sync/renderer/setup-sync.injectable.ts +++ b/packages/core/src/features/cluster/state-sync/renderer/setup-sync.injectable.ts @@ -3,9 +3,9 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable"; import { beforeFrameStartsSecondInjectionToken } from "../../../../renderer/before-frame-starts/tokens"; -import initClusterStoreInjectable from "../../store/renderer/init.injectable"; +import getClusterByIdInjectable from "../../storage/common/get-by-id.injectable"; +import initClusterStoreInjectable from "../../storage/renderer/init.injectable"; import requestInitialClusterStatesInjectable from "./request-initial.injectable"; const setupClusterStateSyncInjectable = getInjectable({ diff --git a/packages/core/src/common/__tests__/cluster-store.test.ts b/packages/core/src/features/cluster/storage/cluster-storage.test.ts similarity index 70% rename from packages/core/src/common/__tests__/cluster-store.test.ts rename to packages/core/src/features/cluster/storage/cluster-storage.test.ts index 5b052548a5..f11ae3a4c5 100644 --- a/packages/core/src/common/__tests__/cluster-store.test.ts +++ b/packages/core/src/features/cluster/storage/cluster-storage.test.ts @@ -3,29 +3,35 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { ClusterStore } from "../cluster-store/cluster-store"; -import type { GetCustomKubeConfigFilePath } from "../app-paths/get-custom-kube-config-directory/get-custom-kube-config-directory.injectable"; -import getCustomKubeConfigFilePathInjectable from "../app-paths/get-custom-kube-config-directory/get-custom-kube-config-directory.injectable"; -import clusterStoreInjectable from "../cluster-store/cluster-store.injectable"; +import type { GetCustomKubeConfigFilePath } from "../../../common/app-paths/get-custom-kube-config-directory/get-custom-kube-config-directory.injectable"; +import getCustomKubeConfigFilePathInjectable from "../../../common/app-paths/get-custom-kube-config-directory/get-custom-kube-config-directory.injectable"; import type { DiContainer } from "@ogre-tools/injectable"; -import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable"; -import { getDiForUnitTesting } from "../../main/getDiForUnitTesting"; +import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; +import { getDiForUnitTesting } from "../../../main/getDiForUnitTesting"; 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 storeMigrationVersionInjectable from "../vars/store-migration-version.injectable"; -import type { WriteJsonSync } from "../fs/write-json-sync.injectable"; -import writeJsonSyncInjectable from "../fs/write-json-sync.injectable"; -import type { ReadFileSync } from "../fs/read-file-sync.injectable"; -import readFileSyncInjectable from "../fs/read-file-sync.injectable"; +import directoryForTempInjectable from "../../../common/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 "../../../common/vars/normalized-platform.injectable"; +import storeMigrationVersionInjectable from "../../../common/vars/store-migration-version.injectable"; +import type { WriteJsonSync } from "../../../common/fs/write-json-sync.injectable"; +import writeJsonSyncInjectable from "../../../common/fs/write-json-sync.injectable"; +import type { ReadFileSync } from "../../../common/fs/read-file-sync.injectable"; +import readFileSyncInjectable from "../../../common/fs/read-file-sync.injectable"; import { readFileSync } from "fs"; -import type { WriteFileSync } from "../fs/write-file-sync.injectable"; -import writeFileSyncInjectable from "../fs/write-file-sync.injectable"; -import type { WriteBufferSync } from "../fs/write-buffer-sync.injectable"; -import writeBufferSyncInjectable from "../fs/write-buffer-sync.injectable"; -import { Cluster } from "../cluster/cluster"; +import type { WriteFileSync } from "../../../common/fs/write-file-sync.injectable"; +import writeFileSyncInjectable from "../../../common/fs/write-file-sync.injectable"; +import type { WriteBufferSync } from "../../../common/fs/write-buffer-sync.injectable"; +import writeBufferSyncInjectable from "../../../common/fs/write-buffer-sync.injectable"; +import { Cluster } from "../../../common/cluster/cluster"; +import clustersPersistentStorageInjectable from "./common/storage.injectable"; +import type { PersistentStorage } from "../../../common/persistent-storage/create.injectable"; +import type { AddCluster } from "./common/add.injectable"; +import addClusterInjectable from "./common/add.injectable"; +import type { GetClusterById } from "./common/get-by-id.injectable"; +import getClusterByIdInjectable from "./common/get-by-id.injectable"; +import type { IComputedValue } from "mobx"; +import clustersInjectable from "./common/clusters.injectable"; // NOTE: this is intended to read the actual file system const testDataIcon = readFileSync("test-data/cluster-store-migration-icon.png"); @@ -54,15 +60,18 @@ users: token: kubeconfig-user-q4lm4:xxxyyyy `; -describe("cluster-store", () => { +describe("cluster storage technical tests", () => { let di: DiContainer; - let clusterStore: ClusterStore; + let clustersPersistentStorage: PersistentStorage; let writeJsonSync: WriteJsonSync; let writeFileSync: WriteFileSync; let writeBufferSync: WriteBufferSync; let readFileSync: ReadFileSync; let getCustomKubeConfigFilePath: GetCustomKubeConfigFilePath; let writeFileSyncAndReturnPath: (filePath: string, contents: string) => string; + let addCluster: AddCluster; + let getClusterById: GetClusterById; + let clusters: IComputedValue; beforeEach(async () => { di = getDiForUnitTesting(); @@ -76,6 +85,9 @@ describe("cluster-store", () => { writeFileSync = di.inject(writeFileSyncInjectable); writeBufferSync = di.inject(writeBufferSyncInjectable); readFileSync = di.inject(readFileSyncInjectable); + addCluster = di.inject(addClusterInjectable); + getClusterById = di.inject(getClusterByIdInjectable); + clusters = di.inject(clustersInjectable); writeFileSyncAndReturnPath = (filePath, contents) => (writeFileSync(filePath, contents), filePath); }); @@ -84,8 +96,8 @@ describe("cluster-store", () => { getCustomKubeConfigFilePath = di.inject(getCustomKubeConfigFilePathInjectable); writeJsonSync("/some-directory-for-user-data/lens-cluster-store.json", {}); - clusterStore = di.inject(clusterStoreInjectable); - clusterStore.load(); + clustersPersistentStorage = di.inject(clustersPersistentStorageInjectable); + clustersPersistentStorage.loadAndStartSyncing(); }); describe("with foo cluster added", () => { @@ -106,11 +118,11 @@ describe("cluster-store", () => { clusterServerUrl, }); - clusterStore.addCluster(cluster); + addCluster(cluster); }); it("adds new cluster to store", async () => { - const storedCluster = clusterStore.getById("foo"); + const storedCluster = getClusterById("foo"); assert(storedCluster); @@ -124,9 +136,7 @@ describe("cluster-store", () => { describe("with prod and dev clusters added", () => { beforeEach(() => { - const store = clusterStore; - - store.addCluster({ + addCluster({ id: "prod", contextName: "foo", preferences: { @@ -137,7 +147,7 @@ describe("cluster-store", () => { kubeconfig, ), }); - store.addCluster({ + addCluster({ id: "dev", contextName: "foo2", preferences: { @@ -151,8 +161,7 @@ describe("cluster-store", () => { }); it("check if store can contain multiple clusters", () => { - expect(clusterStore.hasClusters()).toBeTruthy(); - expect(clusterStore.clusters.size).toBe(2); + expect(clusters.get().length).toBe(2); }); it("check if cluster's kubeconfig file saved", () => { @@ -199,11 +208,11 @@ describe("cluster-store", () => { getCustomKubeConfigFilePath = di.inject(getCustomKubeConfigFilePathInjectable); - clusterStore = di.inject(clusterStoreInjectable); - clusterStore.load(); + clustersPersistentStorage = di.inject(clustersPersistentStorageInjectable); + clustersPersistentStorage.loadAndStartSyncing(); }); it("allows to retrieve a cluster", () => { - const storedCluster = clusterStore.getById("cluster1"); + const storedCluster = getClusterById("cluster1"); assert(storedCluster); @@ -212,7 +221,7 @@ describe("cluster-store", () => { }); it("allows getting all of the clusters", async () => { - const storedClusters = clusterStore.clustersList; + const storedClusters = clusters.get(); expect(storedClusters.length).toBe(3); expect(storedClusters[0].id).toBe("cluster1"); @@ -253,12 +262,12 @@ describe("cluster-store", () => { getCustomKubeConfigFilePath = di.inject(getCustomKubeConfigFilePathInjectable); - clusterStore = di.inject(clusterStoreInjectable); - clusterStore.load(); + clustersPersistentStorage = di.inject(clustersPersistentStorageInjectable); + clustersPersistentStorage.loadAndStartSyncing(); }); it("does not enable clusters with invalid kubeconfig", () => { - const storedClusters = clusterStore.clustersList; + const storedClusters = clusters.get(); expect(storedClusters.length).toBe(1); }); @@ -290,18 +299,18 @@ describe("cluster-store", () => { writeBufferSync("/some-directory-for-user-data/icon_path", testDataIcon); - clusterStore = di.inject(clusterStoreInjectable); - clusterStore.load(); + clustersPersistentStorage = di.inject(clustersPersistentStorageInjectable); + clustersPersistentStorage.loadAndStartSyncing(); }); it("migrates to modern format with kubeconfig in a file", async () => { - const configPath = clusterStore.clustersList[0].kubeConfigPath.get(); + const configPath = clusters.get()[0].kubeConfigPath.get(); expect(readFileSync(configPath)).toBe(minimalValidKubeConfig); }); it("migrates to modern format with icon not in file", async () => { - expect(clusterStore.clustersList[0].preferences.icon).toMatch(/data:;base64,/); + expect(clusters.get()[0].preferences.icon).toMatch(/data:;base64,/); }); }); }); diff --git a/packages/core/src/features/cluster/storage/common/add.injectable.ts b/packages/core/src/features/cluster/storage/common/add.injectable.ts new file mode 100644 index 0000000000..051aa6d23b --- /dev/null +++ b/packages/core/src/features/cluster/storage/common/add.injectable.ts @@ -0,0 +1,39 @@ +/** + * 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 { action } from "mobx"; +import emitAppEventInjectable from "../../../../common/app-event-bus/emit-event.injectable"; +import readClusterConfigSyncInjectable from "./read-cluster-config.injectable"; +import type { ClusterModel } from "../../../../common/cluster-types"; +import { Cluster } from "../../../../common/cluster/cluster"; +import clustersStateInjectable from "./state.injectable"; + +export type AddCluster = (clusterOrModel: ClusterModel | Cluster) => Cluster; + +const addClusterInjectable = getInjectable({ + id: "add-cluster", + instantiate: (di): AddCluster => { + const clustersState = di.inject(clustersStateInjectable); + const emitAppEvent = di.inject(emitAppEventInjectable); + const readClusterConfigSync = di.inject(readClusterConfigSyncInjectable); + + return action((clusterOrModel) => { + emitAppEvent({ name: "cluster", action: "add" }); + + const cluster = clusterOrModel instanceof Cluster + ? clusterOrModel + : new Cluster( + clusterOrModel, + readClusterConfigSync(clusterOrModel), + ); + + clustersState.set(cluster.id, cluster); + + return cluster; + }); + }, +}); + +export default addClusterInjectable; diff --git a/packages/core/src/features/cluster/storage/common/clusters.injectable.ts b/packages/core/src/features/cluster/storage/common/clusters.injectable.ts new file mode 100644 index 0000000000..d251cf784f --- /dev/null +++ b/packages/core/src/features/cluster/storage/common/clusters.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 { computed } from "mobx"; +import clustersStateInjectable from "./state.injectable"; + +const clustersInjectable = getInjectable({ + id: "clusters", + instantiate: (di) => { + const clustersState = di.inject(clustersStateInjectable); + + return computed(() => [...clustersState.values()]); + }, +}); + +export default clustersInjectable; diff --git a/packages/core/src/common/cluster-store/get-by-id.injectable.ts b/packages/core/src/features/cluster/storage/common/get-by-id.injectable.ts similarity index 59% rename from packages/core/src/common/cluster-store/get-by-id.injectable.ts rename to packages/core/src/features/cluster/storage/common/get-by-id.injectable.ts index 534bdb5e76..2e3128f4d6 100644 --- a/packages/core/src/common/cluster-store/get-by-id.injectable.ts +++ b/packages/core/src/features/cluster/storage/common/get-by-id.injectable.ts @@ -3,18 +3,18 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import type { ClusterId } from "../cluster-types"; -import type { Cluster } from "../cluster/cluster"; -import clusterStoreInjectable from "./cluster-store.injectable"; +import type { ClusterId } from "../../../../common/cluster-types"; +import type { Cluster } from "../../../../common/cluster/cluster"; +import clustersStateInjectable from "./state.injectable"; export type GetClusterById = (id: ClusterId) => Cluster | undefined; const getClusterByIdInjectable = getInjectable({ id: "get-cluster-by-id", instantiate: (di): GetClusterById => { - const store = di.inject(clusterStoreInjectable); + const clustersState = di.inject(clustersStateInjectable); - return (id) => store.getById(id); + return (id) => clustersState.get(id); }, }); diff --git a/packages/core/src/common/cluster-store/migration-token.ts b/packages/core/src/features/cluster/storage/common/migration-token.ts similarity index 76% rename from packages/core/src/common/cluster-store/migration-token.ts rename to packages/core/src/features/cluster/storage/common/migration-token.ts index 86489509a2..8fa8064cf6 100644 --- a/packages/core/src/common/cluster-store/migration-token.ts +++ b/packages/core/src/features/cluster/storage/common/migration-token.ts @@ -4,7 +4,7 @@ */ import { getInjectionToken } from "@ogre-tools/injectable"; -import type { MigrationDeclaration } from "../base-store/migrations.injectable"; +import type { MigrationDeclaration } from "../../../../common/persistent-storage/migrations.injectable"; export const clusterStoreMigrationInjectionToken = getInjectionToken({ id: "cluster-store-migration", diff --git a/packages/core/src/common/cluster-store/read-cluster-config.injectable.ts b/packages/core/src/features/cluster/storage/common/read-cluster-config.injectable.ts similarity index 77% rename from packages/core/src/common/cluster-store/read-cluster-config.injectable.ts rename to packages/core/src/features/cluster/storage/common/read-cluster-config.injectable.ts index 9fea013b16..9b3be7733e 100644 --- a/packages/core/src/common/cluster-store/read-cluster-config.injectable.ts +++ b/packages/core/src/features/cluster/storage/common/read-cluster-config.injectable.ts @@ -3,9 +3,9 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import type { ClusterConfigData, ClusterModel } from "../cluster-types"; -import readFileSyncInjectable from "../fs/read-file-sync.injectable"; -import { loadConfigFromString, validateKubeConfig } from "../kube-helpers"; +import type { ClusterConfigData, ClusterModel } from "../../../../common/cluster-types"; +import readFileSyncInjectable from "../../../../common/fs/read-file-sync.injectable"; +import { loadConfigFromString, validateKubeConfig } from "../../../../common/kube-helpers"; export type ReadClusterConfigSync = (model: ClusterModel) => ClusterConfigData; diff --git a/packages/core/src/features/cluster/storage/common/state.injectable.ts b/packages/core/src/features/cluster/storage/common/state.injectable.ts new file mode 100644 index 0000000000..a3234dcb62 --- /dev/null +++ b/packages/core/src/features/cluster/storage/common/state.injectable.ts @@ -0,0 +1,15 @@ +/** + * 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 { observable } from "mobx"; +import type { ClusterId } from "../../../../common/cluster-types"; +import type { Cluster } from "../../../../common/cluster/cluster"; + +const clustersStateInjectable = getInjectable({ + id: "clusters-state", + instantiate: () => observable.map(), +}); + +export default clustersStateInjectable; diff --git a/packages/core/src/features/cluster/storage/common/storage.injectable.ts b/packages/core/src/features/cluster/storage/common/storage.injectable.ts new file mode 100644 index 0000000000..eaac8376cf --- /dev/null +++ b/packages/core/src/features/cluster/storage/common/storage.injectable.ts @@ -0,0 +1,72 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { iter } from "@k8slens/utilities"; +import { getInjectable } from "@ogre-tools/injectable"; +import { comparer, action } from "mobx"; +import { clusterStoreMigrationInjectionToken } from "./migration-token"; +import readClusterConfigSyncInjectable from "./read-cluster-config.injectable"; +import type { ClusterId, ClusterModel } from "../../../../common/cluster-types"; +import { Cluster } from "../../../../common/cluster/cluster"; +import loggerInjectable from "../../../../common/logger.injectable"; +import createPersistentStorageInjectable from "../../../../common/persistent-storage/create.injectable"; +import persistentStorageMigrationsInjectable from "../../../../common/persistent-storage/migrations.injectable"; +import storeMigrationVersionInjectable from "../../../../common/vars/store-migration-version.injectable"; +import clustersStateInjectable from "./state.injectable"; + +export interface ClusterStoreModel { + clusters?: ClusterModel[]; +} + +const clustersPersistentStorageInjectable = getInjectable({ + id: "clusters-persistent-storage", + instantiate: (di) => { + const createPersistentStorage = di.inject(createPersistentStorageInjectable); + const readClusterConfigSync = di.inject(readClusterConfigSyncInjectable); + const clustersState = di.inject(clustersStateInjectable); + const logger = di.inject(loggerInjectable); + + return createPersistentStorage({ + configName: "lens-cluster-store", + accessPropertiesByDotNotation: false, // To make dots safe in cluster context names + syncOptions: { + equals: comparer.structural, + }, + projectVersion: di.inject(storeMigrationVersionInjectable), + migrations: di.inject(persistentStorageMigrationsInjectable, clusterStoreMigrationInjectionToken), + fromStore: action(({ clusters = [] }) => { + const currentClusters = new Map(clustersState); + const newClusters = new Map(); + + // update new clusters + for (const clusterModel of clusters) { + try { + let cluster = currentClusters.get(clusterModel.id); + + if (cluster) { + cluster.updateModel(clusterModel); + } else { + cluster = new Cluster( + clusterModel, + readClusterConfigSync(clusterModel), + ); + } + newClusters.set(clusterModel.id, cluster); + } catch (error) { + logger.warn(`[CLUSTER-STORE]: Failed to update/create a cluster: ${error}`); + } + } + + clustersState.replace(newClusters); + }), + toJSON: () => ({ + clusters: iter.chain(clustersState.values()) + .map(cluster => cluster.toJSON()) + .toArray(), + }), + }); + }, +}); + +export default clustersPersistentStorageInjectable; diff --git a/packages/core/src/features/cluster/store/main/init.injectable.ts b/packages/core/src/features/cluster/storage/main/init.injectable.ts similarity index 60% rename from packages/core/src/features/cluster/store/main/init.injectable.ts rename to packages/core/src/features/cluster/storage/main/init.injectable.ts index c7a6bc1c9a..7a6c906386 100644 --- a/packages/core/src/features/cluster/store/main/init.injectable.ts +++ b/packages/core/src/features/cluster/storage/main/init.injectable.ts @@ -3,19 +3,19 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable"; import { beforeApplicationIsLoadingInjectionToken } from "@k8slens/application"; -import initUserStoreInjectable from "../../../../main/stores/init-user-store.injectable"; +import clustersPersistentStorageInjectable from "../common/storage.injectable"; +import loadUserPreferencesStorageInjectable from "../../../user-preferences/main/load-storage.injectable"; const initClusterStoreInjectable = getInjectable({ id: "init-cluster-store", instantiate: (di) => ({ run: () => { - const clusterStore = di.inject(clusterStoreInjectable); + const storage = di.inject(clustersPersistentStorageInjectable); - clusterStore.load(); + storage.loadAndStartSyncing(); }, - runAfter: initUserStoreInjectable, + runAfter: loadUserPreferencesStorageInjectable, }), injectionToken: beforeApplicationIsLoadingInjectionToken, }); diff --git a/packages/core/src/features/cluster/store/renderer/init.injectable.ts b/packages/core/src/features/cluster/storage/renderer/init.injectable.ts similarity index 67% rename from packages/core/src/features/cluster/store/renderer/init.injectable.ts rename to packages/core/src/features/cluster/storage/renderer/init.injectable.ts index f937796bae..cdedc3fceb 100644 --- a/packages/core/src/features/cluster/store/renderer/init.injectable.ts +++ b/packages/core/src/features/cluster/storage/renderer/init.injectable.ts @@ -3,17 +3,17 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable"; import { beforeFrameStartsSecondInjectionToken } from "../../../../renderer/before-frame-starts/tokens"; -import initUserStoreInjectable from "../../../../renderer/stores/init-user-store.injectable"; +import initUserStoreInjectable from "../../../user-preferences/renderer/load-storage.injectable"; +import clustersPersistentStorageInjectable from "../common/storage.injectable"; const initClusterStoreInjectable = getInjectable({ id: "init-cluster-store", instantiate: (di) => ({ run: () => { - const clusterStore = di.inject(clusterStoreInjectable); + const storage = di.inject(clustersPersistentStorageInjectable); - clusterStore.load(); + storage.loadAndStartSyncing(); }, runAfter: initUserStoreInjectable, }), diff --git a/packages/core/src/features/cluster/visibility-of-sidebar-items.test.tsx b/packages/core/src/features/cluster/visibility-of-sidebar-items.test.tsx index bc96800562..46a8916241 100644 --- a/packages/core/src/features/cluster/visibility-of-sidebar-items.test.tsx +++ b/packages/core/src/features/cluster/visibility-of-sidebar-items.test.tsx @@ -13,7 +13,7 @@ import { frontEndRouteInjectionToken } from "../../common/front-end-routing/fron import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token"; -import { shouldShowResourceInjectionToken } from "../../common/cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "./showing-kube-resources/common/allowed-resources-injection-token"; describe("cluster - visibility of sidebar items", () => { let builder: ApplicationBuilder; diff --git a/packages/core/src/features/command-pallet/__snapshots__/keyboard-shortcuts.test.tsx.snap b/packages/core/src/features/command-pallet/__snapshots__/keyboard-shortcuts.test.tsx.snap index 0269032531..d21ce102d2 100644 --- a/packages/core/src/features/command-pallet/__snapshots__/keyboard-shortcuts.test.tsx.snap +++ b/packages/core/src/features/command-pallet/__snapshots__/keyboard-shortcuts.test.tsx.snap @@ -322,7 +322,7 @@ exports[`Command Pallet: keyboard shortcut tests when on linux renders 1`] = ` class="HotbarSelector" > { let builder: ApplicationBuilder; @@ -19,23 +19,11 @@ describe("Showing correct entity settings", () => { let clusterEntity: KubernetesCluster; let localClusterEntity: KubernetesCluster; let otherEntity: WebLink; - let cluster: Cluster; beforeEach(async () => { builder = getApplicationBuilder(); - builder.beforeWindowStart(({ windowDi }) => { - // TODO: remove once ClusterStore can be used without overriding it - windowDi.override(getClusterByIdInjectable, () => (clusterId) => { - if (clusterId === cluster.id) { - return cluster; - } - - return undefined; - }); - }); - - builder.afterWindowStart(({ windowDi }) => { + builder.afterWindowStart(async ({ windowDi }) => { clusterEntity = new KubernetesCluster({ metadata: { labels: {}, @@ -78,14 +66,34 @@ describe("Showing correct entity settings", () => { phase: "available", }, }); - cluster = new Cluster({ - contextName: clusterEntity.spec.kubeconfigContext, - id: clusterEntity.getId(), - kubeConfigPath: clusterEntity.spec.kubeconfigPath, - }, { - clusterServerUrl: "https://localhost:9999", + + const writeJsonFile = windowDi.inject(writeJsonFileInjectable); + const addCluster = windowDi.inject(addClusterInjectable); + + await writeJsonFile(clusterEntity.spec.kubeconfigPath, { + contexts: [{ + name: clusterEntity.spec.kubeconfigContext, + context: { + cluster: "some-cluster", + user: "some-user", + }, + }], + clusters: [{ + name: "some-cluster", + cluster: { + server: "https://localhost:9999", + }, + }], + users: [{ + name: "some-user", + }], }); + addCluster({ + id: clusterEntity.getId(), + kubeConfigPath: clusterEntity.spec.kubeconfigPath, + contextName: clusterEntity.spec.kubeconfigContext, + }); // TODO: replace with proper entity source once syncing entities between main and windows is injectable const catalogEntityRegistry = windowDi.inject(catalogEntityRegistryInjectable); diff --git a/packages/core/src/features/extensions/__snapshots__/navigation-using-application-menu.test.ts.snap b/packages/core/src/features/extensions/__snapshots__/navigation-using-application-menu.test.ts.snap index 53dc28e961..dbaf12b978 100644 --- a/packages/core/src/features/extensions/__snapshots__/navigation-using-application-menu.test.ts.snap +++ b/packages/core/src/features/extensions/__snapshots__/navigation-using-application-menu.test.ts.snap @@ -230,7 +230,7 @@ exports[`extensions - navigation using application menu renders 1`] = ` class="HotbarSelector" > { + const state = di.inject(enabledExtensionsStateInjectable); + + return computed(() => ( + iter.chain(state.values()) + .filter(({ enabled }) => enabled) + .map(({ name }) => name) + .toArray() + )); + }, +}); + +export default enabledExtensionsInjectable; diff --git a/packages/core/src/features/extensions/enabled/common/is-enabled.injectable.ts b/packages/core/src/features/extensions/enabled/common/is-enabled.injectable.ts new file mode 100644 index 0000000000..bb7f531cb3 --- /dev/null +++ b/packages/core/src/features/extensions/enabled/common/is-enabled.injectable.ts @@ -0,0 +1,24 @@ +/** + * 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 enabledExtensionsStateInjectable from "./state.injectable"; + +export interface IsEnabledExtensionDescriptor { + readonly id: string; + readonly isBundled: boolean; +} + +export type IsExtensionEnabled = (desc: IsEnabledExtensionDescriptor) => boolean; + +const isExtensionEnabledInjectable = getInjectable({ + id: "is-extension-enabled", + instantiate: (di): IsExtensionEnabled => { + const state = di.inject(enabledExtensionsStateInjectable); + + return ({ id, isBundled }) => isBundled || (state.get(id)?.enabled ?? false); + }, +}); + +export default isExtensionEnabledInjectable; diff --git a/packages/core/src/features/extensions/enabled/common/migrations.ts b/packages/core/src/features/extensions/enabled/common/migrations.ts new file mode 100644 index 0000000000..eef1c4c996 --- /dev/null +++ b/packages/core/src/features/extensions/enabled/common/migrations.ts @@ -0,0 +1,11 @@ +/** + * 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 type { MigrationDeclaration } from "../../../../common/persistent-storage/migrations.injectable"; + +export const enabledExtensionsMigrationDeclarationInjectionToken = getInjectionToken({ + id: "enabled-extensions-migration-declaration", +}); diff --git a/packages/core/src/features/extensions/enabled/common/state.injectable.ts b/packages/core/src/features/extensions/enabled/common/state.injectable.ts new file mode 100644 index 0000000000..6cf87ace88 --- /dev/null +++ b/packages/core/src/features/extensions/enabled/common/state.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 type { LensExtensionId } from "@k8slens/legacy-extensions"; +import { getInjectable } from "@ogre-tools/injectable"; +import { observable } from "mobx"; + +export interface LensExtensionState { + enabled?: boolean; + name: string; +} + +const enabledExtensionsStateInjectable = getInjectable({ + id: "enabled-extensions-state", + instantiate: () => observable.map(), +}); + +export default enabledExtensionsStateInjectable; diff --git a/packages/core/src/features/extensions/enabled/common/storage.injectable.ts b/packages/core/src/features/extensions/enabled/common/storage.injectable.ts new file mode 100644 index 0000000000..47a9930ccf --- /dev/null +++ b/packages/core/src/features/extensions/enabled/common/storage.injectable.ts @@ -0,0 +1,39 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import type { LensExtensionId } from "@k8slens/legacy-extensions"; +import { getInjectable } from "@ogre-tools/injectable"; +import { action, toJS } from "mobx"; +import createPersistentStorageInjectable from "../../../../common/persistent-storage/create.injectable"; +import persistentStorageMigrationsInjectable from "../../../../common/persistent-storage/migrations.injectable"; +import storageMigrationVersionInjectable from "../../../../common/persistent-storage/storage-migration-version.injectable"; +import { enabledExtensionsMigrationDeclarationInjectionToken } from "./migrations"; +import type { LensExtensionState } from "./state.injectable"; +import enabledExtensionsStateInjectable from "./state.injectable"; + +interface EnabledExtensionsStorageModal { + extensions: [LensExtensionId, LensExtensionState][]; +} + +const enabledExtensionsPersistentStorageInjectable = getInjectable({ + id: "enabled-extensions-persistent-storage", + instantiate: (di) => { + const createPersistentStorage = di.inject(createPersistentStorageInjectable); + const state = di.inject(enabledExtensionsStateInjectable); + + return createPersistentStorage({ + configName: "lens-extensions", + fromStore: action(({ extensions = [] }) => { + state.replace(extensions); + }), + toJSON: () => ({ + extensions: [...toJS(state)], + }), + projectVersion: di.inject(storageMigrationVersionInjectable, enabledExtensionsMigrationDeclarationInjectionToken), + migrations: di.inject(persistentStorageMigrationsInjectable, enabledExtensionsMigrationDeclarationInjectionToken), + }); + }, +}); + +export default enabledExtensionsPersistentStorageInjectable; diff --git a/packages/core/src/features/extensions/enabled/common/update-state.injectable.ts b/packages/core/src/features/extensions/enabled/common/update-state.injectable.ts new file mode 100644 index 0000000000..e12c2d32d9 --- /dev/null +++ b/packages/core/src/features/extensions/enabled/common/update-state.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 type { LensExtensionId } from "@k8slens/legacy-extensions"; +import { getInjectable } from "@ogre-tools/injectable"; +import type { IObservableMapInitialValues } from "mobx"; +import { action } from "mobx"; +import type { LensExtensionState } from "./state.injectable"; +import enabledExtensionsStateInjectable from "./state.injectable"; + +export type UpdateExtensionsState = (state: IObservableMapInitialValues) => void; + +const updateExtensionsStateInjectable = getInjectable({ + id: "update-extensions-state", + instantiate: (di): UpdateExtensionsState => { + const state = di.inject(enabledExtensionsStateInjectable); + + return action((newState) => state.merge(newState)); + }, +}); + +export default updateExtensionsStateInjectable; diff --git a/packages/core/src/features/extensions/enabled/main/load-storage.injectable.ts b/packages/core/src/features/extensions/enabled/main/load-storage.injectable.ts new file mode 100644 index 0000000000..e3c301627b --- /dev/null +++ b/packages/core/src/features/extensions/enabled/main/load-storage.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 { beforeApplicationIsLoadingInjectionToken } from "@k8slens/application"; +import { getInjectable } from "@ogre-tools/injectable"; +import enabledExtensionsPersistentStorageInjectable from "../common/storage.injectable"; + +const loadEnabledExtensionsStorageInjectable = getInjectable({ + id: "load-enabled-extensions-storage", + instantiate: (di) => ({ + run: () => { + const storage = di.inject(enabledExtensionsPersistentStorageInjectable); + + storage.loadAndStartSyncing(); + }, + }), + injectionToken: beforeApplicationIsLoadingInjectionToken, +}); + +export default loadEnabledExtensionsStorageInjectable; diff --git a/packages/core/src/features/extensions/enabled/main/v6.5.0-migration.injectable.ts b/packages/core/src/features/extensions/enabled/main/v6.5.0-migration.injectable.ts new file mode 100644 index 0000000000..f658180535 --- /dev/null +++ b/packages/core/src/features/extensions/enabled/main/v6.5.0-migration.injectable.ts @@ -0,0 +1,26 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { isObject } from "@k8slens/utilities"; +import { getInjectable } from "@ogre-tools/injectable"; +import { enabledExtensionsMigrationDeclarationInjectionToken } from "../common/migrations"; + +const enabledExtensionsMigrationV650Injectable = getInjectable({ + id: "enabled-extensions-migration-v650", + instantiate: () => ({ + version: "6.5.0", + run: (store) => { + const extensions = store.get("extensions"); + + if (!isObject(extensions)) { + store.delete("extensions"); + } else { + store.set("extensions", Object.entries(extensions)); + } + }, + }), + injectionToken: enabledExtensionsMigrationDeclarationInjectionToken, +}); + +export default enabledExtensionsMigrationV650Injectable; diff --git a/packages/core/src/features/extensions/enabled/renderer/load-storage.injectable.ts b/packages/core/src/features/extensions/enabled/renderer/load-storage.injectable.ts new file mode 100644 index 0000000000..50be3cd88d --- /dev/null +++ b/packages/core/src/features/extensions/enabled/renderer/load-storage.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 { beforeFrameStartsSecondInjectionToken } from "../../../../renderer/before-frame-starts/tokens"; +import enabledExtensionsPersistentStorageInjectable from "../common/storage.injectable"; + +const loadEnabledExtensionsStorageInjectable = getInjectable({ + id: "load-enabled-extensions-storage", + instantiate: (di) => ({ + run: () => { + const storage = di.inject(enabledExtensionsPersistentStorageInjectable); + + storage.loadAndStartSyncing(); + }, + }), + injectionToken: beforeFrameStartsSecondInjectionToken, +}); + +export default loadEnabledExtensionsStorageInjectable; diff --git a/packages/core/src/features/helm-charts/__snapshots__/add-custom-helm-repository-in-preferences.test.ts.snap b/packages/core/src/features/helm-charts/__snapshots__/add-custom-helm-repository-in-preferences.test.ts.snap index 7932686bbf..7de4de3f87 100644 --- a/packages/core/src/features/helm-charts/__snapshots__/add-custom-helm-repository-in-preferences.test.ts.snap +++ b/packages/core/src/features/helm-charts/__snapshots__/add-custom-helm-repository-in-preferences.test.ts.snap @@ -649,7 +649,7 @@ exports[`add custom helm repository in preferences when navigating to preference class="HotbarSelector" > { + const computeHotbarIndex = di.inject(computeHotbarIndexInjectable); + const activeHotbarId = di.inject(activeHotbarIdInjectable); + + return computed(() => { + const activeId = activeHotbarId.get(); + + return (activeId && computeHotbarIndex(activeId)) || 0; + }); + }, +}); + +export default activeHotbarIndexInjectable; diff --git a/packages/core/src/features/hotbar/storage/common/active-id.injectable.ts b/packages/core/src/features/hotbar/storage/common/active-id.injectable.ts new file mode 100644 index 0000000000..2514bc834d --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/active-id.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 { observable } from "mobx"; + +const activeHotbarIdInjectable = getInjectable({ + id: "active-hotbar-id", + instantiate: () => observable.box(), +}); + +export default activeHotbarIdInjectable; diff --git a/packages/core/src/features/hotbar/storage/common/active.injectable.ts b/packages/core/src/features/hotbar/storage/common/active.injectable.ts new file mode 100644 index 0000000000..433a6f4323 --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/active.injectable.ts @@ -0,0 +1,24 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { computed } from "mobx"; +import activeHotbarIdInjectable from "./active-id.injectable"; +import hotbarsStateInjectable from "./state.injectable"; + +const activeHotbarInjectable = getInjectable({ + id: "active-hotbar", + instantiate: (di) => { + const state = di.inject(hotbarsStateInjectable); + const activeHotbarId = di.inject(activeHotbarIdInjectable); + + return computed(() => { + const id = activeHotbarId.get(); + + return (id && state.get(id)) || undefined; + }); + }, +}); + +export default activeHotbarInjectable; diff --git a/packages/core/src/features/hotbar/storage/common/add.injectable.ts b/packages/core/src/features/hotbar/storage/common/add.injectable.ts new file mode 100644 index 0000000000..19cbadc7c6 --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/add.injectable.ts @@ -0,0 +1,33 @@ +/** + * 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 { action } from "mobx"; +import type { CreateHotbarData, CreateHotbarOptions } from "./types"; +import activeHotbarIdInjectable from "./active-id.injectable"; +import hotbarsStateInjectable from "./state.injectable"; +import createHotbarInjectable from "./create-hotbar.injectable"; + +export type AddHotbar = (data: CreateHotbarData, { setActive }?: CreateHotbarOptions) => void; + +const addHotbarInjectable = getInjectable({ + id: "add-hotbar", + instantiate: (di): AddHotbar => { + const state = di.inject(hotbarsStateInjectable); + const activeHotbarId = di.inject(activeHotbarIdInjectable); + const createHotbar = di.inject(createHotbarInjectable); + + return action((data, { setActive = false } = {}) => { + const hotbar = createHotbar(data); + + state.set(hotbar.id, hotbar); + + if (setActive) { + activeHotbarId.set(hotbar.id); + } + }); + }, +}); + +export default addHotbarInjectable; diff --git a/packages/core/src/features/hotbar/storage/common/compute-display-index.injectable.ts b/packages/core/src/features/hotbar/storage/common/compute-display-index.injectable.ts new file mode 100644 index 0000000000..c67b75db39 --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/compute-display-index.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 { getInjectable } from "@ogre-tools/injectable"; +import computeHotbarIndexInjectable from "./compute-hotbar-index.injectable"; + +export type ComputeDisplayIndex = (hotbarId: string) => string; + +const computeDisplayIndexInjectable = getInjectable({ + id: "compute-display-index", + instantiate: (di): ComputeDisplayIndex => { + const computeHotbarIndex = di.inject(computeHotbarIndexInjectable); + + return (hotbarId) => `${computeHotbarIndex(hotbarId) + 1}`; + }, +}); + +export default computeDisplayIndexInjectable; diff --git a/packages/core/src/features/hotbar/storage/common/compute-display-label.injectable.ts b/packages/core/src/features/hotbar/storage/common/compute-display-label.injectable.ts new file mode 100644 index 0000000000..5900563cb2 --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/compute-display-label.injectable.ts @@ -0,0 +1,20 @@ +/** + * 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 { Hotbar } from "./hotbar"; +import computeDisplayIndexInjectable from "./compute-display-index.injectable"; + +export type ComputeHotbarDisplayLabel = (hotbar: Hotbar) => string; + +const computeHotbarDisplayLabelInjectable = getInjectable({ + id: "compute-hotbar-display-label", + instantiate: (di): ComputeHotbarDisplayLabel => { + const computeDisplayIndex = di.inject(computeDisplayIndexInjectable); + + return (hotbar) => `${computeDisplayIndex(hotbar.id)}: ${hotbar.name}`; + }, +}); + +export default computeHotbarDisplayLabelInjectable; diff --git a/packages/core/src/features/hotbar/storage/common/compute-hotbar-index.injectable.ts b/packages/core/src/features/hotbar/storage/common/compute-hotbar-index.injectable.ts new file mode 100644 index 0000000000..b54954c618 --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/compute-hotbar-index.injectable.ts @@ -0,0 +1,31 @@ +/** + * 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 hotbarsStateInjectable from "./state.injectable"; + +export type ComputeHotbarIndex = (hotbarId: string) => number; + +const computeHotbarIndexInjectable = getInjectable({ + id: "compute-hotbar-index", + instantiate: (di): ComputeHotbarIndex => { + const state = di.inject(hotbarsStateInjectable); + + return (hotbarId) => { + let i = 0; + + for (const hotbar of state.values()) { + if (hotbar.id === hotbarId) { + return i; + } + + i += 1; + } + + return 0; + }; + }, +}); + +export default computeHotbarIndexInjectable; diff --git a/packages/core/src/features/hotbar/storage/common/create-hotbar.injectable.ts b/packages/core/src/features/hotbar/storage/common/create-hotbar.injectable.ts new file mode 100644 index 0000000000..8d35af255b --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/create-hotbar.injectable.ts @@ -0,0 +1,24 @@ +/** + * 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 { CreateHotbarData } from "./types"; +import prefixedLoggerInjectable from "../../../../common/logger/prefixed-logger.injectable"; +import type { HotbarDependencies } from "./hotbar"; +import { Hotbar } from "./hotbar"; + +export type CreateHotbar = (data: CreateHotbarData) => Hotbar; + +const createHotbarInjectable = getInjectable({ + id: "create-hotbar", + instantiate: (di): CreateHotbar => { + const deps: HotbarDependencies = { + logger: di.inject(prefixedLoggerInjectable, "HOTBAR"), + }; + + return (data) => new Hotbar(deps, data); + }, +}); + +export default createHotbarInjectable; diff --git a/packages/core/src/features/hotbar/storage/common/find-by-name.injectable.ts b/packages/core/src/features/hotbar/storage/common/find-by-name.injectable.ts new file mode 100644 index 0000000000..321bc74b2e --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/find-by-name.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 { iter } from "@k8slens/utilities"; +import { getInjectable } from "@ogre-tools/injectable"; +import type { Hotbar } from "./hotbar"; +import hotbarsStateInjectable from "./state.injectable"; + +export type FindHotbarByName = (name: string) => Hotbar | undefined; + +const findHotbarByNameInjectable = getInjectable({ + id: "find-hotbar-by-name", + instantiate: (di): FindHotbarByName => { + const state = di.inject(hotbarsStateInjectable); + + return (name) => iter.find(state.values(), hotbar => hotbar.name.get() === name); + }, +}); + +export default findHotbarByNameInjectable; diff --git a/packages/core/src/features/hotbar/storage/common/get-by-id.injectable.ts b/packages/core/src/features/hotbar/storage/common/get-by-id.injectable.ts new file mode 100644 index 0000000000..00fe43814f --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/get-by-id.injectable.ts @@ -0,0 +1,20 @@ +/** + * 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 { Hotbar } from "./hotbar"; +import hotbarsStateInjectable from "./state.injectable"; + +export type GetHotbarById = (id: string) => Hotbar | undefined; + +const getHotbarByIdInjectable = getInjectable({ + id: "get-hotbar-by-id", + instantiate: (di): GetHotbarById => { + const state = di.inject(hotbarsStateInjectable); + + return (id) => state.get(id); + }, +}); + +export default getHotbarByIdInjectable; diff --git a/packages/core/src/features/hotbar/storage/common/hotbar.ts b/packages/core/src/features/hotbar/storage/common/hotbar.ts new file mode 100644 index 0000000000..efb2e60579 --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/hotbar.ts @@ -0,0 +1,175 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { type IObservableValue, type IObservableArray, observable, runInAction, toJS } from "mobx"; +import type { CatalogEntity } from "../../../../common/catalog"; +import { getShortName } from "../../../../common/catalog/helpers"; +import type { HotbarItem, CreateHotbarData } from "./types"; +import { defaultHotbarCells } from "./types"; +import { broadcastMessage } from "../../../../common/ipc"; +import { hotbarTooManyItemsChannel } from "../../../../common/ipc/hotbar"; +import * as uuid from "uuid"; +import type { Logger } from "../../../../common/logger"; +import { tuple } from "@k8slens/utilities"; + +export interface HotbarDependencies { + readonly logger: Logger; +} + +export interface HotbarData { + readonly id: string; + readonly name: string; + readonly items: (HotbarItem | null)[]; +} + +export class Hotbar { + readonly id: string; + readonly name: IObservableValue; + readonly items: IObservableArray; + + constructor(private readonly dependencies: HotbarDependencies, data: CreateHotbarData) { + this.id = data.id ?? uuid.v4(); + this.name = observable.box(data.name); + this.items = observable.array(data.items ?? tuple.filled(defaultHotbarCells, null)); + } + + isFull() { + for (const item of this.items) { + if (!item) { + return false; + } + } + + return true; + } + + hasEntity(entityId: string) { + return this.items.findIndex(item => item?.entity.uid === entityId) >= 0; + } + + private findClosestEmptyIndex(from: number, direction = 1) { + let index = from; + + while (this.items[index] != null) { + index += direction; + } + + return index; + } + + restack(from: number, to: number) { + runInAction(() => { + const source = this.items[from]; + const moveDown = from < to; + + if ( + from < 0 || + to < 0 || + from >= this.items.length || + to >= this.items.length || + isNaN(from) || + isNaN(to) + ) { + throw new Error("Invalid 'from' or 'to' arguments"); + } + + if (from == to) { + return; + } + + this.items.splice(from, 1, null); + + if (this.items[to] == null) { + this.items.splice(to, 1, source); + } else { + // Move cells up or down to closes empty cell + this.items.splice(this.findClosestEmptyIndex(to, moveDown ? -1 : 1), 1); + this.items.splice(to, 0, source); + } + }); + } + + toggleEntity(item: CatalogEntity) { + runInAction(() => { + if (this.hasEntity(item.getId())) { + this.removeEntity(item.getId()); + } else { + this.addEntity(item); + } + }); + } + + removeEntity(uid: string) { + runInAction(() => { + const index = this.items.findIndex((item) => item?.entity.uid === uid); + + if (index < 0) { + return; + } + + this.items[index] = null; + }); + } + + addEntity(item: CatalogEntity, cellIndex?: number) { + const uid = item.getId(); + const name = item.getName(); + const shortName = getShortName(item); + + if (typeof uid !== "string") { + throw new TypeError("CatalogEntity's ID must be a string"); + } + + if (typeof name !== "string") { + throw new TypeError("CatalogEntity's NAME must be a string"); + } + + if (typeof shortName !== "string") { + throw new TypeError("CatalogEntity's SHORT_NAME must be a string"); + } + + if (this.hasEntity(item.getId())) { + return; + } + + const entity = { + uid, + name, + source: item.metadata.source, + shortName, + }; + const newItem = { entity }; + + if (cellIndex === undefined) { + // Add item to empty cell + const emptyCellIndex = this.items.indexOf(null); + + if (emptyCellIndex >= 0) { + runInAction(() => { + this.items[emptyCellIndex] = newItem; + }); + } else { + broadcastMessage(hotbarTooManyItemsChannel); + } + } else if (0 <= cellIndex && cellIndex < this.items.length) { + runInAction(() => { + this.items[cellIndex] = newItem; + }); + } else { + this.dependencies.logger.error( + "cannot pin entity to hotbar outside of index range", + { entityId: uid, hotbarId: this.id, cellIndex }, + ); + } + } + + toJSON(): HotbarData { + return { + id: this.id, + items: toJS(this.items), + name: this.name.get(), + }; + } +} diff --git a/packages/core/src/features/hotbar/storage/common/hotbars.injectable.ts b/packages/core/src/features/hotbar/storage/common/hotbars.injectable.ts new file mode 100644 index 0000000000..2a13b4fc27 --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/hotbars.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 { computed } from "mobx"; +import hotbarsStateInjectable from "./state.injectable"; + +const hotbarsInjectable = getInjectable({ + id: "hotbars", + instantiate: (di) => { + const state = di.inject(hotbarsStateInjectable); + + return computed(() => [...state.values()]); + }, +}); + +export default hotbarsInjectable; diff --git a/packages/core/src/common/hotbars/migrations-token.ts b/packages/core/src/features/hotbar/storage/common/migrations-token.ts similarity index 76% rename from packages/core/src/common/hotbars/migrations-token.ts rename to packages/core/src/features/hotbar/storage/common/migrations-token.ts index 5441844933..ede5cd1966 100644 --- a/packages/core/src/common/hotbars/migrations-token.ts +++ b/packages/core/src/features/hotbar/storage/common/migrations-token.ts @@ -4,7 +4,7 @@ */ import { getInjectionToken } from "@ogre-tools/injectable"; -import type { MigrationDeclaration } from "../base-store/migrations.injectable"; +import type { MigrationDeclaration } from "../../../../common/persistent-storage/migrations.injectable"; export const hotbarStoreMigrationInjectionToken = getInjectionToken({ id: "hotbar-store-migration-token", diff --git a/packages/core/src/features/hotbar/storage/common/remove-entity-from-all.injectable.ts b/packages/core/src/features/hotbar/storage/common/remove-entity-from-all.injectable.ts new file mode 100644 index 0000000000..5890a0e995 --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/remove-entity-from-all.injectable.ts @@ -0,0 +1,24 @@ +/** + * 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 { action } from "mobx"; +import hotbarsInjectable from "./hotbars.injectable"; + +export type RemoveEntityFromAllHotbars = (entityId: string) => void; + +const removeEntityFromAllHotbarsInjectable = getInjectable({ + id: "remove-entity-from-all-hotbars", + instantiate: (di): RemoveEntityFromAllHotbars => { + const hotbars = di.inject(hotbarsInjectable); + + return action((entityId) => { + for (const hotbar of hotbars.get()) { + hotbar.removeEntity(entityId); + } + }); + }, +}); + +export default removeEntityFromAllHotbarsInjectable; diff --git a/packages/core/src/features/hotbar/storage/common/remove.injectable.ts b/packages/core/src/features/hotbar/storage/common/remove.injectable.ts new file mode 100644 index 0000000000..d06c19b2e0 --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/remove.injectable.ts @@ -0,0 +1,33 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { iter } from "@k8slens/utilities"; +import { getInjectable } from "@ogre-tools/injectable"; +import assert from "assert"; +import { action } from "mobx"; +import activeHotbarIdInjectable from "./active-id.injectable"; +import type { Hotbar } from "./hotbar"; +import hotbarsStateInjectable from "./state.injectable"; + +export type RemoveHotbar = (hotbar: Hotbar) => void; + +const removeHotbarInjectable = getInjectable({ + id: "remove-hotbar", + instantiate: (di): RemoveHotbar => { + const state = di.inject(hotbarsStateInjectable); + const activeHotbarId = di.inject(activeHotbarIdInjectable); + + return action((hotbar) => { + assert(state.size >= 2, "Cannot remove the last hotbar"); + + state.delete(hotbar.id); + + if (activeHotbarId.get() === hotbar.id) { + activeHotbarId.set(iter.first(state.values())?.id); + } + }); + }, +}); + +export default removeHotbarInjectable; diff --git a/packages/core/src/features/hotbar/storage/common/set-as-active.injectable.ts b/packages/core/src/features/hotbar/storage/common/set-as-active.injectable.ts new file mode 100644 index 0000000000..226914fcae --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/set-as-active.injectable.ts @@ -0,0 +1,40 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { iter } from "@k8slens/utilities"; +import { getInjectable } from "@ogre-tools/injectable"; +import { action } from "mobx"; +import activeHotbarIdInjectable from "./active-id.injectable"; +import type { Hotbar } from "./hotbar"; +import hotbarsStateInjectable from "./state.injectable"; + +export type SetAsActiveHotbar = (desc: Hotbar | number | string) => void; + +const setAsActiveHotbarInjectable = getInjectable({ + id: "set-as-active-hotbar", + instantiate: (di): SetAsActiveHotbar => { + const hotbarsState = di.inject(hotbarsStateInjectable); + const activeHotbarId = di.inject(activeHotbarIdInjectable); + + return action((desc) => { + if (typeof desc === "number") { + const hotbar = iter.nth(hotbarsState.values(), desc); + + if (hotbar) { + activeHotbarId.set(hotbar.id); + } + } else if (typeof desc === "string") { + if (hotbarsState.has(desc)) { + activeHotbarId.set(desc); + } + } else { + if (hotbarsState.has(desc.id)) { + activeHotbarId.set(desc.id); + } + } + }); + }, +}); + +export default setAsActiveHotbarInjectable; diff --git a/packages/core/src/features/hotbar/storage/common/state.injectable.ts b/packages/core/src/features/hotbar/storage/common/state.injectable.ts new file mode 100644 index 0000000000..c544172d9a --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/state.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 { observable } from "mobx"; +import type { Hotbar } from "./hotbar"; + +const hotbarsStateInjectable = getInjectable({ + id: "hotbars-state", + instantiate: () => observable.map(), +}); + +export default hotbarsStateInjectable; diff --git a/packages/core/src/features/hotbar/storage/common/storage.injectable.ts b/packages/core/src/features/hotbar/storage/common/storage.injectable.ts new file mode 100644 index 0000000000..3bdc2bd3b6 --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/storage.injectable.ts @@ -0,0 +1,116 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { iter } from "@k8slens/utilities"; +import { getInjectable } from "@ogre-tools/injectable"; +import { action, comparer } from "mobx"; +import catalogCatalogEntityInjectable from "../../../../common/catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable"; +import { hotbarStoreMigrationInjectionToken } from "./migrations-token"; +import { defaultHotbarCells } from "./types"; +import createPersistentStorageInjectable from "../../../../common/persistent-storage/create.injectable"; +import persistentStorageMigrationsInjectable from "../../../../common/persistent-storage/migrations.injectable"; +import storeMigrationVersionInjectable from "../../../../common/vars/store-migration-version.injectable"; +import activeHotbarIdInjectable from "./active-id.injectable"; +import createHotbarInjectable from "./create-hotbar.injectable"; +import type { Hotbar, HotbarData } from "./hotbar"; +import hotbarsStateInjectable from "./state.injectable"; + +export interface HotbarStoreModel { + hotbars: HotbarData[]; + activeHotbarId: string | undefined; +} + +const hotbarsPersistentStorageInjectable = getInjectable({ + id: "hotbars-persistent-storage", + instantiate: (di) => { + const state = di.inject(hotbarsStateInjectable); + const createPersistentStorage = di.inject(createPersistentStorageInjectable); + const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable); + const activeHotbarId = di.inject(activeHotbarIdInjectable); + const createHotbar = di.inject(createHotbarInjectable); + + return createPersistentStorage({ + configName: "lens-hotbar-store", + accessPropertiesByDotNotation: false, // To make dots safe in cluster context names + syncOptions: { + equals: comparer.structural, + }, + projectVersion: di.inject(storeMigrationVersionInjectable), + migrations: di.inject(persistentStorageMigrationsInjectable, hotbarStoreMigrationInjectionToken), + fromStore: action((data) => { + if (!data.hotbars || !data.hotbars.length) { + const hotbar = createHotbar({ + name: "Default", + }); + const { + metadata: { + uid, + name, + source, + }, + } = catalogCatalogEntity; + + hotbar.items[0] = { + entity: { + uid, + name, + source, + }, + }; + state.replace([[hotbar.id, hotbar]]); + } else { + state.replace(data.hotbars.map((hotbar) => [hotbar.id, createHotbar(hotbar)])); + } + + for (const hotbar of state.values()) { + ensureExactHotbarItemLength(hotbar); + } + + if (data.activeHotbarId) { + activeHotbarId.set(data.activeHotbarId); + } + + const firstHotbarId = iter.first(state.values())?.id; + + if (!activeHotbarId.get()) { + activeHotbarId.set(firstHotbarId); + } else if (!iter.find(state.values(), hotbar => hotbar.id === activeHotbarId.get())) { + activeHotbarId.set(firstHotbarId); + } + }), + toJSON: () => ({ + hotbars: iter.chain(state.values()) + .map(hotbar => hotbar.toJSON()) + .toArray(), + activeHotbarId: activeHotbarId.get(), + }), + }); + }, +}); + +export default hotbarsPersistentStorageInjectable; + +/** + * This function ensures that there are always exactly `defaultHotbarCells` + * worth of items in the hotbar. + * @param hotbar The hotbar to modify + */ +function ensureExactHotbarItemLength(hotbar: Hotbar) { + // if there are not enough items + while (hotbar.items.length < defaultHotbarCells) { + hotbar.items.push(null); + } + + // if for some reason the hotbar was overfilled before, remove as many entries + // as needed, but prefer empty slots and items at the end first. + while (hotbar.items.length > defaultHotbarCells) { + const lastNull = hotbar.items.lastIndexOf(null); + + if (lastNull >= 0) { + hotbar.items.splice(lastNull, 1); + } else { + hotbar.items.length = defaultHotbarCells; + } + } +} diff --git a/packages/core/src/features/hotbar/storage/common/switch-to-next.injectable.ts b/packages/core/src/features/hotbar/storage/common/switch-to-next.injectable.ts new file mode 100644 index 0000000000..5648c5bfc4 --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/switch-to-next.injectable.ts @@ -0,0 +1,32 @@ +/** + * 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 { action } from "mobx"; +import activeHotbarIndexInjectable from "./active-hotbar-index.injectable"; +import setAsActiveHotbarInjectable from "./set-as-active.injectable"; +import hotbarsStateInjectable from "./state.injectable"; + +export type SwitchToNextHotbar = () => void; + +const switchToNextHotbarInjectable = getInjectable({ + id: "switch-to-next-hotbar", + instantiate: (di): SwitchToNextHotbar => { + const setAsActiveHotbar = di.inject(setAsActiveHotbarInjectable); + const activeHotbarIndex = di.inject(activeHotbarIndexInjectable); + const state = di.inject(hotbarsStateInjectable); + + return action(() => { + const index = activeHotbarIndex.get() + 1; + + if (index >= state.size) { + setAsActiveHotbar(0); + } else { + setAsActiveHotbar(index); + } + }); + }, +}); + +export default switchToNextHotbarInjectable; diff --git a/packages/core/src/features/hotbar/storage/common/switch-to-previous.injectable.ts b/packages/core/src/features/hotbar/storage/common/switch-to-previous.injectable.ts new file mode 100644 index 0000000000..d18a12c27c --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/switch-to-previous.injectable.ts @@ -0,0 +1,32 @@ +/** + * 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 { action } from "mobx"; +import activeHotbarIndexInjectable from "./active-hotbar-index.injectable"; +import setAsActiveHotbarInjectable from "./set-as-active.injectable"; +import hotbarsStateInjectable from "./state.injectable"; + +export type SwitchToPreviousHotbar = () => void; + +const switchToPreviousHotbarInjectable = getInjectable({ + id: "switch-to-previous-hotbar", + instantiate: (di): SwitchToPreviousHotbar => { + const setAsActiveHotbar = di.inject(setAsActiveHotbarInjectable); + const activeHotbarIndex = di.inject(activeHotbarIndexInjectable); + const state = di.inject(hotbarsStateInjectable); + + return action(() => { + const index = activeHotbarIndex.get() - 1; + + if (index < 0) { + setAsActiveHotbar(state.size - 1); + } else { + setAsActiveHotbar(index); + } + }); + }, +}); + +export default switchToPreviousHotbarInjectable; diff --git a/packages/core/src/features/hotbar/storage/common/toggling.injectable.ts b/packages/core/src/features/hotbar/storage/common/toggling.injectable.ts new file mode 100644 index 0000000000..4daf9ca41e --- /dev/null +++ b/packages/core/src/features/hotbar/storage/common/toggling.injectable.ts @@ -0,0 +1,25 @@ +/** + * 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 activeHotbarInjectable from "./active.injectable"; +import type { Hotbar } from "./hotbar"; + +export type ActiveHotbarModel = Pick; + +const activeHotbarModelInjectable = getInjectable({ + id: "active-hotbar-model", + instantiate: (di): ActiveHotbarModel => { + const activeHotbar = di.inject(activeHotbarInjectable); + + return { + hasEntity: (entityId) => activeHotbar.get()?.hasEntity(entityId) ?? false, + toggleEntity: (entity) => activeHotbar.get()?.toggleEntity(entity), + addEntity: (entity) => activeHotbar.get()?.addEntity(entity), + removeEntity: (entityId) => activeHotbar.get()?.removeEntity(entityId), + }; + }, +}); + +export default activeHotbarModelInjectable; diff --git a/packages/core/src/common/hotbars/types.ts b/packages/core/src/features/hotbar/storage/common/types.ts similarity index 56% rename from packages/core/src/common/hotbars/types.ts rename to packages/core/src/features/hotbar/storage/common/types.ts index 2925c785a0..3153fdd2fa 100644 --- a/packages/core/src/common/hotbars/types.ts +++ b/packages/core/src/features/hotbar/storage/common/types.ts @@ -3,9 +3,6 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import * as uuid from "uuid"; -import type { Tuple } from "@k8slens/utilities"; -import { tuple } from "@k8slens/utilities"; export interface HotbarItem { entity: { @@ -18,12 +15,10 @@ export interface HotbarItem { }; } -export type Hotbar = Required; - export interface CreateHotbarData { id?: string; name: string; - items?: Tuple; + items?: (HotbarItem | null)[]; } export interface CreateHotbarOptions { @@ -31,11 +26,3 @@ export interface CreateHotbarOptions { } export const defaultHotbarCells = 12; // Number is chosen to easy hit any item with keyboard - -export function getEmptyHotbar(name: string, id: string = uuid.v4()): Hotbar { - return { - id, - items: tuple.filled(defaultHotbarCells, null), - name, - }; -} diff --git a/packages/core/src/features/hotbar/storage/main/5.0.0-alpha.0.injectable.ts b/packages/core/src/features/hotbar/storage/main/5.0.0-alpha.0.injectable.ts new file mode 100644 index 0000000000..9450b9528f --- /dev/null +++ b/packages/core/src/features/hotbar/storage/main/5.0.0-alpha.0.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. + */ + +// Cleans up a store that had the state related data stored +import catalogCatalogEntityInjectable from "../../../../common/catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable"; +import { getInjectable } from "@ogre-tools/injectable"; +import { hotbarStoreMigrationInjectionToken } from "../common/migrations-token"; +import createHotbarInjectable from "../common/create-hotbar.injectable"; + +const v500Alpha0HotbarStoreMigrationInjectable = getInjectable({ + id: "v5.0.0-alpha.0-hotbar-store-migration", + instantiate: (di) => ({ + version: "5.0.0-alpha.0", + run(store) { + const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable); + const createHotbar = di.inject(createHotbarInjectable); + const hotbar = createHotbar({ name: "default" }); + + hotbar.addEntity(catalogCatalogEntity); + + store.set("hotbars", [hotbar.toJSON()]); + }, + }), + injectionToken: hotbarStoreMigrationInjectionToken, +}); + +export default v500Alpha0HotbarStoreMigrationInjectable; + diff --git a/packages/core/src/main/hotbar-store/migrations/5.0.0-alpha.2.injectable.ts b/packages/core/src/features/hotbar/storage/main/5.0.0-alpha.2.injectable.ts similarity index 76% rename from packages/core/src/main/hotbar-store/migrations/5.0.0-alpha.2.injectable.ts rename to packages/core/src/features/hotbar/storage/main/5.0.0-alpha.2.injectable.ts index 550f46a940..adf7ff4f30 100644 --- a/packages/core/src/main/hotbar-store/migrations/5.0.0-alpha.2.injectable.ts +++ b/packages/core/src/features/hotbar/storage/main/5.0.0-alpha.2.injectable.ts @@ -4,10 +4,10 @@ */ // Cleans up a store that had the state related data stored -import type { Hotbar } from "../../../common/hotbars/types"; import * as uuid from "uuid"; import { getInjectable } from "@ogre-tools/injectable"; -import { hotbarStoreMigrationInjectionToken } from "../../../common/hotbars/migrations-token"; +import { hotbarStoreMigrationInjectionToken } from "../common/migrations-token"; +import type { HotbarData } from "../common/hotbar"; const v500Alpha2HotbarStoreMigrationInjectable = getInjectable({ id: "v5.0.0-alpha.2-hotbar-store-migration", @@ -15,7 +15,7 @@ const v500Alpha2HotbarStoreMigrationInjectable = getInjectable({ version: "5.0.0-alpha.2", run(store) { const rawHotbars = store.get("hotbars"); - const hotbars: Hotbar[] = Array.isArray(rawHotbars) ? rawHotbars : []; + const hotbars: HotbarData[] = Array.isArray(rawHotbars) ? rawHotbars : []; store.set("hotbars", hotbars.map(({ id, ...rest }) => ({ id: id || uuid.v4(), diff --git a/packages/core/src/features/hotbar/storage/main/5.0.0-beta.10.injectable.ts b/packages/core/src/features/hotbar/storage/main/5.0.0-beta.10.injectable.ts new file mode 100644 index 0000000000..a777a81b6a --- /dev/null +++ b/packages/core/src/features/hotbar/storage/main/5.0.0-beta.10.injectable.ts @@ -0,0 +1,168 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import * as uuid from "uuid"; +import directoryForUserDataInjectable from "../../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; +import catalogCatalogEntityInjectable from "../../../../common/catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable"; +import { isDefined, isErrnoException } from "@k8slens/utilities"; +import joinPathsInjectable from "../../../../common/path/join-paths.injectable"; +import { getInjectable } from "@ogre-tools/injectable"; +import { hotbarStoreMigrationInjectionToken } from "../common/migrations-token"; +import readJsonSyncInjectable from "../../../../common/fs/read-json-sync.injectable"; +import loggerInjectable from "../../../../common/logger.injectable"; +import { generateNewIdFor } from "../../../../common/utils/generate-new-id-for"; +import type { ClusterModel } from "../../../../common/cluster-types"; +import { defaultHotbarCells } from "../common/types"; +import type { HotbarData } from "../common/hotbar"; +import createHotbarInjectable from "../common/create-hotbar.injectable"; + +interface Pre500WorkspaceStoreModel { + workspaces: { + id: string; + name: string; + }[]; +} + +interface Pre500ClusterModel extends ClusterModel { + workspace?: string; + workspaces?: string[]; +} + +interface Pre500ClusterStoreModel { + clusters?: Pre500ClusterModel[]; +} + +const v500Beta10HotbarStoreMigrationInjectable = getInjectable({ + id: "v5.0.0-beta.10-hotbar-store-migration", + instantiate: (di) => ({ + version: "5.0.0-beta.10", + run(store) { + const userDataPath = di.inject(directoryForUserDataInjectable); + const joinPaths = di.inject(joinPathsInjectable); + const readJsonSync = di.inject(readJsonSyncInjectable); + const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable); + const logger = di.inject(loggerInjectable); + const createHotbar = di.inject(createHotbarInjectable); + const rawHotbars = store.get("hotbars"); + const hotbars: HotbarData[] = Array.isArray(rawHotbars) ? rawHotbars.filter(h => h && typeof h === "object") : []; + + // Hotbars might be empty, if some of the previous migrations weren't run + if (hotbars.length === 0) { + const hotbar = createHotbar({ name: "default" }); + + hotbar.addEntity(catalogCatalogEntity); + hotbars.push(hotbar.toJSON()); + } + + try { + const workspaceStoreData: Pre500WorkspaceStoreModel = readJsonSync(joinPaths(userDataPath, "lens-workspace-store.json")); + const { clusters = [] }: Pre500ClusterStoreModel = readJsonSync(joinPaths(userDataPath, "lens-cluster-store.json")); + const workspaceHotbars = new Map(); // mapping from WorkspaceId to HotBar + + for (const { id, name } of workspaceStoreData.workspaces) { + logger.info(`Creating new hotbar for ${name}`); + workspaceHotbars.set(id, { + id: uuid.v4(), + items: [], + name: `Workspace: ${name}`, + }); + } + + { + // grab the default named hotbar or the first. + const defaultHotbarIndex = Math.max(0, hotbars.findIndex(hotbar => hotbar.name === "default")); + const [{ name, id, items }] = hotbars.splice(defaultHotbarIndex, 1); + + workspaceHotbars.set("default", { + name, + id, + items: items.filter(isDefined), + }); + } + + for (const cluster of clusters) { + const uid = generateNewIdFor(cluster); + + for (const workspaceId of cluster.workspaces ?? [cluster.workspace].filter(isDefined)) { + const workspaceHotbar = workspaceHotbars.get(workspaceId); + + if (!workspaceHotbar) { + logger.info(`Cluster ${uid} has unknown workspace ID, skipping`); + continue; + } + + logger.info(`Adding cluster ${uid} to ${workspaceHotbar.name}`); + + if (workspaceHotbar?.items.length < defaultHotbarCells) { + workspaceHotbar.items.push({ + entity: { + uid: generateNewIdFor(cluster), + name: cluster.preferences?.clusterName || cluster.contextName, + }, + }); + } + } + } + + for (const hotbar of workspaceHotbars.values()) { + if (hotbar.items.length === 0) { + logger.info(`Skipping ${hotbar.name} due to it being empty`); + continue; + } + + while (hotbar.items.length < defaultHotbarCells) { + hotbar.items.push(null); + } + + hotbars.push(hotbar); + } + + /** + * Finally, make sure that the catalog entity hotbar item is in place. + * Just in case something else removed it. + * + * if every hotbar has elements that all not the `catalog-entity` item + */ + if (hotbars.every(hotbar => hotbar.items.every(item => item?.entity?.uid !== "catalog-entity"))) { + // note, we will add a new whole hotbar here called "default" if that was previously removed + const defaultHotbarIndex = hotbars.findIndex(hotbar => hotbar.name === "default"); + + if (defaultHotbarIndex >= 0) { + const defaultHotbar = createHotbar(hotbars[defaultHotbarIndex]); + + if (defaultHotbar.isFull()) { + // making a new hotbar is less destructive if the first hotbar + // called "default" is full than overriding a hotbar item + const hotbar = createHotbar({ name: "initial" }); + + hotbar.addEntity(catalogCatalogEntity); + hotbars.unshift(hotbar.toJSON()); + } else { + defaultHotbar.addEntity(catalogCatalogEntity); + hotbars[defaultHotbarIndex] = defaultHotbar.toJSON(); + } + } else { + const hotbar = createHotbar({ name: "default" }); + + hotbar.addEntity(catalogCatalogEntity); + hotbars.unshift(hotbar.toJSON()); + } + } + + } catch (error) { + // ignore files being missing + if (isErrnoException(error) && error.code !== "ENOENT") { + throw error; + } + } + + store.set("hotbars", hotbars); + }, + }), + injectionToken: hotbarStoreMigrationInjectionToken, +}); + +export default v500Beta10HotbarStoreMigrationInjectable; + diff --git a/packages/core/src/features/hotbar/storage/main/5.0.0-beta.5.injectable.ts b/packages/core/src/features/hotbar/storage/main/5.0.0-beta.5.injectable.ts new file mode 100644 index 0000000000..75f3868d7b --- /dev/null +++ b/packages/core/src/features/hotbar/storage/main/5.0.0-beta.5.injectable.ts @@ -0,0 +1,51 @@ +/** + * 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 catalogEntityRegistryInjectable from "../../../../main/catalog/entity-registry.injectable"; +import type { HotbarData } from "../common/hotbar"; +import { hotbarStoreMigrationInjectionToken } from "../common/migrations-token"; + +const v500Beta5HotbarStoreMigrationInjectable = getInjectable({ + id: "v500-beta5-hotbar-store-migration", + instantiate: (di) => ({ + version: "5.0.0-beta.5", + run(store) { + const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable); + const rawHotbars = store.get("hotbars"); + const hotbars: HotbarData[] = Array.isArray(rawHotbars) ? rawHotbars : []; + + for (const hotbar of hotbars) { + for (let i = 0; i < hotbar.items.length; i += 1) { + const item = hotbar.items[i]; + + if (!item) { + continue; + } + + const entity = catalogEntityRegistry.findById(item.entity.uid); + + if (!entity) { + // Clear disabled item + hotbar.items[i] = null; + } else { + // Save additional data + item.entity = { + ...item.entity, + name: entity.metadata.name, + source: entity.metadata.source, + }; + } + } + } + + store.set("hotbars", hotbars); + }, + }), + injectionToken: hotbarStoreMigrationInjectionToken, +}); + +export default v500Beta5HotbarStoreMigrationInjectable; + diff --git a/packages/core/src/features/hotbar/store/main/init.injectable.ts b/packages/core/src/features/hotbar/storage/main/load-storage.injectable.ts similarity index 66% rename from packages/core/src/features/hotbar/store/main/init.injectable.ts rename to packages/core/src/features/hotbar/storage/main/load-storage.injectable.ts index cb45c396ac..d541f80249 100644 --- a/packages/core/src/features/hotbar/store/main/init.injectable.ts +++ b/packages/core/src/features/hotbar/storage/main/load-storage.injectable.ts @@ -3,21 +3,21 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable"; import { onLoadOfApplicationInjectionToken } from "@k8slens/application"; import setupSyncingOfGeneralCatalogEntitiesInjectable from "../../../../main/start-main-application/runnables/setup-syncing-of-general-catalog-entities.injectable"; +import hotbarsPersistentStorageInjectable from "../common/storage.injectable"; -const initHotbarStoreInjectable = getInjectable({ - id: "init-hotbar-store", +const loadHotbarStorageInjectable = getInjectable({ + id: "load-hotbar-storage", instantiate: (di) => ({ run: () => { - const hotbarStore = di.inject(hotbarStoreInjectable); + const storage = di.inject(hotbarsPersistentStorageInjectable); - hotbarStore.load(); + storage.loadAndStartSyncing(); }, runAfter: setupSyncingOfGeneralCatalogEntitiesInjectable, }), injectionToken: onLoadOfApplicationInjectionToken, }); -export default initHotbarStoreInjectable; +export default loadHotbarStorageInjectable; diff --git a/packages/core/src/features/hotbar/store/renderer/init.injectable.ts b/packages/core/src/features/hotbar/storage/renderer/init.injectable.ts similarity index 53% rename from packages/core/src/features/hotbar/store/renderer/init.injectable.ts rename to packages/core/src/features/hotbar/storage/renderer/init.injectable.ts index 239807dfda..ebc787bd4a 100644 --- a/packages/core/src/features/hotbar/store/renderer/init.injectable.ts +++ b/packages/core/src/features/hotbar/storage/renderer/init.injectable.ts @@ -3,21 +3,21 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable"; import { beforeFrameStartsSecondInjectionToken } from "../../../../renderer/before-frame-starts/tokens"; -import initClusterStoreInjectable from "../../../cluster/store/renderer/init.injectable"; +import initClusterStoreInjectable from "../../../cluster/storage/renderer/init.injectable"; +import hotbarsPersistentStorageInjectable from "../common/storage.injectable"; -const initHotbarStoreInjectable = getInjectable({ - id: "init-hotbar-store", +const loadHotbarStorageInjectable = getInjectable({ + id: "load-hotbar-storage", instantiate: (di) => ({ run: () => { - const hotbarStore = di.inject(hotbarStoreInjectable); + const storage = di.inject(hotbarsPersistentStorageInjectable); - hotbarStore.load(); + storage.loadAndStartSyncing(); }, runAfter: initClusterStoreInjectable, }), injectionToken: beforeFrameStartsSecondInjectionToken, }); -export default initHotbarStoreInjectable; +export default loadHotbarStorageInjectable; diff --git a/packages/core/src/features/hotbar/storage/storage-technical.test.ts b/packages/core/src/features/hotbar/storage/storage-technical.test.ts new file mode 100644 index 0000000000..54e6875c0a --- /dev/null +++ b/packages/core/src/features/hotbar/storage/storage-technical.test.ts @@ -0,0 +1,373 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { anyObject } from "jest-mock-extended"; +import type { CatalogEntity, CatalogEntityData, CatalogEntityKindData } from "../../../common/catalog"; +import { getDiForUnitTesting } from "../../../main/getDiForUnitTesting"; +import type { DiContainer } from "@ogre-tools/injectable"; +import catalogEntityRegistryInjectable from "../../../main/catalog/entity-registry.injectable"; +import type { IComputedValue } from "mobx"; +import { computed } from "mobx"; +import hasCategoryForEntityInjectable from "../../../common/catalog/has-category-for-entity.injectable"; +import catalogCatalogEntityInjectable from "../../../common/catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable"; +import loggerInjectable from "../../../common/logger.injectable"; +import type { Logger } from "../../../common/logger"; +import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; +import storeMigrationVersionInjectable from "../../../common/vars/store-migration-version.injectable"; +import writeJsonSyncInjectable from "../../../common/fs/write-json-sync.injectable"; +import type { SetAsActiveHotbar } from "./common/set-as-active.injectable"; +import setAsActiveHotbarInjectable from "./common/set-as-active.injectable"; +import hotbarsPersistentStorageInjectable from "./common/storage.injectable"; +import type { Hotbar } from "./common/hotbar"; +import hotbarsInjectable from "./common/hotbars.injectable"; +import activeHotbarInjectable from "./common/active.injectable"; +import type { AddHotbar } from "./common/add.injectable"; +import type { GetHotbarById } from "./common/get-by-id.injectable"; +import getHotbarByIdInjectable from "./common/get-by-id.injectable"; +import addHotbarInjectable from "./common/add.injectable"; +import { defaultHotbarCells } from "./common/types"; + +function getMockCatalogEntity(data: Partial & CatalogEntityKindData): CatalogEntity { + return { + getName: jest.fn(() => data.metadata?.name), + getId: jest.fn(() => data.metadata?.uid), + getSource: jest.fn(() => data.metadata?.source ?? "unknown"), + isEnabled: jest.fn(() => data.status?.enabled ?? true), + onContextMenuOpen: jest.fn(), + onSettingsOpen: jest.fn(), + metadata: {}, + spec: {}, + status: {}, + ...data, + } as CatalogEntity; +} + +describe("Hotbars technical tests", () => { + let di: DiContainer; + let testCluster: CatalogEntity; + let minikubeCluster: CatalogEntity; + let awsCluster: CatalogEntity; + let loggerMock: jest.Mocked; + let setAsActiveHotbar: SetAsActiveHotbar; + let hotbars: IComputedValue; + let activeHotbar: IComputedValue; + let addHotbar: AddHotbar; + let getHotbarById: GetHotbarById; + + beforeEach(async () => { + di = getDiForUnitTesting(); + + testCluster = getMockCatalogEntity({ + apiVersion: "v1", + kind: "Cluster", + status: { + phase: "Running", + }, + metadata: { + uid: "some-test-id", + name: "my-test-cluster", + source: "local", + labels: {}, + }, + }); + minikubeCluster = getMockCatalogEntity({ + apiVersion: "v1", + kind: "Cluster", + status: { + phase: "Running", + }, + metadata: { + uid: "some-minikube-id", + name: "my-minikube-cluster", + source: "local", + labels: {}, + }, + }); + awsCluster = getMockCatalogEntity({ + apiVersion: "v1", + kind: "Cluster", + status: { + phase: "Running", + }, + metadata: { + uid: "some-aws-id", + name: "my-aws-cluster", + source: "local", + labels: {}, + }, + }); + + di.override(hasCategoryForEntityInjectable, () => () => true); + + loggerMock = { + warn: jest.fn(), + debug: jest.fn(), + error: jest.fn(), + info: jest.fn(), + silly: jest.fn(), + }; + + di.override(loggerInjectable, () => loggerMock); + + di.override(directoryForUserDataInjectable, () => "/some-directory-for-user-data"); + + const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable); + const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable); + + catalogEntityRegistry.addComputedSource("some-id", computed(() => [ + testCluster, + minikubeCluster, + awsCluster, + catalogCatalogEntity, + ])); + + setAsActiveHotbar = di.inject(setAsActiveHotbarInjectable); + hotbars = di.inject(hotbarsInjectable); + activeHotbar = di.inject(activeHotbarInjectable); + addHotbar = di.inject(addHotbarInjectable); + getHotbarById = di.inject(getHotbarByIdInjectable); + }); + + describe("given no previous data in store, running all migrations", () => { + beforeEach(() => { + di.override(storeMigrationVersionInjectable, () => "9999.0.0"); + di.inject(hotbarsPersistentStorageInjectable).loadAndStartSyncing(); + }); + + describe("load", () => { + it("loads one hotbar by default", () => { + expect(hotbars.get().length).toEqual(1); + }); + }); + + describe("add", () => { + it("adds a hotbar", () => { + addHotbar({ name: "hottest" }); + expect(hotbars.get().length).toEqual(2); + }); + }); + + describe("hotbar items", () => { + it("initially creates default number of empty cells", () => { + expect(activeHotbar.get()?.items?.length).toEqual(defaultHotbarCells); + }); + + it("initially adds catalog entity as first item", () => { + expect(activeHotbar.get()?.items[0]?.entity.name).toEqual("Catalog"); + }); + + it("adds items", () => { + activeHotbar.get()?.addEntity(testCluster); + const items = activeHotbar.get()?.items.filter(Boolean); + + expect(items?.length).toEqual(2); + }); + + it("removes items", () => { + activeHotbar.get()?.addEntity(testCluster); + activeHotbar.get()?.removeEntity("some-test-id"); + activeHotbar.get()?.removeEntity("catalog-entity"); + const items = activeHotbar.get()?.items.filter(Boolean); + + expect(items).toStrictEqual([]); + }); + + it("does nothing if removing with invalid uid", () => { + activeHotbar.get()?.addEntity(testCluster); + activeHotbar.get()?.removeEntity("invalid uid"); + const items = activeHotbar.get()?.items.filter(Boolean); + + expect(items?.length).toEqual(2); + }); + + it("moves item to empty cell", () => { + activeHotbar.get()?.addEntity(testCluster); + activeHotbar.get()?.addEntity(minikubeCluster); + activeHotbar.get()?.addEntity(awsCluster); + + expect(activeHotbar.get()?.items[6]).toBeNull(); + + activeHotbar.get()?.restack(1, 5); + + expect(activeHotbar.get()?.items[5]).toBeTruthy(); + expect(activeHotbar.get()?.items[5]?.entity.uid).toEqual("some-test-id"); + }); + + it("moves items down", () => { + activeHotbar.get()?.addEntity(testCluster); + activeHotbar.get()?.addEntity(minikubeCluster); + activeHotbar.get()?.addEntity(awsCluster); + + // aws -> catalog + activeHotbar.get()?.restack(3, 0); + + const items = activeHotbar.get()?.items.map(item => item?.entity.uid || null); + + expect(items?.slice(0, 4)).toEqual(["some-aws-id", "catalog-entity", "some-test-id", "some-minikube-id"]); + }); + + it("moves items up", () => { + activeHotbar.get()?.addEntity(testCluster); + activeHotbar.get()?.addEntity(minikubeCluster); + activeHotbar.get()?.addEntity(awsCluster); + + // test -> aws + activeHotbar.get()?.restack(1, 3); + + const items = activeHotbar.get()?.items.map(item => item?.entity.uid || null); + + expect(items?.slice(0, 4)).toEqual(["catalog-entity", "some-minikube-id", "some-aws-id", "some-test-id"]); + }); + + it("logs an error if cellIndex is out of bounds", () => { + addHotbar({ name: "hottest", id: "hottest" }); + setAsActiveHotbar("hottest"); + + activeHotbar.get()?.addEntity(testCluster, -1); + expect(loggerMock.error).toBeCalledWith("[HOTBAR]: cannot pin entity to hotbar outside of index range", anyObject()); + + activeHotbar.get()?.addEntity(testCluster, 12); + expect(loggerMock.error).toBeCalledWith("[HOTBAR]: cannot pin entity to hotbar outside of index range", anyObject()); + + activeHotbar.get()?.addEntity(testCluster, 13); + expect(loggerMock.error).toBeCalledWith("[HOTBAR]: cannot pin entity to hotbar outside of index range", anyObject()); + }); + + it("throws an error if getId is invalid or returns not a string", () => { + expect(() => activeHotbar.get()?.addEntity({} as any)).toThrowError(TypeError); + expect(() => activeHotbar.get()?.addEntity({ getId: () => true } as any)).toThrowError(TypeError); + }); + + it("throws an error if getName is invalid or returns not a string", () => { + expect(() => activeHotbar.get()?.addEntity({ getId: () => "" } as any)).toThrowError(TypeError); + expect(() => activeHotbar.get()?.addEntity({ getId: () => "", getName: () => 4 } as any)).toThrowError(TypeError); + }); + + it("does nothing when item moved to same cell", () => { + activeHotbar.get()?.addEntity(testCluster); + activeHotbar.get()?.restack(1, 1); + + expect(activeHotbar.get()?.items[1]?.entity.uid).toEqual("some-test-id"); + }); + + it("new items takes first empty cell", () => { + activeHotbar.get()?.addEntity(testCluster); + activeHotbar.get()?.addEntity(awsCluster); + activeHotbar.get()?.restack(0, 3); + activeHotbar.get()?.addEntity(minikubeCluster); + + expect(activeHotbar.get()?.items[0]?.entity.uid).toEqual("some-minikube-id"); + }); + + it("throws if invalid arguments provided", () => { + activeHotbar.get()?.addEntity(testCluster); + + expect(() => activeHotbar.get()?.restack(-5, 0)).toThrow(); + expect(() => activeHotbar.get()?.restack(2, -1)).toThrow(); + expect(() => activeHotbar.get()?.restack(14, 1)).toThrow(); + expect(() => activeHotbar.get()?.restack(11, 112)).toThrow(); + }); + + it("checks if entity already pinned to hotbar", () => { + activeHotbar.get()?.addEntity(testCluster); + + expect(activeHotbar.get()?.hasEntity(testCluster.getId())).toBeTruthy(); + expect(activeHotbar.get()?.hasEntity(awsCluster.getId())).toBeFalsy(); + }); + }); + }); + + describe("given data from 5.0.0-beta.3 and version being 5.0.0-beta.10", () => { + beforeEach(() => { + const writeJsonSync = di.inject(writeJsonSyncInjectable); + + writeJsonSync("/some-directory-for-user-data/lens-hotbar-store.json", { + __internal__: { + migrations: { + version: "5.0.0-beta.3", + }, + }, + hotbars: [ + { + id: "3caac17f-aec2-4723-9694-ad204465d935", + name: "myhotbar", + items: [ + { + entity: { + uid: "some-aws-id", + }, + }, + { + entity: { + uid: "55b42c3c7ba3b04193416cda405269a5", + }, + }, + { + entity: { + uid: "176fd331968660832f62283219d7eb6e", + }, + }, + { + entity: { + uid: "61c4fb45528840ebad1badc25da41d14", + name: "user1-context", + source: "local", + }, + }, + { + entity: { + uid: "27d6f99fe9e7548a6e306760bfe19969", + name: "foo2", + source: "local", + }, + }, + null, + { + entity: { + uid: "c0b20040646849bb4dcf773e43a0bf27", + name: "multinode-demo", + source: "local", + }, + }, + null, + null, + null, + null, + null, + ], + }, + ], + }); + + di.override(storeMigrationVersionInjectable, () => "5.0.0-beta.10"); + + di.inject(hotbarsPersistentStorageInjectable).loadAndStartSyncing(); + }); + + it("allows to retrieve a hotbar", () => { + const hotbar = getHotbarById("3caac17f-aec2-4723-9694-ad204465d935"); + + expect(hotbar?.id).toBe("3caac17f-aec2-4723-9694-ad204465d935"); + }); + + it("clears cells without entity", () => { + const items = hotbars.get()[0].items; + + expect(items[2]).toBeNull(); + }); + + it("adds extra data to cells with according entity", () => { + const items = hotbars.get()[0].items; + + expect(items[0]).toEqual({ + entity: { + name: "my-aws-cluster", + source: "local", + uid: "some-aws-id", + }, + }); + }); + }); +}); diff --git a/packages/core/src/features/preferences/__snapshots__/closing-preferences.test.tsx.snap b/packages/core/src/features/preferences/__snapshots__/closing-preferences.test.tsx.snap index 23530d3cb7..90b64e5302 100644 --- a/packages/core/src/features/preferences/__snapshots__/closing-preferences.test.tsx.snap +++ b/packages/core/src/features/preferences/__snapshots__/closing-preferences.test.tsx.snap @@ -709,7 +709,7 @@ exports[`preferences - closing-preferences given accessing preferences directly class="HotbarSelector" > { - const [customUrl, setCustomUrl] = React.useState(userStore.extensionRegistryUrl.customUrl || ""); +const NonInjectedExtensionInstallRegistry = observer(({ state }: Dependencies) => { + const [customUrl, setCustomUrl] = React.useState(state.extensionRegistryUrl.customUrl || ""); return (
@@ -42,14 +42,14 @@ const NonInjectedExtensionInstallRegistry = observer(({ userStore }: Dependencie - (userStore.colorTheme = value?.value ?? defaultTheme.name) + (state.colorTheme = value?.value ?? defaultTheme.name) } themeName="lens" /> @@ -53,7 +53,7 @@ const NonInjectedTheme = observer(({ export const Theme = withInjectables(NonInjectedTheme, { getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), + state: di.inject(userPreferencesStateInjectable), defaultTheme: di.inject(defaultLensThemeInjectable), themes: di.injectMany(lensThemeDeclarationInjectionToken), }), diff --git a/packages/core/src/features/preferences/renderer/preference-items/application/timezone/timezone.tsx b/packages/core/src/features/preferences/renderer/preference-items/application/timezone/timezone.tsx index c3ee8f2ea1..987f378bd9 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/application/timezone/timezone.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/application/timezone/timezone.tsx @@ -5,15 +5,15 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { Select } from "../../../../../../renderer/components/select"; import moment from "moment-timezone"; import { observer } from "mobx-react"; -import currentTimezoneInjectable from "../../../../../../common/user-store/current-timezone.injectable"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import currentTimezoneInjectable from "../../../../../../common/vars/current-timezone.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; currentTimezone: string; } @@ -23,9 +23,8 @@ const timezoneOptions = moment.tz.names() label: timezone.replace("_", " "), })); - const NonInjectedTimezone = observer(({ - userStore, + state, currentTimezone, }: Dependencies) => (
@@ -33,17 +32,16 @@ const NonInjectedTimezone = observer(({ )); -export const EditorFontFamily = withInjectables( - NonInjectedEditorFontFamily, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const EditorFontFamily = withInjectables(NonInjectedEditorFontFamily, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/editor/editor-font-size/editor-font-size.tsx b/packages/core/src/features/preferences/renderer/preference-items/editor/editor-font-size/editor-font-size.tsx index 7fe83ec6aa..df144df2b7 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/editor/editor-font-size/editor-font-size.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/editor/editor-font-size/editor-font-size.tsx @@ -5,16 +5,16 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { Input, InputValidators } from "../../../../../../renderer/components/input"; import { observer } from "mobx-react"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } -const NonInjectedEditorFontSize = observer(({ userStore: { editorConfiguration }}: Dependencies) => ( +const NonInjectedEditorFontSize = observer(({ state: { editorConfiguration }}: Dependencies) => (
)); -export const EditorFontSize = withInjectables( - NonInjectedEditorFontSize, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const EditorFontSize = withInjectables(NonInjectedEditorFontSize, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/editor/line-numbers/line-numbers.tsx b/packages/core/src/features/preferences/renderer/preference-items/editor/line-numbers/line-numbers.tsx index 10cc508baa..bfd73f7415 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/editor/line-numbers/line-numbers.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/editor/line-numbers/line-numbers.tsx @@ -5,15 +5,15 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { Select } from "../../../../../../renderer/components/select"; -import { defaultEditorConfig } from "../../../../../../common/user-store/preferences-helpers"; import { capitalize } from "lodash/fp"; import { observer } from "mobx-react"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import { defaultEditorConfig } from "../../../../../user-preferences/common/preferences-helpers"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } const lineNumberOptions = ([ @@ -26,7 +26,7 @@ const lineNumberOptions = ([ label: capitalize(lineNumbers), })); -const NonInjectedLineNumbers = observer(({ userStore: { editorConfiguration }}: Dependencies) => ( +const NonInjectedLineNumbers = observer(({ state: { editorConfiguration }}: Dependencies) => (
)); -export const TabSize = withInjectables( - NonInjectedTabSize, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const TabSize = withInjectables(NonInjectedTabSize, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubeconfig-sync/kubeconfig-sync.tsx b/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubeconfig-sync/kubeconfig-sync.tsx index 77642f1082..510fbd0115 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubeconfig-sync/kubeconfig-sync.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubeconfig-sync/kubeconfig-sync.tsx @@ -7,13 +7,11 @@ import { computed, makeObservable, observable, reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import React from "react"; import { Notice } from "../../../../../../renderer/components/+extensions/notice"; -import type { UserStore } from "../../../../../../common/user-store"; import { iter, tuple } from "@k8slens/utilities"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { PathPicker } from "../../../../../../renderer/components/path-picker/path-picker"; import { Spinner } from "../../../../../../renderer/components/spinner"; import { RemovableItem } from "../../../removable-item/removable-item"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import isWindowsInjectable from "../../../../../../common/vars/is-windows.injectable"; import loggerInjectable from "../../../../../../common/logger.injectable"; import type { Logger } from "../../../../../../common/logger"; @@ -21,13 +19,15 @@ import type { DiscoverAllKubeconfigSyncKinds } from "./discover-all-sync-kinds.i import type { DiscoverKubeconfigSyncKind, SyncKind } from "./discover-sync-kind.injectable"; import discoverKubeconfigSyncKindInjectable from "./discover-sync-kind.injectable"; import discoverAllKubeconfigSyncKindsInjectable from "./discover-all-sync-kinds.injectable"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Entry extends SyncKind { filePath: string; } interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; isWindows: boolean; logger: Logger; discoverAllKubeconfigSyncKinds: DiscoverAllKubeconfigSyncKinds; @@ -47,7 +47,7 @@ class NonInjectedKubeconfigSync extends React.Component { async componentDidMount() { const mapEntries = await Promise.all( iter.map( - this.props.userStore.syncKubeconfigEntries, + this.props.state.syncKubeconfigEntries, ([filePath]) => this.props.discoverKubeconfigSyncKind(filePath), ), ); @@ -59,7 +59,7 @@ class NonInjectedKubeconfigSync extends React.Component { reaction( () => Array.from(this.syncs.entries(), ([filePath, kind]) => tuple.from(filePath, kind)), syncs => { - this.props.userStore.syncKubeconfigEntries.replace(syncs); + this.props.state.syncKubeconfigEntries.replace(syncs); }, ), ]); @@ -177,7 +177,7 @@ class NonInjectedKubeconfigSync extends React.Component { export const KubeconfigSync = withInjectables(NonInjectedKubeconfigSync, { getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), + state: di.inject(userPreferencesStateInjectable), isWindows: di.inject(isWindowsInjectable), logger: di.inject(loggerInjectable), discoverAllKubeconfigSyncKinds: di.inject(discoverAllKubeconfigSyncKindsInjectable), diff --git a/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-binary-download/kubectl-binary-download.tsx b/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-binary-download/kubectl-binary-download.tsx index de096191fd..35d0ebff62 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-binary-download/kubectl-binary-download.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-binary-download/kubectl-binary-download.tsx @@ -5,34 +5,29 @@ import React from "react"; import { SubTitle } from "../../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Switch } from "../../../../../../../renderer/components/switch"; +import type { UserPreferencesState } from "../../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } -const NonInjectedKubectlBinaryDownload = observer(({ userStore }: Dependencies) => ( +const NonInjectedKubectlBinaryDownload = observer(({ state }: Dependencies) => (
userStore.downloadKubectlBinaries = !userStore.downloadKubectlBinaries} + checked={state.downloadKubectlBinaries} + onChange={() => state.downloadKubectlBinaries = !state.downloadKubectlBinaries} > Download kubectl binaries matching the Kubernetes cluster version
- )); -export const KubectlBinaryDownload = withInjectables( - NonInjectedKubectlBinaryDownload, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const KubectlBinaryDownload = withInjectables(NonInjectedKubectlBinaryDownload, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-directory-for-binaries/kubectl-directory-for-binaries.tsx b/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-directory-for-binaries/kubectl-directory-for-binaries.tsx index 497ec68f8e..7e4bc8a2ab 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-directory-for-binaries/kubectl-directory-for-binaries.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-directory-for-binaries/kubectl-directory-for-binaries.tsx @@ -5,24 +5,24 @@ import React, { useState } from "react"; import { SubTitle } from "../../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Input, InputValidators } from "../../../../../../../renderer/components/input"; import directoryForBinariesInjectable from "../../../../../../../common/app-paths/directory-for-binaries/directory-for-binaries.injectable"; +import type { UserPreferencesState } from "../../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; defaultPathForGeneralBinaries: string; } const NonInjectedKubectlDirectoryForBinaries = observer( - ({ userStore, defaultPathForGeneralBinaries }: Dependencies) => { - const [downloadPath, setDownloadPath] = useState(userStore.downloadBinariesPath || ""); + ({ state, defaultPathForGeneralBinaries }: Dependencies) => { + const [downloadPath, setDownloadPath] = useState(state.downloadBinariesPath || ""); const pathValidator = downloadPath ? InputValidators.isPath : undefined; const save = () => { - userStore.downloadBinariesPath = downloadPath; + state.downloadBinariesPath = downloadPath; }; return ( @@ -35,7 +35,7 @@ const NonInjectedKubectlDirectoryForBinaries = observer( validators={pathValidator} onChange={setDownloadPath} onBlur={save} - disabled={!userStore.downloadKubectlBinaries} + disabled={!state.downloadKubectlBinaries} />
The directory to download binaries into.
@@ -43,13 +43,9 @@ const NonInjectedKubectlDirectoryForBinaries = observer( }, ); -export const KubectlDirectoryForBinaries = withInjectables( - NonInjectedKubectlDirectoryForBinaries, - - { - getProps: (di) => ({ - defaultPathForGeneralBinaries: di.inject(directoryForBinariesInjectable), - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const KubectlDirectoryForBinaries = withInjectables(NonInjectedKubectlDirectoryForBinaries, { + getProps: (di) => ({ + defaultPathForGeneralBinaries: di.inject(directoryForBinariesInjectable), + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-download-mirror/kubectl-download-mirror.tsx b/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-download-mirror/kubectl-download-mirror.tsx index e880ff3308..7f01d8a933 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-download-mirror/kubectl-download-mirror.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/kubernetes/kubectl/kubectl-download-mirror/kubectl-download-mirror.tsx @@ -5,14 +5,14 @@ import React from "react"; import { SubTitle } from "../../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Select } from "../../../../../../../renderer/components/select"; -import { defaultPackageMirror, packageMirrors } from "../../../../../../../common/user-store/preferences-helpers"; +import { defaultPackageMirror, packageMirrors } from "../../../../../../user-preferences/common/preferences-helpers"; +import type { UserPreferencesState } from "../../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } const downloadMirrorOptions = Array.from(packageMirrors, ([name, mirror]) => ({ @@ -24,27 +24,23 @@ const downloadMirrorOptions = Array.from(packageMirrors, ([name, mirror]) => ({ })); -const NonInjectedKubectlDownloadMirror = observer(({ userStore }: Dependencies) => ( +const NonInjectedKubectlDownloadMirror = observer(({ state }: Dependencies) => (
-
- ); - }, + return ( +
+ + +
+ ); +}, ); -export const KubectlPathToBinary = withInjectables( - NonInjectedKubectlPathToBinary, - - { - getProps: (di) => ({ - defaultPathForKubectlBinaries: di.inject(directoryForKubectlBinariesInjectable), - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const KubectlPathToBinary = withInjectables(NonInjectedKubectlPathToBinary, { + getProps: (di) => ({ + defaultPathForKubectlBinaries: di.inject(directoryForKubectlBinariesInjectable), + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/proxy/allow-untrusted-certificates/allow-untrusted-certificates.tsx b/packages/core/src/features/preferences/renderer/preference-items/proxy/allow-untrusted-certificates/allow-untrusted-certificates.tsx index bb1abd9a57..eea78f6cda 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/proxy/allow-untrusted-certificates/allow-untrusted-certificates.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/proxy/allow-untrusted-certificates/allow-untrusted-certificates.tsx @@ -5,23 +5,21 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Switch } from "../../../../../../renderer/components/switch"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } -const NonInjectedAllowUntrustedCertificates = observer(({ userStore }: Dependencies) => ( +const NonInjectedAllowUntrustedCertificates = observer(({ state }: Dependencies) => (
- (userStore.allowUntrustedCAs = !userStore.allowUntrustedCAs) - } + checked={state.allowUntrustedCAs} + onChange={() => state.allowUntrustedCAs = !state.allowUntrustedCAs} > Allow untrusted Certificate Authorities @@ -33,12 +31,8 @@ const NonInjectedAllowUntrustedCertificates = observer(({ userStore }: Dependenc
)); -export const AllowUntrustedCertificates = withInjectables( - NonInjectedAllowUntrustedCertificates, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const AllowUntrustedCertificates = withInjectables(NonInjectedAllowUntrustedCertificates, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/proxy/http-proxy-url/http-proxy-url.tsx b/packages/core/src/features/preferences/renderer/preference-items/proxy/http-proxy-url/http-proxy-url.tsx index 7d55fd2b3b..9cc8e38d4b 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/proxy/http-proxy-url/http-proxy-url.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/proxy/http-proxy-url/http-proxy-url.tsx @@ -5,43 +5,39 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Input } from "../../../../../../renderer/components/input"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } -const NonInjectedHttpProxyUrl = observer( - ({ userStore }: Dependencies) => { - const [proxy, setProxy] = React.useState(userStore.httpsProxy || ""); +const NonInjectedHttpProxyUrl = observer(({ + state, +}: Dependencies) => { + const [proxy, setProxy] = React.useState(state.httpsProxy || ""); - return ( -
- - setProxy(v)} - onBlur={() => (userStore.httpsProxy = proxy)} - /> - - Proxy is used only for non-cluster communication. - -
- ); - }, -); + return ( +
+ + setProxy(v)} + onBlur={() => (state.httpsProxy = proxy)} + /> + + Proxy is used only for non-cluster communication. + +
+ ); +}); -export const HttpProxyUrl = withInjectables( - NonInjectedHttpProxyUrl, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const HttpProxyUrl = withInjectables(NonInjectedHttpProxyUrl, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/telemetry/automatic-error-reporting/automatic-error-reporting.tsx b/packages/core/src/features/preferences/renderer/preference-items/telemetry/automatic-error-reporting/automatic-error-reporting.tsx index 7e23c0af35..167189fffc 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/telemetry/automatic-error-reporting/automatic-error-reporting.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/telemetry/automatic-error-reporting/automatic-error-reporting.tsx @@ -5,16 +5,16 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Checkbox } from "../../../../../../renderer/components/checkbox"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } -const NonInjectedAutomaticErrorReporting = observer(({ userStore }: Dependencies) => ( +const NonInjectedAutomaticErrorReporting = observer(({ state }: Dependencies) => (
(userStore.allowErrorReporting = value)} + value={state.allowErrorReporting} + onChange={(value) => (state.allowErrorReporting = value)} />
@@ -36,12 +36,8 @@ const NonInjectedAutomaticErrorReporting = observer(({ userStore }: Dependencies
)); -export const AutomaticErrorReporting = withInjectables( - NonInjectedAutomaticErrorReporting, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const AutomaticErrorReporting = withInjectables(NonInjectedAutomaticErrorReporting, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/terminal/copy-paste-from-terminal/copy-paste-from-terminal.tsx b/packages/core/src/features/preferences/renderer/preference-items/terminal/copy-paste-from-terminal/copy-paste-from-terminal.tsx index 6fd65ccbbd..8e1f6701d8 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/terminal/copy-paste-from-terminal/copy-paste-from-terminal.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/terminal/copy-paste-from-terminal/copy-paste-from-terminal.tsx @@ -5,38 +5,31 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Switch } from "../../../../../../renderer/components/switch"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } -const NonInjectedCopyPasteFromTerminal = observer( - ({ userStore }: Dependencies) => { +const NonInjectedCopyPasteFromTerminal = observer(({ + state, +}: Dependencies) => ( +
+ + state.terminalCopyOnSelect = !state.terminalCopyOnSelect} + > + Copy on select and paste on right-click + +
+)); - return ( -
- - userStore.terminalCopyOnSelect = !userStore.terminalCopyOnSelect} - > - Copy on select and paste on right-click - -
- ); - }, -); - -export const CopyPasteFromTerminal = withInjectables( - NonInjectedCopyPasteFromTerminal, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const CopyPasteFromTerminal = withInjectables(NonInjectedCopyPasteFromTerminal, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-font-family/terminal-font-options.injectable.tsx b/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-font-family/terminal-font-options.injectable.tsx index 3d6a0d2ae0..ceedb3fe02 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-font-family/terminal-font-options.injectable.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-font-family/terminal-font-options.injectable.tsx @@ -7,10 +7,10 @@ import type { IComputedValue } from "mobx"; import { action, computed } from "mobx"; import React from "react"; import type { SingleValue } from "react-select"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { defaultTerminalFontFamily } from "../../../../../../common/vars"; import type { SelectOption } from "../../../../../../renderer/components/select"; import { terminalFontInjectionToken } from "../../../../../terminal/renderer/fonts/token"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; export interface TerminalFontPreferencePresenter { readonly options: IComputedValue[]>; @@ -21,7 +21,7 @@ export interface TerminalFontPreferencePresenter { const terminalFontPreferencePresenterInjectable = getInjectable({ id: "terminal-font-preference-presenter", instantiate: (di): TerminalFontPreferencePresenter => { - const userStore = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); const terminalFonts = di.injectMany(terminalFontInjectionToken); return { @@ -30,18 +30,18 @@ const terminalFontPreferencePresenterInjectable = getInjectable({ {font.name} ), value: font.name, - isSelected: userStore.terminalConfig.fontFamily === font.name, + isSelected: state.terminalConfig.fontFamily === font.name, }))), - current: computed(() => userStore.terminalConfig.fontFamily), + current: computed(() => state.terminalConfig.fontFamily), onSelection: action(selection => { - userStore.terminalConfig.fontFamily = selection?.value ?? defaultTerminalFontFamily; + state.terminalConfig.fontFamily = selection?.value ?? defaultTerminalFontFamily; }), }; }, diff --git a/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-font-size/terminal-font-size.tsx b/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-font-size/terminal-font-size.tsx index bf11285509..75a6a35242 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-font-size/terminal-font-size.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-font-size/terminal-font-size.tsx @@ -5,40 +5,32 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Input } from "../../../../../../renderer/components/input"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } -const NonInjectedTerminalFontSize = observer( - ({ userStore }: Dependencies) => { +const NonInjectedTerminalFontSize = observer(({ + state, +}: Dependencies) => ( +
+ + state.terminalConfig.fontSize = Number(value)} /> +
+)); - return ( -
- - userStore.terminalConfig.fontSize = Number(value)} - /> -
- ); - }, -); - -export const TerminalFontSize = withInjectables( - NonInjectedTerminalFontSize, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - }), - }, -); +export const TerminalFontSize = withInjectables(NonInjectedTerminalFontSize, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-shell-path/terminal-shell-path.tsx b/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-shell-path/terminal-shell-path.tsx index 5fe14ab9df..bb5deaefe4 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-shell-path/terminal-shell-path.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-shell-path/terminal-shell-path.tsx @@ -5,42 +5,35 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Input } from "../../../../../../renderer/components/input"; import defaultShellInjectable from "./default-shell/default-shell.injectable"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; defaultShell: string; } -const NonInjectedTerminalShellPath = observer( - ({ userStore, defaultShell }: Dependencies) => { +const NonInjectedTerminalShellPath = observer(({ + state, + defaultShell, +}: Dependencies) => ( +
+ + state.shell = value} + /> +
+)); - return ( -
- - userStore.shell = value} - /> -
- - ); - }, -); - -export const TerminalShellPath = withInjectables( - NonInjectedTerminalShellPath, - - { - getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), - defaultShell: di.inject(defaultShellInjectable), - }), - }, -); +export const TerminalShellPath = withInjectables(NonInjectedTerminalShellPath, { + getProps: (di) => ({ + state: di.inject(userPreferencesStateInjectable), + defaultShell: di.inject(defaultShellInjectable), + }), +}); diff --git a/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-theme/terminal-theme.tsx b/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-theme/terminal-theme.tsx index bea6b1279e..5819171c8c 100644 --- a/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-theme/terminal-theme.tsx +++ b/packages/core/src/features/preferences/renderer/preference-items/terminal/terminal-theme/terminal-theme.tsx @@ -5,26 +5,25 @@ import React from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { UserStore } from "../../../../../../common/user-store"; -import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable"; import { observer } from "mobx-react"; import { Select } from "../../../../../../renderer/components/select"; import type { LensTheme } from "../../../../../../renderer/themes/lens-theme"; import { lensThemeDeclarationInjectionToken } from "../../../../../../renderer/themes/declaration"; +import type { UserPreferencesState } from "../../../../../user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../../user-preferences/common/state.injectable"; interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; themes: LensTheme[]; } const NonInjectedTerminalTheme = observer(({ - userStore, + state, themes, }: Dependencies) => { - const themeOptions = [ { - value: "", // TODO: replace with a sentinal value that isn't string (and serialize it differently) + value: "", // TODO: replace with a sentinel value that isn't string (and serialize it differently) label: "Match Lens Theme", }, ...themes.map(theme => ({ @@ -40,8 +39,8 @@ const NonInjectedTerminalTheme = observer(({ id="terminal-theme-input" themeName="lens" options={themeOptions} - value={userStore.terminalTheme} - onChange={option => userStore.terminalTheme = option?.value ?? ""} + value={state.terminalTheme} + onChange={option => state.terminalTheme = option?.value ?? ""} />
); @@ -50,7 +49,7 @@ const NonInjectedTerminalTheme = observer(({ export const TerminalTheme = withInjectables(NonInjectedTerminalTheme, { getProps: (di) => ({ - userStore: di.inject(userStoreInjectable), + state: di.inject(userPreferencesStateInjectable), themes: di.injectMany(lensThemeDeclarationInjectionToken), }), }); diff --git a/packages/core/src/features/shell-sync/main/setup-shell.injectable.ts b/packages/core/src/features/shell-sync/main/setup-shell.injectable.ts index 3a763b7426..f7a8b65974 100644 --- a/packages/core/src/features/shell-sync/main/setup-shell.injectable.ts +++ b/packages/core/src/features/shell-sync/main/setup-shell.injectable.ts @@ -8,9 +8,9 @@ import { onLoadOfApplicationInjectionToken } from "@k8slens/application"; import isSnapPackageInjectable from "../../../common/vars/is-snap-package.injectable"; import electronAppInjectable from "../../../main/electron-app/electron-app.injectable"; import computeShellEnvironmentInjectable from "./compute-shell-environment.injectable"; -import userShellSettingInjectable from "../../../common/user-store/shell-setting.injectable"; import emitShellSyncFailedInjectable from "./emit-failure.injectable"; import { unionPATHs } from "@k8slens/utilities"; +import userShellSettingInjectable from "../../user-preferences/common/shell-setting.injectable"; const setupShellInjectable = getInjectable({ id: "setup-shell", diff --git a/packages/core/src/features/status-bar/__snapshots__/status-bar-items-originating-from-extensions.test.tsx.snap b/packages/core/src/features/status-bar/__snapshots__/status-bar-items-originating-from-extensions.test.tsx.snap index f652074bf8..1b21dc2909 100644 --- a/packages/core/src/features/status-bar/__snapshots__/status-bar-items-originating-from-extensions.test.tsx.snap +++ b/packages/core/src/features/status-bar/__snapshots__/status-bar-items-originating-from-extensions.test.tsx.snap @@ -231,7 +231,7 @@ exports[`status-bar-items-originating-from-extensions when application starts wh class="HotbarSelector" > { - const userStore = di.inject(userStoreInjectable); + const userStore = di.inject(userPreferencesStateInjectable); return computed(() => userStore.httpsProxy); }, diff --git a/packages/core/src/features/user-preferences/common/is-table-column-hidden.injectable.ts b/packages/core/src/features/user-preferences/common/is-table-column-hidden.injectable.ts new file mode 100644 index 0000000000..f1e3d72318 --- /dev/null +++ b/packages/core/src/features/user-preferences/common/is-table-column-hidden.injectable.ts @@ -0,0 +1,38 @@ +/** + * 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 userPreferencesStateInjectable from "./state.injectable"; + +/** + * Checks if a column (by ID) for a table (by ID) is configured to be hidden + * @param tableId The ID of the table to be checked against + * @param columnIds The list of IDs the check if one is hidden + * @returns true if at least one column under the table is set to hidden + */ +export type IsTableColumnHidden = (tableId: string, ...columnIds: (string | undefined)[]) => boolean; + +const isTableColumnHiddenInjectable = getInjectable({ + id: "is-table-column-hidden", + instantiate: (di): IsTableColumnHidden => { + const state = di.inject(userPreferencesStateInjectable); + + return (tableId, ...columnIds) => { + if (columnIds.length === 0) { + return false; + } + + const config = state.hiddenTableColumns.get(tableId); + + if (!config) { + return false; + } + + return columnIds.some(columnId => columnId && config.has(columnId)); + }; + }, +}); + +export default isTableColumnHiddenInjectable; diff --git a/packages/core/src/common/user-store/kubeconfig-syncs.injectable.ts b/packages/core/src/features/user-preferences/common/kubeconfig-syncs.injectable.ts similarity index 68% rename from packages/core/src/common/user-store/kubeconfig-syncs.injectable.ts rename to packages/core/src/features/user-preferences/common/kubeconfig-syncs.injectable.ts index 7327b9d8e4..db34b53c1f 100644 --- a/packages/core/src/common/user-store/kubeconfig-syncs.injectable.ts +++ b/packages/core/src/features/user-preferences/common/kubeconfig-syncs.injectable.ts @@ -3,11 +3,11 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import userStoreInjectable from "./user-store.injectable"; +import userPreferencesStateInjectable from "./state.injectable"; const kubeconfigSyncsInjectable = getInjectable({ id: "kubeconfig-syncs", - instantiate: (di) => di.inject(userStoreInjectable).syncKubeconfigEntries, + instantiate: (di) => di.inject(userPreferencesStateInjectable).syncKubeconfigEntries, }); export default kubeconfigSyncsInjectable; diff --git a/packages/core/src/common/user-store/lens-color-theme.injectable.ts b/packages/core/src/features/user-preferences/common/lens-color-theme.injectable.ts similarity index 78% rename from packages/core/src/common/user-store/lens-color-theme.injectable.ts rename to packages/core/src/features/user-preferences/common/lens-color-theme.injectable.ts index 5b48de1a37..1ed2930a37 100644 --- a/packages/core/src/common/user-store/lens-color-theme.injectable.ts +++ b/packages/core/src/features/user-preferences/common/lens-color-theme.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { computed } from "mobx"; -import userStoreInjectable from "./user-store.injectable"; +import userPreferencesStateInjectable from "./state.injectable"; export type LensColorThemePreference = { useSystemTheme: true; @@ -16,11 +16,11 @@ export type LensColorThemePreference = { const lensColorThemePreferenceInjectable = getInjectable({ id: "lens-color-theme-preference", instantiate: (di) => { - const userStore = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); return computed((): LensColorThemePreference => { // TODO: remove magic strings - if (userStore.colorTheme === "system") { + if (state.colorTheme === "system") { return { useSystemTheme: true, }; @@ -28,7 +28,7 @@ const lensColorThemePreferenceInjectable = getInjectable({ return { useSystemTheme: false, - lensThemeId: userStore.colorTheme, + lensThemeId: state.colorTheme, }; }); }, diff --git a/packages/core/src/features/user-preferences/common/migrations-token.ts b/packages/core/src/features/user-preferences/common/migrations-token.ts new file mode 100644 index 0000000000..0da426e3e6 --- /dev/null +++ b/packages/core/src/features/user-preferences/common/migrations-token.ts @@ -0,0 +1,11 @@ +/** + * 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 type { MigrationDeclaration } from "../../../common/persistent-storage/migrations.injectable"; + +export const userPreferencesMigrationInjectionToken = getInjectionToken({ + id: "user-preferences-migration-token", +}); diff --git a/packages/core/src/common/user-store/preference-descriptors.injectable.ts b/packages/core/src/features/user-preferences/common/preference-descriptors.injectable.ts similarity index 89% rename from packages/core/src/common/user-store/preference-descriptors.injectable.ts rename to packages/core/src/features/user-preferences/common/preference-descriptors.injectable.ts index 35815dbbea..afb84cb892 100644 --- a/packages/core/src/common/user-store/preference-descriptors.injectable.ts +++ b/packages/core/src/features/user-preferences/common/preference-descriptors.injectable.ts @@ -6,17 +6,17 @@ import { getInjectable } from "@ogre-tools/injectable"; import { merge } from "lodash"; import type { ObservableMap } from "mobx"; import { observable } from "mobx"; -import homeDirectoryPathInjectable from "../os/home-directory-path.injectable"; -import joinPathsInjectable from "../path/join-paths.injectable"; -import { defaultThemeId } from "../vars"; -import currentTimezoneInjectable from "./current-timezone.injectable"; +import homeDirectoryPathInjectable from "../../../common/os/home-directory-path.injectable"; +import joinPathsInjectable from "../../../common/path/join-paths.injectable"; +import { defaultThemeId } from "../../../common/vars"; +import currentTimezoneInjectable from "../../../common/vars/current-timezone.injectable"; import type { EditorConfiguration, ExtensionRegistry, KubeconfigSyncEntry, KubeconfigSyncValue, TerminalConfig } from "./preferences-helpers"; import { defaultExtensionRegistryUrlLocation, defaultEditorConfig, defaultTerminalConfig, defaultPackageMirror, getPreferenceDescriptor, packageMirrors } from "./preferences-helpers"; -export type PreferenceDescriptors = ReturnType; +export type PreferenceDescriptors = ReturnType; -const userStorePreferenceDescriptorsInjectable = getInjectable({ - id: "user-store-preference-descriptors", +const userPreferenceDescriptorsInjectable = getInjectable({ + id: "user-preference-descriptors", instantiate: (di) => { const currentTimezone = di.inject(currentTimezoneInjectable); const joinPaths = di.inject(joinPathsInjectable); @@ -140,4 +140,4 @@ const userStorePreferenceDescriptorsInjectable = getInjectable({ }, }); -export default userStorePreferenceDescriptorsInjectable; +export default userPreferenceDescriptorsInjectable; diff --git a/packages/core/src/common/user-store/preferences-helpers.ts b/packages/core/src/features/user-preferences/common/preferences-helpers.ts similarity index 94% rename from packages/core/src/common/user-store/preferences-helpers.ts rename to packages/core/src/features/user-preferences/common/preferences-helpers.ts index ecb9108bee..1a80dccd28 100644 --- a/packages/core/src/common/user-store/preferences-helpers.ts +++ b/packages/core/src/features/user-preferences/common/preferences-helpers.ts @@ -4,7 +4,7 @@ */ import type { editor } from "monaco-editor"; -import { defaultEditorFontFamily, defaultFontSize, defaultTerminalFontFamily } from "../vars"; +import { defaultFontSize, defaultTerminalFontFamily, defaultEditorFontFamily } from "../../../common/vars"; import type { PreferenceDescriptors } from "./preference-descriptors.injectable"; export interface KubeconfigSyncEntry extends KubeconfigSyncValue { @@ -95,5 +95,5 @@ export type UserStoreFlatModel = { }; export type UserPreferencesModel = { - [field in keyof PreferenceDescriptors]: PreferencesModelType; + [field in keyof PreferenceDescriptors]?: PreferencesModelType; } & { updateChannel: string }; diff --git a/packages/core/src/features/user-preferences/common/reset-theme.injectable.ts b/packages/core/src/features/user-preferences/common/reset-theme.injectable.ts new file mode 100644 index 0000000000..cdff170946 --- /dev/null +++ b/packages/core/src/features/user-preferences/common/reset-theme.injectable.ts @@ -0,0 +1,24 @@ +/** + * 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 { action } from "mobx"; +import userPreferenceDescriptorsInjectable from "./preference-descriptors.injectable"; +import userPreferencesStateInjectable from "./state.injectable"; + +export type ResetTheme = () => void; + +const resetThemeInjectable = getInjectable({ + id: "reset-theme", + instantiate: (di): ResetTheme => { + const state = di.inject(userPreferencesStateInjectable); + const preferenceDescriptors = di.inject(userPreferenceDescriptorsInjectable); + + return action(() => { + state.colorTheme = preferenceDescriptors.colorTheme.fromStore(undefined); + }); + }, +}); + +export default resetThemeInjectable; diff --git a/packages/core/src/common/user-store/shell-setting.injectable.ts b/packages/core/src/features/user-preferences/common/shell-setting.injectable.ts similarity index 63% rename from packages/core/src/common/user-store/shell-setting.injectable.ts rename to packages/core/src/features/user-preferences/common/shell-setting.injectable.ts index f93a4e5874..a4f7a42585 100644 --- a/packages/core/src/common/user-store/shell-setting.injectable.ts +++ b/packages/core/src/features/user-preferences/common/shell-setting.injectable.ts @@ -4,16 +4,16 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { computed } from "mobx"; -import userInfoInjectable from "./user-info.injectable"; -import userStoreInjectable from "./user-store.injectable"; +import userInfoInjectable from "../../../common/vars/user-info.injectable"; +import userPreferencesStateInjectable from "./state.injectable"; const userShellSettingInjectable = getInjectable({ id: "user-shell-setting", instantiate: (di) => { - const userStore = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); const userInfo = di.inject(userInfoInjectable); - return computed(() => userStore.shell || userInfo.shell); + return computed(() => state.shell || userInfo.shell); }, }); diff --git a/packages/core/src/features/user-preferences/common/state.injectable.ts b/packages/core/src/features/user-preferences/common/state.injectable.ts new file mode 100644 index 0000000000..53f4ac0356 --- /dev/null +++ b/packages/core/src/features/user-preferences/common/state.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 { getInjectable } from "@ogre-tools/injectable"; +import { observable } from "mobx"; +import type { PreferenceDescriptors } from "./preference-descriptors.injectable"; +import type { StoreType } from "./preferences-helpers"; + +export type UserPreferencesState = { + -readonly [Field in keyof PreferenceDescriptors]: StoreType; +}; + +const userPreferencesStateInjectable = getInjectable({ + id: "user-preferences-state", + instantiate: () => observable.object({} as UserPreferencesState), +}); + +export default userPreferencesStateInjectable; diff --git a/packages/core/src/features/user-preferences/common/storage.injectable.ts b/packages/core/src/features/user-preferences/common/storage.injectable.ts new file mode 100644 index 0000000000..d736c28677 --- /dev/null +++ b/packages/core/src/features/user-preferences/common/storage.injectable.ts @@ -0,0 +1,88 @@ +/** + * 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 { action } from "mobx"; +import prefixedLoggerInjectable from "../../../common/logger/prefixed-logger.injectable"; +import createPersistentStorageInjectable from "../../../common/persistent-storage/create.injectable"; +import persistentStorageMigrationsInjectable from "../../../common/persistent-storage/migrations.injectable"; +import { userPreferencesMigrationInjectionToken } from "./migrations-token"; +import { toJS } from "../../../common/utils"; +import storeMigrationVersionInjectable from "../../../common/vars/store-migration-version.injectable"; +import selectedUpdateChannelInjectable from "../../application-update/common/selected-update-channel/selected-update-channel.injectable"; +import type { ReleaseChannel } from "../../application-update/common/update-channels"; +import userPreferencesStateInjectable from "./state.injectable"; +import userPreferenceDescriptorsInjectable from "./preference-descriptors.injectable"; +import type { UserPreferencesModel } from "./preferences-helpers"; + +export interface UserStoreModel { + preferences: UserPreferencesModel; +} + +const userPreferencesPersistentStorageInjectable = getInjectable({ + id: "user-preferences-persistent-storage", + instantiate: (di) => { + const createPersistentStorage = di.inject(createPersistentStorageInjectable); + const logger = di.inject(prefixedLoggerInjectable, "USER-PREFERENCES"); + const descriptors = di.inject(userPreferenceDescriptorsInjectable); + const selectedUpdateChannel = di.inject(selectedUpdateChannelInjectable); + const state = di.inject(userPreferencesStateInjectable); + + return createPersistentStorage({ + configName: "lens-user-store", + projectVersion: di.inject(storeMigrationVersionInjectable), + migrations: di.inject(persistentStorageMigrationsInjectable, userPreferencesMigrationInjectionToken), + fromStore: action(({ preferences = {}}) => { + logger.debug("fromStore()", { preferences }); + + state.allowErrorReporting = descriptors.allowErrorReporting.fromStore(preferences.allowErrorReporting); + state.allowUntrustedCAs = descriptors.allowUntrustedCAs.fromStore(preferences.allowUntrustedCAs); + state.colorTheme = descriptors.colorTheme.fromStore(preferences.colorTheme); + state.downloadBinariesPath = descriptors.downloadBinariesPath.fromStore(preferences.downloadBinariesPath); + state.downloadKubectlBinaries = descriptors.downloadKubectlBinaries.fromStore(preferences.downloadKubectlBinaries); + state.downloadMirror = descriptors.downloadMirror.fromStore(preferences.downloadMirror); + state.editorConfiguration = descriptors.editorConfiguration.fromStore(preferences.editorConfiguration); + state.extensionRegistryUrl = descriptors.extensionRegistryUrl.fromStore(preferences.extensionRegistryUrl); + state.hiddenTableColumns = descriptors.hiddenTableColumns.fromStore(preferences.hiddenTableColumns); + state.httpsProxy = descriptors.httpsProxy.fromStore(preferences.httpsProxy); + state.kubectlBinariesPath = descriptors.kubectlBinariesPath.fromStore(preferences.kubectlBinariesPath); + state.localeTimezone = descriptors.localeTimezone.fromStore(preferences.localeTimezone); + state.openAtLogin = descriptors.openAtLogin.fromStore(preferences.openAtLogin); + state.shell = descriptors.shell.fromStore(preferences.shell); + state.syncKubeconfigEntries = descriptors.syncKubeconfigEntries.fromStore(preferences.syncKubeconfigEntries); + state.terminalConfig = descriptors.terminalConfig.fromStore(preferences.terminalConfig); + state.terminalCopyOnSelect = descriptors.terminalCopyOnSelect.fromStore(preferences.terminalCopyOnSelect); + state.terminalTheme = descriptors.terminalTheme.fromStore(preferences.terminalTheme); + + // TODO: Switch to action-based saving instead saving stores by reaction + selectedUpdateChannel.setValue(preferences?.updateChannel as ReleaseChannel); + }), + toJSON: () => toJS({ + preferences: { + allowErrorReporting: descriptors.allowErrorReporting.toStore(state.allowErrorReporting), + allowUntrustedCAs: descriptors.allowUntrustedCAs.toStore(state.allowUntrustedCAs), + colorTheme: descriptors.colorTheme.toStore(state.colorTheme), + downloadBinariesPath: descriptors.downloadBinariesPath.toStore(state.downloadBinariesPath), + downloadKubectlBinaries: descriptors.downloadKubectlBinaries.toStore(state.downloadKubectlBinaries), + downloadMirror: descriptors.downloadMirror.toStore(state.downloadMirror), + editorConfiguration: descriptors.editorConfiguration.toStore(state.editorConfiguration), + extensionRegistryUrl: descriptors.extensionRegistryUrl.toStore(state.extensionRegistryUrl), + hiddenTableColumns: descriptors.hiddenTableColumns.toStore(state.hiddenTableColumns), + httpsProxy: descriptors.httpsProxy.toStore(state.httpsProxy), + kubectlBinariesPath: descriptors.kubectlBinariesPath.toStore(state.kubectlBinariesPath), + localeTimezone: descriptors.localeTimezone.toStore(state.localeTimezone), + openAtLogin: descriptors.openAtLogin.toStore(state.openAtLogin), + shell: descriptors.shell.toStore(state.shell), + syncKubeconfigEntries: descriptors.syncKubeconfigEntries.toStore(state.syncKubeconfigEntries), + terminalConfig: descriptors.terminalConfig.toStore(state.terminalConfig), + terminalCopyOnSelect: descriptors.terminalCopyOnSelect.toStore(state.terminalCopyOnSelect), + terminalTheme: descriptors.terminalTheme.toStore(state.terminalTheme), + updateChannel: selectedUpdateChannel.value.get().id, + }, + }), + }); + }, +}); + +export default userPreferencesPersistentStorageInjectable; diff --git a/packages/core/src/common/user-store/terminal-config.injectable.ts b/packages/core/src/features/user-preferences/common/terminal-config.injectable.ts similarity index 60% rename from packages/core/src/common/user-store/terminal-config.injectable.ts rename to packages/core/src/features/user-preferences/common/terminal-config.injectable.ts index 6f5be75eaf..cfa9cffb3c 100644 --- a/packages/core/src/common/user-store/terminal-config.injectable.ts +++ b/packages/core/src/features/user-preferences/common/terminal-config.injectable.ts @@ -3,16 +3,15 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { computed } from "mobx"; -import { toJS } from "../utils"; -import userStoreInjectable from "./user-store.injectable"; +import { computed, toJS } from "mobx"; +import userPreferencesStateInjectable from "./state.injectable"; const terminalConfigInjectable = getInjectable({ id: "terminal-config", instantiate: (di) => { - const store = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); - return computed(() => toJS(store.terminalConfig)); + return computed(() => toJS(state.terminalConfig)); }, }); diff --git a/packages/core/src/common/user-store/terminal-copy-on-select.injectable.ts b/packages/core/src/features/user-preferences/common/terminal-copy-on-select.injectable.ts similarity index 69% rename from packages/core/src/common/user-store/terminal-copy-on-select.injectable.ts rename to packages/core/src/features/user-preferences/common/terminal-copy-on-select.injectable.ts index 543a4f73b9..494b43039a 100644 --- a/packages/core/src/common/user-store/terminal-copy-on-select.injectable.ts +++ b/packages/core/src/features/user-preferences/common/terminal-copy-on-select.injectable.ts @@ -4,14 +4,14 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { computed } from "mobx"; -import userStoreInjectable from "./user-store.injectable"; +import userPreferencesStateInjectable from "./state.injectable"; const terminalCopyOnSelectInjectable = getInjectable({ id: "terminal-copy-on-select", instantiate: (di) => { - const store = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); - return computed(() => store.terminalCopyOnSelect); + return computed(() => state.terminalCopyOnSelect); }, }); diff --git a/packages/core/src/common/user-store/terminal-theme.injectable.ts b/packages/core/src/features/user-preferences/common/terminal-theme.injectable.ts similarity index 79% rename from packages/core/src/common/user-store/terminal-theme.injectable.ts rename to packages/core/src/features/user-preferences/common/terminal-theme.injectable.ts index a0a00c3253..f9e5c6d6f5 100644 --- a/packages/core/src/common/user-store/terminal-theme.injectable.ts +++ b/packages/core/src/features/user-preferences/common/terminal-theme.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { computed } from "mobx"; -import userStoreInjectable from "./user-store.injectable"; +import userPreferencesStateInjectable from "./state.injectable"; export type TerminalThemePreference = { matchLensTheme: true; @@ -16,11 +16,11 @@ export type TerminalThemePreference = { const terminalThemePreferenceInjectable = getInjectable({ id: "terminal-theme-preference", instantiate: (di) => { - const userStore = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); return computed((): TerminalThemePreference => { // NOTE: remove use of magic strings - if (!userStore.terminalTheme) { + if (!state.terminalTheme) { return { matchLensTheme: true, }; @@ -28,7 +28,7 @@ const terminalThemePreferenceInjectable = getInjectable({ return { matchLensTheme: false, - themeId: userStore.terminalTheme, + themeId: state.terminalTheme, }; }); }, diff --git a/packages/core/src/features/user-preferences/common/toggle-table-column-visibility.injectable.ts b/packages/core/src/features/user-preferences/common/toggle-table-column-visibility.injectable.ts new file mode 100644 index 0000000000..94d1d07701 --- /dev/null +++ b/packages/core/src/features/user-preferences/common/toggle-table-column-visibility.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 { getOrInsertSet, toggle } from "@k8slens/utilities"; +import { getInjectable } from "@ogre-tools/injectable"; +import { action } from "mobx"; +import userPreferencesStateInjectable from "./state.injectable"; + +export type ToggleTableColumnVisibility = (tableId: string, columnId: string) => void; + +const toggleTableColumnVisibilityInjectable = getInjectable({ + id: "toggle-table-column-visibility", + instantiate: (di): ToggleTableColumnVisibility => { + const state = di.inject(userPreferencesStateInjectable); + + return action((tableId, columnId) => { + toggle(getOrInsertSet(state.hiddenTableColumns, tableId), columnId); + }); + }, +}); + +export default toggleTableColumnVisibilityInjectable; diff --git a/packages/core/src/main/user-store/migrations/5.0.0-alpha.3.injectable.ts b/packages/core/src/features/user-preferences/main/5.0.0-alpha.3.injectable.ts similarity index 70% rename from packages/core/src/main/user-store/migrations/5.0.0-alpha.3.injectable.ts rename to packages/core/src/features/user-preferences/main/5.0.0-alpha.3.injectable.ts index 617f32ad5d..70127386cb 100644 --- a/packages/core/src/main/user-store/migrations/5.0.0-alpha.3.injectable.ts +++ b/packages/core/src/features/user-preferences/main/5.0.0-alpha.3.injectable.ts @@ -5,14 +5,14 @@ // Switch representation of hiddenTableColumns in store import { getInjectable } from "@ogre-tools/injectable"; -import { userStoreMigrationInjectionToken } from "../../../common/user-store/migrations-token"; +import { userPreferencesMigrationInjectionToken } from "../common/migrations-token"; interface PreV500Alpha3UserPreferencesModel { hiddenTableColumns?: Record; } -const v500Alpha3UserStoreMigrationInjectable = getInjectable({ - id: "v5.0.0-alpha.3-user-store-migration", +const v500Alpha3UserPreferencesStorageMigrationInjectable = getInjectable({ + id: "v5.0.0-alpha.3-preferences-storage-migration", instantiate: () => ({ version: "5.0.0-alpha.3", run(store) { @@ -29,8 +29,8 @@ const v500Alpha3UserStoreMigrationInjectable = getInjectable({ }); }, }), - injectionToken: userStoreMigrationInjectionToken, + injectionToken: userPreferencesMigrationInjectionToken, }); -export default v500Alpha3UserStoreMigrationInjectable; +export default v500Alpha3UserPreferencesStorageMigrationInjectable; diff --git a/packages/core/src/main/user-store/migrations/5.0.3-beta.1.injectable.ts b/packages/core/src/features/user-preferences/main/5.0.3-beta.1.injectable.ts similarity index 87% rename from packages/core/src/main/user-store/migrations/5.0.3-beta.1.injectable.ts rename to packages/core/src/features/user-preferences/main/5.0.3-beta.1.injectable.ts index 7739c67e66..d7baa496b0 100644 --- a/packages/core/src/main/user-store/migrations/5.0.3-beta.1.injectable.ts +++ b/packages/core/src/features/user-preferences/main/5.0.3-beta.1.injectable.ts @@ -3,8 +3,6 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { ClusterStoreModel } from "../../../common/cluster-store/cluster-store"; -import type { KubeconfigSyncEntry, UserPreferencesModel } from "../../../common/user-store"; import { isErrnoException } from "@k8slens/utilities"; import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; import directoryForKubeConfigsInjectable from "../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable"; @@ -12,14 +10,16 @@ import joinPathsInjectable from "../../../common/path/join-paths.injectable"; import isLogicalChildPathInjectable from "../../../common/path/is-logical-child-path.injectable"; import getDirnameOfPathInjectable from "../../../common/path/get-dirname.injectable"; import { getInjectable } from "@ogre-tools/injectable"; -import { userStoreMigrationInjectionToken } from "../../../common/user-store/migrations-token"; +import { userPreferencesMigrationInjectionToken } from "../../../features/user-preferences/common/migrations-token"; import readJsonSyncInjectable from "../../../common/fs/read-json-sync.injectable"; import homeDirectoryPathInjectable from "../../../common/os/home-directory-path.injectable"; import loggerInjectable from "../../../common/logger.injectable"; import pathExistsSyncInjectable from "../../../common/fs/path-exists-sync.injectable"; +import type { ClusterStoreModel } from "../../../features/cluster/storage/common/storage.injectable"; +import type { UserPreferencesModel, KubeconfigSyncEntry } from "../common/preferences-helpers"; -const v503Beta1UserStoreMigrationInjectable = getInjectable({ - id: "v5.0.3-beta.1-user-store-migration", +const v503Beta1UserPreferencesStorageMigrationInjectable = getInjectable({ + id: "v5.0.3-beta.1-preferences-storage-migration", instantiate: (di) => { const userDataPath = di.inject(directoryForUserDataInjectable); const kubeConfigsPath = di.inject(directoryForKubeConfigsInjectable); @@ -85,7 +85,7 @@ const v503Beta1UserStoreMigrationInjectable = getInjectable({ }, }; }, - injectionToken: userStoreMigrationInjectionToken, + injectionToken: userPreferencesMigrationInjectionToken, }); -export default v503Beta1UserStoreMigrationInjectable; +export default v503Beta1UserPreferencesStorageMigrationInjectable; diff --git a/packages/core/src/common/user-store/file-name-migration.injectable.ts b/packages/core/src/features/user-preferences/main/file-name-migration.injectable.ts similarity index 64% rename from packages/core/src/common/user-store/file-name-migration.injectable.ts rename to packages/core/src/features/user-preferences/main/file-name-migration.injectable.ts index 31d5352056..e474e7f5c6 100644 --- a/packages/core/src/common/user-store/file-name-migration.injectable.ts +++ b/packages/core/src/features/user-preferences/main/file-name-migration.injectable.ts @@ -3,28 +3,29 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import fse from "fs-extra"; -import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable"; +import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; import { isErrnoException } from "@k8slens/utilities"; import { getInjectable } from "@ogre-tools/injectable"; -import joinPathsInjectable from "../path/join-paths.injectable"; +import joinPathsInjectable from "../../../common/path/join-paths.injectable"; +import fsInjectable from "../../../common/fs/fs.injectable"; export type UserStoreFileNameMigration = () => Promise; -const userStoreFileNameMigrationInjectable = getInjectable({ - id: "user-store-file-name-migration", +const userPreferencesStorageFileNameMigrationInjectable = getInjectable({ + id: "preferences-storage-file-name-migration", instantiate: (di): UserStoreFileNameMigration => { const userDataPath = di.inject(directoryForUserDataInjectable); const joinPaths = di.inject(joinPathsInjectable); const configJsonPath = joinPaths(userDataPath, "config.json"); const lensUserStoreJsonPath = joinPaths(userDataPath, "lens-user-store.json"); + const { rename, rm } = di.inject(fsInjectable); return async () => { try { - await fse.move(configJsonPath, lensUserStoreJsonPath); + await rename(configJsonPath, lensUserStoreJsonPath); } catch (error) { if (error instanceof Error && error.message === "dest already exists.") { - await fse.remove(configJsonPath); + await rm(configJsonPath); } else if (isErrnoException(error) && error.code === "ENOENT" && error.path === configJsonPath) { // (No such file or directory) return; // file already moved @@ -35,7 +36,6 @@ const userStoreFileNameMigrationInjectable = getInjectable({ } }; }, - causesSideEffects: true, }); -export default userStoreFileNameMigrationInjectable; +export default userPreferencesStorageFileNameMigrationInjectable; diff --git a/packages/core/src/features/user-preferences/main/load-storage.injectable.ts b/packages/core/src/features/user-preferences/main/load-storage.injectable.ts new file mode 100644 index 0000000000..dac1c2aebb --- /dev/null +++ b/packages/core/src/features/user-preferences/main/load-storage.injectable.ts @@ -0,0 +1,26 @@ +/** + * 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 "@k8slens/application"; +import initDefaultUpdateChannelInjectable from "../../../main/vars/default-update-channel/init.injectable"; +import userPreferencesPersistentStorageInjectable from "../common/storage.injectable"; +import userPreferencesStorageFileNameMigrationInjectable from "./file-name-migration.injectable"; + +const loadUserPreferencesStorageInjectable = getInjectable({ + id: "load-user-preferences-storage", + instantiate: (di) => ({ + run: async () => { + const storage = di.inject(userPreferencesPersistentStorageInjectable); + const userStoreFileNameMigration = di.inject(userPreferencesStorageFileNameMigrationInjectable); + + await userStoreFileNameMigration(); + storage.loadAndStartSyncing(); + }, + runAfter: initDefaultUpdateChannelInjectable, + }), + injectionToken: beforeApplicationIsLoadingInjectionToken, +}); + +export default loadUserPreferencesStorageInjectable; diff --git a/packages/core/src/main/user-store/sync-open-at-login-with-os.injectable.ts b/packages/core/src/features/user-preferences/main/sync-open-at-login-with-os.injectable.ts similarity index 72% rename from packages/core/src/main/user-store/sync-open-at-login-with-os.injectable.ts rename to packages/core/src/features/user-preferences/main/sync-open-at-login-with-os.injectable.ts index a06d65163e..41f3dff55c 100644 --- a/packages/core/src/main/user-store/sync-open-at-login-with-os.injectable.ts +++ b/packages/core/src/features/user-preferences/main/sync-open-at-login-with-os.injectable.ts @@ -4,18 +4,18 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { reaction } from "mobx"; -import userStoreInjectable from "../../common/user-store/user-store.injectable"; -import setLoginItemSettingsInjectable from "../electron-app/features/set-login-item-settings.injectable"; +import setLoginItemSettingsInjectable from "../../../main/electron-app/features/set-login-item-settings.injectable"; import { onLoadOfApplicationInjectionToken } from "@k8slens/application"; +import userPreferencesStateInjectable from "../common/state.injectable"; const setupSyncOpenAtLoginWithOsInjectable = getInjectable({ id: "setup-sync-open-at-login-with-os", instantiate: (di) => ({ run: () => { const setLoginItemSettings = di.inject(setLoginItemSettingsInjectable); - const userStore = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); - reaction(() => userStore.openAtLogin, openAtLogin => { + reaction(() => state.openAtLogin, openAtLogin => { setLoginItemSettings({ openAtLogin, openAsHidden: true, diff --git a/packages/core/src/features/user-preferences/renderer/load-storage.injectable.ts b/packages/core/src/features/user-preferences/renderer/load-storage.injectable.ts new file mode 100644 index 0000000000..43e10c1707 --- /dev/null +++ b/packages/core/src/features/user-preferences/renderer/load-storage.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 { beforeFrameStartsSecondInjectionToken } from "../../../renderer/before-frame-starts/tokens"; +import initDefaultUpdateChannelInjectable from "../../../renderer/vars/default-update-channel/init.injectable"; +import userPreferencesPersistentStorageInjectable from "../common/storage.injectable"; + +const loadUserPreferencesStorageInjectable = getInjectable({ + id: "load-user-preferences-storage", + instantiate: (di) => ({ + run: () => { + const storage = di.inject(userPreferencesPersistentStorageInjectable); + + return storage.loadAndStartSyncing(); + }, + runAfter: initDefaultUpdateChannelInjectable, + }), + injectionToken: beforeFrameStartsSecondInjectionToken, +}); + +export default loadUserPreferencesStorageInjectable; diff --git a/packages/core/src/features/weblinks/common/add.injectable.ts b/packages/core/src/features/weblinks/common/add.injectable.ts new file mode 100644 index 0000000000..75450d237d --- /dev/null +++ b/packages/core/src/features/weblinks/common/add.injectable.ts @@ -0,0 +1,41 @@ +/** + * 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 { action } from "mobx"; +import weblinksStateInjectable from "./state.injectable"; +import type { WeblinkData } from "./storage.injectable"; +import * as uuid from "uuid"; +import { getOrInsert } from "@k8slens/utilities"; + +export interface WeblinkCreateOptions { + id?: string; + name: string; + url: string; +} + +export type AddWeblink = (data: WeblinkCreateOptions) => WeblinkData; + +const addWeblinkInjectable = getInjectable({ + id: "add-weblink", + instantiate: (di): AddWeblink => { + const state = di.inject(weblinksStateInjectable); + + return action((data) => { + const { + id = uuid.v4(), + name, + url, + } = data; + + if (state.has(id)) { + throw new Error(`There already exists a weblink with id=${id}`); + } + + return getOrInsert(state, id, { id, name, url }); + }); + }, +}); + +export default addWeblinkInjectable; diff --git a/packages/core/src/common/weblinks-store/migration-token.ts b/packages/core/src/features/weblinks/common/migration-token.ts similarity index 77% rename from packages/core/src/common/weblinks-store/migration-token.ts rename to packages/core/src/features/weblinks/common/migration-token.ts index d1cea9334b..a0d8ce58fc 100644 --- a/packages/core/src/common/weblinks-store/migration-token.ts +++ b/packages/core/src/features/weblinks/common/migration-token.ts @@ -4,7 +4,7 @@ */ import { getInjectionToken } from "@ogre-tools/injectable"; -import type { MigrationDeclaration } from "../base-store/migrations.injectable"; +import type { MigrationDeclaration } from "../../../common/persistent-storage/migrations.injectable"; export const weblinkStoreMigrationInjectionToken = getInjectionToken({ id: "weblink-store-migration-token", diff --git a/packages/core/src/features/weblinks/common/remove.injectable.ts b/packages/core/src/features/weblinks/common/remove.injectable.ts new file mode 100644 index 0000000000..0928903561 --- /dev/null +++ b/packages/core/src/features/weblinks/common/remove.injectable.ts @@ -0,0 +1,20 @@ +/** + * 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 { action } from "mobx"; +import weblinksStateInjectable from "./state.injectable"; + +export type RemoveWeblink = (id: string) => void; + +const removeWeblinkInjectable = getInjectable({ + id: "remove-weblink", + instantiate: (di): RemoveWeblink => { + const state = di.inject(weblinksStateInjectable); + + return action((id) => state.delete(id)); + }, +}); + +export default removeWeblinkInjectable; diff --git a/packages/core/src/features/weblinks/common/state.injectable.ts b/packages/core/src/features/weblinks/common/state.injectable.ts new file mode 100644 index 0000000000..ab909050aa --- /dev/null +++ b/packages/core/src/features/weblinks/common/state.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 { observable } from "mobx"; +import type { WeblinkData } from "./storage.injectable"; + +const weblinksStateInjectable = getInjectable({ + id: "weblinks-state", + instantiate: () => observable.map(), +}); + +export default weblinksStateInjectable; diff --git a/packages/core/src/features/weblinks/common/storage.injectable.ts b/packages/core/src/features/weblinks/common/storage.injectable.ts new file mode 100644 index 0000000000..6b6c668b83 --- /dev/null +++ b/packages/core/src/features/weblinks/common/storage.injectable.ts @@ -0,0 +1,47 @@ +/** + * 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 { action, comparer, toJS } from "mobx"; +import createPersistentStorageInjectable from "../../../common/persistent-storage/create.injectable"; +import persistentStorageMigrationsInjectable from "../../../common/persistent-storage/migrations.injectable"; +import storeMigrationVersionInjectable from "../../../common/vars/store-migration-version.injectable"; +import { weblinkStoreMigrationInjectionToken } from "./migration-token"; +import weblinksStateInjectable from "./state.injectable"; + +export interface WeblinkData { + id: string; + name: string; + url: string; +} + +export interface WeblinkStoreModel { + weblinks: WeblinkData[]; +} + +const weblinksPersistentStorageInjectable = getInjectable({ + id: "weblinks-persistent-storage", + instantiate: (di) => { + const state = di.inject(weblinksStateInjectable); + const createPersistentStorage = di.inject(createPersistentStorageInjectable); + + return createPersistentStorage({ + configName: "lens-weblink-store", + accessPropertiesByDotNotation: false, // To make dots safe in cluster context names + syncOptions: { + equals: comparer.structural, + }, + projectVersion: di.inject(storeMigrationVersionInjectable), + migrations: di.inject(persistentStorageMigrationsInjectable, weblinkStoreMigrationInjectionToken), + fromStore: action(({ weblinks = [] }) => { + state.replace(weblinks.map(weblink => [weblink.id, weblink])); + }), + toJSON: () => ({ + weblinks: [...toJS(state).values()], + }), + }); + }, +}); + +export default weblinksPersistentStorageInjectable; diff --git a/packages/core/src/features/weblinks/common/weblinks.injectable.ts b/packages/core/src/features/weblinks/common/weblinks.injectable.ts new file mode 100644 index 0000000000..a4dca05caf --- /dev/null +++ b/packages/core/src/features/weblinks/common/weblinks.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 { computed } from "mobx"; +import weblinksStateInjectable from "./state.injectable"; + +const weblinksInjectable = getInjectable({ + id: "weblinks", + instantiate: (di) => { + const state = di.inject(weblinksStateInjectable); + + return computed(() => [...state.values()]); + }, +}); + +export default weblinksInjectable; diff --git a/packages/core/src/main/weblinks-store/migrations/5.1.4.injectable.ts b/packages/core/src/features/weblinks/main/5.1.4.injectable.ts similarity index 86% rename from packages/core/src/main/weblinks-store/migrations/5.1.4.injectable.ts rename to packages/core/src/features/weblinks/main/5.1.4.injectable.ts index 000937abba..db8eb1510b 100644 --- a/packages/core/src/main/weblinks-store/migrations/5.1.4.injectable.ts +++ b/packages/core/src/features/weblinks/main/5.1.4.injectable.ts @@ -4,10 +4,10 @@ */ import { docsUrl, forumsUrl } from "../../../common/vars"; -import type { WeblinkData } from "../../../common/weblinks-store/weblink-store"; import { getInjectable } from "@ogre-tools/injectable"; -import { weblinkStoreMigrationInjectionToken } from "../../../common/weblinks-store/migration-token"; -import * as links from "../links"; +import { weblinkStoreMigrationInjectionToken } from "../common/migration-token"; +import * as links from "./links"; +import type { WeblinkData } from "../common/storage.injectable"; const v514WeblinkStoreMigrationInjectable = getInjectable({ id: "v5.1.4-weblink-store-migration", diff --git a/packages/core/src/main/weblinks-store/migrations/5.4.5-beta.1.injectable.ts b/packages/core/src/features/weblinks/main/5.4.5-beta.1.injectable.ts similarity index 89% rename from packages/core/src/main/weblinks-store/migrations/5.4.5-beta.1.injectable.ts rename to packages/core/src/features/weblinks/main/5.4.5-beta.1.injectable.ts index fc67e4a2f5..01f252deb1 100644 --- a/packages/core/src/main/weblinks-store/migrations/5.4.5-beta.1.injectable.ts +++ b/packages/core/src/features/weblinks/main/5.4.5-beta.1.injectable.ts @@ -3,10 +3,10 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { WeblinkData } from "../../../common/weblinks-store/weblink-store"; -import * as links from "../links"; +import * as links from "../../../features/weblinks/main/links"; import { getInjectable } from "@ogre-tools/injectable"; -import { weblinkStoreMigrationInjectionToken } from "../../../common/weblinks-store/migration-token"; +import { weblinkStoreMigrationInjectionToken } from "../../../features/weblinks/common/migration-token"; +import type { WeblinkData } from "../common/storage.injectable"; const v545Beta1WeblinkStoreMigrationInjectable = getInjectable({ id: "v5.4.5-beta.1-weblink-store-migration", diff --git a/packages/core/src/main/weblinks-store/migrations/currentVersion.injectable.ts b/packages/core/src/features/weblinks/main/currentVersion.injectable.ts similarity index 87% rename from packages/core/src/main/weblinks-store/migrations/currentVersion.injectable.ts rename to packages/core/src/features/weblinks/main/currentVersion.injectable.ts index 4b873d78c4..dfb2946164 100644 --- a/packages/core/src/main/weblinks-store/migrations/currentVersion.injectable.ts +++ b/packages/core/src/features/weblinks/main/currentVersion.injectable.ts @@ -4,11 +4,11 @@ */ import { docsUrl, forumsUrl } from "../../../common/vars"; -import type { WeblinkData } from "../../../common/weblinks-store/weblink-store"; import { getInjectable } from "@ogre-tools/injectable"; -import { weblinkStoreMigrationInjectionToken } from "../../../common/weblinks-store/migration-token"; -import { lensDocumentationWeblinkId, lensForumsWeblinkId } from "../links"; +import { weblinkStoreMigrationInjectionToken } from "../../../features/weblinks/common/migration-token"; +import { lensDocumentationWeblinkId, lensForumsWeblinkId } from "../../../features/weblinks/main/links"; import { applicationInformationToken } from "@k8slens/application"; +import type { WeblinkData } from "../common/storage.injectable"; const currentVersionWeblinkStoreMigrationInjectable = getInjectable({ id: "current-version-weblink-store-migration", diff --git a/packages/core/src/main/weblinks-store/links.ts b/packages/core/src/features/weblinks/main/links.ts similarity index 100% rename from packages/core/src/main/weblinks-store/links.ts rename to packages/core/src/features/weblinks/main/links.ts diff --git a/packages/core/src/main/start-main-application/runnables/setup-syncing-of-weblinks.injectable.ts b/packages/core/src/features/weblinks/main/load-storage.injectable.ts similarity index 55% rename from packages/core/src/main/start-main-application/runnables/setup-syncing-of-weblinks.injectable.ts rename to packages/core/src/features/weblinks/main/load-storage.injectable.ts index 09a630db37..e309381bbd 100644 --- a/packages/core/src/main/start-main-application/runnables/setup-syncing-of-weblinks.injectable.ts +++ b/packages/core/src/features/weblinks/main/load-storage.injectable.ts @@ -2,22 +2,20 @@ * 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 { onLoadOfApplicationInjectionToken } from "@k8slens/application"; -import syncWeblinksInjectable from "../../catalog-sources/sync-weblinks.injectable"; - -const setupSyncingOfWeblinksInjectable = getInjectable({ - id: "setup-syncing-of-weblinks", +import { getInjectable } from "@ogre-tools/injectable"; +import weblinksPersistentStorageInjectable from "../common/storage.injectable"; +const loadWeblinkStorageInjectable = getInjectable({ + id: "load-weblink-storage", instantiate: (di) => ({ run: () => { - const syncWeblinks = di.inject(syncWeblinksInjectable); + const storage = di.inject(weblinksPersistentStorageInjectable); - syncWeblinks(); + storage.loadAndStartSyncing(); }, }), - injectionToken: onLoadOfApplicationInjectionToken, }); -export default setupSyncingOfWeblinksInjectable; +export default loadWeblinkStorageInjectable; diff --git a/packages/core/src/features/weblinks/main/setup-syncing-of-weblinks.injectable.ts b/packages/core/src/features/weblinks/main/setup-syncing-of-weblinks.injectable.ts new file mode 100644 index 0000000000..1f6b440904 --- /dev/null +++ b/packages/core/src/features/weblinks/main/setup-syncing-of-weblinks.injectable.ts @@ -0,0 +1,34 @@ +/** + * 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 { onLoadOfApplicationInjectionToken } from "@k8slens/application"; +import weblinkVerificationStartableStoppableInjectable from "./weblink-verification.injectable"; +import catalogEntityRegistryInjectable from "../../../main/catalog/entity-registry.injectable"; +import weblinkVerificationsInjectable from "./weblink-verifications.injectable"; +import { computed } from "mobx"; +import { iter } from "@k8slens/utilities"; + +const setupSyncingOfWeblinksInjectable = getInjectable({ + id: "setup-syncing-of-weblinks", + + instantiate: (di) => ({ + run: () => { + const weblinkVerificationStartableStoppable = di.inject(weblinkVerificationStartableStoppableInjectable); + const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable); + const weblinkVerifications = di.inject(weblinkVerificationsInjectable); + + weblinkVerificationStartableStoppable.start(); + catalogEntityRegistry.addComputedSource("weblinks", computed(() => ( + iter.chain(weblinkVerifications.values()) + .map(([weblink]) => weblink) + .toArray() + ))); + }, + }), + + injectionToken: onLoadOfApplicationInjectionToken, +}); + +export default setupSyncingOfWeblinksInjectable; diff --git a/packages/core/src/features/weblinks/main/stop-validating-weblinks.injectable.ts b/packages/core/src/features/weblinks/main/stop-validating-weblinks.injectable.ts new file mode 100644 index 0000000000..221a3ee0dd --- /dev/null +++ b/packages/core/src/features/weblinks/main/stop-validating-weblinks.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 { beforeQuitOfBackEndInjectionToken } from "../../../main/start-main-application/runnable-tokens/phases"; +import weblinkVerificationStartableStoppableInjectable from "./weblink-verification.injectable"; + +const stopValidatingWeblinksInjectable = getInjectable({ + id: "stop-validating-weblinks", + instantiate: (di) => ({ + run: () => { + const weblinkVerificationStartableStoppable = di.inject(weblinkVerificationStartableStoppableInjectable); + + weblinkVerificationStartableStoppable.stop(); + + return undefined; + }, + }), + injectionToken: beforeQuitOfBackEndInjectionToken, +}); + +export default stopValidatingWeblinksInjectable; diff --git a/packages/core/src/common/user-store/file-name-migration.global-override-for-injectable.ts b/packages/core/src/features/weblinks/main/validate-weblink.global-override-for-injectable.ts similarity index 53% rename from packages/core/src/common/user-store/file-name-migration.global-override-for-injectable.ts rename to packages/core/src/features/weblinks/main/validate-weblink.global-override-for-injectable.ts index 0cd1383cc6..8ec03bebaf 100644 --- a/packages/core/src/common/user-store/file-name-migration.global-override-for-injectable.ts +++ b/packages/core/src/features/weblinks/main/validate-weblink.global-override-for-injectable.ts @@ -4,6 +4,6 @@ */ import { getGlobalOverride } from "@k8slens/test-utils"; -import userStoreFileNameMigrationInjectable from "./file-name-migration.injectable"; +import validateWeblinkInjectable from "./validate-weblink.injectable"; -export default getGlobalOverride(userStoreFileNameMigrationInjectable, () => async () => {}); +export default getGlobalOverride(validateWeblinkInjectable, () => async () => "available"); diff --git a/packages/core/src/features/weblinks/main/validate-weblink.injectable.ts b/packages/core/src/features/weblinks/main/validate-weblink.injectable.ts new file mode 100644 index 0000000000..c38b483a95 --- /dev/null +++ b/packages/core/src/features/weblinks/main/validate-weblink.injectable.ts @@ -0,0 +1,42 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { chainSignal } from "@k8slens/utilities"; +import { getInjectable } from "@ogre-tools/injectable"; +import fetchInjectable from "../../../common/fetch/fetch.injectable"; +import { withTimeout } from "../../../common/fetch/timeout-controller"; + +export type ValidateWeblink = (url: string, signal: AbortSignal) => Promise<"available" | "unavailable">; + +const validateWeblinkInjectable = getInjectable({ + id: "validate-weblink", + instantiate: (di): ValidateWeblink => { + const fetch = di.inject(fetchInjectable); + + return async (url, signal) => { + const timeout = withTimeout(20_000); + + chainSignal(timeout, signal); + + try { + const res = await fetch(url, { + signal: timeout.signal, + }); + + if (res.status >= 200 && res.status < 500) { + return "available"; + } + } catch { + // ignore + } finally { + timeout.abort(); + } + + return "unavailable"; + }; + }, + causesSideEffects: true, +}); + +export default validateWeblinkInjectable; diff --git a/packages/core/src/features/weblinks/main/weblink-verification.injectable.ts b/packages/core/src/features/weblinks/main/weblink-verification.injectable.ts new file mode 100644 index 0000000000..991575de46 --- /dev/null +++ b/packages/core/src/features/weblinks/main/weblink-verification.injectable.ts @@ -0,0 +1,105 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getStartableStoppable } from "@k8slens/startable-stoppable"; +import type { Disposer } from "@k8slens/utilities"; +import { delay, disposer } from "@k8slens/utilities"; +import { getInjectable } from "@ogre-tools/injectable"; +import { random } from "lodash"; +import { reaction, runInAction } from "mobx"; +import { WebLink } from "../../../common/catalog-entities"; +import weblinksInjectable from "../common/weblinks.injectable"; +import validateWeblinkInjectable from "./validate-weblink.injectable"; +import weblinkVerificationsInjectable from "./weblink-verifications.injectable"; + +const sixtyMinutes = 60 * 60 * 1000; + +const weblinkVerificationStartableStoppableInjectable = getInjectable({ + id: "weblink-verification-startable-stoppable", + instantiate: (di) => { + const weblinkVerifications = di.inject(weblinkVerificationsInjectable); + const validateWeblink = di.inject(validateWeblinkInjectable); + const weblinks = di.inject(weblinksInjectable); + + const startPeriodicallyCheckingWebLink = (link: WebLink): Disposer => { + const controller = new AbortController(); + const dispose = disposer(() => controller.abort()); + + void (async () => { + for (;;) { + const newStatus = await validateWeblink(link.spec.url, controller.signal); + + runInAction(() => { + link.status.phase = newStatus; + }); + + const nextCheckAfter = sixtyMinutes + random(0, 5 * 60 * 1000, false); + + await delay(nextCheckAfter, controller.signal); + + if (controller.signal.aborted) { + return; + } + } + })(); + + return dispose; + }; + + return getStartableStoppable("weblink-verification", () => disposer( + reaction( + () => weblinks.get(), + (links) => { + const seenWeblinks = new Set(); + + for (const weblinkData of links) { + seenWeblinks.add(weblinkData.id); + + if (!weblinkVerifications.has(weblinkData.id)) { + const link = new WebLink({ + metadata: { + uid: weblinkData.id, + name: weblinkData.name, + source: "local", + labels: {}, + }, + spec: { + url: weblinkData.url, + }, + status: { + phase: "available", + active: true, + }, + }); + + weblinkVerifications.set(weblinkData.id, [ + link, + startPeriodicallyCheckingWebLink(link), + ]); + } + } + + // Stop checking and remove weblinks that are no longer in the store + for (const [weblinkId, [, disposer]] of weblinkVerifications) { + if (!seenWeblinks.has(weblinkId)) { + disposer(); + weblinkVerifications.delete(weblinkId); + } + } + }, + { + fireImmediately: true, + }, + ), + () => { + // Stop the validations + for (const [, [, disposer]] of weblinkVerifications) { + disposer(); + } + }, + )); + }, +}); + +export default weblinkVerificationStartableStoppableInjectable; diff --git a/packages/core/src/features/weblinks/main/weblink-verifications.injectable.ts b/packages/core/src/features/weblinks/main/weblink-verifications.injectable.ts new file mode 100644 index 0000000000..6e3f7d8f0f --- /dev/null +++ b/packages/core/src/features/weblinks/main/weblink-verifications.injectable.ts @@ -0,0 +1,15 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import type { Disposer } from "@k8slens/utilities"; +import { getInjectable } from "@ogre-tools/injectable"; +import { observable } from "mobx"; +import type { WebLink } from "../../../common/catalog-entities"; + +const weblinkVerificationsInjectable = getInjectable({ + id: "weblink-verifications", + instantiate: () => observable.map(), +}); + +export default weblinkVerificationsInjectable; diff --git a/packages/core/src/features/weblinks/renderer/load-storage.injectable.ts b/packages/core/src/features/weblinks/renderer/load-storage.injectable.ts new file mode 100644 index 0000000000..3cfacc3fa3 --- /dev/null +++ b/packages/core/src/features/weblinks/renderer/load-storage.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 { beforeFrameStartsSecondInjectionToken } from "../../../renderer/before-frame-starts/tokens"; +import weblinksPersistentStorageInjectable from "../common/storage.injectable"; + +const loadWeblinkStorageInjectable = getInjectable({ + id: "load-weblink-storage", + instantiate: (di) => ({ + run: () => { + const storage = di.inject(weblinksPersistentStorageInjectable); + + storage.loadAndStartSyncing(); + }, + }), + injectionToken: beforeFrameStartsSecondInjectionToken, +}); + +export default loadWeblinkStorageInjectable; diff --git a/packages/core/src/features/welcome/__snapshots__/navigation-using-application-menu.test.ts.snap b/packages/core/src/features/welcome/__snapshots__/navigation-using-application-menu.test.ts.snap index 4016a617c3..2ff50d8b1a 100644 --- a/packages/core/src/features/welcome/__snapshots__/navigation-using-application-menu.test.ts.snap +++ b/packages/core/src/features/welcome/__snapshots__/navigation-using-application-menu.test.ts.snap @@ -230,7 +230,7 @@ exports[`welcome - navigation using application menu renders 1`] = ` class="HotbarSelector" > false, - injectionToken: shouldBaseStoreDisableSyncInIpcListenerInjectionToken, + injectionToken: shouldPersistentStorageDisableSyncInIpcListenerInjectionToken, }); export default shouldBaseStoreDisableSyncInIpcListenerInjectable; diff --git a/packages/core/src/main/base-store/ipc-channel-prefix.injectable.ts b/packages/core/src/main/base-store/ipc-channel-prefix.injectable.ts index 635f857fc4..a0a96ce3af 100644 --- a/packages/core/src/main/base-store/ipc-channel-prefix.injectable.ts +++ b/packages/core/src/main/base-store/ipc-channel-prefix.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 { baseStoreIpcChannelPrefixesInjectionToken } from "../../common/base-store/channel-prefix"; +import { persistentStorageIpcChannelPrefixesInjectionToken } from "../../common/persistent-storage/channel-prefix"; const baseStoreIpcChannelPrefixInjectable = getInjectable({ id: "base-store-ipc-channel-prefix", @@ -11,7 +11,7 @@ const baseStoreIpcChannelPrefixInjectable = getInjectable({ local: "store-sync-main", remote: "store-sync-renderer", }), - injectionToken: baseStoreIpcChannelPrefixesInjectionToken, + injectionToken: persistentStorageIpcChannelPrefixesInjectionToken, }); export default baseStoreIpcChannelPrefixInjectable; diff --git a/packages/core/src/main/base-store/persist-state-to-config.injectable.ts b/packages/core/src/main/base-store/persist-state-to-config.injectable.ts index f6d28982ec..7869bbd6c5 100644 --- a/packages/core/src/main/base-store/persist-state-to-config.injectable.ts +++ b/packages/core/src/main/base-store/persist-state-to-config.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 { persistStateToConfigInjectionToken } from "../../common/base-store/save-to-file"; +import { persistStateToConfigInjectionToken } from "../../common/persistent-storage/save-to-file"; import loggerInjectable from "../../common/logger.injectable"; const persistStateToConfigInjectable = getInjectable({ diff --git a/packages/core/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts b/packages/core/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts index 42ffbedf30..6d23610e79 100644 --- a/packages/core/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts +++ b/packages/core/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts @@ -17,9 +17,6 @@ import type { ConfigToModels } from "../kubeconfig-sync/config-to-models.injecta import configToModelsInjectable from "../kubeconfig-sync/config-to-models.injectable"; import kubeconfigSyncManagerInjectable from "../kubeconfig-sync/manager.injectable"; import type { KubeconfigSyncManager } from "../kubeconfig-sync/manager"; -import type { KubeconfigSyncValue } from "../../../common/user-store"; -import kubeconfigSyncsInjectable from "../../../common/user-store/kubeconfig-syncs.injectable"; -import getClusterByIdInjectable from "../../../common/cluster-store/get-by-id.injectable"; import type { DiContainer } from "@ogre-tools/injectable"; import type { AsyncFnMock } from "@async-fn/jest"; import type { Stat } from "../../../common/fs/stat.injectable"; @@ -36,12 +33,13 @@ import readJsonSyncInjectable from "../../../common/fs/read-json-sync.injectable import writeJsonSyncInjectable from "../../../common/fs/write-json-sync.injectable"; import type { KubeconfigManager } from "../../kubeconfig-manager/kubeconfig-manager"; import kubeconfigManagerInjectable from "../../kubeconfig-manager/kubeconfig-manager.injectable"; +import type { KubeconfigSyncValue } from "../../../features/user-preferences/common/preferences-helpers"; +import kubeconfigSyncsInjectable from "../../../features/user-preferences/common/kubeconfig-syncs.injectable"; describe("kubeconfig-sync.source tests", () => { let computeKubeconfigDiff: ComputeKubeconfigDiff; let configToModels: ConfigToModels; let kubeconfigSyncs: ObservableMap; - let clusters: Map; let di: DiContainer; beforeEach(async () => { @@ -58,9 +56,6 @@ describe("kubeconfig-sync.source tests", () => { ensurePath: async () => "/some-proxy-kubeconfig-file", } as Partial as KubeconfigManager)); - clusters = new Map(); - di.override(getClusterByIdInjectable, () => id => clusters.get(id)); - kubeconfigSyncs = observable.map(); di.override(kubeconfigSyncsInjectable, () => kubeconfigSyncs); diff --git a/packages/core/src/main/catalog-sources/index.ts b/packages/core/src/main/catalog-sources/index.ts deleted file mode 100644 index 98c3f08536..0000000000 --- a/packages/core/src/main/catalog-sources/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -export { syncWeblinks } from "./weblinks"; diff --git a/packages/core/src/main/catalog-sources/kubeconfig-sync/compute-diff.injectable.ts b/packages/core/src/main/catalog-sources/kubeconfig-sync/compute-diff.injectable.ts index 3b81e82382..87475931fe 100644 --- a/packages/core/src/main/catalog-sources/kubeconfig-sync/compute-diff.injectable.ts +++ b/packages/core/src/main/catalog-sources/kubeconfig-sync/compute-diff.injectable.ts @@ -9,7 +9,6 @@ import { action } from "mobx"; import { homedir } from "os"; import directoryForKubeConfigsInjectable from "../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable"; import type { CatalogEntity } from "../../../common/catalog"; -import getClusterByIdInjectable from "../../../common/cluster-store/get-by-id.injectable"; import { Cluster } from "../../../common/cluster/cluster"; import { loadConfigFromString } from "../../../common/kube-helpers"; import clustersThatAreBeingDeletedInjectable from "../../cluster/are-being-deleted.injectable"; @@ -17,6 +16,7 @@ import { catalogEntityFromCluster } from "../../cluster/manager"; import configToModelsInjectable from "./config-to-models.injectable"; import kubeconfigSyncLoggerInjectable from "./logger.injectable"; import clusterConnectionInjectable from "../../cluster/cluster-connection.injectable"; +import getClusterByIdInjectable from "../../../features/cluster/storage/common/get-by-id.injectable"; export type ComputeKubeconfigDiff = (contents: string, source: ObservableMap, filePath: string) => void; diff --git a/packages/core/src/main/catalog-sources/kubeconfig-sync/manager.injectable.ts b/packages/core/src/main/catalog-sources/kubeconfig-sync/manager.injectable.ts index 06265764c8..9160df83da 100644 --- a/packages/core/src/main/catalog-sources/kubeconfig-sync/manager.injectable.ts +++ b/packages/core/src/main/catalog-sources/kubeconfig-sync/manager.injectable.ts @@ -7,7 +7,7 @@ import directoryForKubeConfigsInjectable from "../../../common/app-paths/directo import { KubeconfigSyncManager } from "./manager"; import kubeconfigSyncLoggerInjectable from "./logger.injectable"; import watchKubeconfigFileChangesInjectable from "./watch-file-changes.injectable"; -import kubeconfigSyncsInjectable from "../../../common/user-store/kubeconfig-syncs.injectable"; +import kubeconfigSyncsInjectable from "../../../features/user-preferences/common/kubeconfig-syncs.injectable"; const kubeconfigSyncManagerInjectable = getInjectable({ id: "kubeconfig-sync-manager", diff --git a/packages/core/src/main/catalog-sources/kubeconfig-sync/manager.ts b/packages/core/src/main/catalog-sources/kubeconfig-sync/manager.ts index 77ef96b765..c7b53d8973 100644 --- a/packages/core/src/main/catalog-sources/kubeconfig-sync/manager.ts +++ b/packages/core/src/main/catalog-sources/kubeconfig-sync/manager.ts @@ -8,9 +8,9 @@ import { action, observable, computed, makeObservable, observe } from "mobx"; import type { CatalogEntity } from "../../../common/catalog"; import type { Disposer } from "@k8slens/utilities"; import { iter } from "@k8slens/utilities"; -import type { KubeconfigSyncValue } from "../../../common/user-store"; import type { Logger } from "../../../common/logger"; import type { WatchKubeconfigFileChanges } from "./watch-file-changes.injectable"; +import type { KubeconfigSyncValue } from "../../../features/user-preferences/common/preferences-helpers"; interface KubeconfigSyncManagerDependencies { readonly directoryForKubeConfigs: string; diff --git a/packages/core/src/main/catalog-sources/sync-weblinks.injectable.ts b/packages/core/src/main/catalog-sources/sync-weblinks.injectable.ts deleted file mode 100644 index f75de34a9d..0000000000 --- a/packages/core/src/main/catalog-sources/sync-weblinks.injectable.ts +++ /dev/null @@ -1,19 +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 { syncWeblinks } from "./weblinks"; -import weblinkStoreInjectable from "../../common/weblinks-store/weblink-store.injectable"; -import catalogEntityRegistryInjectable from "../catalog/entity-registry.injectable"; - -const syncWeblinksInjectable = getInjectable({ - id: "sync-weblinks", - - instantiate: (di) => syncWeblinks({ - weblinkStore: di.inject(weblinkStoreInjectable), - catalogEntityRegistry: di.inject(catalogEntityRegistryInjectable), - }), -}); - -export default syncWeblinksInjectable; diff --git a/packages/core/src/main/catalog-sources/weblinks.ts b/packages/core/src/main/catalog-sources/weblinks.ts deleted file mode 100644 index 2ff2b645a1..0000000000 --- a/packages/core/src/main/catalog-sources/weblinks.ts +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { computed, observable, reaction } from "mobx"; -import type { WeblinkStore } from "../../common/weblinks-store/weblink-store"; -import { WebLink } from "../../common/catalog-entities"; -import type { CatalogEntityRegistry } from "../catalog"; -import got from "got"; -import type { Disposer } from "@k8slens/utilities"; -import { random } from "lodash"; - -async function validateLink(link: WebLink) { - try { - const response = await got.get(link.spec.url, { - throwHttpErrors: false, - timeout: 20_000, - }); - - if (response.statusCode >= 200 && response.statusCode < 500) { - link.status.phase = "available"; - } else { - link.status.phase = "unavailable"; - } - } catch { - link.status.phase = "unavailable"; - } -} - -interface Dependencies { - weblinkStore: WeblinkStore; - catalogEntityRegistry: CatalogEntityRegistry; -} - -export const syncWeblinks = ({ weblinkStore, catalogEntityRegistry }: Dependencies) => () => { - const webLinkEntities = observable.map(); - - function periodicallyCheckLink(link: WebLink): Disposer { - validateLink(link); - - let interval: NodeJS.Timeout; - const timeout = setTimeout(() => { - interval = setInterval(() => validateLink(link), 60 * 60 * 1000); // every 60 minutes - }, random(0, 5 * 60 * 1000, false)); // spread out over 5 minutes - - return () => { - clearTimeout(timeout); - clearInterval(interval); - }; - } - - reaction(() => weblinkStore.weblinks, (links) => { - const seenWeblinks = new Set(); - - for (const weblinkData of links) { - seenWeblinks.add(weblinkData.id); - - if (!webLinkEntities.has(weblinkData.id)) { - const link = new WebLink({ - metadata: { - uid: weblinkData.id, - name: weblinkData.name, - source: "local", - labels: {}, - }, - spec: { - url: weblinkData.url, - }, - status: { - phase: "available", - active: true, - }, - }); - - webLinkEntities.set(weblinkData.id, [ - link, - periodicallyCheckLink(link), - ]); - } - } - - // Stop checking and remove weblinks that are no longer in the store - for (const [weblinkId, [, disposer]] of webLinkEntities) { - if (!seenWeblinks.has(weblinkId)) { - disposer(); - webLinkEntities.delete(weblinkId); - } - } - }, { fireImmediately: true }); - - catalogEntityRegistry.addComputedSource("weblinks", computed(() => Array.from(webLinkEntities.values(), ([link]) => link))); -}; diff --git a/packages/core/src/main/cluster/manager.injectable.ts b/packages/core/src/main/cluster/manager.injectable.ts index e1567e51b6..21530dfe4d 100644 --- a/packages/core/src/main/cluster/manager.injectable.ts +++ b/packages/core/src/main/cluster/manager.injectable.ts @@ -3,8 +3,10 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import clusterStoreInjectable from "../../common/cluster-store/cluster-store.injectable"; import loggerInjectable from "../../common/logger.injectable"; +import addClusterInjectable from "../../features/cluster/storage/common/add.injectable"; +import clustersInjectable from "../../features/cluster/storage/common/clusters.injectable"; +import getClusterByIdInjectable from "../../features/cluster/storage/common/get-by-id.injectable"; import catalogEntityRegistryInjectable from "../catalog/entity-registry.injectable"; import clustersThatAreBeingDeletedInjectable from "./are-being-deleted.injectable"; import clusterConnectionInjectable from "./cluster-connection.injectable"; @@ -17,11 +19,13 @@ const clusterManagerInjectable = getInjectable({ id: "cluster-manager", instantiate: (di) => new ClusterManager({ - store: di.inject(clusterStoreInjectable), catalogEntityRegistry: di.inject(catalogEntityRegistryInjectable), clustersThatAreBeingDeleted: di.inject(clustersThatAreBeingDeletedInjectable), visibleCluster: di.inject(visibleClusterInjectable), logger: di.inject(loggerInjectable), + addCluster: di.inject(addClusterInjectable), + clusters: di.inject(clustersInjectable), + getClusterById: di.inject(getClusterByIdInjectable), updateEntityMetadata: di.inject(updateEntityMetadataInjectable), updateEntitySpec: di.inject(updateEntitySpecInjectable), getClusterConnection: (cluster) => di.inject(clusterConnectionInjectable, cluster), diff --git a/packages/core/src/main/cluster/manager.ts b/packages/core/src/main/cluster/manager.ts index bc270b79f1..f9f844bd9f 100644 --- a/packages/core/src/main/cluster/manager.ts +++ b/packages/core/src/main/cluster/manager.ts @@ -4,34 +4,37 @@ */ import "../../common/ipc/cluster"; -import type { IObservableValue, ObservableSet } from "mobx"; +import type { IComputedValue, IObservableValue, ObservableSet } from "mobx"; import { action, makeObservable, observe, reaction, toJS } from "mobx"; import type { Cluster } from "../../common/cluster/cluster"; import { isErrnoException } from "@k8slens/utilities"; import { isKubernetesCluster, KubernetesCluster, LensKubernetesClusterStatus } from "../../common/catalog-entities/kubernetes-cluster"; import { ipcMainOn } from "../../common/ipc"; import { once } from "lodash"; -import type { ClusterStore } from "../../common/cluster-store/cluster-store"; import type { ClusterId } from "../../common/cluster-types"; import type { CatalogEntityRegistry } from "../catalog"; import type { Logger } from "../../common/logger"; import type { UpdateEntityMetadata } from "./update-entity-metadata.injectable"; import type { UpdateEntitySpec } from "./update-entity-spec.injectable"; import type { ClusterConnection } from "./cluster-connection.injectable"; +import type { GetClusterById } from "../../features/cluster/storage/common/get-by-id.injectable"; +import type { AddCluster } from "../../features/cluster/storage/common/add.injectable"; const logPrefix = "[CLUSTER-MANAGER]:"; const lensSpecificClusterStatuses: Set = new Set(Object.values(LensKubernetesClusterStatus)); interface Dependencies { - readonly store: ClusterStore; readonly catalogEntityRegistry: CatalogEntityRegistry; readonly clustersThatAreBeingDeleted: ObservableSet; readonly visibleCluster: IObservableValue; readonly logger: Logger; + readonly clusters: IComputedValue; updateEntityMetadata: UpdateEntityMetadata; updateEntitySpec: UpdateEntitySpec; getClusterConnection: (cluster: Cluster) => ClusterConnection; + getClusterById: GetClusterById; + addCluster: AddCluster; } export class ClusterManager { @@ -42,15 +45,15 @@ export class ClusterManager { init = once(() => { // reacting to every cluster's state change and total amount of items reaction( - () => this.dependencies.store.clustersList.map(c => c.getState()), - () => this.updateCatalog(this.dependencies.store.clustersList), + () => this.dependencies.clusters.get().map(c => c.getState()), + () => this.updateCatalog(this.dependencies.clusters.get()), { fireImmediately: false }, ); // reacting to every cluster's preferences change and total amount of items reaction( - () => this.dependencies.store.clustersList.map(c => toJS(c.preferences)), - () => this.updateCatalog(this.dependencies.store.clustersList), + () => this.dependencies.clusters.get().map(c => toJS(c.preferences)), + () => this.updateCatalog(this.dependencies.clusters.get()), { fireImmediately: false }, ); @@ -152,7 +155,7 @@ export class ClusterManager { @action protected syncClustersFromCatalog(entities: KubernetesCluster[]) { for (const entity of entities) { - const cluster = this.dependencies.store.getById(entity.getId()); + const cluster = this.dependencies.getClusterById(entity.getId()); if (!cluster) { const model = { @@ -167,7 +170,7 @@ export class ClusterManager { * Add the bare minimum of data to ClusterStore. And especially no * preferences, as those might be configured by the entity's source */ - this.dependencies.store.addCluster(model); + this.dependencies.addCluster(model); } catch (error) { if (isErrnoException(error) && error.code === "ENOENT" && error.path === entity.spec.kubeconfigPath) { this.dependencies.logger.warn(`${logPrefix} kubeconfig file disappeared`, model); @@ -208,7 +211,9 @@ export class ClusterManager { this.dependencies.logger.info(`${logPrefix} network is offline`); await Promise.allSettled( - this.dependencies.store.clustersList + this.dependencies + .clusters + .get() .filter(cluster => !cluster.disconnected.get()) .map(async (cluster) => { cluster.online.set(false); @@ -225,7 +230,9 @@ export class ClusterManager { this.dependencies.logger.info(`${logPrefix} network is online`); await Promise.allSettled( - this.dependencies.store.clustersList + this.dependencies + .clusters + .get() .filter(cluster => !cluster.disconnected.get()) .map((cluster) => ( this.dependencies @@ -236,7 +243,7 @@ export class ClusterManager { }; stop() { - for (const cluster of this.dependencies.store.clustersList) { + for (const cluster of this.dependencies.clusters.get()) { this.dependencies .getClusterConnection(cluster) .disconnect(); diff --git a/packages/core/src/main/cluster/store-migrations/3.6.0-beta.1.injectable.ts b/packages/core/src/main/cluster/store-migrations/3.6.0-beta.1.injectable.ts index 9b8bb83e2b..5f43359d8d 100644 --- a/packages/core/src/main/cluster/store-migrations/3.6.0-beta.1.injectable.ts +++ b/packages/core/src/main/cluster/store-migrations/3.6.0-beta.1.injectable.ts @@ -18,7 +18,7 @@ interface Pre360ClusterModel extends ClusterModel { } import { getInjectable } from "@ogre-tools/injectable"; -import { clusterStoreMigrationInjectionToken } from "../../../common/cluster-store/migration-token"; +import { clusterStoreMigrationInjectionToken } from "../../../features/cluster/storage/common/migration-token"; import readFileBufferSyncInjectable from "../../../common/fs/read-file-buffer-sync.injectable"; import loggerInjectable from "../../../common/logger.injectable"; import writeFileSyncInjectable from "../../../common/fs/write-file-sync.injectable"; diff --git a/packages/core/src/main/cluster/store-migrations/5.0.0-beta.10.injectable.ts b/packages/core/src/main/cluster/store-migrations/5.0.0-beta.10.injectable.ts index 026ded3d1b..3ba3629578 100644 --- a/packages/core/src/main/cluster/store-migrations/5.0.0-beta.10.injectable.ts +++ b/packages/core/src/main/cluster/store-migrations/5.0.0-beta.10.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; -import { clusterStoreMigrationInjectionToken } from "../../../common/cluster-store/migration-token"; +import { clusterStoreMigrationInjectionToken } from "../../../features/cluster/storage/common/migration-token"; import type { ClusterModel } from "../../../common/cluster-types"; import readJsonSyncInjectable from "../../../common/fs/read-json-sync.injectable"; import joinPathsInjectable from "../../../common/path/join-paths.injectable"; diff --git a/packages/core/src/main/cluster/store-migrations/5.0.0-beta.13.injectable.ts b/packages/core/src/main/cluster/store-migrations/5.0.0-beta.13.injectable.ts index 9137c81fed..6c33cfa2c4 100644 --- a/packages/core/src/main/cluster/store-migrations/5.0.0-beta.13.injectable.ts +++ b/packages/core/src/main/cluster/store-migrations/5.0.0-beta.13.injectable.ts @@ -10,7 +10,7 @@ import { isDefined } from "@k8slens/utilities"; import joinPathsInjectable from "../../../common/path/join-paths.injectable"; import { getInjectable } from "@ogre-tools/injectable"; import loggerInjectable from "../../../common/logger.injectable"; -import { clusterStoreMigrationInjectionToken } from "../../../common/cluster-store/migration-token"; +import { clusterStoreMigrationInjectionToken } from "../../../features/cluster/storage/common/migration-token"; import { generateNewIdFor } from "../../../common/utils/generate-new-id-for"; interface Pre500ClusterModel extends ClusterModel { diff --git a/packages/core/src/main/cluster/store-migrations/snap.injectable.ts b/packages/core/src/main/cluster/store-migrations/snap.injectable.ts index d4efc37612..f20f0a4820 100644 --- a/packages/core/src/main/cluster/store-migrations/snap.injectable.ts +++ b/packages/core/src/main/cluster/store-migrations/snap.injectable.ts @@ -6,7 +6,7 @@ // Fix embedded kubeconfig paths under snap config import { getInjectable } from "@ogre-tools/injectable"; -import { clusterStoreMigrationInjectionToken } from "../../../common/cluster-store/migration-token"; +import { clusterStoreMigrationInjectionToken } from "../../../features/cluster/storage/common/migration-token"; import loggerInjectable from "../../../common/logger.injectable"; import isSnapPackageInjectable from "../../../common/vars/is-snap-package.injectable"; import type { ClusterModel } from "../../../common/cluster-types"; diff --git a/packages/core/src/main/create-cluster/allowed-resources.injectable.ts b/packages/core/src/main/create-cluster/allowed-resources.injectable.ts index 09beae9fd2..7b520fd29a 100644 --- a/packages/core/src/main/create-cluster/allowed-resources.injectable.ts +++ b/packages/core/src/main/create-cluster/allowed-resources.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable"; import { computed } from "mobx"; -import { shouldShowResourceInjectionToken } from "../../common/cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import type { KubeApiResourceDescriptor } from "../../common/rbac"; import { formatKubeApiResource } from "../../common/rbac"; diff --git a/packages/core/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.injectable.ts b/packages/core/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.injectable.ts index cdf120dad7..61e37642e1 100644 --- a/packages/core/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.injectable.ts +++ b/packages/core/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.injectable.ts @@ -5,12 +5,12 @@ import { getInjectable } from "@ogre-tools/injectable"; import { setupIpcMainHandlers } from "./setup-ipc-main-handlers"; import loggerInjectable from "../../../../common/logger.injectable"; -import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable"; import { onLoadOfApplicationInjectionToken } from "@k8slens/application"; import applicationMenuItemCompositeInjectable from "../../../../features/application-menu/main/application-menu-item-composite.injectable"; -import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable"; import pushCatalogToRendererInjectable from "../../../catalog-sync-to-renderer/push-catalog-to-renderer.injectable"; import clusterFramesInjectable from "../../../../common/cluster-frames.injectable"; +import getClusterByIdInjectable from "../../../../features/cluster/storage/common/get-by-id.injectable"; +import clustersInjectable from "../../../../features/cluster/storage/common/clusters.injectable"; const setupIpcMainHandlersInjectable = getInjectable({ id: "setup-ipc-main-handlers", @@ -24,7 +24,7 @@ const setupIpcMainHandlersInjectable = getInjectable({ setupIpcMainHandlers({ applicationMenuItemComposite: di.inject(applicationMenuItemCompositeInjectable), pushCatalogToRenderer: di.inject(pushCatalogToRendererInjectable), - clusterStore: di.inject(clusterStoreInjectable), + clusters: di.inject(clustersInjectable), getClusterById: di.inject(getClusterByIdInjectable), clusterFrames: di.inject(clusterFramesInjectable), }); diff --git a/packages/core/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.ts b/packages/core/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.ts index d5b85c440a..6fdd498910 100644 --- a/packages/core/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.ts +++ b/packages/core/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.ts @@ -7,7 +7,6 @@ import { BrowserWindow, Menu } from "electron"; import type { ClusterFrameInfo } from "../../../../common/cluster-frames.injectable"; import { clusterSetFrameIdHandler, clusterStates } from "../../../../common/ipc/cluster"; import type { ClusterId } from "../../../../common/cluster-types"; -import type { ClusterStore } from "../../../../common/cluster-store/cluster-store"; import { broadcastMainChannel, broadcastMessage, ipcMainHandle, ipcMainOn } from "../../../../common/ipc"; import type { IComputedValue, ObservableMap } from "mobx"; import { windowActionHandleChannel, windowLocationChangedChannel, windowOpenAppMenuAsContextMenuChannel } from "../../../../common/ipc/window"; @@ -16,21 +15,23 @@ import type { ApplicationMenuItemTypes } from "../../../../features/application- import type { Composite } from "../../../../common/utils/composite/get-composite/get-composite"; import { getApplicationMenuTemplate } from "../../../../features/application-menu/main/populate-application-menu.injectable"; import type { MenuItemRoot } from "../../../../features/application-menu/main/application-menu-item-composite.injectable"; -import type { GetClusterById } from "../../../../common/cluster-store/get-by-id.injectable"; +import type { GetClusterById } from "../../../../features/cluster/storage/common/get-by-id.injectable"; +import type { Cluster } from "../../../../common/cluster/cluster"; + interface Dependencies { applicationMenuItemComposite: IComputedValue>; - clusterStore: ClusterStore; getClusterById: GetClusterById; pushCatalogToRenderer: () => void; clusterFrames: ObservableMap; + clusters: IComputedValue; } export const setupIpcMainHandlers = ({ applicationMenuItemComposite, - clusterStore, getClusterById, pushCatalogToRenderer, clusterFrames, + clusters, }: Dependencies) => { ipcMainHandle(clusterSetFrameIdHandler, (event: IpcMainInvokeEvent, clusterId: ClusterId) => { const cluster = getClusterById(clusterId); @@ -60,7 +61,7 @@ export const setupIpcMainHandlers = ({ }); ipcMainHandle(clusterStates, () => ( - clusterStore.clustersList.map(cluster => ({ + clusters.get().map(cluster => ({ id: cluster.id, state: cluster.getState(), })) diff --git a/packages/core/src/main/extension-loader/create-extension-instance.injectable.ts b/packages/core/src/main/extension-loader/create-extension-instance.injectable.ts index 62417149d4..cd20ab7ede 100644 --- a/packages/core/src/main/extension-loader/create-extension-instance.injectable.ts +++ b/packages/core/src/main/extension-loader/create-extension-instance.injectable.ts @@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import type { Writable } from "type-fest"; import loggerInjectable from "../../common/logger.injectable"; import { createExtensionInstanceInjectionToken } from "../../extensions/extension-loader/create-extension-instance.token"; -import fileSystemProvisionerStoreInjectable from "../../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable"; +import ensureHashedDirectoryForExtensionInjectable from "../../extensions/extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.injectable"; import { lensExtensionDependencies } from "../../extensions/lens-extension"; import type { LensMainExtensionDependencies } from "../../extensions/lens-extension-set-dependencies"; import type { LensMainExtension } from "../../extensions/lens-main-extension"; @@ -17,7 +17,7 @@ const createExtensionInstanceInjectable = getInjectable({ id: "create-extension-instance", instantiate: (di) => { const deps: LensMainExtensionDependencies = { - fileSystemProvisionerStore: di.inject(fileSystemProvisionerStoreInjectable), + ensureHashedDirectoryForExtension: di.inject(ensureHashedDirectoryForExtensionInjectable), entityRegistry: di.inject(catalogEntityRegistryInjectable), navigate: di.inject(navigateForExtensionInjectable), logger: di.inject(loggerInjectable), diff --git a/packages/core/src/main/getDiForUnitTesting.ts b/packages/core/src/main/getDiForUnitTesting.ts index b374eec1ca..83b3aa6d82 100644 --- a/packages/core/src/main/getDiForUnitTesting.ts +++ b/packages/core/src/main/getDiForUnitTesting.ts @@ -10,7 +10,7 @@ import spawnInjectable from "./child-process/spawn.injectable"; import initializeExtensionsInjectable from "./start-main-application/runnables/initialize-extensions.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 setupSyncingOfWeblinksInjectable from "./start-main-application/runnables/setup-syncing-of-weblinks.injectable"; +import setupSyncingOfWeblinksInjectable from "../features/weblinks/main/setup-syncing-of-weblinks.injectable"; import setupDeepLinkingInjectable from "./electron-app/runnables/setup-deep-linking.injectable"; import setupMainWindowVisibilityAfterActivationInjectable from "./electron-app/runnables/setup-main-window-visibility-after-activation.injectable"; import setupDeviceShutdownInjectable from "./electron-app/runnables/setup-device-shutdown.injectable"; diff --git a/packages/core/src/main/helm/exec-helm/exec-env.injectable.ts b/packages/core/src/main/helm/exec-helm/exec-env.injectable.ts index 3a72d0c17c..29864427a4 100644 --- a/packages/core/src/main/helm/exec-helm/exec-env.injectable.ts +++ b/packages/core/src/main/helm/exec-helm/exec-env.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { computed } from "mobx"; -import httpsProxyConfigurationInjectable from "../../../common/user-store/https-proxy.injectable"; +import httpsProxyConfigurationInjectable from "../../../features/user-preferences/common/https-proxy.injectable"; const execHelmEnvInjectable = getInjectable({ id: "exec-helm-env", diff --git a/packages/core/src/main/hotbar-store/migrations/5.0.0-alpha.0.injectable.ts b/packages/core/src/main/hotbar-store/migrations/5.0.0-alpha.0.injectable.ts deleted file mode 100644 index 9143167b47..0000000000 --- a/packages/core/src/main/hotbar-store/migrations/5.0.0-alpha.0.injectable.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -// Cleans up a store that had the state related data stored -import { getEmptyHotbar } from "../../../common/hotbars/types"; -import catalogCatalogEntityInjectable from "../../../common/catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable"; -import { getInjectable } from "@ogre-tools/injectable"; -import { hotbarStoreMigrationInjectionToken } from "../../../common/hotbars/migrations-token"; - -const v500Alpha0HotbarStoreMigrationInjectable = getInjectable({ - id: "v5.0.0-alpha.0-hotbar-store-migration", - instantiate: (di) => { - const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable); - - return { - version: "5.0.0-alpha.0", - run(store) { - const hotbar = getEmptyHotbar("default"); - - const { metadata: { uid, name, source }} = catalogCatalogEntity; - - hotbar.items[0] = { entity: { uid, name, source }}; - - store.set("hotbars", [hotbar]); - }, - }; - }, - injectionToken: hotbarStoreMigrationInjectionToken, -}); - -export default v500Alpha0HotbarStoreMigrationInjectable; - diff --git a/packages/core/src/main/hotbar-store/migrations/5.0.0-beta.10.injectable.ts b/packages/core/src/main/hotbar-store/migrations/5.0.0-beta.10.injectable.ts deleted file mode 100644 index b327085aa6..0000000000 --- a/packages/core/src/main/hotbar-store/migrations/5.0.0-beta.10.injectable.ts +++ /dev/null @@ -1,182 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import * as uuid from "uuid"; -import type { Hotbar, HotbarItem } from "../../../common/hotbars/types"; -import { defaultHotbarCells, getEmptyHotbar } from "../../../common/hotbars/types"; -import { getLegacyGlobalDiForExtensionApi } from "../../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; -import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; -import catalogCatalogEntityInjectable from "../../../common/catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable"; -import { isDefined, isErrnoException } from "@k8slens/utilities"; -import joinPathsInjectable from "../../../common/path/join-paths.injectable"; -import { getInjectable } from "@ogre-tools/injectable"; -import { hotbarStoreMigrationInjectionToken } from "../../../common/hotbars/migrations-token"; -import readJsonSyncInjectable from "../../../common/fs/read-json-sync.injectable"; -import loggerInjectable from "../../../common/logger.injectable"; -import { generateNewIdFor } from "../../../common/utils/generate-new-id-for"; -import type { ClusterModel } from "../../../common/cluster-types"; - -interface Pre500WorkspaceStoreModel { - workspaces: { - id: string; - name: string; - }[]; -} - -interface PartialHotbar { - id: string; - name: string; - items: (null | HotbarItem)[]; -} - -interface Pre500ClusterModel extends ClusterModel { - workspace?: string; - workspaces?: string[]; -} - -interface Pre500ClusterStoreModel { - clusters?: Pre500ClusterModel[]; -} - -const v500Beta10HotbarStoreMigrationInjectable = getInjectable({ - id: "v5.0.0-beta.10-hotbar-store-migration", - instantiate: (di) => { - const userDataPath = di.inject(directoryForUserDataInjectable); - const joinPaths = di.inject(joinPathsInjectable); - const readJsonSync = di.inject(readJsonSyncInjectable); - const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable); - const logger = di.inject(loggerInjectable); - - return { - version: "5.0.0-beta.10", - run(store) { - const rawHotbars = store.get("hotbars"); - const hotbars: Hotbar[] = Array.isArray(rawHotbars) ? rawHotbars.filter(h => h && typeof h === "object") : []; - - - // Hotbars might be empty, if some of the previous migrations weren't run - if (hotbars.length === 0) { - const hotbar = getEmptyHotbar("default"); - const { metadata: { uid, name, source }} = catalogCatalogEntity; - - hotbar.items[0] = { entity: { uid, name, source }}; - - hotbars.push(hotbar); - } - - try { - const workspaceStoreData: Pre500WorkspaceStoreModel = readJsonSync(joinPaths(userDataPath, "lens-workspace-store.json")); - const { clusters = [] }: Pre500ClusterStoreModel = readJsonSync(joinPaths(userDataPath, "lens-cluster-store.json")); - const workspaceHotbars = new Map(); // mapping from WorkspaceId to HotBar - - for (const { id, name } of workspaceStoreData.workspaces) { - logger.info(`Creating new hotbar for ${name}`); - workspaceHotbars.set(id, { - id: uuid.v4(), // don't use the old IDs as they aren't necessarily UUIDs - items: [], - name: `Workspace: ${name}`, - }); - } - - { - // grab the default named hotbar or the first. - const defaultHotbarIndex = Math.max(0, hotbars.findIndex(hotbar => hotbar.name === "default")); - const [{ name, id, items }] = hotbars.splice(defaultHotbarIndex, 1); - - workspaceHotbars.set("default", { - name, - id, - items: items.filter(isDefined), - }); - } - - for (const cluster of clusters) { - const uid = generateNewIdFor(cluster); - - for (const workspaceId of cluster.workspaces ?? [cluster.workspace].filter(isDefined)) { - const workspaceHotbar = workspaceHotbars.get(workspaceId); - - if (!workspaceHotbar) { - logger.info(`Cluster ${uid} has unknown workspace ID, skipping`); - continue; - } - - logger.info(`Adding cluster ${uid} to ${workspaceHotbar.name}`); - - if (workspaceHotbar?.items.length < defaultHotbarCells) { - workspaceHotbar.items.push({ - entity: { - uid: generateNewIdFor(cluster), - name: cluster.preferences?.clusterName || cluster.contextName, - }, - }); - } - } - } - - for (const hotbar of workspaceHotbars.values()) { - if (hotbar.items.length === 0) { - logger.info(`Skipping ${hotbar.name} due to it being empty`); - continue; - } - - while (hotbar.items.length < defaultHotbarCells) { - hotbar.items.push(null); - } - - hotbars.push(hotbar as Hotbar); - } - - /** - * Finally, make sure that the catalog entity hotbar item is in place. - * Just in case something else removed it. - * - * if every hotbar has elements that all not the `catalog-entity` item - */ - if (hotbars.every(hotbar => hotbar.items.every(item => item?.entity?.uid !== "catalog-entity"))) { - // note, we will add a new whole hotbar here called "default" if that was previously removed - const di = getLegacyGlobalDiForExtensionApi(); - const catalogCatalogEntity = di.inject(catalogCatalogEntityInjectable); - - const defaultHotbar = hotbars.find(hotbar => hotbar.name === "default"); - const { metadata: { uid, name, source }} = catalogCatalogEntity; - - if (defaultHotbar) { - const freeIndex = defaultHotbar.items.findIndex(i => i === null); - - if (freeIndex === -1) { - // making a new hotbar is less destructive if the first hotbar - // called "default" is full than overriding a hotbar item - const hotbar = getEmptyHotbar("initial"); - - hotbar.items[0] = { entity: { uid, name, source }}; - hotbars.unshift(hotbar); - } else { - defaultHotbar.items[freeIndex] = { entity: { uid, name, source }}; - } - } else { - const hotbar = getEmptyHotbar("default"); - - hotbar.items[0] = { entity: { uid, name, source }}; - hotbars.unshift(hotbar); - } - } - - } catch (error) { - // ignore files being missing - if (isErrnoException(error) && error.code !== "ENOENT") { - throw error; - } - } - - store.set("hotbars", hotbars); - }, - }; - }, - injectionToken: hotbarStoreMigrationInjectionToken, -}); - -export default v500Beta10HotbarStoreMigrationInjectable; - diff --git a/packages/core/src/main/hotbar-store/migrations/5.0.0-beta.5.injectable.ts b/packages/core/src/main/hotbar-store/migrations/5.0.0-beta.5.injectable.ts deleted file mode 100644 index eef10f7033..0000000000 --- a/packages/core/src/main/hotbar-store/migrations/5.0.0-beta.5.injectable.ts +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { Hotbar } from "../../../common/hotbars/types"; -import catalogEntityRegistryInjectable from "../../catalog/entity-registry.injectable"; -import { getInjectable } from "@ogre-tools/injectable"; -import { hotbarStoreMigrationInjectionToken } from "../../../common/hotbars/migrations-token"; - -const v500Beta5HotbarStoreMigrationInjectable = getInjectable({ - id: "v500-beta5-hotbar-store-migration", - instantiate: (di) => { - const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable); - - return { - version: "5.0.0-beta.5", - run(store) { - const rawHotbars = store.get("hotbars"); - const hotbars: Hotbar[] = Array.isArray(rawHotbars) ? rawHotbars : []; - - for (const hotbar of hotbars) { - for (let i = 0; i < hotbar.items.length; i += 1) { - const item = hotbar.items[i]; - - if (!item) { - continue; - } - - const entity = catalogEntityRegistry.findById(item.entity.uid); - - if (!entity) { - // Clear disabled item - hotbar.items[i] = null; - } else { - // Save additional data - item.entity = { - ...item.entity, - name: entity.metadata.name, - source: entity.metadata.source, - }; - } - } - } - - store.set("hotbars", hotbars); - }, - }; - }, - injectionToken: hotbarStoreMigrationInjectionToken, -}); - -export default v500Beta5HotbarStoreMigrationInjectable; - diff --git a/packages/core/src/main/kubectl/apply-all-handler.injectable.ts b/packages/core/src/main/kubectl/apply-all-handler.injectable.ts index 00f58e5e3f..fb5f3a040f 100644 --- a/packages/core/src/main/kubectl/apply-all-handler.injectable.ts +++ b/packages/core/src/main/kubectl/apply-all-handler.injectable.ts @@ -3,8 +3,8 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import emitAppEventInjectable from "../../common/app-event-bus/emit-event.injectable"; -import getClusterByIdInjectable from "../../common/cluster-store/get-by-id.injectable"; import { kubectlApplyAllChannel } from "../../common/kube-helpers/channels"; +import getClusterByIdInjectable from "../../features/cluster/storage/common/get-by-id.injectable"; import resourceApplierInjectable from "../resource-applier/create-resource-applier.injectable"; import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; @@ -15,14 +15,16 @@ const kubectlApplyAllChannelHandlerInjectable = getRequestChannelListenerInjecta const getClusterById = di.inject(getClusterByIdInjectable); const emitAppEvent = di.inject(emitAppEventInjectable); - return async ({ - clusterId, - extraArgs, - resources, - }) => { - emitAppEvent({ name: "cluster", action: "kubectl-apply-all" }); + return async (event) => { + const { + clusterId, + extraArgs, + resources, + } = event; const cluster = getClusterById(clusterId); + emitAppEvent({ name: "cluster", action: "kubectl-apply-all" }); + if (!cluster) { return { callWasSuccessful: false, diff --git a/packages/core/src/main/kubectl/create-kubectl.injectable.ts b/packages/core/src/main/kubectl/create-kubectl.injectable.ts index 5d7b19162c..84e5fee601 100644 --- a/packages/core/src/main/kubectl/create-kubectl.injectable.ts +++ b/packages/core/src/main/kubectl/create-kubectl.injectable.ts @@ -6,7 +6,6 @@ import { getInjectable } from "@ogre-tools/injectable"; import type { KubectlDependencies } from "./kubectl"; import { Kubectl } from "./kubectl"; import directoryForKubectlBinariesInjectable from "../../common/app-paths/directory-for-kubectl-binaries/directory-for-kubectl-binaries.injectable"; -import userStoreInjectable from "../../common/user-store/user-store.injectable"; import kubectlDownloadingNormalizedArchInjectable from "./normalized-arch.injectable"; import normalizedPlatformInjectable from "../../common/vars/normalized-platform.injectable"; import kubectlBinaryNameInjectable from "./binary-name.injectable"; @@ -20,6 +19,7 @@ import getBasenameOfPathInjectable from "../../common/path/get-basename.injectab import loggerInjectable from "../../common/logger.injectable"; import execFileInjectable from "../../common/fs/exec-file.injectable"; import unlinkInjectable from "../../common/fs/unlink.injectable"; +import userPreferencesStateInjectable from "../../features/user-preferences/common/state.injectable"; export type CreateKubectl = (version: string) => Kubectl; @@ -28,7 +28,7 @@ const createKubectlInjectable = getInjectable({ instantiate: (di): CreateKubectl => { const dependencies: KubectlDependencies = { - userStore: di.inject(userStoreInjectable), + state: di.inject(userPreferencesStateInjectable), directoryForKubectlBinaries: di.inject(directoryForKubectlBinariesInjectable), normalizedDownloadArch: di.inject(kubectlDownloadingNormalizedArchInjectable), normalizedDownloadPlatform: di.inject(normalizedPlatformInjectable), diff --git a/packages/core/src/main/kubectl/delete-all-handler.injectable.ts b/packages/core/src/main/kubectl/delete-all-handler.injectable.ts index 5d207be482..b7e21b4d8e 100644 --- a/packages/core/src/main/kubectl/delete-all-handler.injectable.ts +++ b/packages/core/src/main/kubectl/delete-all-handler.injectable.ts @@ -3,8 +3,8 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import emitAppEventInjectable from "../../common/app-event-bus/emit-event.injectable"; -import getClusterByIdInjectable from "../../common/cluster-store/get-by-id.injectable"; import { kubectlDeleteAllChannel } from "../../common/kube-helpers/channels"; +import getClusterByIdInjectable from "../../features/cluster/storage/common/get-by-id.injectable"; import resourceApplierInjectable from "../resource-applier/create-resource-applier.injectable"; import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; @@ -15,15 +15,16 @@ const kubectlDeleteAllChannelHandlerInjectable = getRequestChannelListenerInject const emitAppEvent = di.inject(emitAppEventInjectable); const getClusterById = di.inject(getClusterByIdInjectable); - return async ({ - clusterId, - extraArgs, - resources, - }) => { - emitAppEvent({ name: "cluster", action: "kubectl-delete-all" }); - + return async (event) => { + const { + clusterId, + extraArgs, + resources, + } = event; const cluster = getClusterById(clusterId); + emitAppEvent({ name: "cluster", action: "kubectl-delete-all" }); + if (!cluster) { return { callWasSuccessful: false, diff --git a/packages/core/src/main/kubectl/kubectl.ts b/packages/core/src/main/kubectl/kubectl.ts index ca0fac16e2..631e08b833 100644 --- a/packages/core/src/main/kubectl/kubectl.ts +++ b/packages/core/src/main/kubectl/kubectl.ts @@ -7,7 +7,6 @@ import fs from "fs"; import { ensureDir, pathExists } from "fs-extra"; import * as lockFile from "proper-lockfile"; import { SemVer, coerce } from "semver"; -import { defaultPackageMirror, packageMirrors } from "../../common/user-store/preferences-helpers"; import got from "got/dist/source"; import { promisify } from "util"; import stream from "stream"; @@ -20,6 +19,7 @@ import type { Logger } from "../../common/logger"; import type { ExecFile } from "../../common/fs/exec-file.injectable"; import { hasTypedProperty, isObject, isString, json } from "@k8slens/utilities"; import type { Unlink } from "../../common/fs/unlink.injectable"; +import { packageMirrors, defaultPackageMirror } from "../../features/user-preferences/common/preferences-helpers"; const initScriptVersionString = "# lens-initscript v3"; @@ -30,7 +30,7 @@ export interface KubectlDependencies { readonly kubectlBinaryName: string; readonly bundledKubectlBinaryPath: string; readonly baseBundeledBinariesDirectory: string; - readonly userStore: { + readonly state: { readonly kubectlBinariesPath?: string; readonly downloadBinariesPath?: string; readonly downloadKubectlBinaries: boolean; @@ -91,12 +91,12 @@ export class Kubectl { } public getPathFromPreferences() { - return this.dependencies.userStore.kubectlBinariesPath || this.getBundledPath(); + return this.dependencies.state.kubectlBinariesPath || this.getBundledPath(); } protected getDownloadDir() { - if (this.dependencies.userStore.downloadBinariesPath) { - return this.dependencies.joinPaths(this.dependencies.userStore.downloadBinariesPath, "kubectl"); + if (this.dependencies.state.downloadBinariesPath) { + return this.dependencies.joinPaths(this.dependencies.state.downloadBinariesPath, "kubectl"); } return this.dependencies.directoryForKubectlBinaries; @@ -107,7 +107,7 @@ export class Kubectl { return this.getBundledPath(); } - if (this.dependencies.userStore.downloadKubectlBinaries === false) { + if (this.dependencies.state.downloadKubectlBinaries === false) { return this.getPathFromPreferences(); } @@ -231,7 +231,7 @@ export class Kubectl { } public async ensureKubectl(): Promise { - if (this.dependencies.userStore.downloadKubectlBinaries === false) { + if (this.dependencies.state.downloadKubectlBinaries === false) { return true; } @@ -303,7 +303,7 @@ export class Kubectl { protected async writeInitScripts() { const binariesDir = this.dependencies.baseBundeledBinariesDirectory; - const kubectlPath = this.dependencies.userStore.downloadKubectlBinaries + const kubectlPath = this.dependencies.state.downloadKubectlBinaries ? this.dirname : this.dependencies.getDirnameOfPath(this.getPathFromPreferences()); @@ -370,7 +370,7 @@ export class Kubectl { protected getDownloadMirror(): string { // MacOS packages are only available from default - const { url } = packageMirrors.get(this.dependencies.userStore.downloadMirror) + const { url } = packageMirrors.get(this.dependencies.state.downloadMirror) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion ?? packageMirrors.get(defaultPackageMirror)!; diff --git a/packages/core/src/main/lens-proxy/get-cluster-for-request.injectable.ts b/packages/core/src/main/lens-proxy/get-cluster-for-request.injectable.ts index 7d529540d1..8be8d1d4e4 100644 --- a/packages/core/src/main/lens-proxy/get-cluster-for-request.injectable.ts +++ b/packages/core/src/main/lens-proxy/get-cluster-for-request.injectable.ts @@ -3,9 +3,9 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import getClusterByIdInjectable from "../../common/cluster-store/get-by-id.injectable"; import { getClusterIdFromHost } from "../../common/utils"; import { apiKubePrefix } from "../../common/vars"; +import getClusterByIdInjectable from "../../features/cluster/storage/common/get-by-id.injectable"; import type { GetClusterForRequest } from "./lens-proxy"; const getClusterForRequestInjectable = getInjectable({ diff --git a/packages/core/src/main/protocol-handler/__test__/router.test.ts b/packages/core/src/main/protocol-handler/__test__/router.test.ts index 5af2e588d8..e3eddb6b34 100644 --- a/packages/core/src/main/protocol-handler/__test__/router.test.ts +++ b/packages/core/src/main/protocol-handler/__test__/router.test.ts @@ -6,12 +6,10 @@ import * as uuid from "uuid"; import { ProtocolHandlerExtension, ProtocolHandlerInternal, ProtocolHandlerInvalid } from "../../../common/protocol-handler"; -import { delay, noop } from "@k8slens/utilities"; -import type { ExtensionsStore, IsEnabledExtensionDescriptor } from "../../../extensions/extensions-store/extensions-store"; +import { noop } from "@k8slens/utilities"; import type { LensProtocolRouterMain } from "../lens-protocol-router-main/lens-protocol-router-main"; import { getDiForUnitTesting } from "../../getDiForUnitTesting"; import lensProtocolRouterMainInjectable from "../lens-protocol-router-main/lens-protocol-router-main.injectable"; -import extensionsStoreInjectable from "../../../extensions/extensions-store/extensions-store.injectable"; import getConfigurationFileModelInjectable from "../../../common/get-configuration-file-model/get-configuration-file-model.injectable"; import { LensExtension } from "../../../extensions/lens-extension"; import type { ObservableMap } from "mobx"; @@ -23,6 +21,8 @@ import pathExistsInjectable from "../../../common/fs/path-exists.injectable"; import readJsonSyncInjectable from "../../../common/fs/read-json-sync.injectable"; import writeJsonSyncInjectable from "../../../common/fs/write-json-sync.injectable"; import type { LensExtensionId } from "@k8slens/legacy-extensions"; +import type { LensExtensionState } from "../../../features/extensions/enabled/common/state.injectable"; +import enabledExtensionsStateInjectable from "../../../features/extensions/enabled/common/state.injectable"; function throwIfDefined(val: any): void { if (val != null) { @@ -33,7 +33,7 @@ function throwIfDefined(val: any): void { describe("protocol router tests", () => { let extensionInstances: ObservableMap; let lpr: LensProtocolRouterMain; - let enabledExtensions: Set; + let enabledExtensions: ObservableMap; let broadcastMessageMock: jest.Mock; beforeEach(async () => { @@ -44,11 +44,7 @@ describe("protocol router tests", () => { di.override(readJsonSyncInjectable, () => () => { throw new Error("tried call readJsonSync without override"); }); di.override(writeJsonSyncInjectable, () => () => { throw new Error("tried call writeJsonSync without override"); }); - enabledExtensions = new Set(); - - di.override(extensionsStoreInjectable, () => ({ - isEnabled: ({ id, isBundled }: IsEnabledExtensionDescriptor) => isBundled || enabledExtensions.has(id), - } as unknown as ExtensionsStore)); + enabledExtensions = di.inject(enabledExtensionsStateInjectable); di.permitSideEffects(getConfigurationFileModelInjectable); @@ -95,7 +91,7 @@ describe("protocol router tests", () => { }); extensionInstances.set(extId, ext); - enabledExtensions.add(extId); + enabledExtensions.set(extId, { name: "@mirantis/minikube", enabled: true }); lpr.addInternalHandler("/", noop); @@ -105,14 +101,14 @@ describe("protocol router tests", () => { expect(throwIfDefined(error)).not.toThrow(); } + expect(broadcastMessageMock).toHaveBeenCalledWith(ProtocolHandlerInternal, "lens://app", "matched"); + try { expect(await lpr.route("lens://extension/@mirantis/minikube")).toBeUndefined(); } catch (error) { expect(throwIfDefined(error)).not.toThrow(); } - await delay(50); - expect(broadcastMessageMock).toHaveBeenCalledWith(ProtocolHandlerInternal, "lens://app", "matched"); expect(broadcastMessageMock).toHaveBeenCalledWith(ProtocolHandlerExtension, "lens://extension/@mirantis/minikube", "matched"); }); @@ -175,7 +171,7 @@ describe("protocol router tests", () => { }); extensionInstances.set(extId, ext); - enabledExtensions.add(extId); + enabledExtensions.set(extId, { name: "@foobar/icecream", enabled: true }); try { expect(await lpr.route("lens://extension/@foobar/icecream/page/foob")).toBeUndefined(); @@ -183,7 +179,6 @@ describe("protocol router tests", () => { expect(throwIfDefined(error)).not.toThrow(); } - await delay(50); expect(called).toBe("foob"); expect(broadcastMessageMock).toBeCalledWith(ProtocolHandlerExtension, "lens://extension/@foobar/icecream/page/foob", "matched"); }); @@ -214,7 +209,7 @@ describe("protocol router tests", () => { }); extensionInstances.set(extId, ext); - enabledExtensions.add(extId); + enabledExtensions.set(extId, { name: "@foobar/icecream", enabled: true }); } { @@ -240,19 +235,15 @@ describe("protocol router tests", () => { }); extensionInstances.set(extId, ext); - enabledExtensions.add(extId); + enabledExtensions.set(extId, { name: "icecream", enabled: true }); } - enabledExtensions.add("@foobar/icecream"); - enabledExtensions.add("icecream"); - try { expect(await lpr.route("lens://extension/icecream/page")).toBeUndefined(); } catch (error) { expect(throwIfDefined(error)).not.toThrow(); } - await delay(50); expect(called).toBe(1); expect(broadcastMessageMock).toBeCalledWith(ProtocolHandlerExtension, "lens://extension/icecream/page", "matched"); diff --git a/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.injectable.ts b/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.injectable.ts index bce91119c2..92fbdd8737 100644 --- a/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.injectable.ts +++ b/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.injectable.ts @@ -5,22 +5,21 @@ import { getInjectable } from "@ogre-tools/injectable"; import extensionLoaderInjectable from "../../../extensions/extension-loader/extension-loader.injectable"; import { LensProtocolRouterMain } from "./lens-protocol-router-main"; -import extensionsStoreInjectable from "../../../extensions/extensions-store/extensions-store.injectable"; import showApplicationWindowInjectable from "../../start-main-application/lens-window/show-application-window.injectable"; import broadcastMessageInjectable from "../../../common/ipc/broadcast-message.injectable"; import loggerInjectable from "../../../common/logger.injectable"; +import isExtensionEnabledInjectable from "../../../features/extensions/enabled/common/is-enabled.injectable"; const lensProtocolRouterMainInjectable = getInjectable({ id: "lens-protocol-router-main", - instantiate: (di) => - new LensProtocolRouterMain({ - extensionLoader: di.inject(extensionLoaderInjectable), - extensionsStore: di.inject(extensionsStoreInjectable), - showApplicationWindow: di.inject(showApplicationWindowInjectable), - broadcastMessage: di.inject(broadcastMessageInjectable), - logger: di.inject(loggerInjectable), - }), + instantiate: (di) => new LensProtocolRouterMain({ + extensionLoader: di.inject(extensionLoaderInjectable), + isExtensionEnabled: di.inject(isExtensionEnabledInjectable), + showApplicationWindow: di.inject(showApplicationWindowInjectable), + broadcastMessage: di.inject(broadcastMessageInjectable), + logger: di.inject(loggerInjectable), + }), }); export default lensProtocolRouterMainInjectable; diff --git a/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.ts b/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.ts index fb0ad71892..8185ca4e68 100644 --- a/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.ts +++ b/packages/core/src/main/protocol-handler/lens-protocol-router-main/lens-protocol-router-main.ts @@ -119,7 +119,13 @@ export class LensProtocolRouterMain extends proto.LensProtocolRouter { const rawUrl = url.toString(); // for sending to renderer const attempt = super._routeToInternal(url); - this.disposers.push(when(() => this.rendererLoaded, () => this.dependencies.broadcastMessage(proto.ProtocolHandlerInternal, rawUrl, attempt))); + const sendRoutingToRenderer = () => this.dependencies.broadcastMessage(proto.ProtocolHandlerInternal, rawUrl, attempt); + + if (this.rendererLoaded) { + sendRoutingToRenderer(); + } else { + this.disposers.push(when(() => this.rendererLoaded, sendRoutingToRenderer)); + } return attempt; } @@ -136,7 +142,13 @@ export class LensProtocolRouterMain extends proto.LensProtocolRouter { */ const attempt = await super._routeToExtension(new URLParse(url.toString(), true)); - this.disposers.push(when(() => this.rendererLoaded, () => this.dependencies.broadcastMessage(proto.ProtocolHandlerExtension, rawUrl, attempt))); + const sendRoutingToRenderer = () => this.dependencies.broadcastMessage(proto.ProtocolHandlerExtension, rawUrl, attempt); + + if (this.rendererLoaded) { + sendRoutingToRenderer(); + } else { + this.disposers.push(when(() => this.rendererLoaded, sendRoutingToRenderer)); + } return attempt; } diff --git a/packages/core/src/main/shell-session/local-shell-session/local-shell-session.ts b/packages/core/src/main/shell-session/local-shell-session/local-shell-session.ts index 567fc1dca7..b066702266 100644 --- a/packages/core/src/main/shell-session/local-shell-session/local-shell-session.ts +++ b/packages/core/src/main/shell-session/local-shell-session/local-shell-session.ts @@ -3,17 +3,17 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { UserStore } from "../../../common/user-store"; import type { ShellSessionArgs, ShellSessionDependencies } from "../shell-session"; import { ShellSession } from "../shell-session"; import type { ModifyTerminalShellEnv } from "../shell-env-modifier/modify-terminal-shell-env.injectable"; import type { JoinPaths } from "../../../common/path/join-paths.injectable"; import type { GetDirnameOfPath } from "../../../common/path/get-dirname.injectable"; import type { GetBasenameOfPath } from "../../../common/path/get-basename.injectable"; +import type { UserPreferencesState } from "../../../features/user-preferences/common/state.injectable"; export interface LocalShellSessionDependencies extends ShellSessionDependencies { readonly directoryForBinaries: string; - readonly userStore: UserStore; + readonly state: UserPreferencesState; modifyTerminalShellEnv: ModifyTerminalShellEnv; joinPaths: JoinPaths; getDirnameOfPath: GetDirnameOfPath; @@ -50,8 +50,8 @@ export class LocalShellSession extends ShellSession { } protected async getShellArgs(shell: string): Promise { - const pathFromPreferences = this.dependencies.userStore.kubectlBinariesPath || this.kubectl.getBundledPath(); - const kubectlPathDir = this.dependencies.userStore.downloadKubectlBinaries + const pathFromPreferences = this.dependencies.state.kubectlBinariesPath || this.kubectl.getBundledPath(); + const kubectlPathDir = this.dependencies.state.downloadKubectlBinaries ? this.dependencies.directoryContainingKubectl : this.dependencies.getDirnameOfPath(pathFromPreferences); diff --git a/packages/core/src/main/shell-session/local-shell-session/open.injectable.ts b/packages/core/src/main/shell-session/local-shell-session/open.injectable.ts index 4d5d54984a..c7d396b41a 100644 --- a/packages/core/src/main/shell-session/local-shell-session/open.injectable.ts +++ b/packages/core/src/main/shell-session/local-shell-session/open.injectable.ts @@ -12,19 +12,19 @@ import isMacInjectable from "../../../common/vars/is-mac.injectable"; import type { Cluster } from "../../../common/cluster/cluster"; import isWindowsInjectable from "../../../common/vars/is-windows.injectable"; import loggerInjectable from "../../../common/logger.injectable"; -import userStoreInjectable from "../../../common/user-store/user-store.injectable"; import type WebSocket from "ws"; import getDirnameOfPathInjectable from "../../../common/path/get-dirname.injectable"; import joinPathsInjectable from "../../../common/path/join-paths.injectable"; import getBasenameOfPathInjectable from "../../../common/path/get-basename.injectable"; import computeShellEnvironmentInjectable from "../../../features/shell-sync/main/compute-shell-environment.injectable"; import spawnPtyInjectable from "../spawn-pty.injectable"; -import userShellSettingInjectable from "../../../common/user-store/shell-setting.injectable"; import appNameInjectable from "../../../common/vars/app-name.injectable"; import buildVersionInjectable from "../../vars/build-version/build-version.injectable"; import emitAppEventInjectable from "../../../common/app-event-bus/emit-event.injectable"; import statInjectable from "../../../common/fs/stat.injectable"; import kubeconfigManagerInjectable from "../../kubeconfig-manager/kubeconfig-manager.injectable"; +import userPreferencesStateInjectable from "../../../features/user-preferences/common/state.injectable"; +import userShellSettingInjectable from "../../../features/user-preferences/common/shell-setting.injectable"; export interface OpenLocalShellSessionArgs { websocket: WebSocket; @@ -44,7 +44,7 @@ const openLocalShellSessionInjectable = getInjectable({ isMac: di.inject(isMacInjectable), isWindows: di.inject(isWindowsInjectable), logger: di.inject(loggerInjectable), - userStore: di.inject(userStoreInjectable), + state: di.inject(userPreferencesStateInjectable), userShellSetting: di.inject(userShellSettingInjectable), appName: di.inject(appNameInjectable), buildVersion: di.inject(buildVersionInjectable), diff --git a/packages/core/src/main/shell-session/node-shell-session/open.injectable.ts b/packages/core/src/main/shell-session/node-shell-session/open.injectable.ts index 55ec26d362..d2ce8ffb17 100644 --- a/packages/core/src/main/shell-session/node-shell-session/open.injectable.ts +++ b/packages/core/src/main/shell-session/node-shell-session/open.injectable.ts @@ -14,7 +14,6 @@ import loggerInjectable from "../../../common/logger.injectable"; import createKubeJsonApiForClusterInjectable from "../../../common/k8s-api/create-kube-json-api-for-cluster.injectable"; import computeShellEnvironmentInjectable from "../../../features/shell-sync/main/compute-shell-environment.injectable"; import spawnPtyInjectable from "../spawn-pty.injectable"; -import userShellSettingInjectable from "../../../common/user-store/shell-setting.injectable"; import appNameInjectable from "../../../common/vars/app-name.injectable"; import buildVersionInjectable from "../../vars/build-version/build-version.injectable"; import emitAppEventInjectable from "../../../common/app-event-bus/emit-event.injectable"; @@ -22,6 +21,7 @@ import statInjectable from "../../../common/fs/stat.injectable"; import createKubeApiInjectable from "../../../common/k8s-api/create-kube-api.injectable"; import loadProxyKubeconfigInjectable from "../../cluster/load-proxy-kubeconfig.injectable"; import kubeconfigManagerInjectable from "../../kubeconfig-manager/kubeconfig-manager.injectable"; +import userShellSettingInjectable from "../../../features/user-preferences/common/shell-setting.injectable"; export interface NodeShellSessionArgs { websocket: WebSocket; diff --git a/packages/core/src/main/stores/init-user-store.injectable.ts b/packages/core/src/main/stores/init-user-store.injectable.ts deleted file mode 100644 index b7d1dac33d..0000000000 --- a/packages/core/src/main/stores/init-user-store.injectable.ts +++ /dev/null @@ -1,26 +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 userStoreFileNameMigrationInjectable from "../../common/user-store/file-name-migration.injectable"; -import userStoreInjectable from "../../common/user-store/user-store.injectable"; -import { beforeApplicationIsLoadingInjectionToken } from "@k8slens/application"; -import initDefaultUpdateChannelInjectable from "../vars/default-update-channel/init.injectable"; - -const initUserStoreInjectable = getInjectable({ - id: "init-user-store", - instantiate: (di) => ({ - run: async () => { - const userStore = di.inject(userStoreInjectable); - const userStoreFileNameMigration = di.inject(userStoreFileNameMigrationInjectable); - - await userStoreFileNameMigration(); - userStore.load(); - }, - runAfter: initDefaultUpdateChannelInjectable, - }), - injectionToken: beforeApplicationIsLoadingInjectionToken, -}); - -export default initUserStoreInjectable; diff --git a/packages/core/src/renderer/api/catalog/entity/get-active-cluster-entity.injectable.ts b/packages/core/src/renderer/api/catalog/entity/get-active-cluster-entity.injectable.ts index b856c15ffd..5a8c691c82 100644 --- a/packages/core/src/renderer/api/catalog/entity/get-active-cluster-entity.injectable.ts +++ b/packages/core/src/renderer/api/catalog/entity/get-active-cluster-entity.injectable.ts @@ -4,16 +4,24 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { computed } from "mobx"; -import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable"; +import getClusterByIdInjectable from "../../../../features/cluster/storage/common/get-by-id.injectable"; import catalogEntityRegistryInjectable from "./registry.injectable"; const activeEntityInternalClusterInjectable = getInjectable({ id: "active-entity-internal-cluster", instantiate: (di) => { - const store = di.inject(clusterStoreInjectable); + const getClusterById = di.inject(getClusterByIdInjectable); const entityRegistry = di.inject(catalogEntityRegistryInjectable); - return computed(() => store.getById(entityRegistry.activeEntity?.getId())); + return computed(() => { + const entityId = entityRegistry.activeEntity?.getId(); + + if (entityId) { + return getClusterById(entityId); + } + + return undefined; + }); }, }); diff --git a/packages/core/src/renderer/base-store/disable-sync-in-ipc-listener.injectable.ts b/packages/core/src/renderer/base-store/disable-sync-in-ipc-listener.injectable.ts index 82670d8e1b..a1ae454992 100644 --- a/packages/core/src/renderer/base-store/disable-sync-in-ipc-listener.injectable.ts +++ b/packages/core/src/renderer/base-store/disable-sync-in-ipc-listener.injectable.ts @@ -3,12 +3,12 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../../common/base-store/disable-sync"; +import { shouldPersistentStorageDisableSyncInIpcListenerInjectionToken } from "../../common/persistent-storage/disable-sync"; const shouldBaseStoreDisableSyncInIpcListenerInjectable = getInjectable({ id: "should-base-store-disable-sync-in-ipc-listener", instantiate: () => true, - injectionToken: shouldBaseStoreDisableSyncInIpcListenerInjectionToken, + injectionToken: shouldPersistentStorageDisableSyncInIpcListenerInjectionToken, }); export default shouldBaseStoreDisableSyncInIpcListenerInjectable; diff --git a/packages/core/src/renderer/base-store/ipc-channel-prefix.injectable.ts b/packages/core/src/renderer/base-store/ipc-channel-prefix.injectable.ts index bb2d407720..8a27bc456e 100644 --- a/packages/core/src/renderer/base-store/ipc-channel-prefix.injectable.ts +++ b/packages/core/src/renderer/base-store/ipc-channel-prefix.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 { baseStoreIpcChannelPrefixesInjectionToken } from "../../common/base-store/channel-prefix"; +import { persistentStorageIpcChannelPrefixesInjectionToken } from "../../common/persistent-storage/channel-prefix"; const baseStoreIpcChannelPrefixInjectable = getInjectable({ id: "base-store-ipc-channel-prefix", @@ -11,7 +11,7 @@ const baseStoreIpcChannelPrefixInjectable = getInjectable({ local: "store-sync-renderer", remote: "store-sync-main", }), - injectionToken: baseStoreIpcChannelPrefixesInjectionToken, + injectionToken: persistentStorageIpcChannelPrefixesInjectionToken, }); export default baseStoreIpcChannelPrefixInjectable; diff --git a/packages/core/src/renderer/base-store/persist-state-to-config.injectable.ts b/packages/core/src/renderer/base-store/persist-state-to-config.injectable.ts index 0cf594062a..78d87c7fb1 100644 --- a/packages/core/src/renderer/base-store/persist-state-to-config.injectable.ts +++ b/packages/core/src/renderer/base-store/persist-state-to-config.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 { persistStateToConfigInjectionToken } from "../../common/base-store/save-to-file"; +import { persistStateToConfigInjectionToken } from "../../common/persistent-storage/save-to-file"; import { noop } from "@k8slens/utilities"; const persistStateToConfigInjectable = getInjectable({ diff --git a/packages/core/src/renderer/before-frame-starts/runnables/setup-kubernetes-cluster-context-menu-open.injectable.ts b/packages/core/src/renderer/before-frame-starts/runnables/setup-kubernetes-cluster-context-menu-open.injectable.ts index 0775b501b5..d175ce2899 100644 --- a/packages/core/src/renderer/before-frame-starts/runnables/setup-kubernetes-cluster-context-menu-open.injectable.ts +++ b/packages/core/src/renderer/before-frame-starts/runnables/setup-kubernetes-cluster-context-menu-open.injectable.ts @@ -4,9 +4,9 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import catalogCategoryRegistryInjectable from "../../../common/catalog/category-registry.injectable"; -import getClusterByIdInjectable from "../../../common/cluster-store/get-by-id.injectable"; import loadKubeconfigInjectable from "../../../common/cluster/load-kubeconfig.injectable"; import loggerInjectable from "../../../common/logger.injectable"; +import getClusterByIdInjectable from "../../../features/cluster/storage/common/get-by-id.injectable"; import openDeleteClusterDialogInjectable from "../../components/delete-cluster-dialog/open.injectable"; import { beforeFrameStartsSecondInjectionToken } from "../tokens"; diff --git a/packages/core/src/renderer/cluster-frame-context/hosted-cluster.injectable.ts b/packages/core/src/renderer/cluster-frame-context/hosted-cluster.injectable.ts index a466984952..934a660188 100644 --- a/packages/core/src/renderer/cluster-frame-context/hosted-cluster.injectable.ts +++ b/packages/core/src/renderer/cluster-frame-context/hosted-cluster.injectable.ts @@ -4,16 +4,20 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import hostedClusterIdInjectable from "./hosted-cluster-id.injectable"; -import clusterStoreInjectable from "../../common/cluster-store/cluster-store.injectable"; +import getClusterByIdInjectable from "../../features/cluster/storage/common/get-by-id.injectable"; const hostedClusterInjectable = getInjectable({ id: "hosted-cluster", instantiate: (di) => { const hostedClusterId = di.inject(hostedClusterIdInjectable); - const store = di.inject(clusterStoreInjectable); + const getClusterById = di.inject(getClusterByIdInjectable); - return store.getById(hostedClusterId); + if (!hostedClusterId) { + return undefined; + } + + return getClusterById(hostedClusterId); }, }); diff --git a/packages/core/src/renderer/cluster-frame-context/should-show-resource.injectable.ts b/packages/core/src/renderer/cluster-frame-context/should-show-resource.injectable.ts index 6258796a0b..39b6070c3b 100644 --- a/packages/core/src/renderer/cluster-frame-context/should-show-resource.injectable.ts +++ b/packages/core/src/renderer/cluster-frame-context/should-show-resource.injectable.ts @@ -5,7 +5,7 @@ import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable"; import { computed } from "mobx"; import hostedClusterInjectable from "./hosted-cluster.injectable"; -import { shouldShowResourceInjectionToken } from "../../common/cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import type { KubeApiResourceDescriptor } from "../../common/rbac"; import { formatKubeApiResource } from "../../common/rbac"; diff --git a/packages/core/src/renderer/components/+catalog/__tests__/custom-columns.test.ts b/packages/core/src/renderer/components/+catalog/__tests__/custom-columns.test.ts index 8b5ed60a36..381f9541ac 100644 --- a/packages/core/src/renderer/components/+catalog/__tests__/custom-columns.test.ts +++ b/packages/core/src/renderer/components/+catalog/__tests__/custom-columns.test.ts @@ -11,7 +11,6 @@ import { getDiForUnitTesting } from "../../../getDiForUnitTesting"; import type { AdditionalCategoryColumnRegistration, CategoryColumnRegistration } from "../custom-category-columns"; import type { CategoryColumns, GetCategoryColumnsParams } from "../columns/get.injectable"; import getCategoryColumnsInjectable from "../columns/get.injectable"; -import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable"; import extensionInjectable from "../../../../extensions/extension-loader/extension/extension.injectable"; import currentlyInClusterFrameInjectable from "../../../routes/currently-in-cluster-frame.injectable"; @@ -46,7 +45,6 @@ describe("Custom Category Columns", () => { beforeEach(() => { di = getDiForUnitTesting(); - di.override(hotbarStoreInjectable, () => ({})); di.override(currentlyInClusterFrameInjectable, () => false); getCategoryColumns = di.inject(getCategoryColumnsInjectable); diff --git a/packages/core/src/renderer/components/+catalog/catalog.tsx b/packages/core/src/renderer/components/+catalog/catalog.tsx index 1d385d78c4..0d11d070ab 100644 --- a/packages/core/src/renderer/components/+catalog/catalog.tsx +++ b/packages/core/src/renderer/components/+catalog/catalog.tsx @@ -28,8 +28,6 @@ import type { VisitEntityContextMenu } from "../../../common/catalog/visit-entit import visitEntityContextMenuInjectable from "../../../common/catalog/visit-entity-context-menu.injectable"; import type { NavigateToCatalog } from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable"; import navigateToCatalogInjectable from "../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable"; -import type { HotbarStore } from "../../../common/hotbars/store"; -import hotbarStoreInjectable from "../../../common/hotbars/store.injectable"; import type { Logger } from "../../../common/logger"; import loggerInjectable from "../../../common/logger.injectable"; import type { NormalizeCatalogEntityContextMenu } from "../../catalog/normalize-menu-item.injectable"; @@ -51,6 +49,8 @@ import type { OnCatalogEntityListClick } from "./entity-details/on-catalog-click import onCatalogEntityListClickInjectable from "./entity-details/on-catalog-click.injectable"; import type { ShowEntityDetails } from "./entity-details/show.injectable"; import showEntityDetailsInjectable from "./entity-details/show.injectable"; +import type { Hotbar } from "../../../features/hotbar/storage/common/hotbar"; +import activeHotbarInjectable from "../../../features/hotbar/storage/common/active.injectable"; interface Dependencies { catalogPreviousActiveTabStorage: StorageLayer; @@ -65,13 +65,13 @@ interface Dependencies { kind: IComputedValue; }; navigateToCatalog: NavigateToCatalog; - hotbarStore: HotbarStore; catalogCategoryRegistry: CatalogCategoryRegistry; visitEntityContextMenu: VisitEntityContextMenu; navigate: Navigate; normalizeMenuItem: NormalizeCatalogEntityContextMenu; showErrorNotification: ShowNotification; logger: Logger; + activeHotbar: IComputedValue; } @observer @@ -156,11 +156,11 @@ class NonInjectedCatalog extends React.Component { } addToHotbar(entity: CatalogEntity): void { - this.props.hotbarStore.addToHotbar(entity); + this.props.activeHotbar.get()?.addEntity(entity); } removeFromHotbar(entity: CatalogEntity): void { - this.props.hotbarStore.removeFromHotbar(entity.getId()); + this.props.activeHotbar.get()?.removeEntity(entity.getId()); } onTabChange = action((tabId: string | null) => { @@ -323,7 +323,7 @@ export const Catalog = withInjectables(NonInjectedCatalog, { routeParameters: di.inject(catalogRouteParametersInjectable), navigateToCatalog: di.inject(navigateToCatalogInjectable), emitEvent: di.inject(emitAppEventInjectable), - hotbarStore: di.inject(hotbarStoreInjectable), + activeHotbar: di.inject(activeHotbarInjectable), catalogCategoryRegistry: di.inject(catalogCategoryRegistryInjectable), visitEntityContextMenu: di.inject(visitEntityContextMenuInjectable), navigate: di.inject(navigateInjectable), diff --git a/packages/core/src/renderer/components/+catalog/columns/named-category.injectable.ts b/packages/core/src/renderer/components/+catalog/columns/named-category.injectable.ts new file mode 100644 index 0000000000..433d263b79 --- /dev/null +++ b/packages/core/src/renderer/components/+catalog/columns/named-category.injectable.ts @@ -0,0 +1,27 @@ +/** + * 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 styles from "../catalog.module.scss"; +import type { RegisteredAdditionalCategoryColumn } from "../custom-category-columns"; +import renderNamedCategoryColumnCellInjectable from "./render-named-category-column-cell.injectable"; + +const namedCategoryColumnInjectable = getInjectable({ + id: "name-category-column", + instantiate: (di): RegisteredAdditionalCategoryColumn => ({ + id: "name", + priority: 0, + renderCell: di.inject(renderNamedCategoryColumnCellInjectable), + titleProps: { + title: "Name", + className: styles.entityName, + id: "name", + sortBy: "name", + }, + searchFilter: (entity) => entity.getName(), + sortCallback: (entity) => `name=${entity.getName()}`, + }), +}); + +export default namedCategoryColumnInjectable; diff --git a/packages/core/src/renderer/components/+catalog/columns/named-category.injectable.tsx b/packages/core/src/renderer/components/+catalog/columns/named-category.injectable.tsx deleted file mode 100644 index 0f7544ffc1..0000000000 --- a/packages/core/src/renderer/components/+catalog/columns/named-category.injectable.tsx +++ /dev/null @@ -1,65 +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 styles from "../catalog.module.scss"; -import type { CatalogEntity } from "../../../../common/catalog"; -import { prevDefault } from "@k8slens/utilities"; -import { Avatar } from "../../avatar"; -import { Icon } from "../../icon"; -import React from "react"; -import type { RegisteredAdditionalCategoryColumn } from "../custom-category-columns"; -import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable"; -import type { HotbarStore } from "../../../../common/hotbars/store"; - -const renderEntityName = (hotbarStore: HotbarStore) => (entity: CatalogEntity) => { - const isItemInHotbar = hotbarStore.isAddedToActive(entity); - const onClick = prevDefault( - isItemInHotbar - ? () => hotbarStore.removeFromHotbar(entity.getId()) - : () => hotbarStore.addToHotbar(entity), - ); - - return ( - <> - - {entity.spec.icon?.material && } - - {entity.getName()} - - - ); -}; - -const namedCategoryColumnInjectable = getInjectable({ - id: "name-category-column", - instantiate: (di): RegisteredAdditionalCategoryColumn => ({ - id: "name", - priority: 0, - renderCell: renderEntityName(di.inject(hotbarStoreInjectable)), - titleProps: { - title: "Name", - className: styles.entityName, - id: "name", - sortBy: "name", - }, - searchFilter: (entity) => entity.getName(), - sortCallback: (entity) => `name=${entity.getName()}`, - }), -}); - -export default namedCategoryColumnInjectable; diff --git a/packages/core/src/renderer/components/+catalog/columns/render-named-category-column-cell.injectable.tsx b/packages/core/src/renderer/components/+catalog/columns/render-named-category-column-cell.injectable.tsx new file mode 100644 index 0000000000..21fd683ffb --- /dev/null +++ b/packages/core/src/renderer/components/+catalog/columns/render-named-category-column-cell.injectable.tsx @@ -0,0 +1,59 @@ +/** + * 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 styles from "../catalog.module.scss"; +import React from "react"; +import activeHotbarInjectable from "../../../../features/hotbar/storage/common/active.injectable"; +import { Avatar } from "../../avatar"; +import type { RegisteredAdditionalCategoryColumn } from "../custom-category-columns"; +import { Icon } from "../../icon"; +import { prevDefault } from "@k8slens/utilities"; + +const renderNamedCategoryColumnCellInjectable = getInjectable({ + id: "render-named-category-column-cell", + instantiate: (di): RegisteredAdditionalCategoryColumn["renderCell"] => { + const activeHotbar = di.inject(activeHotbarInjectable); + + return (entity) => { + const hotbar = activeHotbar.get(); + + if (!hotbar) { + return null; + } + + const isItemInHotbar = hotbar.hasEntity(entity.getId()); + const onClick = prevDefault(( + isItemInHotbar + ? () => hotbar.removeEntity(entity.getId()) + : () => hotbar.addEntity(entity) + )); + + return ( + <> + + {entity.spec.icon?.material && } + + {entity.getName()} + + + ); + }; + }, +}); + +export default renderNamedCategoryColumnCellInjectable; diff --git a/packages/core/src/renderer/components/+catalog/hotbar-toggle-menu-item.tsx b/packages/core/src/renderer/components/+catalog/hotbar-toggle-menu-item.tsx index bae8895ff7..bab9b79eb5 100644 --- a/packages/core/src/renderer/components/+catalog/hotbar-toggle-menu-item.tsx +++ b/packages/core/src/renderer/components/+catalog/hotbar-toggle-menu-item.tsx @@ -9,11 +9,12 @@ import { MenuItem } from "../menu"; import type { CatalogEntity } from "../../api/catalog-entity"; import { withInjectables } from "@ogre-tools/injectable-react"; -import hotbarStoreInjectable from "../../../common/hotbars/store.injectable"; -import type { HotbarStore } from "../../../common/hotbars/store"; +import type { IComputedValue } from "mobx"; +import type { Hotbar } from "../../../features/hotbar/storage/common/hotbar"; +import activeHotbarInjectable from "../../../features/hotbar/storage/common/active.injectable"; interface Dependencies { - hotbarStore: HotbarStore; + activeHotbar: IComputedValue; } interface HotbarToggleMenuItemProps { @@ -25,19 +26,19 @@ interface HotbarToggleMenuItemProps { function NonInjectedHotbarToggleMenuItem({ addContent, entity, - hotbarStore, + activeHotbar, removeContent, }: Dependencies & HotbarToggleMenuItemProps) { - const [itemInHotbar, setItemInHotbar] = useState(hotbarStore.isAddedToActive(entity)); + const [itemInHotbar, setItemInHotbar] = useState(activeHotbar.get()?.hasEntity(entity.getId()) ?? false); return ( { if (itemInHotbar) { - hotbarStore.removeFromHotbar(entity.getId()); + activeHotbar.get()?.removeEntity(entity.getId()); setItemInHotbar(false); } else { - hotbarStore.addToHotbar(entity); + activeHotbar.get()?.addEntity(entity); setItemInHotbar(true); } }} @@ -47,14 +48,10 @@ function NonInjectedHotbarToggleMenuItem({ ); } -export const HotbarToggleMenuItem = withInjectables( - NonInjectedHotbarToggleMenuItem, - - { - getProps: (di, props) => ({ - hotbarStore: di.inject(hotbarStoreInjectable), - ...props, - }), - }, -); +export const HotbarToggleMenuItem = withInjectables(NonInjectedHotbarToggleMenuItem, { + getProps: (di, props) => ({ + ...props, + activeHotbar: di.inject(activeHotbarInjectable), + }), +}); diff --git a/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/general-settings.injectable.tsx b/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/general-settings.injectable.tsx index 059f8c15eb..64d4028f24 100644 --- a/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/general-settings.injectable.tsx +++ b/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/general-settings.injectable.tsx @@ -6,8 +6,8 @@ import { getInjectable } from "@ogre-tools/injectable"; import { withInjectables } from "@ogre-tools/injectable-react"; import React from "react"; import type { KubernetesCluster } from "../../../../common/catalog-entities"; -import type { GetClusterById } from "../../../../common/cluster-store/get-by-id.injectable"; -import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable"; +import type { GetClusterById } from "../../../../features/cluster/storage/common/get-by-id.injectable"; +import getClusterByIdInjectable from "../../../../features/cluster/storage/common/get-by-id.injectable"; import { ClusterIconSetting } from "../../cluster-settings/icon-settings"; import { ClusterKubeconfig } from "../../cluster-settings/kubeconfig"; import { ClusterNameSetting } from "../../cluster-settings/name-setting"; diff --git a/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/metrics-settings.injectable.tsx b/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/metrics-settings.injectable.tsx index 1be5f7e78a..0a860300a3 100644 --- a/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/metrics-settings.injectable.tsx +++ b/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/metrics-settings.injectable.tsx @@ -5,8 +5,8 @@ import { getInjectable } from "@ogre-tools/injectable"; import { withInjectables } from "@ogre-tools/injectable-react"; import React from "react"; -import type { GetClusterById } from "../../../../common/cluster-store/get-by-id.injectable"; -import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable"; +import type { GetClusterById } from "../../../../features/cluster/storage/common/get-by-id.injectable"; +import getClusterByIdInjectable from "../../../../features/cluster/storage/common/get-by-id.injectable"; import { ClusterMetricsSetting } from "../../cluster-settings/metrics-setting"; import { ClusterPrometheusSetting } from "../../cluster-settings/prometheus-setting"; import { ShowMetricsSetting } from "../../cluster-settings/show-metrics"; diff --git a/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/namespace-settings.injectable.tsx b/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/namespace-settings.injectable.tsx index a7c86265b8..c84827f2a7 100644 --- a/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/namespace-settings.injectable.tsx +++ b/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/namespace-settings.injectable.tsx @@ -5,8 +5,8 @@ import { getInjectable } from "@ogre-tools/injectable"; import { withInjectables } from "@ogre-tools/injectable-react"; import React from "react"; -import type { GetClusterById } from "../../../../common/cluster-store/get-by-id.injectable"; -import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable"; +import type { GetClusterById } from "../../../../features/cluster/storage/common/get-by-id.injectable"; +import getClusterByIdInjectable from "../../../../features/cluster/storage/common/get-by-id.injectable"; import { ClusterAccessibleNamespaces } from "../../cluster-settings/accessible-namespaces"; import type { EntitySettingViewProps } from "../extension-registrator.injectable"; import { entitySettingInjectionToken } from "../token"; diff --git a/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/node-shell-settings.injectable.tsx b/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/node-shell-settings.injectable.tsx index ff899095d6..1a1424b5b3 100644 --- a/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/node-shell-settings.injectable.tsx +++ b/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/node-shell-settings.injectable.tsx @@ -5,8 +5,8 @@ import { getInjectable } from "@ogre-tools/injectable"; import { withInjectables } from "@ogre-tools/injectable-react"; import React from "react"; -import type { GetClusterById } from "../../../../common/cluster-store/get-by-id.injectable"; -import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable"; +import type { GetClusterById } from "../../../../features/cluster/storage/common/get-by-id.injectable"; +import getClusterByIdInjectable from "../../../../features/cluster/storage/common/get-by-id.injectable"; import { ClusterNodeShellSetting } from "../../cluster-settings/node-shell-setting"; import type { EntitySettingViewProps } from "../extension-registrator.injectable"; import { entitySettingInjectionToken } from "../token"; diff --git a/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/proxy-settings.injectable.tsx b/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/proxy-settings.injectable.tsx index 4479a04c2a..90b30ce7d2 100644 --- a/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/proxy-settings.injectable.tsx +++ b/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/proxy-settings.injectable.tsx @@ -5,8 +5,8 @@ import { getInjectable } from "@ogre-tools/injectable"; import { withInjectables } from "@ogre-tools/injectable-react"; import React from "react"; -import type { GetClusterById } from "../../../../common/cluster-store/get-by-id.injectable"; -import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable"; +import type { GetClusterById } from "../../../../features/cluster/storage/common/get-by-id.injectable"; +import getClusterByIdInjectable from "../../../../features/cluster/storage/common/get-by-id.injectable"; import { ClusterProxySetting } from "../../cluster-settings/proxy-setting"; import type { EntitySettingViewProps } from "../extension-registrator.injectable"; import { entitySettingInjectionToken } from "../token"; diff --git a/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/terminal-settings.injectable.tsx b/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/terminal-settings.injectable.tsx index e778c97728..6448c935bc 100644 --- a/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/terminal-settings.injectable.tsx +++ b/packages/core/src/renderer/components/+entity-settings/internal-kubernetes-cluster/terminal-settings.injectable.tsx @@ -5,8 +5,8 @@ import { getInjectable } from "@ogre-tools/injectable"; import { withInjectables } from "@ogre-tools/injectable-react"; import React from "react"; -import type { GetClusterById } from "../../../../common/cluster-store/get-by-id.injectable"; -import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable"; +import type { GetClusterById } from "../../../../features/cluster/storage/common/get-by-id.injectable"; +import getClusterByIdInjectable from "../../../../features/cluster/storage/common/get-by-id.injectable"; import { ClusterLocalTerminalSetting } from "../../cluster-settings/local-terminal-settings"; import type { EntitySettingViewProps } from "../extension-registrator.injectable"; import { entitySettingInjectionToken } from "../token"; diff --git a/packages/core/src/renderer/components/+extensions/get-base-registry-url/get-base-registry-url.injectable.tsx b/packages/core/src/renderer/components/+extensions/get-base-registry-url/get-base-registry-url.injectable.tsx index 6a03466abd..2707f99a3b 100644 --- a/packages/core/src/renderer/components/+extensions/get-base-registry-url/get-base-registry-url.injectable.tsx +++ b/packages/core/src/renderer/components/+extensions/get-base-registry-url/get-base-registry-url.injectable.tsx @@ -7,15 +7,15 @@ import { getInjectable } from "@ogre-tools/injectable"; import React from "react"; import execFileInjectable from "../../../../common/fs/exec-file.injectable"; import loggerInjectable from "../../../../common/logger.injectable"; -import { defaultExtensionRegistryUrl } from "../../../../common/user-store/preferences-helpers"; -import userStoreInjectable from "../../../../common/user-store/user-store.injectable"; +import { defaultExtensionRegistryUrl } from "../../../../features/user-preferences/common/preferences-helpers"; +import userPreferencesStateInjectable from "../../../../features/user-preferences/common/state.injectable"; import showErrorNotificationInjectable from "../../notifications/show-error-notification.injectable"; const getBaseRegistryUrlInjectable = getInjectable({ id: "get-base-registry-url", instantiate: (di) => { - const { extensionRegistryUrl } = di.inject(userStoreInjectable); + const { extensionRegistryUrl } = di.inject(userPreferencesStateInjectable); const showErrorNotification = di.inject(showErrorNotificationInjectable); const logger = di.inject(loggerInjectable); const execFile = di.inject(execFileInjectable); diff --git a/packages/core/src/renderer/components/+workloads-overview/workloads/workloads.injectable.ts b/packages/core/src/renderer/components/+workloads-overview/workloads/workloads.injectable.ts index d6b23b582f..a90e3d63d9 100644 --- a/packages/core/src/renderer/components/+workloads-overview/workloads/workloads.injectable.ts +++ b/packages/core/src/renderer/components/+workloads-overview/workloads/workloads.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { computed } from "mobx"; -import { shouldShowResourceInjectionToken } from "../../../../common/cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { byOrderNumber } from "../../../../common/utils/composable-responsibilities/orderable/orderable"; import { workloadInjectionToken } from "./workload-injection-token"; diff --git a/packages/core/src/renderer/components/avatar/avatar.tsx b/packages/core/src/renderer/components/avatar/avatar.tsx index 84892b081c..991b7e761b 100644 --- a/packages/core/src/renderer/components/avatar/avatar.tsx +++ b/packages/core/src/renderer/components/avatar/avatar.tsx @@ -8,9 +8,9 @@ import styles from "./avatar.module.scss"; import type { ImgHTMLAttributes, MouseEventHandler } from "react"; import React from "react"; import randomColor from "randomcolor"; -import GraphemeSplitter from "grapheme-splitter"; import type { SingleOrMany } from "@k8slens/utilities"; -import { cssNames, isDefined, iter } from "@k8slens/utilities"; +import { cssNames } from "@k8slens/utilities"; +import { computeDefaultShortName } from "../../../common/catalog/helpers"; export interface AvatarProps { title: string; @@ -28,40 +28,6 @@ export interface AvatarProps { "data-testid"?: string; } -function getNameParts(name: string): string[] { - const byWhitespace = name.split(/\s+/); - - if (byWhitespace.length > 1) { - return byWhitespace; - } - - const byDashes = name.split(/[-_]+/); - - if (byDashes.length > 1) { - return byDashes; - } - - return name.split(/@+/); -} - -function getLabelFromTitle(title: string) { - if (!title) { - return "??"; - } - - const [rawFirst, rawSecond, rawThird] = getNameParts(title); - const splitter = new GraphemeSplitter(); - const first = splitter.iterateGraphemes(rawFirst); - const second = rawSecond ? splitter.iterateGraphemes(rawSecond): first; - const third = rawThird ? splitter.iterateGraphemes(rawThird) : iter.newEmpty(); - - return [ - ...iter.take(first, 1), - ...iter.take(second, 1), - ...iter.take(third, 1), - ].filter(isDefined).join(""); -} - export const Avatar = ({ title, variant = "rounded", @@ -104,6 +70,6 @@ export const Avatar = ({ alt={title} /> ) - : children || getLabelFromTitle(title)} + : children || computeDefaultShortName(title)} ); diff --git a/packages/core/src/renderer/components/catalog-entities/weblink-add-command.tsx b/packages/core/src/renderer/components/catalog-entities/weblink-add-command.tsx index 0209ff93fa..221af86f38 100644 --- a/packages/core/src/renderer/components/catalog-entities/weblink-add-command.tsx +++ b/packages/core/src/renderer/components/catalog-entities/weblink-add-command.tsx @@ -7,15 +7,15 @@ import React from "react"; import { observer } from "mobx-react"; import { Input } from "../input"; import { isUrl } from "../input/input_validators"; -import type { WeblinkStore } from "../../../common/weblinks-store/weblink-store"; import { computed, makeObservable, observable } from "mobx"; import { withInjectables } from "@ogre-tools/injectable-react"; import commandOverlayInjectable from "../command-palette/command-overlay.injectable"; -import weblinkStoreInjectable from "../../../common/weblinks-store/weblink-store.injectable"; +import type { AddWeblink } from "../../../features/weblinks/common/add.injectable"; +import addWeblinkInjectable from "../../../features/weblinks/common/add.injectable"; interface Dependencies { closeCommandOverlay: () => void; - weblinkStore: WeblinkStore; + addWeblink: AddWeblink; } @@ -42,7 +42,7 @@ class NonInjectedWeblinkAddCommand extends React.Component { } onSubmit(name: string) { - this.props.weblinkStore.add({ + this.props.addWeblink({ name: name || this.url, url: this.url, }); @@ -97,6 +97,6 @@ export const WeblinkAddCommand = withInjectables(NonInjectedWeblin getProps: (di, props) => ({ ...props, closeCommandOverlay: di.inject(commandOverlayInjectable).close, - weblinkStore: di.inject(weblinkStoreInjectable), + addWeblink: di.inject(addWeblinkInjectable), }), }); diff --git a/packages/core/src/renderer/components/cluster-manager/cluster-frame-handler.injectable.ts b/packages/core/src/renderer/components/cluster-manager/cluster-frame-handler.injectable.ts index 3f40455527..079bf22b2d 100644 --- a/packages/core/src/renderer/components/cluster-manager/cluster-frame-handler.injectable.ts +++ b/packages/core/src/renderer/components/cluster-manager/cluster-frame-handler.injectable.ts @@ -3,8 +3,8 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import getClusterByIdInjectable from "../../../common/cluster-store/get-by-id.injectable"; import loggerInjectable from "../../../common/logger.injectable"; +import getClusterByIdInjectable from "../../../features/cluster/storage/common/get-by-id.injectable"; import { ClusterFrameHandler } from "./cluster-frame-handler"; import emitClusterVisibilityInjectable from "./emit-cluster-visibility.injectable"; diff --git a/packages/core/src/renderer/components/cluster-manager/cluster-frame-handler.ts b/packages/core/src/renderer/components/cluster-manager/cluster-frame-handler.ts index 7420fa680a..eca0e28e11 100644 --- a/packages/core/src/renderer/components/cluster-manager/cluster-frame-handler.ts +++ b/packages/core/src/renderer/components/cluster-manager/cluster-frame-handler.ts @@ -9,8 +9,8 @@ import type { Disposer } from "@k8slens/utilities"; import { onceDefined } from "@k8slens/utilities"; import assert from "assert"; import type { Logger } from "../../../common/logger"; -import type { GetClusterById } from "../../../common/cluster-store/get-by-id.injectable"; import { getClusterFrameUrl } from "../../../common/utils"; +import type { GetClusterById } from "../../../features/cluster/storage/common/get-by-id.injectable"; export interface LensView { isLoaded: boolean; diff --git a/packages/core/src/renderer/components/cluster-manager/cluster-view.tsx b/packages/core/src/renderer/components/cluster-manager/cluster-view.tsx index 6749fdd9d3..1e5062b313 100644 --- a/packages/core/src/renderer/components/cluster-manager/cluster-view.tsx +++ b/packages/core/src/renderer/components/cluster-manager/cluster-view.tsx @@ -18,10 +18,10 @@ import clusterViewRouteParametersInjectable from "./cluster-view-route-parameter import clusterFrameHandlerInjectable from "./cluster-frame-handler.injectable"; import type { CatalogEntityRegistry } from "../../api/catalog/entity/registry"; import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable"; -import type { GetClusterById } from "../../../common/cluster-store/get-by-id.injectable"; -import getClusterByIdInjectable from "../../../common/cluster-store/get-by-id.injectable"; import type { RequestClusterActivation } from "../../../features/cluster/activation/common/request-token"; import requestClusterActivationInjectable from "../../../features/cluster/activation/renderer/request-activation.injectable"; +import type { GetClusterById } from "../../../features/cluster/storage/common/get-by-id.injectable"; +import getClusterByIdInjectable from "../../../features/cluster/storage/common/get-by-id.injectable"; interface Dependencies { clusterId: IComputedValue; diff --git a/packages/core/src/renderer/components/delete-cluster-dialog/view.tsx b/packages/core/src/renderer/components/delete-cluster-dialog/view.tsx index b1548354fd..69666efede 100644 --- a/packages/core/src/renderer/components/delete-cluster-dialog/view.tsx +++ b/packages/core/src/renderer/components/delete-cluster-dialog/view.tsx @@ -15,9 +15,7 @@ import { Dialog } from "../dialog"; import { Icon } from "../icon"; import { Select } from "../select"; import { Checkbox } from "../checkbox"; -import type { HotbarStore } from "../../../common/hotbars/store"; import { withInjectables } from "@ogre-tools/injectable-react"; -import hotbarStoreInjectable from "../../../common/hotbars/store.injectable"; import type { DeleteClusterDialogState } from "./state.injectable"; import deleteClusterDialogStateInjectable from "./state.injectable"; import type { RequestSetClusterAsDeleting } from "../../../features/cluster/delete-dialog/renderer/request-set-as-deleting.injectable"; @@ -32,16 +30,18 @@ import showErrorNotificationInjectable from "../notifications/show-error-notific import { isCurrentContext } from "./is-current-context"; import type { IsInLocalKubeconfig } from "./is-in-local-kubeconfig.injectable"; import isInLocalKubeconfigInjectable from "./is-in-local-kubeconfig.injectable"; +import type { RemoveEntityFromAllHotbars } from "../../../features/hotbar/storage/common/remove-entity-from-all.injectable"; +import removeEntityFromAllHotbarsInjectable from "../../../features/hotbar/storage/common/remove-entity-from-all.injectable"; interface Dependencies { state: IObservableValue; - hotbarStore: HotbarStore; requestSetClusterAsDeleting: RequestSetClusterAsDeleting; requestDeleteCluster: RequestDeleteCluster; requestClearClusterAsDeleting: RequestClearClusterAsDeleting; showErrorNotification: ShowNotification; saveKubeconfig: SaveKubeconfig; isInLocalKubeconfig: IsInLocalKubeconfig; + removeEntityFromAllHotbars: RemoveEntityFromAllHotbars; } @observer @@ -65,7 +65,7 @@ class NonInjectedDeleteClusterDialog extends React.Component { try { await this.props.saveKubeconfig(config, cluster.kubeConfigPath.get()); - this.props.hotbarStore.removeAllHotbarItems(cluster.id); + this.props.removeEntityFromAllHotbars(cluster.id); await this.props.requestDeleteCluster(cluster.id); } catch(error) { this.props.showErrorNotification(`Cannot remove cluster, failed to process config file. ${error}`); @@ -267,7 +267,6 @@ class NonInjectedDeleteClusterDialog extends React.Component { export const DeleteClusterDialog = withInjectables(NonInjectedDeleteClusterDialog, { getProps: (di) => ({ - hotbarStore: di.inject(hotbarStoreInjectable), state: di.inject(deleteClusterDialogStateInjectable), requestSetClusterAsDeleting: di.inject(requestSetClusterAsDeletingInjectable), requestClearClusterAsDeleting: di.inject(requestClearClusterAsDeletingInjectable), @@ -275,5 +274,6 @@ export const DeleteClusterDialog = withInjectables(NonInjectedDele saveKubeconfig: di.inject(saveKubeconfigInjectable), showErrorNotification: di.inject(showErrorNotificationInjectable), isInLocalKubeconfig: di.inject(isInLocalKubeconfigInjectable), + removeEntityFromAllHotbars: di.inject(removeEntityFromAllHotbarsInjectable), }), }); diff --git a/packages/core/src/renderer/components/dock/logs/list.tsx b/packages/core/src/renderer/components/dock/logs/list.tsx index 6b3eded365..d0e437e720 100644 --- a/packages/core/src/renderer/components/dock/logs/list.tsx +++ b/packages/core/src/renderer/components/dock/logs/list.tsx @@ -15,7 +15,6 @@ import { disposeOnUnmount, observer } from "mobx-react"; import moment from "moment-timezone"; import type { Align, ListOnScrollProps } from "react-window"; import { SearchStore } from "../../../search-store/search-store"; -import type { UserStore } from "../../../../common/user-store"; import { array, cssNames } from "@k8slens/utilities"; import type { VirtualListRef } from "../../virtual-list"; import { VirtualList } from "../../virtual-list"; @@ -23,8 +22,9 @@ import { ToBottom } from "./to-bottom"; import type { LogTabViewModel } from "../logs/logs-view-model"; import { Spinner } from "../../spinner"; import { withInjectables } from "@ogre-tools/injectable-react"; -import userStoreInjectable from "../../../../common/user-store/user-store.injectable"; import autoBindReact from "auto-bind/react"; +import type { UserPreferencesState } from "../../../../features/user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../../features/user-preferences/common/state.injectable"; export interface LogListProps { model: LogTabViewModel; @@ -37,7 +37,7 @@ export interface LogListRef { } interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } @observer @@ -129,7 +129,7 @@ class NonForwardedLogList extends React.Component (`${logTimestamp && moment.tz(logTimestamp, this.props.userStore.localeTimezone).format()}${log}`)); + .map(([logTimestamp, log]) => (`${logTimestamp && moment.tz(logTimestamp, this.props.state.localeTimezone).format()}${log}`)); } /** @@ -283,7 +283,7 @@ class NonForwardedLogList extends React.Component }>(NonForwardedLogList, { getProps: (di, props) => ({ ...props, - userStore: di.inject(userStoreInjectable), + state: di.inject(userPreferencesStateInjectable), }), }); diff --git a/packages/core/src/renderer/components/dock/terminal/create-terminal.injectable.ts b/packages/core/src/renderer/components/dock/terminal/create-terminal.injectable.ts index 2ff82e2c17..88e7514855 100644 --- a/packages/core/src/renderer/components/dock/terminal/create-terminal.injectable.ts +++ b/packages/core/src/renderer/components/dock/terminal/create-terminal.injectable.ts @@ -8,13 +8,12 @@ import { Terminal } from "./terminal"; import type { TabId } from "../dock/store"; import type { TerminalApi } from "../../../api/terminal-api"; import terminalSpawningPoolInjectable from "./terminal-spawning-pool.injectable"; -import terminalConfigInjectable from "../../../../common/user-store/terminal-config.injectable"; -import terminalCopyOnSelectInjectable - from "../../../../common/user-store/terminal-copy-on-select.injectable"; import isMacInjectable from "../../../../common/vars/is-mac.injectable"; import openLinkInBrowserInjectable from "../../../../common/utils/open-link-in-browser.injectable"; import xtermColorThemeInjectable from "../../../themes/terminal-colors.injectable"; import loggerInjectable from "../../../../common/logger.injectable"; +import terminalConfigInjectable from "../../../../features/user-preferences/common/terminal-config.injectable"; +import terminalCopyOnSelectInjectable from "../../../../features/user-preferences/common/terminal-copy-on-select.injectable"; export type CreateTerminal = (tabId: TabId, api: TerminalApi) => Terminal; diff --git a/packages/core/src/renderer/components/dock/terminal/terminal.ts b/packages/core/src/renderer/components/dock/terminal/terminal.ts index 9e307aa7dc..a0c3a5384a 100644 --- a/packages/core/src/renderer/components/dock/terminal/terminal.ts +++ b/packages/core/src/renderer/components/dock/terminal/terminal.ts @@ -14,11 +14,11 @@ import { disposer } from "@k8slens/utilities"; import { once } from "lodash"; import { clipboard } from "electron"; import type { Logger } from "../../../../common/logger"; -import type { TerminalConfig } from "../../../../common/user-store/preferences-helpers"; import assert from "assert"; import { TerminalChannels } from "../../../../common/terminal/channels"; import { LinkProvider } from "xterm-link-provider"; import type { OpenLinkInBrowser } from "../../../../common/utils/open-link-in-browser.injectable"; +import type { TerminalConfig } from "../../../../features/user-preferences/common/preferences-helpers"; export interface TerminalDependencies { readonly spawningPool: HTMLElement; diff --git a/packages/core/src/renderer/components/hotbar/__tests__/__snapshots__/hotbar-remove-command.test.tsx.snap b/packages/core/src/renderer/components/hotbar/__tests__/__snapshots__/hotbar-remove-command.test.tsx.snap new file mode 100644 index 0000000000..89eacf6e48 --- /dev/null +++ b/packages/core/src/renderer/components/hotbar/__tests__/__snapshots__/hotbar-remove-command.test.tsx.snap @@ -0,0 +1,97 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` renders w/o errors 1`] = ` +
+
+ + + option , selected. + + + 2 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu. + + + +
+
+
+ Remove hotbar +
+
+ +
+
+
+
+
+
+
+ 1: default +
+
+ 2: non-default +
+
+
+
+
+`; diff --git a/packages/core/src/renderer/components/hotbar/__tests__/hotbar-remove-command.test.tsx b/packages/core/src/renderer/components/hotbar/__tests__/hotbar-remove-command.test.tsx index bb370562f3..98b007206c 100644 --- a/packages/core/src/renderer/components/hotbar/__tests__/hotbar-remove-command.test.tsx +++ b/packages/core/src/renderer/components/hotbar/__tests__/hotbar-remove-command.test.tsx @@ -5,75 +5,56 @@ import "@testing-library/jest-dom/extend-expect"; import { HotbarRemoveCommand } from "../hotbar-remove-command"; +import type { RenderResult } from "@testing-library/react"; import { fireEvent } from "@testing-library/react"; import React from "react"; -import type { DiContainer } from "@ogre-tools/injectable"; import { getDiForUnitTesting } from "../../../getDiForUnitTesting"; -import type { DiRender } from "../../test-utils/renderFor"; import { renderFor } from "../../test-utils/renderFor"; -import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable"; import { ConfirmDialog } from "../../confirm-dialog"; import directoryForUserDataInjectable from "../../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; -import type { HotbarStore } from "../../../../common/hotbars/store"; -import storesAndApisCanBeCreatedInjectable from "../../../stores-apis-can-be-created.injectable"; - -const mockHotbars: Partial> = { - "1": { - id: "1", - name: "Default", - items: [], - }, -}; +import hotbarsStateInjectable from "../../../../features/hotbar/storage/common/state.injectable"; +import type { CreateHotbar } from "../../../../features/hotbar/storage/common/create-hotbar.injectable"; +import createHotbarInjectable from "../../../../features/hotbar/storage/common/create-hotbar.injectable"; +import type { IComputedValue } from "mobx"; +import type { Hotbar } from "../../../../features/hotbar/storage/common/hotbar"; +import hotbarsInjectable from "../../../../features/hotbar/storage/common/hotbars.injectable"; describe("", () => { - let di: DiContainer; - let render: DiRender; + let result: RenderResult; + let createHotbar: CreateHotbar; + let hotbars: IComputedValue; beforeEach(() => { - di = getDiForUnitTesting(); + const di = getDiForUnitTesting(); + const render = renderFor(di); - di.override(storesAndApisCanBeCreatedInjectable, () => true); di.override(directoryForUserDataInjectable, () => "/some-directory-for-user-data"); - render = renderFor(di); - }); + createHotbar = di.inject(createHotbarInjectable); + hotbars = di.inject(hotbarsInjectable); - it("renders w/o errors", () => { - di.override(hotbarStoreInjectable, () => ({ - hotbars: [mockHotbars["1"]], - getById: (id: string) => mockHotbars[id], - remove: () => { - }, - hotbarIndex: () => 0, - getDisplayLabel: () => "1: Default", - }) as unknown as HotbarStore); + const hotbarsState = di.inject(hotbarsStateInjectable); + const defaultHotbar = createHotbar({ name: "default" }); + const nonDefaultHotbar = createHotbar({ name: "non-default" }); - const { container } = render(); + hotbarsState.set(defaultHotbar.id, defaultHotbar); + hotbarsState.set(nonDefaultHotbar.id, nonDefaultHotbar); - expect(container).toBeInstanceOf(HTMLElement); - }); - - it("calls remove if you click on the entry", () => { - const removeMock = jest.fn(); - - di.override(hotbarStoreInjectable, () => ({ - hotbars: [mockHotbars["1"]], - getById: (id: string) => mockHotbars[id], - remove: removeMock, - hotbarIndex: () => 0, - getDisplayLabel: () => "1: Default", - }) as unknown as HotbarStore); - - const { getByText } = render( + result = render(( <> - , - ); + + )); + }); - fireEvent.click(getByText("1: Default")); - fireEvent.click(getByText("Remove Hotbar")); + it("renders w/o errors", () => { + expect(result.container).toMatchSnapshot(); + }); - expect(removeMock).toHaveBeenCalled(); + it("calls remove if you click on the entry", () => { + fireEvent.click(result.getByText("1: default")); + fireEvent.click(result.getByText("Remove Hotbar")); + expect(hotbars.get().length).toBe(1); }); }); diff --git a/packages/core/src/renderer/components/hotbar/hotbar-add-command.tsx b/packages/core/src/renderer/components/hotbar/hotbar-add-command.tsx index 3fd261b213..cb97f638e9 100644 --- a/packages/core/src/renderer/components/hotbar/hotbar-add-command.tsx +++ b/packages/core/src/renderer/components/hotbar/hotbar-add-command.tsx @@ -7,15 +7,15 @@ import React from "react"; import { observer } from "mobx-react"; import type { InputValidator } from "../input"; import { Input } from "../input"; -import type { CreateHotbarData, CreateHotbarOptions } from "../../../common/hotbars/types"; import { withInjectables } from "@ogre-tools/injectable-react"; import commandOverlayInjectable from "../command-palette/command-overlay.injectable"; import uniqueHotbarNameInjectable from "../input/validators/unique-hotbar-name.injectable"; -import addHotbarInjectable from "../../../common/hotbars/add-hotbar.injectable"; +import type { AddHotbar } from "../../../features/hotbar/storage/common/add.injectable"; +import addHotbarInjectable from "../../../features/hotbar/storage/common/add.injectable"; interface Dependencies { closeCommandOverlay: () => void; - addHotbar: (data: CreateHotbarData, opts: CreateHotbarOptions) => void; + addHotbar: AddHotbar; uniqueHotbarName: InputValidator; } diff --git a/packages/core/src/renderer/components/hotbar/hotbar-menu.tsx b/packages/core/src/renderer/components/hotbar/hotbar-menu.tsx index e83848cdfd..b9ba43b711 100644 --- a/packages/core/src/renderer/components/hotbar/hotbar-menu.tsx +++ b/packages/core/src/renderer/components/hotbar/hotbar-menu.tsx @@ -5,7 +5,7 @@ import "./hotbar-menu.scss"; -import React from "react"; +import React, { useState } from "react"; import { observer } from "mobx-react"; import { HotbarEntityIcon } from "./hotbar-entity-icon"; import type { IClassName } from "@k8slens/utilities"; @@ -16,57 +16,46 @@ import { DragDropContext, Draggable, Droppable, type DropResult } from "react-be import { HotbarSelector } from "./hotbar-selector"; import { HotbarCell } from "./hotbar-cell"; import { HotbarIcon } from "./hotbar-icon"; -import type { HotbarItem } from "../../../common/hotbars/types"; -import { defaultHotbarCells } from "../../../common/hotbars/types"; -import { action, makeObservable, observable } from "mobx"; -import hotbarStoreInjectable from "../../../common/hotbars/store.injectable"; +import type { HotbarItem } from "../../../features/hotbar/storage/common/types"; +import { defaultHotbarCells } from "../../../features/hotbar/storage/common/types"; +import type { IComputedValue } from "mobx"; import { withInjectables } from "@ogre-tools/injectable-react"; -import type { HotbarStore } from "../../../common/hotbars/store"; import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable"; +import type { Hotbar } from "../../../features/hotbar/storage/common/hotbar"; +import activeHotbarInjectable from "../../../features/hotbar/storage/common/active.injectable"; export interface HotbarMenuProps { className?: IClassName; } interface Dependencies { - hotbarStore: HotbarStore; + activeHotbar: IComputedValue; entityRegistry: CatalogEntityRegistry; } -@observer -class NonInjectedHotbarMenu extends React.Component { - @observable draggingOver = false; +const NonInjectedHotbarMenu = observer((props: Dependencies & HotbarMenuProps) => { + const { + activeHotbar, + entityRegistry, + className, + } = props; - constructor(props: Dependencies & HotbarMenuProps) { - super(props); - makeObservable(this); - } + const [draggingOver, setDraggingOver] = useState(false); + const hotbar = activeHotbar.get(); - get hotbar() { - return this.props.hotbarStore.getActive(); - } - - getEntity(item: HotbarItem | null) { - const hotbar = this.props.hotbarStore.getActive(); - - if (!hotbar || !item) { - return null; + const getEntity = (item: HotbarItem | null) => { + if (!item) { + return undefined; } - return this.props.entityRegistry.getById(item.entity.uid) ?? null; - } + return entityRegistry.getById(item.entity.uid); + }; + const onDragStart = () => setDraggingOver(true); + const onDragEnd = (result: DropResult) => { + setDraggingOver(false); - @action - onDragStart() { - this.draggingOver = true; - } - - @action - onDragEnd(result: DropResult) { const { source, destination } = result; - this.draggingOver = false; - if (!destination) { // Dropped outside of the list return; } @@ -74,135 +63,115 @@ class NonInjectedHotbarMenu extends React.Component { - const hotbar = this.props.hotbarStore; - - hotbar.removeFromHotbar(uid); + hotbar?.restack(from, to); }; - - addItem = (entity: CatalogEntity, index = -1) => { - const hotbar = this.props.hotbarStore; - - hotbar.addToHotbar(entity, index); + const removeItem = (entityId: string) => { + hotbar?.removeEntity(entityId); }; - - getMoveAwayDirection(entityId: string | undefined | null, cellIndex: number) { - if (!entityId) { + const addItem = (entity: CatalogEntity) => { + hotbar?.addEntity(entity); + }; + const getMoveAwayDirection = (entityId: string | undefined | null, cellIndex: number) => { + if (!entityId || !hotbar) { return "animateDown"; } - const draggableItemIndex = this.hotbar.items.findIndex(item => item?.entity.uid == entityId); + const draggableItemIndex = hotbar.items.findIndex(item => item?.entity.uid == entityId); return draggableItemIndex > cellIndex ? "animateDown" : "animateUp"; - } + }; - renderGrid() { - return this.hotbar.items.map((item, index) => { - const entity = this.getEntity(item); - - return ( - - {(provided, snapshot) => ( - - {item && ( - - {(provided, snapshot) => { - const style = { - zIndex: defaultHotbarCells - index, - position: "absolute", - ...provided.draggableProps.style, - } as React.CSSProperties; - - return ( -
- {entity ? ( - this.props.entityRegistry.onRun(entity)} - className={cssNames({ isDragging: snapshot.isDragging })} - remove={this.removeItem} - add={this.addItem} - size={40} - /> - ) : ( - this.removeItem(item.entity.uid), - }, - ]} - disabled - size={40} - /> - )} -
- ); - }} -
- )} - {provided.placeholder} -
- )} -
- ); - }); - } - - render() { - const { className, hotbarStore } = this.props; - const hotbar = hotbarStore.getActive(); + const renderGrid = () => hotbar?.items.map((item, index) => { + const entity = getEntity(item); return ( -
-
- this.onDragStart()} - onDragEnd={(result) => this.onDragEnd(result)}> - {this.renderGrid()} - -
- -
+ + {(provided, snapshot) => ( + + {item && ( + + {(provided, snapshot) => ( +
+ {entity ? ( + entityRegistry.onRun(entity)} + className={cssNames({ isDragging: snapshot.isDragging })} + remove={removeItem} + add={addItem} + size={40} /> + ) : ( + removeItem(item.entity.uid), + }, + ]} + disabled + size={40} /> + )} +
+ )} +
+ )} + {provided.placeholder} +
+ )} +
); - } -} + }); + + return ( +
+
+ onDragStart()} + onDragEnd={(result) => onDragEnd(result)}> + {renderGrid()} + +
+ +
+ ); +}); export const HotbarMenu = withInjectables(NonInjectedHotbarMenu, { getProps: (di, props) => ({ ...props, - hotbarStore: di.inject(hotbarStoreInjectable), entityRegistry: di.inject(catalogEntityRegistryInjectable), + activeHotbar: di.inject(activeHotbarInjectable), }), }); diff --git a/packages/core/src/renderer/components/hotbar/hotbar-remove-command.tsx b/packages/core/src/renderer/components/hotbar/hotbar-remove-command.tsx index 0199b7f739..4f2b1a4e17 100644 --- a/packages/core/src/renderer/components/hotbar/hotbar-remove-command.tsx +++ b/packages/core/src/renderer/components/hotbar/hotbar-remove-command.tsx @@ -6,23 +6,32 @@ import React from "react"; import { observer } from "mobx-react"; import { Select } from "../select"; -import hotbarStoreInjectable from "../../../common/hotbars/store.injectable"; import { withInjectables } from "@ogre-tools/injectable-react"; import commandOverlayInjectable from "../command-palette/command-overlay.injectable"; -import type { HotbarStore } from "../../../common/hotbars/store"; import type { OpenConfirmDialog } from "../confirm-dialog/open.injectable"; import openConfirmDialogInjectable from "../confirm-dialog/open.injectable"; +import type { IComputedValue } from "mobx"; +import type { Hotbar } from "../../../features/hotbar/storage/common/hotbar"; +import type { ComputeHotbarDisplayLabel } from "../../../features/hotbar/storage/common/compute-display-label.injectable"; +import computeHotbarDisplayLabelInjectable from "../../../features/hotbar/storage/common/compute-display-label.injectable"; +import hotbarsInjectable from "../../../features/hotbar/storage/common/hotbars.injectable"; +import type { RemoveHotbar } from "../../../features/hotbar/storage/common/remove.injectable"; +import removeHotbarInjectable from "../../../features/hotbar/storage/common/remove.injectable"; interface Dependencies { closeCommandOverlay: () => void; openConfirmDialog: OpenConfirmDialog; - hotbarStore: HotbarStore; + hotbars: IComputedValue; + computeHotbarDisplayLabel: ComputeHotbarDisplayLabel; + removeHotbar: RemoveHotbar; } const NonInjectedHotbarRemoveCommand = observer(({ closeCommandOverlay, - hotbarStore, openConfirmDialog, + hotbars, + computeHotbarDisplayLabel, + removeHotbar, }: Dependencies) => ( ); } } else { - hotbarStore.setActiveHotbar(option.value); + setAsActiveHotbar(option.value); commandOverlay.close(); } }} components={{ DropdownIndicator: null, IndicatorSeparator: null }} menuIsOpen={true} options={[ - ...hotbarStore.hotbars.map(hotbar => ({ + ...hotbars.get().map(hotbar => ({ value: hotbar, - label: hotbarStore.getDisplayLabel(hotbar), + label: computeHotbarDisplayLabel(hotbar), })), { value: hotbarAddAction, label: "Add hotbar ...", }, - ...ignoreIf(hotbarStore.hotbars.length > 1, [ + ...ignoreIf(hotbars.get().length > 1, [ { value: hotbarRemoveAction, label: "Remove hotbar ...", @@ -85,8 +94,10 @@ const NonInjectedHotbarSwitchCommand = observer(({ export const HotbarSwitchCommand = withInjectables(NonInjectedHotbarSwitchCommand, { getProps: (di, props) => ({ - hotbarStore: di.inject(hotbarStoreInjectable), - commandOverlay: di.inject(commandOverlayInjectable), ...props, + commandOverlay: di.inject(commandOverlayInjectable), + computeHotbarDisplayLabel: di.inject(computeHotbarDisplayLabelInjectable), + hotbars: di.inject(hotbarsInjectable), + setAsActiveHotbar: di.inject(setAsActiveHotbarInjectable), }), }); diff --git a/packages/core/src/renderer/components/input/validators/unique-hotbar-name.injectable.ts b/packages/core/src/renderer/components/input/validators/unique-hotbar-name.injectable.ts index e4d68e9f29..48c1fb6fc1 100644 --- a/packages/core/src/renderer/components/input/validators/unique-hotbar-name.injectable.ts +++ b/packages/core/src/renderer/components/input/validators/unique-hotbar-name.injectable.ts @@ -4,19 +4,19 @@ */ import { getInjectable } from "@ogre-tools/injectable"; -import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable"; +import findHotbarByNameInjectable from "../../../../features/hotbar/storage/common/find-by-name.injectable"; import { inputValidator } from "../input_validators"; const uniqueHotbarNameInjectable = getInjectable({ id: "unique-hotbar-name", instantiate: di => { - const store = di.inject(hotbarStoreInjectable); + const findHotbarByName = di.inject(findHotbarByNameInjectable); return inputValidator({ condition: ({ required }) => required, message: () => "Hotbar with this name already exists", - validate: value => !store.findByName(value), + validate: value => !findHotbarByName(value), }); }, }); diff --git a/packages/core/src/renderer/components/item-object-list/content.tsx b/packages/core/src/renderer/components/item-object-list/content.tsx index 17b864ed6e..2b11a97570 100644 --- a/packages/core/src/renderer/components/item-object-list/content.tsx +++ b/packages/core/src/renderer/components/item-object-list/content.tsx @@ -25,15 +25,17 @@ import type { LensTheme } from "../../themes/lens-theme"; import { MenuActions } from "../menu/menu-actions"; import { MenuItem } from "../menu"; import { Checkbox } from "../checkbox"; -import type { UserStore } from "../../../common/user-store"; import type { ItemListStore } from "./list-layout"; import { withInjectables } from "@ogre-tools/injectable-react"; -import userStoreInjectable from "../../../common/user-store/user-store.injectable"; import pageFiltersStoreInjectable from "./page-filters/store.injectable"; import type { OpenConfirmDialog } from "../confirm-dialog/open.injectable"; import openConfirmDialogInjectable from "../confirm-dialog/open.injectable"; import activeThemeInjectable from "../../themes/active.injectable"; import autoBindReact from "auto-bind/react"; +import type { ToggleTableColumnVisibility } from "../../../features/user-preferences/common/toggle-table-column-visibility.injectable"; +import toggleTableColumnVisibilityInjectable from "../../../features/user-preferences/common/toggle-table-column-visibility.injectable"; +import type { IsTableColumnHidden } from "../../../features/user-preferences/common/is-table-column-hidden.injectable"; +import isTableColumnHiddenInjectable from "../../../features/user-preferences/common/is-table-column-hidden.injectable"; export interface ItemListLayoutContentProps { getFilters: () => Filter[]; @@ -74,9 +76,10 @@ export interface ItemListLayoutContentProps; - userStore: UserStore; pageFiltersStore: PageFiltersStore; openConfirmDialog: OpenConfirmDialog; + toggleTableColumnVisibility: ToggleTableColumnVisibility; + isTableColumnHidden: IsTableColumnHidden; } @observer @@ -342,7 +345,7 @@ class NonInjectedItemListLayoutContent< showColumn({ id: columnId, showWithColumn }: TableCellProps): boolean { const { tableId, isConfigurable } = this.props; - return !isConfigurable || !tableId || !this.props.userStore.isTableColumnHidden(tableId, columnId, showWithColumn); + return !isConfigurable || !tableId || !this.props.isTableColumnHidden(tableId, columnId, showWithColumn); } renderColumnVisibilityMenu(tableId: string) { @@ -365,7 +368,7 @@ class NonInjectedItemListLayoutContent< `} value={this.showColumn(cellProps)} - onChange={() => this.props.userStore.toggleTableColumnVisibility(tableId, cellProps.id)} + onChange={() => this.props.toggleTableColumnVisibility(tableId, cellProps.id)} /> )) @@ -379,8 +382,9 @@ export const ItemListLayoutContent = withInjectables ({ ...props, activeTheme: di.inject(activeThemeInjectable), - userStore: di.inject(userStoreInjectable), pageFiltersStore: di.inject(pageFiltersStoreInjectable), openConfirmDialog: di.inject(openConfirmDialogInjectable), + toggleTableColumnVisibility: di.inject(toggleTableColumnVisibilityInjectable), + isTableColumnHidden: di.inject(isTableColumnHiddenInjectable), }), }) as (props: ItemListLayoutContentProps) => React.ReactElement; diff --git a/packages/core/src/renderer/components/layout/__tests__/__snapshots__/sidebar-cluster.test.tsx.snap b/packages/core/src/renderer/components/layout/__tests__/__snapshots__/sidebar-cluster.test.tsx.snap new file mode 100644 index 0000000000..26aab5675c --- /dev/null +++ b/packages/core/src/renderer/components/layout/__tests__/__snapshots__/sidebar-cluster.test.tsx.snap @@ -0,0 +1,36 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` renders w/o errors 1`] = ` +
+ +
+`; diff --git a/packages/core/src/renderer/components/layout/__tests__/sidebar-cluster.test.tsx b/packages/core/src/renderer/components/layout/__tests__/sidebar-cluster.test.tsx index f9d447dd5e..69bfe5458c 100644 --- a/packages/core/src/renderer/components/layout/__tests__/sidebar-cluster.test.tsx +++ b/packages/core/src/renderer/components/layout/__tests__/sidebar-cluster.test.tsx @@ -5,56 +5,47 @@ import React from "react"; import "@testing-library/jest-dom/extend-expect"; +import type { RenderResult } from "@testing-library/react"; import { fireEvent } from "@testing-library/react"; import { SidebarCluster } from "../sidebar-cluster"; import { KubernetesCluster } from "../../../../common/catalog-entities"; import { getDiForUnitTesting } from "../../../getDiForUnitTesting"; -import type { DiRender } from "../../test-utils/renderFor"; import { renderFor } from "../../test-utils/renderFor"; -import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable"; -import type { HotbarStore } from "../../../../common/hotbars/store"; - -const clusterEntity = new KubernetesCluster({ - metadata: { - uid: "test-uid", - name: "test-cluster", - source: "local", - labels: {}, - }, - spec: { - kubeconfigPath: "", - kubeconfigContext: "", - }, - status: { - phase: "connected", - }, -}); describe("", () => { - let render: DiRender; + let result: RenderResult; beforeEach(() => { const di = getDiForUnitTesting(); + const render = renderFor(di); - di.override(hotbarStoreInjectable, () => ({ - isAddedToActive: () => {}, - }) as unknown as HotbarStore); + const clusterEntity = new KubernetesCluster({ + metadata: { + uid: "test-uid", + name: "test-cluster", + source: "local", + labels: {}, + }, + spec: { + kubeconfigPath: "", + kubeconfigContext: "", + }, + status: { + phase: "connected", + }, + }); - render = renderFor(di); + result = render(); }); it("renders w/o errors", () => { - const { container } = render(); - - expect(container).toBeInstanceOf(HTMLElement); + expect(result.container).toMatchSnapshot(); }); it("renders cluster avatar and name", () => { - const { getByText, getAllByText } = render(); + expect(result.getByText("tc")).toBeInTheDocument(); - expect(getByText("tc")).toBeInTheDocument(); - - const v = getAllByText("test-cluster"); + const v = result.getAllByText("test-cluster"); expect(v.length).toBeGreaterThan(0); @@ -64,11 +55,8 @@ describe("", () => { }); it("renders cluster menu", () => { - const { getByTestId, getByText } = render(); - const link = getByTestId("sidebar-cluster-dropdown"); - - fireEvent.click(link); - expect(getByText("Add to Hotbar")).toBeInTheDocument(); + fireEvent.click(result.getByTestId("sidebar-cluster-dropdown")); + expect(result.getByText("Add to Hotbar")).toBeInTheDocument(); }); }); diff --git a/packages/core/src/renderer/components/layout/sidebar-cluster.tsx b/packages/core/src/renderer/components/layout/sidebar-cluster.tsx index ba5ae7e387..7ae6ee9405 100644 --- a/packages/core/src/renderer/components/layout/sidebar-cluster.tsx +++ b/packages/core/src/renderer/components/layout/sidebar-cluster.tsx @@ -14,8 +14,6 @@ import { Icon } from "../icon"; import { Menu, MenuItem } from "../menu"; import { Tooltip } from "../tooltip"; import { withInjectables } from "@ogre-tools/injectable-react"; -import hotbarStoreInjectable from "../../../common/hotbars/store.injectable"; -import type { HotbarStore } from "../../../common/hotbars/store"; import { observer } from "mobx-react"; import type { VisitEntityContextMenu } from "../../../common/catalog/visit-entity-context-menu.injectable"; import visitEntityContextMenuInjectable from "../../../common/catalog/visit-entity-context-menu.injectable"; @@ -23,6 +21,8 @@ import type { Navigate } from "../../navigation/navigate.injectable"; import type { NormalizeCatalogEntityContextMenu } from "../../catalog/normalize-menu-item.injectable"; import navigateInjectable from "../../navigation/navigate.injectable"; import normalizeCatalogEntityContextMenuInjectable from "../../catalog/normalize-menu-item.injectable"; +import type { ActiveHotbarModel } from "../../../features/hotbar/storage/common/toggling.injectable"; +import activeHotbarInjectable from "../../../features/hotbar/storage/common/toggling.injectable"; export interface SidebarClusterProps { clusterEntity: CatalogEntity | null | undefined; @@ -31,16 +31,16 @@ export interface SidebarClusterProps { interface Dependencies { navigate: Navigate; normalizeMenuItem: NormalizeCatalogEntityContextMenu; - hotbarStore: HotbarStore; visitEntityContextMenu: VisitEntityContextMenu; + entityInActiveHotbar: ActiveHotbarModel; } const NonInjectedSidebarCluster = observer(({ clusterEntity, - hotbarStore, visitEntityContextMenu: onContextMenuOpen, navigate, normalizeMenuItem, + entityInActiveHotbar, }: Dependencies & SidebarClusterProps) => { const [menuItems] = useState(observable.array()); const [opened, setOpened] = useState(false ); @@ -61,13 +61,10 @@ const NonInjectedSidebarCluster = observer(({ } const onMenuOpen = () => { - const isAddedToActive = hotbarStore.isAddedToActive(clusterEntity); - const title = isAddedToActive + const title = entityInActiveHotbar.hasEntity(clusterEntity.getId()) ? "Remove from Hotbar" : "Add to Hotbar"; - const onClick = isAddedToActive - ? () => hotbarStore.removeFromHotbar(clusterEntity.getId()) - : () => hotbarStore.addToHotbar(clusterEntity); + const onClick = () => entityInActiveHotbar.toggleEntity(clusterEntity); menuItems.replace([{ title, onClick }]); onContextMenuOpen(clusterEntity, { @@ -148,9 +145,9 @@ const NonInjectedSidebarCluster = observer(({ export const SidebarCluster = withInjectables(NonInjectedSidebarCluster, { getProps: (di, props) => ({ ...props, - hotbarStore: di.inject(hotbarStoreInjectable), visitEntityContextMenu: di.inject(visitEntityContextMenuInjectable), navigate: di.inject(navigateInjectable), normalizeMenuItem: di.inject(normalizeCatalogEntityContextMenuInjectable), + entityInActiveHotbar: di.inject(activeHotbarInjectable), }), }); diff --git a/packages/core/src/renderer/components/locale-date/locale-date.tsx b/packages/core/src/renderer/components/locale-date/locale-date.tsx index 28b5f6b05a..4ec558e617 100644 --- a/packages/core/src/renderer/components/locale-date/locale-date.tsx +++ b/packages/core/src/renderer/components/locale-date/locale-date.tsx @@ -6,27 +6,27 @@ import React from "react"; import { observer } from "mobx-react"; import moment from "moment-timezone"; -import type { UserStore } from "../../../common/user-store"; import { withInjectables } from "@ogre-tools/injectable-react"; -import userStoreInjectable from "../../../common/user-store/user-store.injectable"; +import type { UserPreferencesState } from "../../../features/user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../features/user-preferences/common/state.injectable"; export interface LocaleDateProps { date: string; } interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; } -const NonInjectedLocaleDate = observer(({ date, userStore }: LocaleDateProps & Dependencies) => ( +const NonInjectedLocaleDate = observer(({ date, state }: LocaleDateProps & Dependencies) => ( <> - {`${moment.tz(date, userStore.localeTimezone).format()}`} + {`${moment.tz(date, state.localeTimezone).format()}`} )); export const LocaleDate = withInjectables(NonInjectedLocaleDate, { getProps: (di, props) => ({ ...props, - userStore: di.inject(userStoreInjectable), + state: di.inject(userPreferencesStateInjectable), }), }); diff --git a/packages/core/src/renderer/components/monaco-editor/monaco-editor.tsx b/packages/core/src/renderer/components/monaco-editor/monaco-editor.tsx index d41ab4157b..7e36639c41 100644 --- a/packages/core/src/renderer/components/monaco-editor/monaco-editor.tsx +++ b/packages/core/src/renderer/components/monaco-editor/monaco-editor.tsx @@ -13,15 +13,15 @@ import type { MonacoTheme } from "./monaco-themes"; import { type MonacoValidator, monacoValidators } from "./monaco-validators"; import { debounce, merge } from "lodash"; import { cssNames, disposer } from "@k8slens/utilities"; -import type { UserStore } from "../../../common/user-store"; import type { LensTheme } from "../../themes/lens-theme"; import { withInjectables } from "@ogre-tools/injectable-react"; -import userStoreInjectable from "../../../common/user-store/user-store.injectable"; import activeThemeInjectable from "../../themes/active.injectable"; import getEditorHeightFromLinesCountInjectable from "./get-editor-height-from-lines-number.injectable"; import type { Logger } from "../../../common/logger"; import loggerInjectable from "../../../common/logger.injectable"; import autoBindReact from "auto-bind/react"; +import type { UserPreferencesState } from "../../../features/user-preferences/common/state.injectable"; +import userPreferencesStateInjectable from "../../../features/user-preferences/common/state.injectable"; export type MonacoEditorId = string; @@ -45,7 +45,7 @@ export interface MonacoEditorProps { } interface Dependencies { - userStore: UserStore; + state: UserPreferencesState; activeTheme: IComputedValue; getEditorHeightFromLinesCount: (linesCount: number) => number; logger: Logger; @@ -116,7 +116,7 @@ class NonInjectedMonacoEditor extends React.Component( - React.forwardRef((props, ref) => ), - { - getProps: (di, props) => ({ - ...props, - userStore: di.inject(userStoreInjectable), - activeTheme: di.inject(activeThemeInjectable), - getEditorHeightFromLinesCount: di.inject(getEditorHeightFromLinesCountInjectable), - logger: di.inject(loggerInjectable), - }), - }, -); +const ForwardedRefMonacoEditor = React.forwardRef(( + (props, ref) => +)); + +export const MonacoEditor = withInjectables(ForwardedRefMonacoEditor, { + getProps: (di, props) => ({ + ...props, + state: di.inject(userPreferencesStateInjectable), + activeTheme: di.inject(activeThemeInjectable), + getEditorHeightFromLinesCount: di.inject(getEditorHeightFromLinesCountInjectable), + logger: di.inject(loggerInjectable), + }), +}); diff --git a/packages/core/src/renderer/components/test-utils/get-extension-fake.ts b/packages/core/src/renderer/components/test-utils/get-extension-fake.ts index 675b7e93e2..9da4adb019 100644 --- a/packages/core/src/renderer/components/test-utils/get-extension-fake.ts +++ b/packages/core/src/renderer/components/test-utils/get-extension-fake.ts @@ -3,7 +3,6 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import type { Writable } from "type-fest"; -import fileSystemProvisionerStoreInjectable from "../../../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable"; import { lensExtensionDependencies } from "../../../extensions/lens-extension"; import { LensMainExtension } from "../../../extensions/lens-main-extension"; import navigateForExtensionInjectable from "../../../main/start-main-application/lens-window/navigate-for-extension.injectable"; @@ -16,6 +15,7 @@ import catalogEntityRegistryForMainInjectable from "../../../main/catalog/entity import catalogEntityRegistryForRendererInjectable from "../../api/catalog/entity/registry.injectable"; import type { DiContainer } from "@ogre-tools/injectable"; import loggerInjectable from "../../../common/logger.injectable"; +import ensureHashedDirectoryForExtensionInjectable from "../../../extensions/extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.injectable"; export class TestExtensionMain extends LensMainExtension {} export class TestExtensionRenderer extends LensRendererExtension {} @@ -47,7 +47,7 @@ export const getMainExtensionFakeWith = (di: DiContainer) => ({ id, name, mainOp Object.assign(instance, mainOptions); (instance as Writable)[lensExtensionDependencies] = { - fileSystemProvisionerStore: di.inject(fileSystemProvisionerStoreInjectable), + ensureHashedDirectoryForExtension: di.inject(ensureHashedDirectoryForExtensionInjectable), entityRegistry: di.inject(catalogEntityRegistryForMainInjectable), navigate: di.inject(navigateForExtensionInjectable), logger: di.inject(loggerInjectable), @@ -78,7 +78,7 @@ export const getRendererExtensionFakeWith = (di: DiContainer) => ({ id, name, re (instance as Writable)[lensExtensionDependencies] = { categoryRegistry: di.inject(catalogCategoryRegistryInjectable), entityRegistry: di.inject(catalogEntityRegistryForRendererInjectable), - fileSystemProvisionerStore: di.inject(fileSystemProvisionerStoreInjectable), + ensureHashedDirectoryForExtension: di.inject(ensureHashedDirectoryForExtensionInjectable), getExtensionPageParameters: di.inject(getExtensionPageParametersInjectable), navigateToRoute: di.inject(navigateToRouteInjectable), routes: di.inject(routesInjectable), diff --git a/packages/core/src/renderer/extension-loader/create-extension-instance.injectable.ts b/packages/core/src/renderer/extension-loader/create-extension-instance.injectable.ts index 0f92440338..ebc424641a 100644 --- a/packages/core/src/renderer/extension-loader/create-extension-instance.injectable.ts +++ b/packages/core/src/renderer/extension-loader/create-extension-instance.injectable.ts @@ -7,7 +7,7 @@ import type { Writable } from "type-fest"; import catalogCategoryRegistryInjectable from "../../common/catalog/category-registry.injectable"; import loggerInjectable from "../../common/logger.injectable"; import { createExtensionInstanceInjectionToken } from "../../extensions/extension-loader/create-extension-instance.token"; -import fileSystemProvisionerStoreInjectable from "../../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable"; +import ensureHashedDirectoryForExtensionInjectable from "../../extensions/extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.injectable"; import { lensExtensionDependencies } from "../../extensions/lens-extension"; import type { LensRendererExtensionDependencies } from "../../extensions/lens-extension-set-dependencies"; import type { LensRendererExtension } from "../../extensions/lens-renderer-extension"; @@ -22,7 +22,7 @@ const createExtensionInstanceInjectable = getInjectable({ const deps: LensRendererExtensionDependencies = { categoryRegistry: di.inject(catalogCategoryRegistryInjectable), entityRegistry: di.inject(catalogEntityRegistryInjectable), - fileSystemProvisionerStore: di.inject(fileSystemProvisionerStoreInjectable), + ensureHashedDirectoryForExtension: di.inject(ensureHashedDirectoryForExtensionInjectable), getExtensionPageParameters: di.inject(getExtensionPageParametersInjectable), navigateToRoute: di.inject(navigateToRouteInjectable), routes: di.inject(routesInjectable), diff --git a/packages/core/src/renderer/initializers/add-sync-entries.injectable.tsx b/packages/core/src/renderer/initializers/add-sync-entries.injectable.tsx index 2f9f3ec74e..5d42d0e496 100644 --- a/packages/core/src/renderer/initializers/add-sync-entries.injectable.tsx +++ b/packages/core/src/renderer/initializers/add-sync-entries.injectable.tsx @@ -3,24 +3,24 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import userStoreInjectable from "../../common/user-store/user-store.injectable"; import React from "react"; import navigateToKubernetesPreferencesInjectable from "../../features/preferences/common/navigate-to-kubernetes-preferences.injectable"; import { runInAction } from "mobx"; import showSuccessNotificationInjectable from "../components/notifications/show-success-notification.injectable"; +import userPreferencesStateInjectable from "../../features/user-preferences/common/state.injectable"; const addSyncEntriesInjectable = getInjectable({ id: "add-sync-entries", instantiate: (di) => { - const userStore = di.inject(userStoreInjectable); + const state = di.inject(userPreferencesStateInjectable); const navigateToKubernetesPreferences = di.inject(navigateToKubernetesPreferencesInjectable); const showSuccessNotification = di.inject(showSuccessNotificationInjectable); return async (paths: string[]) => { runInAction(() => { for (const path of paths) { - userStore.syncKubeconfigEntries.set(path, {}); + state.syncKubeconfigEntries.set(path, {}); } }); diff --git a/packages/core/src/renderer/initializers/workload-events.tsx b/packages/core/src/renderer/initializers/workload-events.tsx index 73251382c8..945746cb2f 100644 --- a/packages/core/src/renderer/initializers/workload-events.tsx +++ b/packages/core/src/renderer/initializers/workload-events.tsx @@ -7,7 +7,7 @@ import { withInjectables } from "@ogre-tools/injectable-react"; import type { IComputedValue } from "mobx"; import { observer } from "mobx-react"; import React from "react"; -import { shouldShowResourceInjectionToken } from "../../common/cluster-store/allowed-resources-injection-token"; +import { shouldShowResourceInjectionToken } from "../../features/cluster/showing-kube-resources/common/allowed-resources-injection-token"; import { Events } from "../components/+events/events"; export interface WorkloadEventsProps {} diff --git a/packages/core/src/renderer/ipc/list-namespaces-forbidden-handler.injectable.tsx b/packages/core/src/renderer/ipc/list-namespaces-forbidden-handler.injectable.tsx index 4acf8182b1..f8c850e7f1 100644 --- a/packages/core/src/renderer/ipc/list-namespaces-forbidden-handler.injectable.tsx +++ b/packages/core/src/renderer/ipc/list-namespaces-forbidden-handler.injectable.tsx @@ -10,8 +10,8 @@ import type { IpcRendererEvent } from "electron"; import React from "react"; import notificationsStoreInjectable from "../components/notifications/notifications-store.injectable"; import { getMillisecondsFromUnixEpoch } from "../../common/utils/date/get-current-date-time"; -import getClusterByIdInjectable from "../../common/cluster-store/get-by-id.injectable"; import showSuccessNotificationInjectable from "../components/notifications/show-success-notification.injectable"; +import getClusterByIdInjectable from "../../features/cluster/storage/common/get-by-id.injectable"; const intervalBetweenNotifications = 1000 * 60; // 60s diff --git a/packages/core/src/renderer/ipc/register-ipc-listeners.injectable.ts b/packages/core/src/renderer/ipc/register-ipc-listeners.injectable.ts index 0c2d407d59..0a80abb9e6 100644 --- a/packages/core/src/renderer/ipc/register-ipc-listeners.injectable.ts +++ b/packages/core/src/renderer/ipc/register-ipc-listeners.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 { defaultHotbarCells } from "../../common/hotbars/types"; +import { defaultHotbarCells } from "../../features/hotbar/storage/common/types"; import { clusterListNamespaceForbiddenChannel } from "../../common/ipc/cluster"; import { hotbarTooManyItemsChannel } from "../../common/ipc/hotbar"; import showErrorNotificationInjectable from "../components/notifications/show-error-notification.injectable"; diff --git a/packages/core/src/renderer/protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.injectable.ts b/packages/core/src/renderer/protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.injectable.ts index 1d378df375..c4497dfaeb 100644 --- a/packages/core/src/renderer/protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.injectable.ts +++ b/packages/core/src/renderer/protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.injectable.ts @@ -12,11 +12,9 @@ import navigateToExtensionsInjectable from "../../../common/front-end-routing/ro import navigateToEntitySettingsInjectable from "../../../common/front-end-routing/routes/entity-settings/navigate-to-entity-settings.injectable"; import navigateToClusterViewInjectable from "../../../common/front-end-routing/routes/cluster-view/navigate-to-cluster-view.injectable"; import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable"; - -// TODO: Importing from features is not OK. Make protocol-router to comply with Open Closed Principle to allow moving implementation under a feature import navigateToPreferencesInjectable from "../../../features/preferences/common/navigate-to-preferences.injectable"; -import getClusterByIdInjectable from "../../../common/cluster-store/get-by-id.injectable"; import showShortInfoNotificationInjectable from "../../components/notifications/show-short-info.injectable"; +import getClusterByIdInjectable from "../../../features/cluster/storage/common/get-by-id.injectable"; const bindProtocolAddRouteHandlersInjectable = getInjectable({ id: "bind-protocol-add-route-handlers", diff --git a/packages/core/src/renderer/protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.tsx b/packages/core/src/renderer/protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.tsx index 4bcf207340..bf80d6c4d4 100644 --- a/packages/core/src/renderer/protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.tsx +++ b/packages/core/src/renderer/protocol-handler/bind-protocol-add-route-handlers/bind-protocol-add-route-handlers.tsx @@ -17,7 +17,7 @@ import type { NavigateToEntitySettings } from "../../../common/front-end-routing import type { NavigateToClusterView } from "../../../common/front-end-routing/routes/cluster-view/navigate-to-cluster-view.injectable"; import assert from "assert"; import type { AttemptInstallByInfo } from "../../components/+extensions/attempt-install-by-info.injectable"; -import type { GetClusterById } from "../../../common/cluster-store/get-by-id.injectable"; +import type { GetClusterById } from "../../../features/cluster/storage/common/get-by-id.injectable"; interface Dependencies { attemptInstallByInfo: AttemptInstallByInfo; diff --git a/packages/core/src/renderer/protocol-handler/lens-protocol-router-renderer/lens-protocol-router-renderer.injectable.ts b/packages/core/src/renderer/protocol-handler/lens-protocol-router-renderer/lens-protocol-router-renderer.injectable.ts index 35938b32fd..aa9525b31a 100644 --- a/packages/core/src/renderer/protocol-handler/lens-protocol-router-renderer/lens-protocol-router-renderer.injectable.ts +++ b/packages/core/src/renderer/protocol-handler/lens-protocol-router-renderer/lens-protocol-router-renderer.injectable.ts @@ -5,17 +5,17 @@ import { getInjectable } from "@ogre-tools/injectable"; import extensionLoaderInjectable from "../../../extensions/extension-loader/extension-loader.injectable"; import { LensProtocolRouterRenderer } from "./lens-protocol-router-renderer"; -import extensionsStoreInjectable from "../../../extensions/extensions-store/extensions-store.injectable"; import loggerInjectable from "../../../common/logger.injectable"; import showErrorNotificationInjectable from "../../components/notifications/show-error-notification.injectable"; import showShortInfoNotificationInjectable from "../../components/notifications/show-short-info.injectable"; +import isExtensionEnabledInjectable from "../../../features/extensions/enabled/common/is-enabled.injectable"; const lensProtocolRouterRendererInjectable = getInjectable({ id: "lens-protocol-router-renderer", instantiate: (di) => new LensProtocolRouterRenderer({ extensionLoader: di.inject(extensionLoaderInjectable), - extensionsStore: di.inject(extensionsStoreInjectable), + isExtensionEnabled: di.inject(isExtensionEnabledInjectable), logger: di.inject(loggerInjectable), showErrorNotification: di.inject(showErrorNotificationInjectable), showShortInfoNotification: di.inject(showShortInfoNotificationInjectable), diff --git a/packages/core/src/renderer/stores/init-user-store.injectable.ts b/packages/core/src/renderer/stores/init-user-store.injectable.ts deleted file mode 100644 index af192d9b2e..0000000000 --- a/packages/core/src/renderer/stores/init-user-store.injectable.ts +++ /dev/null @@ -1,23 +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 userStoreInjectable from "../../common/user-store/user-store.injectable"; -import { beforeFrameStartsSecondInjectionToken } from "../before-frame-starts/tokens"; -import initDefaultUpdateChannelInjectable from "../vars/default-update-channel/init.injectable"; - -const initUserStoreInjectable = getInjectable({ - id: "init-user-store", - instantiate: (di) => ({ - run: () => { - const userStore = di.inject(userStoreInjectable); - - return userStore.load(); - }, - runAfter: initDefaultUpdateChannelInjectable, - }), - injectionToken: beforeFrameStartsSecondInjectionToken, -}); - -export default initUserStoreInjectable; diff --git a/packages/core/src/renderer/themes/active.injectable.ts b/packages/core/src/renderer/themes/active.injectable.ts index e22aee237b..324bbf8117 100644 --- a/packages/core/src/renderer/themes/active.injectable.ts +++ b/packages/core/src/renderer/themes/active.injectable.ts @@ -5,7 +5,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import assert from "assert"; import { computed } from "mobx"; -import lensColorThemePreferenceInjectable from "../../common/user-store/lens-color-theme.injectable"; +import lensColorThemePreferenceInjectable from "../../features/user-preferences/common/lens-color-theme.injectable"; import { lensThemeDeclarationInjectionToken } from "./declaration"; import defaultLensThemeInjectable from "./default-theme.injectable"; import systemThemeConfigurationInjectable from "./system-theme.injectable"; diff --git a/packages/core/src/renderer/themes/apply-lens-theme.injectable.ts b/packages/core/src/renderer/themes/apply-lens-theme.injectable.ts index 94afd5c531..977c5eb77c 100644 --- a/packages/core/src/renderer/themes/apply-lens-theme.injectable.ts +++ b/packages/core/src/renderer/themes/apply-lens-theme.injectable.ts @@ -4,9 +4,9 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import loggerInjectable from "../../common/logger.injectable"; -import userStoreInjectable from "../../common/user-store/user-store.injectable"; import { object } from "@k8slens/utilities"; import type { LensTheme } from "./lens-theme"; +import resetThemeInjectable from "../../features/user-preferences/common/reset-theme.injectable"; export type ApplyLensTheme = (theme: LensTheme) => void; @@ -14,7 +14,7 @@ const applyLensThemeInjectable = getInjectable({ id: "apply-lens-theme", instantiate: (di): ApplyLensTheme => { const logger = di.inject(loggerInjectable); - const userStore = di.inject(userStoreInjectable); + const resetTheme = di.inject(resetThemeInjectable); return (theme) => { try { @@ -28,7 +28,7 @@ const applyLensThemeInjectable = getInjectable({ document.body.classList.toggle("theme-light", theme.type === "light"); } catch (error) { logger.error("[THEME]: Failed to apply active theme", error); - userStore.resetTheme(); + resetTheme(); } }; }, diff --git a/packages/core/src/renderer/themes/setup-apply-active-theme.injectable.ts b/packages/core/src/renderer/themes/setup-apply-active-theme.injectable.ts index c71dd5baa7..f658093f8e 100644 --- a/packages/core/src/renderer/themes/setup-apply-active-theme.injectable.ts +++ b/packages/core/src/renderer/themes/setup-apply-active-theme.injectable.ts @@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import { reaction } from "mobx"; import initializeSystemThemeTypeInjectable from "../../features/theme/system-type/renderer/initialize.injectable"; import { beforeFrameStartsSecondInjectionToken } from "../before-frame-starts/tokens"; -import initUserStoreInjectable from "../stores/init-user-store.injectable"; +import initUserStoreInjectable from "../../features/user-preferences/renderer/load-storage.injectable"; import activeThemeInjectable from "./active.injectable"; import applyLensThemeInjectable from "./apply-lens-theme.injectable"; diff --git a/packages/core/src/renderer/themes/terminal-colors.injectable.ts b/packages/core/src/renderer/themes/terminal-colors.injectable.ts index c7010b08b6..7b83d7b16c 100644 --- a/packages/core/src/renderer/themes/terminal-colors.injectable.ts +++ b/packages/core/src/renderer/themes/terminal-colors.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { computed } from "mobx"; -import terminalThemePreferenceInjectable from "../../common/user-store/terminal-theme.injectable"; +import terminalThemePreferenceInjectable from "../../features/user-preferences/common/terminal-theme.injectable"; import activeThemeInjectable from "./active.injectable"; import lensThemesInjectable from "./themes.injectable"; diff --git a/packages/core/src/test-utils/override-fs-with-fakes.ts b/packages/core/src/test-utils/override-fs-with-fakes.ts index 87f8dd583a..5eaeb90ba7 100644 --- a/packages/core/src/test-utils/override-fs-with-fakes.ts +++ b/packages/core/src/test-utils/override-fs-with-fakes.ts @@ -63,6 +63,7 @@ export const getOverrideFsWithFakes = () => { createReadStream: root.createReadStream as any, stat: root.promises.stat as any, unlink: root.promises.unlink, + rename: root.promises.rename, })); }; }; diff --git a/packages/core/src/test-utils/use-fake-time.ts b/packages/core/src/test-utils/use-fake-time.ts index e455984861..11d5fe0918 100644 --- a/packages/core/src/test-utils/use-fake-time.ts +++ b/packages/core/src/test-utils/use-fake-time.ts @@ -19,7 +19,11 @@ export const advanceFakeTime = (milliseconds: number) => { export const testUsingFakeTime = (dateTime = "2015-10-21T07:28:00Z") => { usingFakeTime = true; - jest.useFakeTimers(); + jest.useFakeTimers({ + doNotFake: [ + "nextTick", + ], + }); jest.setSystemTime(new Date(dateTime)); }; diff --git a/packages/open-lens/package.json b/packages/open-lens/package.json index 577c1a2a6b..fb4fbc6616 100644 --- a/packages/open-lens/package.json +++ b/packages/open-lens/package.json @@ -257,7 +257,7 @@ "esbuild-loader": "^2.20.0", "fork-ts-checker-webpack-plugin": "^7.3.0", "html-webpack-plugin": "^5.5.0", - "jest": "^28.1.3", + "jest": "^29.5.0", "jest-environment-jsdom": "^28.1.3", "jsonfile": "^6.1.0", "mini-css-extract-plugin": "^2.7.1", diff --git a/packages/technical-features/messaging/agnostic/src/features/actual/channel.no-coverage.ts b/packages/technical-features/messaging/agnostic/src/features/actual/channel.no-coverage.ts deleted file mode 100644 index 62a2ea1490..0000000000 --- a/packages/technical-features/messaging/agnostic/src/features/actual/channel.no-coverage.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface Channel { - id: string; - _messageTemplate?: MessageTemplate; - _returnTemplate?: ReturnTemplate; -} diff --git a/packages/technical-features/messaging/agnostic/src/features/actual/index.ts b/packages/technical-features/messaging/agnostic/src/features/actual/index.ts index e8209f26f0..f85542c954 100644 --- a/packages/technical-features/messaging/agnostic/src/features/actual/index.ts +++ b/packages/technical-features/messaging/agnostic/src/features/actual/index.ts @@ -6,8 +6,6 @@ export { getMessageChannel } from "./message/get-message-channel"; export { requestFromChannelInjectionToken } from "./request/request-from-channel-injection-token"; -export type { Channel } from "./channel.no-coverage"; - export { sendMessageToChannelInjectionToken } from "./message/message-to-channel-injection-token"; export type { SendMessageToChannel } from "./message/message-to-channel-injection-token"; diff --git a/packages/technical-features/messaging/agnostic/src/features/actual/listening-of-channels/listening-of-channels.injectable.ts b/packages/technical-features/messaging/agnostic/src/features/actual/listening-of-channels/listening-of-channels.injectable.ts index c28d6cbc5a..9040939f06 100644 --- a/packages/technical-features/messaging/agnostic/src/features/actual/listening-of-channels/listening-of-channels.injectable.ts +++ b/packages/technical-features/messaging/agnostic/src/features/actual/listening-of-channels/listening-of-channels.injectable.ts @@ -6,17 +6,24 @@ import { getStartableStoppable, StartableStoppable } from "@k8slens/startable-st import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-for-mobx"; import { IComputedValue, reaction } from "mobx"; -import { messageChannelListenerInjectionToken } from "../message/message-channel-listener-injection-token"; -import { requestChannelListenerInjectionToken } from "../request/request-channel-listener-injection-token"; +import { + MessageChannel, + messageChannelListenerInjectionToken, +} from "../message/message-channel-listener-injection-token"; +import { + RequestChannel, + requestChannelListenerInjectionToken, +} from "../request/request-channel-listener-injection-token"; import { enlistRequestChannelListenerInjectionToken } from "../request/enlist-request-channel-listener-injection-token"; -import type { Channel } from "../channel.no-coverage"; export type ListeningOfChannels = StartableStoppable; export const listeningOfChannelsInjectionToken = getInjectionToken({ id: "listening-of-channels-injection-token", }); -const listening = }>( +const listening = < + T extends { id: string; channel: MessageChannel | RequestChannel }, +>( channelListeners: IComputedValue, enlistChannelListener: (listener: T) => () => void, getId: (listener: T) => string, diff --git a/packages/technical-features/messaging/agnostic/src/features/actual/message/enlist-message-channel-listener-injection-token.ts b/packages/technical-features/messaging/agnostic/src/features/actual/message/enlist-message-channel-listener-injection-token.ts index 9ec6f8b93a..1bb114ca09 100644 --- a/packages/technical-features/messaging/agnostic/src/features/actual/message/enlist-message-channel-listener-injection-token.ts +++ b/packages/technical-features/messaging/agnostic/src/features/actual/message/enlist-message-channel-listener-injection-token.ts @@ -1,3 +1,4 @@ +import type { Disposer } from "@k8slens/utilities"; import { getInjectionToken } from "@ogre-tools/injectable"; import type { @@ -5,9 +6,9 @@ import type { MessageChannelListener, } from "./message-channel-listener-injection-token"; -export type EnlistMessageChannelListener = ( - listener: MessageChannelListener>, -) => () => void; +export type EnlistMessageChannelListener = ( + listener: MessageChannelListener>, +) => Disposer; export const enlistMessageChannelListenerInjectionToken = getInjectionToken({ diff --git a/packages/technical-features/messaging/agnostic/src/features/actual/request/enlist-request-channel-listener-injection-token.ts b/packages/technical-features/messaging/agnostic/src/features/actual/request/enlist-request-channel-listener-injection-token.ts index cdb3ac97d5..7f2a04a78d 100644 --- a/packages/technical-features/messaging/agnostic/src/features/actual/request/enlist-request-channel-listener-injection-token.ts +++ b/packages/technical-features/messaging/agnostic/src/features/actual/request/enlist-request-channel-listener-injection-token.ts @@ -1,3 +1,4 @@ +import type { Disposer } from "@k8slens/utilities/index"; import { getInjectionToken } from "@ogre-tools/injectable"; import type { @@ -5,9 +6,9 @@ import type { RequestChannelListener, } from "./request-channel-listener-injection-token"; -export type EnlistRequestChannelListener = ( - listener: RequestChannelListener>, -) => () => void; +export type EnlistRequestChannelListener = ( + listener: RequestChannelListener>, +) => Disposer; export const enlistRequestChannelListenerInjectionToken = getInjectionToken({ diff --git a/packages/technical-features/messaging/electron/main/src/channel-listeners/enlist-message-channel-listener.injectable.ts b/packages/technical-features/messaging/electron/main/src/channel-listeners/enlist-message-channel-listener.injectable.ts index 5a33ed39d9..a8368c489b 100644 --- a/packages/technical-features/messaging/electron/main/src/channel-listeners/enlist-message-channel-listener.injectable.ts +++ b/packages/technical-features/messaging/electron/main/src/channel-listeners/enlist-message-channel-listener.injectable.ts @@ -10,7 +10,7 @@ const enlistMessageChannelListenerInjectable = getInjectable({ const ipcMain = di.inject(ipcMainInjectable); return ({ channel, handler }) => { - const nativeOnCallback = (nativeEvent: IpcMainEvent, message: unknown) => { + const nativeOnCallback = (nativeEvent: IpcMainEvent, message: any) => { handler(message, { frameId: nativeEvent.frameId, processId: nativeEvent.processId }); }; diff --git a/packages/technical-features/messaging/electron/renderer/src/listening-of-messages/enlist-message-channel-listener.injectable.ts b/packages/technical-features/messaging/electron/renderer/src/listening-of-messages/enlist-message-channel-listener.injectable.ts index 6948e51073..fb1840f33f 100644 --- a/packages/technical-features/messaging/electron/renderer/src/listening-of-messages/enlist-message-channel-listener.injectable.ts +++ b/packages/technical-features/messaging/electron/renderer/src/listening-of-messages/enlist-message-channel-listener.injectable.ts @@ -10,7 +10,7 @@ const enlistMessageChannelListenerInjectable = getInjectable({ const ipcRenderer = di.inject(ipcRendererInjectable); return ({ channel, handler }) => { - const nativeCallback = (event: IpcRendererEvent, message: unknown) => { + const nativeCallback = (_: IpcRendererEvent, message: any) => { handler(message); }; diff --git a/packages/technical-features/messaging/message-bridge-fake/src/get-message-bridge-fake/get-message-bridge-fake.ts b/packages/technical-features/messaging/message-bridge-fake/src/get-message-bridge-fake/get-message-bridge-fake.ts index ef8eed6461..8feb31dcd2 100644 --- a/packages/technical-features/messaging/message-bridge-fake/src/get-message-bridge-fake/get-message-bridge-fake.ts +++ b/packages/technical-features/messaging/message-bridge-fake/src/get-message-bridge-fake/get-message-bridge-fake.ts @@ -1,5 +1,11 @@ import type { DiContainer } from "@ogre-tools/injectable"; -import type { Channel, MessageChannelHandler, RequestChannelHandler } from "@k8slens/messaging"; +import type { + MessageChannel, + MessageChannelHandler, + MessageChannelListener, + RequestChannel, + RequestChannelHandler, +} from "@k8slens/messaging"; import { enlistMessageChannelListenerInjectionToken, @@ -20,6 +26,8 @@ export type MessageBridgeFake = { setAsync: (value: boolean) => void; }; +type MessageHandlers = Set>>; + const overrideMessaging = ({ di, messageListenersByDi, @@ -28,13 +36,13 @@ const overrideMessaging = ({ }: { di: DiContainer; - messageListenersByDi: Map>>>; + messageListenersByDi: Map>; messagePropagationBuffer: Set<{ resolve: () => Promise }>; getAsyncModeStatus: () => boolean; }) => { - const messageHandlersByChannel = new Map>>(); + const messageHandlersByChannel = new Map(); messageListenersByDi.set(di, messageHandlersByChannel); @@ -64,30 +72,36 @@ const overrideMessaging = ({ }); }); - di.override(enlistMessageChannelListenerInjectionToken, () => (listener) => { - if (!messageHandlersByChannel.has(listener.channel.id)) { - messageHandlersByChannel.set(listener.channel.id, new Set()); - } + di.override( + enlistMessageChannelListenerInjectionToken, + () => + (listener: MessageChannelListener>) => { + if (!messageHandlersByChannel.has(listener.channel.id)) { + messageHandlersByChannel.set(listener.channel.id, new Set()); + } - const handlerSet = messageHandlersByChannel.get(listener.channel.id); + const handlerSet = messageHandlersByChannel.get(listener.channel.id); - handlerSet?.add(listener.handler); + handlerSet?.add(listener.handler); - return () => { - handlerSet?.delete(listener.handler); - }; - }); + return () => { + handlerSet?.delete(listener.handler); + }; + }, + ); }; +type RequestHandlers = Set>>; + const overrideRequesting = ({ di, requestListenersByDi, }: { di: DiContainer; - requestListenersByDi: Map>>>; + requestListenersByDi: Map>; }) => { - const requestHandlersByChannel = new Map>>(); + const requestHandlersByChannel = new Map(); requestListenersByDi.set(di, requestHandlersByChannel); @@ -141,15 +155,8 @@ const overrideRequesting = ({ }; export const getMessageBridgeFake = (): MessageBridgeFake => { - const messageListenersByDi = new Map< - DiContainer, - Map>> - >(); - - const requestListenersByDi = new Map< - DiContainer, - Map>> - >(); + const messageListenersByDi = new Map>(); + const requestListenersByDi = new Map>(); const messagePropagationBuffer = new Set void>>(); diff --git a/packages/utility-features/utilities/src/abort-controller.ts b/packages/utility-features/utilities/src/abort-controller.ts index 784b495a9e..d434a24c6f 100644 --- a/packages/utility-features/utilities/src/abort-controller.ts +++ b/packages/utility-features/utilities/src/abort-controller.ts @@ -22,3 +22,11 @@ export function setTimeoutFor(controller: AbortController, timeout: number): voi controller.signal.addEventListener("abort", () => clearTimeout(handle)); } + +export function chainSignal(target: AbortController, signal: AbortSignal) { + if (signal.aborted) { + target.abort(); + } else { + signal.addEventListener("abort", (event) => target.abort(event)); + } +} diff --git a/packages/utility-features/utilities/src/collection-functions.ts b/packages/utility-features/utilities/src/collection-functions.ts index e78e215e8b..0c2d5cf119 100644 --- a/packages/utility-features/utilities/src/collection-functions.ts +++ b/packages/utility-features/utilities/src/collection-functions.ts @@ -74,7 +74,11 @@ export function getOrInsertWith(map: Map | WeakMap(map: Map, key: K, asyncBuilder: () => Promise): Promise { if (!map.has(key)) { - map.set(key, await asyncBuilder()); + const newValue = await asyncBuilder(); + + runInAction(() => { + map.set(key, newValue); + }); } // eslint-disable-next-line @typescript-eslint/no-non-null-assertion diff --git a/packages/utility-features/utilities/src/delay.ts b/packages/utility-features/utilities/src/delay.ts index d86395026b..83be44be71 100644 --- a/packages/utility-features/utilities/src/delay.ts +++ b/packages/utility-features/utilities/src/delay.ts @@ -10,11 +10,11 @@ * @param timeout The number of milliseconds before resolving * @param failFast An abort controller instance to cause the delay to short-circuit */ -export function delay(timeout = 1000, failFast?: AbortController): Promise { +export function delay(timeout = 1000, failFast?: AbortSignal): Promise { return new Promise(resolve => { const timeoutId = setTimeout(resolve, timeout); - failFast?.signal.addEventListener("abort", () => { + failFast?.addEventListener("abort", () => { clearTimeout(timeoutId); resolve(); }); diff --git a/packages/utility-features/utilities/src/iter.ts b/packages/utility-features/utilities/src/iter.ts index abbf4cc92d..b20f48a67a 100644 --- a/packages/utility-features/utilities/src/iter.ts +++ b/packages/utility-features/utilities/src/iter.ts @@ -10,10 +10,14 @@ interface Iterator extends Iterable { filterMap(fn: (val: T) => Falsy | U): Iterator; find(fn: (val: T) => unknown): T | undefined; collect(fn: (values: Iterable) => U): U; + toArray(): T[]; + toMap(): T extends [infer K, infer V] ? Map : never; + toSet(): Set; map(fn: (val: T) => U): Iterator; flatMap(fn: (val: T) => U[]): Iterator; concat(src2: IterableIterator): Iterator; join(sep?: string): string; + take(count: number): Iterator; } function chain(src: IterableIterator): Iterator { @@ -25,7 +29,11 @@ function chain(src: IterableIterator): Iterator { find: (fn) => find(src, fn), join: (sep) => join(src, sep), collect: (fn) => fn(src), + toArray: () => [...src], + toMap: () => new Map(src as IterableIterator<[any, any]>) as any, + toSet: () => new Set(src), concat: (src2) => chain(concat(src, src2)), + take: (count) => chain(take(src, count)), [Symbol.iterator]: () => src, }; } From 15762615d24b607400cbb242a86ce155d44e117e Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Wed, 29 Mar 2023 14:39:57 +0300 Subject: [PATCH 07/35] Block renderering non http(s):// links via (#7419) * Adding HelmChartIcon tests Signed-off-by: Alex Andreev * HelmChartIcon refactoring Signed-off-by: Alex Andreev * Fine-tune styles in HelmChartDetails Signed-off-by: Alex Andreev * Adding styles to separate module Signed-off-by: Alex Andreev * Clean up Signed-off-by: Alex Andreev * Linter fixes Signed-off-by: Alex Andreev * Updating snapshots Signed-off-by: Alex Andreev --------- Signed-off-by: Alex Andreev --- ...lling-helm-chart-from-new-tab.test.ts.snap | 1720 ++--------------- ...tab-for-installing-helm-chart.test.ts.snap | 903 +-------- .../+helm-charts/__tests__/icon.test.tsx | 64 + .../+helm-charts/helm-chart-details.scss | 17 +- .../+helm-charts/helm-chart-details.tsx | 2 +- .../components/+helm-charts/helm-charts.tsx | 2 +- .../components/+helm-charts/icon.module.css | 13 + .../renderer/components/+helm-charts/icon.tsx | 61 +- 8 files changed, 415 insertions(+), 2367 deletions(-) create mode 100644 packages/core/src/renderer/components/+helm-charts/__tests__/icon.test.tsx create mode 100644 packages/core/src/renderer/components/+helm-charts/icon.module.css diff --git a/packages/core/src/features/helm-charts/installing-chart/__snapshots__/installing-helm-chart-from-new-tab.test.ts.snap b/packages/core/src/features/helm-charts/installing-chart/__snapshots__/installing-helm-chart-from-new-tab.test.ts.snap index 04fb109fc6..22cf47bb7c 100644 --- a/packages/core/src/features/helm-charts/installing-chart/__snapshots__/installing-helm-chart-from-new-tab.test.ts.snap +++ b/packages/core/src/features/helm-charts/installing-chart/__snapshots__/installing-helm-chart-from-new-tab.test.ts.snap @@ -964,44 +964,11 @@ exports[`installing helm chart from new tab given tab for installing chart was n class="TableCell icon" >
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
+ class="chartIcon intro-logo imageNotLoaded" + data-testid="image-container" + style="background-image: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNzIyLjggNzAyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogICAgICAgICAgPGcgZmlsbD0iIzhlOTI5NyI+CiAgICAgICAgICAgIDxwYXRoIGQ9Im0zMTggMjk5LjVjMi4xIDEuNiA0LjggMi41IDcuNiAyLjUgNi45IDAgMTIuNi01LjUgMTIuOS0xMi4zbC4zLS4yIDQuMy03Ni43Yy01LjIuNi0xMC40IDEuNS0xNS42IDIuNy0yOC41IDYuNS01My4yIDIwLjUtNzIuNiAzOS41bDYyLjkgNDQuNnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTMwOS41IDQxMS45Yy0xLjQtNS45LTYuNi05LjktMTIuNC0xMC0uOCAwLTEuNy4xLTIuNS4ybC0uMS0uMi03NS41IDEyLjhjMTEuNyAzMi4yIDMzLjQgNTguNSA2MC44IDc2LjFsMjkuMi03MC43LS4yLS4zYzEuMS0yLjQgMS40LTUuMi43LTcuOXoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTI4NC40IDM1Ny41YzIuNS0uNyA0LjktMi4yIDYuNy00LjQgNC4zLTUuNCAzLjYtMTMuMi0xLjYtMTcuOGwuMS0uMy01Ny40LTUxLjRjLTE3IDI3LjgtMjUuMSA2MS4xLTIxLjQgOTUuM2w3My42LTIxLjJ6Ii8+CiAgICAgICAgICAgIDxwYXRoIGQ9Im0zNDAuMiAzODAgMjEuMiAxMC4yIDIxLjEtMTAuMSA1LjMtMjIuOS0xNC42LTE4LjJoLTIzLjZsLTE0LjYgMTguMnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTM4NC4yIDI4OS40Yy4xIDIuNiAxIDUuMiAyLjggNy41IDQuMyA1LjQgMTIuMSA2LjQgMTcuNyAyLjRsLjIuMSA2Mi41LTQ0LjNjLTIzLjYtMjMuMS01NC40LTM4LjItODcuNi00Mi4yeiIvPgogICAgICAgICAgICA8cGF0aCBkPSJtNDkwLjMgMjgzLjctNTcuMSA1MS4xdi4yYy0yIDEuNy0zLjUgNC4xLTQuMSA2LjgtMS41IDYuOCAyLjUgMTMuNSA5LjIgMTUuM2wuMS4zIDc0IDIxLjNjMS42LTE2IC42LTMyLjUtMy4yLTQ5LTMuOS0xNi44LTEwLjQtMzIuMi0xOC45LTQ2eiIvPgogICAgICAgICAgICA8cGF0aCBkPSJtMzcyLjggNDM5LjZjLTEuMi0yLjMtMy4yLTQuMy01LjgtNS41LTItLjktNC0xLjQtNi0xLjMtNC41LjItOC43IDIuNi0xMC45IDYuOGgtLjFsLTM3LjEgNjcuMWMyNS43IDguOCA1NC4xIDEwLjcgODIuNSA0LjIgNS4xLTEuMiAxMC0yLjUgMTQuOS00LjJsLTM3LjMtNjcuMXoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTcxMS43IDQyNS02MC40LTI2Mi4yYy0zLjItMTMuNy0xMi41LTI1LjMtMjUuMy0zMS40bC0yNDQuNC0xMTYuOGMtNy4xLTMuNC0xNC44LTQuOS0yMi43LTQuNS02LjIuMy0xMi4zIDEuOS0xNy45IDQuNWwtMjQ0LjMgMTE2LjdjLTEyLjggNi4xLTIyLjEgMTcuNy0yNS4zIDMxLjRsLTYwLjIgMjYyLjNjLTIuOCAxMi4yLS41IDI1IDYuMyAzNS41LjggMS4zIDEuNyAyLjUgMi43IDMuN2wxNjkuMSAyMTAuM2M4LjkgMTEgMjIuMyAxNy40IDM2LjUgMTcuNGwyNzEuMi0uMWMxNC4yIDAgMjcuNy02LjQgMzYuNS0xNy40bDE2OS4xLTIxMC4zYzguOS0xMC45IDEyLjItMjUuNCA5LjEtMzkuMXptLTkzLTMuMmMtMS44IDcuOC0xMC4yIDEyLjYtMTguOSAxMC43LS4xIDAtLjIgMC0uMiAwLS4xIDAtLjItLjEtLjMtLjEtMS4yLS4zLTIuNy0uNS0zLjgtLjgtNS0xLjMtOC42LTMuMy0xMy4xLTUuMS05LjctMy41LTE3LjctNi40LTI1LjUtNy41LTQtLjMtNiAxLjYtOC4yIDMtMS4xLS4yLTQuNC0uOC02LjItMS4xLTE0IDQ0LTQzLjkgODIuMi04NC4zIDEwNi4xLjcgMS43IDEuOSA1LjMgMi40IDUuOS0uOSAyLjUtMi4zIDQuOC0xLjEgOC42IDIuOCA3LjQgNy40IDE0LjYgMTMgMjMuMiAyLjcgNCA1LjQgNy4xIDcuOCAxMS43LjYgMS4xIDEuMyAyLjggMS45IDMuOSAzLjggOCAxIDE3LjMtNi4yIDIwLjgtNy4zIDMuNS0xNi4zLS4yLTIwLjItOC4zLS42LTEuMS0xLjMtMi43LTEuOC0zLjgtMi4xLTQuNy0yLjgtOC44LTQuMi0xMy40LTMuMy05LjctNi0xNy44LTEwLTI0LjYtMi4yLTMuMy01LTMuNy03LjUtNC41LS41LS44LTIuMi00LTMuMS01LjYtOC4xIDMuMS0xNi40IDUuNi0yNS4xIDcuNi0zNy45IDguNi03NS45IDUuMS0xMDkuOS03LjlsLTMuMyA2Yy0yLjUuNy00LjggMS4zLTYuMyAzLjEtNS4zIDYuNC03LjUgMTYuNi0xMS4zIDI2LjMtMS41IDQuNi0yLjEgOC43LTQuMiAxMy40LS41IDEuMS0xLjMgMi42LTEuOCAzLjctMy45IDguMS0xMi45IDExLjctMjAuMiA4LjItNy4yLTMuNS0xMC0xMi43LTYuMi0yMC44LjYtMS4yIDEuMy0yLjggMS45LTMuOSAyLjQtNC42IDUuMi03LjcgNy44LTExLjcgNS41LTguNyAxMC40LTE2LjQgMTMuMi0yMy44LjctMi40LS4zLTUuOC0xLjMtOC4zbDIuNy02LjRjLTM4LjktMjMuMS02OS43LTU5LjgtODQuMy0xMDUuM2wtNi40IDEuMWMtMS43LTEtNS4xLTMuMi04LjQtMy03LjggMS4xLTE1LjggNC0yNS41IDcuNS00LjUgMS43LTguMSAzLjctMTMuMSA1LTEuMS4zLTIuNi42LTMuOC44LS4xIDAtLjIuMS0uMy4xcy0uMiAwLS4yIDBjLTguNyAxLjktMTcuMS0yLjktMTguOS0xMC43czMuOC0xNS43IDEyLjQtMTcuOGMuMSAwIC4yIDAgLjItLjFoLjFjMS4yLS4zIDIuOC0uNyAzLjktLjkgNS4xLTEgOS4yLS43IDE0LTEuMSAxMC4yLTEuMSAxOC43LTEuOSAyNi4yLTQuMyAyLjQtMSA0LjctNC4zIDYuMy02LjNsNi4xLTEuOGMtNi45LTQ3LjUgNC44LTk0LjIgMjkuOC0xMzEuOWwtNC43LTQuMmMtLjMtMS44LS43LTYtMi45LTguNC01LjgtNS40LTEzLTkuOS0yMS44LTE1LjMtNC4yLTIuNC04LTQtMTIuMS03LjEtLjktLjctMi4xLTEuNy0zLTIuNC0uMS0uMS0uMS0uMS0uMi0uMi03LTUuNi04LjYtMTUuMi0zLjYtMjEuNiAyLjgtMy42IDcuMi01LjMgMTEuNy01LjIgMy41LjEgNy4xIDEuNCAxMC4yIDMuOCAxIC44IDIuNCAxLjggMy4yIDIuNiAzLjkgMy40IDYuMyA2LjcgOS42IDEwLjIgNy4yIDcuMyAxMy4yIDEzLjQgMTkuNyAxNy44IDMuNCAyIDYuMSAxLjIgOC43LjguOC42IDMuNyAyLjYgNS4zIDMuOCAyNC45LTI2LjQgNTcuNi00NiA5NS42LTU0LjYgOC44LTIgMTcuNy0zLjMgMjYuNC00LjFsLjMtNi4yYzEuOS0xLjkgNC4xLTQuNiA0LjgtNy42LjYtNy45LS40LTE2LjMtMS42LTI2LjUtLjctNC44LTEuOC04LjctMi0xMy45IDAtMS4xIDAtMi41IDAtMy44IDAtLjEgMC0uMyAwLS40IDAtOSA2LjUtMTYuMiAxNC42LTE2LjJzMTQuNiA3LjMgMTQuNiAxNi4yYzAgMS4zLjEgMyAwIDQuMi0uMiA1LjItMS4zIDkuMS0yIDEzLjktMS4yIDEwLjItMi4zIDE4LjctMS43IDI2LjUuNiAzLjkgMi45IDUuNSA0LjggNy4zIDAgMS4xLjIgNC42LjMgNi41IDQ2LjUgNC4xIDg5LjcgMjUuNCAxMjEuNCA1OC43bDUuNi00YzEuOS4xIDYgLjcgOC45LTEgNi41LTQuNCAxMi41LTEwLjUgMTkuNy0xNy44IDMuMy0zLjUgNS43LTYuOCA5LjctMTAuMi45LS44IDIuMy0xLjggMy4yLTIuNiA3LTUuNiAxNi44LTUgMjEuOCAxLjNzMy40IDE2LTMuNiAyMS42Yy0xIC44LTIuMyAxLjktMy4yIDIuNi00LjIgMy4xLTggNC43LTEyLjIgNy4xLTguNyA1LjQtMTYgOS45LTIxLjggMTUuMy0yLjcgMi45LTIuNSA1LjctMi44IDguMy0uOC43LTMuNyAzLjMtNS4yIDQuNyAxMi42IDE4LjggMjIuMSA0MC4xIDI3LjQgNjMuMyA1LjMgMjMuMSA2LjEgNDYuMSAzLjEgNjguM2w1LjkgMS43YzEuMSAxLjUgMy4yIDUuMiA2LjMgNi4zIDcuNSAyLjQgMTYgMy4yIDI2LjIgNC4zIDQuOC40IDguOS4yIDE0IDEuMSAxLjIuMiAzIC43IDQuMiAxIDguOSAyLjQgMTQuNCAxMC40IDEyLjYgMTguMnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTQyOCA0MDEuN2MtMS0uMi0yLS4zLTMtLjItMS43LjEtMy4zLjUtNC45IDEuMy02LjIgMy05IDEwLjQtNi4yIDE2LjdsLS4xLjEgMjkuNiA3MS40YzI4LjUtMTguMiA0OS44LTQ1LjMgNjEtNzYuNmwtNzYuMi0xMi45eiIvPgogICAgICAgICAgPC9nPgogICAgICAgIDwvc3ZnPg==);" + />
@@ -1917,44 +1816,11 @@ exports[`installing helm chart from new tab given tab for installing chart was n class="TableCell icon" >
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
+ class="chartIcon intro-logo imageNotLoaded" + data-testid="image-container" + style="background-image: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNzIyLjggNzAyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogICAgICAgICAgPGcgZmlsbD0iIzhlOTI5NyI+CiAgICAgICAgICAgIDxwYXRoIGQ9Im0zMTggMjk5LjVjMi4xIDEuNiA0LjggMi41IDcuNiAyLjUgNi45IDAgMTIuNi01LjUgMTIuOS0xMi4zbC4zLS4yIDQuMy03Ni43Yy01LjIuNi0xMC40IDEuNS0xNS42IDIuNy0yOC41IDYuNS01My4yIDIwLjUtNzIuNiAzOS41bDYyLjkgNDQuNnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTMwOS41IDQxMS45Yy0xLjQtNS45LTYuNi05LjktMTIuNC0xMC0uOCAwLTEuNy4xLTIuNS4ybC0uMS0uMi03NS41IDEyLjhjMTEuNyAzMi4yIDMzLjQgNTguNSA2MC44IDc2LjFsMjkuMi03MC43LS4yLS4zYzEuMS0yLjQgMS40LTUuMi43LTcuOXoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTI4NC40IDM1Ny41YzIuNS0uNyA0LjktMi4yIDYuNy00LjQgNC4zLTUuNCAzLjYtMTMuMi0xLjYtMTcuOGwuMS0uMy01Ny40LTUxLjRjLTE3IDI3LjgtMjUuMSA2MS4xLTIxLjQgOTUuM2w3My42LTIxLjJ6Ii8+CiAgICAgICAgICAgIDxwYXRoIGQ9Im0zNDAuMiAzODAgMjEuMiAxMC4yIDIxLjEtMTAuMSA1LjMtMjIuOS0xNC42LTE4LjJoLTIzLjZsLTE0LjYgMTguMnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTM4NC4yIDI4OS40Yy4xIDIuNiAxIDUuMiAyLjggNy41IDQuMyA1LjQgMTIuMSA2LjQgMTcuNyAyLjRsLjIuMSA2Mi41LTQ0LjNjLTIzLjYtMjMuMS01NC40LTM4LjItODcuNi00Mi4yeiIvPgogICAgICAgICAgICA8cGF0aCBkPSJtNDkwLjMgMjgzLjctNTcuMSA1MS4xdi4yYy0yIDEuNy0zLjUgNC4xLTQuMSA2LjgtMS41IDYuOCAyLjUgMTMuNSA5LjIgMTUuM2wuMS4zIDc0IDIxLjNjMS42LTE2IC42LTMyLjUtMy4yLTQ5LTMuOS0xNi44LTEwLjQtMzIuMi0xOC45LTQ2eiIvPgogICAgICAgICAgICA8cGF0aCBkPSJtMzcyLjggNDM5LjZjLTEuMi0yLjMtMy4yLTQuMy01LjgtNS41LTItLjktNC0xLjQtNi0xLjMtNC41LjItOC43IDIuNi0xMC45IDYuOGgtLjFsLTM3LjEgNjcuMWMyNS43IDguOCA1NC4xIDEwLjcgODIuNSA0LjIgNS4xLTEuMiAxMC0yLjUgMTQuOS00LjJsLTM3LjMtNjcuMXoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTcxMS43IDQyNS02MC40LTI2Mi4yYy0zLjItMTMuNy0xMi41LTI1LjMtMjUuMy0zMS40bC0yNDQuNC0xMTYuOGMtNy4xLTMuNC0xNC44LTQuOS0yMi43LTQuNS02LjIuMy0xMi4zIDEuOS0xNy45IDQuNWwtMjQ0LjMgMTE2LjdjLTEyLjggNi4xLTIyLjEgMTcuNy0yNS4zIDMxLjRsLTYwLjIgMjYyLjNjLTIuOCAxMi4yLS41IDI1IDYuMyAzNS41LjggMS4zIDEuNyAyLjUgMi43IDMuN2wxNjkuMSAyMTAuM2M4LjkgMTEgMjIuMyAxNy40IDM2LjUgMTcuNGwyNzEuMi0uMWMxNC4yIDAgMjcuNy02LjQgMzYuNS0xNy40bDE2OS4xLTIxMC4zYzguOS0xMC45IDEyLjItMjUuNCA5LjEtMzkuMXptLTkzLTMuMmMtMS44IDcuOC0xMC4yIDEyLjYtMTguOSAxMC43LS4xIDAtLjIgMC0uMiAwLS4xIDAtLjItLjEtLjMtLjEtMS4yLS4zLTIuNy0uNS0zLjgtLjgtNS0xLjMtOC42LTMuMy0xMy4xLTUuMS05LjctMy41LTE3LjctNi40LTI1LjUtNy41LTQtLjMtNiAxLjYtOC4yIDMtMS4xLS4yLTQuNC0uOC02LjItMS4xLTE0IDQ0LTQzLjkgODIuMi04NC4zIDEwNi4xLjcgMS43IDEuOSA1LjMgMi40IDUuOS0uOSAyLjUtMi4zIDQuOC0xLjEgOC42IDIuOCA3LjQgNy40IDE0LjYgMTMgMjMuMiAyLjcgNCA1LjQgNy4xIDcuOCAxMS43LjYgMS4xIDEuMyAyLjggMS45IDMuOSAzLjggOCAxIDE3LjMtNi4yIDIwLjgtNy4zIDMuNS0xNi4zLS4yLTIwLjItOC4zLS42LTEuMS0xLjMtMi43LTEuOC0zLjgtMi4xLTQuNy0yLjgtOC44LTQuMi0xMy40LTMuMy05LjctNi0xNy44LTEwLTI0LjYtMi4yLTMuMy01LTMuNy03LjUtNC41LS41LS44LTIuMi00LTMuMS01LjYtOC4xIDMuMS0xNi40IDUuNi0yNS4xIDcuNi0zNy45IDguNi03NS45IDUuMS0xMDkuOS03LjlsLTMuMyA2Yy0yLjUuNy00LjggMS4zLTYuMyAzLjEtNS4zIDYuNC03LjUgMTYuNi0xMS4zIDI2LjMtMS41IDQuNi0yLjEgOC43LTQuMiAxMy40LS41IDEuMS0xLjMgMi42LTEuOCAzLjctMy45IDguMS0xMi45IDExLjctMjAuMiA4LjItNy4yLTMuNS0xMC0xMi43LTYuMi0yMC44LjYtMS4yIDEuMy0yLjggMS45LTMuOSAyLjQtNC42IDUuMi03LjcgNy44LTExLjcgNS41LTguNyAxMC40LTE2LjQgMTMuMi0yMy44LjctMi40LS4zLTUuOC0xLjMtOC4zbDIuNy02LjRjLTM4LjktMjMuMS02OS43LTU5LjgtODQuMy0xMDUuM2wtNi40IDEuMWMtMS43LTEtNS4xLTMuMi04LjQtMy03LjggMS4xLTE1LjggNC0yNS41IDcuNS00LjUgMS43LTguMSAzLjctMTMuMSA1LTEuMS4zLTIuNi42LTMuOC44LS4xIDAtLjIuMS0uMy4xcy0uMiAwLS4yIDBjLTguNyAxLjktMTcuMS0yLjktMTguOS0xMC43czMuOC0xNS43IDEyLjQtMTcuOGMuMSAwIC4yIDAgLjItLjFoLjFjMS4yLS4zIDIuOC0uNyAzLjktLjkgNS4xLTEgOS4yLS43IDE0LTEuMSAxMC4yLTEuMSAxOC43LTEuOSAyNi4yLTQuMyAyLjQtMSA0LjctNC4zIDYuMy02LjNsNi4xLTEuOGMtNi45LTQ3LjUgNC44LTk0LjIgMjkuOC0xMzEuOWwtNC43LTQuMmMtLjMtMS44LS43LTYtMi45LTguNC01LjgtNS40LTEzLTkuOS0yMS44LTE1LjMtNC4yLTIuNC04LTQtMTIuMS03LjEtLjktLjctMi4xLTEuNy0zLTIuNC0uMS0uMS0uMS0uMS0uMi0uMi03LTUuNi04LjYtMTUuMi0zLjYtMjEuNiAyLjgtMy42IDcuMi01LjMgMTEuNy01LjIgMy41LjEgNy4xIDEuNCAxMC4yIDMuOCAxIC44IDIuNCAxLjggMy4yIDIuNiAzLjkgMy40IDYuMyA2LjcgOS42IDEwLjIgNy4yIDcuMyAxMy4yIDEzLjQgMTkuNyAxNy44IDMuNCAyIDYuMSAxLjIgOC43LjguOC42IDMuNyAyLjYgNS4zIDMuOCAyNC45LTI2LjQgNTcuNi00NiA5NS42LTU0LjYgOC44LTIgMTcuNy0zLjMgMjYuNC00LjFsLjMtNi4yYzEuOS0xLjkgNC4xLTQuNiA0LjgtNy42LjYtNy45LS40LTE2LjMtMS42LTI2LjUtLjctNC44LTEuOC04LjctMi0xMy45IDAtMS4xIDAtMi41IDAtMy44IDAtLjEgMC0uMyAwLS40IDAtOSA2LjUtMTYuMiAxNC42LTE2LjJzMTQuNiA3LjMgMTQuNiAxNi4yYzAgMS4zLjEgMyAwIDQuMi0uMiA1LjItMS4zIDkuMS0yIDEzLjktMS4yIDEwLjItMi4zIDE4LjctMS43IDI2LjUuNiAzLjkgMi45IDUuNSA0LjggNy4zIDAgMS4xLjIgNC42LjMgNi41IDQ2LjUgNC4xIDg5LjcgMjUuNCAxMjEuNCA1OC43bDUuNi00YzEuOS4xIDYgLjcgOC45LTEgNi41LTQuNCAxMi41LTEwLjUgMTkuNy0xNy44IDMuMy0zLjUgNS43LTYuOCA5LjctMTAuMi45LS44IDIuMy0xLjggMy4yLTIuNiA3LTUuNiAxNi44LTUgMjEuOCAxLjNzMy40IDE2LTMuNiAyMS42Yy0xIC44LTIuMyAxLjktMy4yIDIuNi00LjIgMy4xLTggNC43LTEyLjIgNy4xLTguNyA1LjQtMTYgOS45LTIxLjggMTUuMy0yLjcgMi45LTIuNSA1LjctMi44IDguMy0uOC43LTMuNyAzLjMtNS4yIDQuNyAxMi42IDE4LjggMjIuMSA0MC4xIDI3LjQgNjMuMyA1LjMgMjMuMSA2LjEgNDYuMSAzLjEgNjguM2w1LjkgMS43YzEuMSAxLjUgMy4yIDUuMiA2LjMgNi4zIDcuNSAyLjQgMTYgMy4yIDI2LjIgNC4zIDQuOC40IDguOS4yIDE0IDEuMSAxLjIuMiAzIC43IDQuMiAxIDguOSAyLjQgMTQuNCAxMC40IDEyLjYgMTguMnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTQyOCA0MDEuN2MtMS0uMi0yLS4zLTMtLjItMS43LjEtMy4zLjUtNC45IDEuMy02LjIgMy05IDEwLjQtNi4yIDE2LjdsLS4xLjEgMjkuNiA3MS40YzI4LjUtMTguMiA0OS44LTQ1LjMgNjEtNzYuNmwtNzYuMi0xMi45eiIvPgogICAgICAgICAgPC9nPgogICAgICAgIDwvc3ZnPg==);" + />
@@ -14739,44 +13811,11 @@ exports[`installing helm chart from new tab given tab for installing chart was n class="TableCell icon" >
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
+ class="chartIcon intro-logo imageNotLoaded" + data-testid="image-container" + style="background-image: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNzIyLjggNzAyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogICAgICAgICAgPGcgZmlsbD0iIzhlOTI5NyI+CiAgICAgICAgICAgIDxwYXRoIGQ9Im0zMTggMjk5LjVjMi4xIDEuNiA0LjggMi41IDcuNiAyLjUgNi45IDAgMTIuNi01LjUgMTIuOS0xMi4zbC4zLS4yIDQuMy03Ni43Yy01LjIuNi0xMC40IDEuNS0xNS42IDIuNy0yOC41IDYuNS01My4yIDIwLjUtNzIuNiAzOS41bDYyLjkgNDQuNnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTMwOS41IDQxMS45Yy0xLjQtNS45LTYuNi05LjktMTIuNC0xMC0uOCAwLTEuNy4xLTIuNS4ybC0uMS0uMi03NS41IDEyLjhjMTEuNyAzMi4yIDMzLjQgNTguNSA2MC44IDc2LjFsMjkuMi03MC43LS4yLS4zYzEuMS0yLjQgMS40LTUuMi43LTcuOXoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTI4NC40IDM1Ny41YzIuNS0uNyA0LjktMi4yIDYuNy00LjQgNC4zLTUuNCAzLjYtMTMuMi0xLjYtMTcuOGwuMS0uMy01Ny40LTUxLjRjLTE3IDI3LjgtMjUuMSA2MS4xLTIxLjQgOTUuM2w3My42LTIxLjJ6Ii8+CiAgICAgICAgICAgIDxwYXRoIGQ9Im0zNDAuMiAzODAgMjEuMiAxMC4yIDIxLjEtMTAuMSA1LjMtMjIuOS0xNC42LTE4LjJoLTIzLjZsLTE0LjYgMTguMnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTM4NC4yIDI4OS40Yy4xIDIuNiAxIDUuMiAyLjggNy41IDQuMyA1LjQgMTIuMSA2LjQgMTcuNyAyLjRsLjIuMSA2Mi41LTQ0LjNjLTIzLjYtMjMuMS01NC40LTM4LjItODcuNi00Mi4yeiIvPgogICAgICAgICAgICA8cGF0aCBkPSJtNDkwLjMgMjgzLjctNTcuMSA1MS4xdi4yYy0yIDEuNy0zLjUgNC4xLTQuMSA2LjgtMS41IDYuOCAyLjUgMTMuNSA5LjIgMTUuM2wuMS4zIDc0IDIxLjNjMS42LTE2IC42LTMyLjUtMy4yLTQ5LTMuOS0xNi44LTEwLjQtMzIuMi0xOC45LTQ2eiIvPgogICAgICAgICAgICA8cGF0aCBkPSJtMzcyLjggNDM5LjZjLTEuMi0yLjMtMy4yLTQuMy01LjgtNS41LTItLjktNC0xLjQtNi0xLjMtNC41LjItOC43IDIuNi0xMC45IDYuOGgtLjFsLTM3LjEgNjcuMWMyNS43IDguOCA1NC4xIDEwLjcgODIuNSA0LjIgNS4xLTEuMiAxMC0yLjUgMTQuOS00LjJsLTM3LjMtNjcuMXoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTcxMS43IDQyNS02MC40LTI2Mi4yYy0zLjItMTMuNy0xMi41LTI1LjMtMjUuMy0zMS40bC0yNDQuNC0xMTYuOGMtNy4xLTMuNC0xNC44LTQuOS0yMi43LTQuNS02LjIuMy0xMi4zIDEuOS0xNy45IDQuNWwtMjQ0LjMgMTE2LjdjLTEyLjggNi4xLTIyLjEgMTcuNy0yNS4zIDMxLjRsLTYwLjIgMjYyLjNjLTIuOCAxMi4yLS41IDI1IDYuMyAzNS41LjggMS4zIDEuNyAyLjUgMi43IDMuN2wxNjkuMSAyMTAuM2M4LjkgMTEgMjIuMyAxNy40IDM2LjUgMTcuNGwyNzEuMi0uMWMxNC4yIDAgMjcuNy02LjQgMzYuNS0xNy40bDE2OS4xLTIxMC4zYzguOS0xMC45IDEyLjItMjUuNCA5LjEtMzkuMXptLTkzLTMuMmMtMS44IDcuOC0xMC4yIDEyLjYtMTguOSAxMC43LS4xIDAtLjIgMC0uMiAwLS4xIDAtLjItLjEtLjMtLjEtMS4yLS4zLTIuNy0uNS0zLjgtLjgtNS0xLjMtOC42LTMuMy0xMy4xLTUuMS05LjctMy41LTE3LjctNi40LTI1LjUtNy41LTQtLjMtNiAxLjYtOC4yIDMtMS4xLS4yLTQuNC0uOC02LjItMS4xLTE0IDQ0LTQzLjkgODIuMi04NC4zIDEwNi4xLjcgMS43IDEuOSA1LjMgMi40IDUuOS0uOSAyLjUtMi4zIDQuOC0xLjEgOC42IDIuOCA3LjQgNy40IDE0LjYgMTMgMjMuMiAyLjcgNCA1LjQgNy4xIDcuOCAxMS43LjYgMS4xIDEuMyAyLjggMS45IDMuOSAzLjggOCAxIDE3LjMtNi4yIDIwLjgtNy4zIDMuNS0xNi4zLS4yLTIwLjItOC4zLS42LTEuMS0xLjMtMi43LTEuOC0zLjgtMi4xLTQuNy0yLjgtOC44LTQuMi0xMy40LTMuMy05LjctNi0xNy44LTEwLTI0LjYtMi4yLTMuMy01LTMuNy03LjUtNC41LS41LS44LTIuMi00LTMuMS01LjYtOC4xIDMuMS0xNi40IDUuNi0yNS4xIDcuNi0zNy45IDguNi03NS45IDUuMS0xMDkuOS03LjlsLTMuMyA2Yy0yLjUuNy00LjggMS4zLTYuMyAzLjEtNS4zIDYuNC03LjUgMTYuNi0xMS4zIDI2LjMtMS41IDQuNi0yLjEgOC43LTQuMiAxMy40LS41IDEuMS0xLjMgMi42LTEuOCAzLjctMy45IDguMS0xMi45IDExLjctMjAuMiA4LjItNy4yLTMuNS0xMC0xMi43LTYuMi0yMC44LjYtMS4yIDEuMy0yLjggMS45LTMuOSAyLjQtNC42IDUuMi03LjcgNy44LTExLjcgNS41LTguNyAxMC40LTE2LjQgMTMuMi0yMy44LjctMi40LS4zLTUuOC0xLjMtOC4zbDIuNy02LjRjLTM4LjktMjMuMS02OS43LTU5LjgtODQuMy0xMDUuM2wtNi40IDEuMWMtMS43LTEtNS4xLTMuMi04LjQtMy03LjggMS4xLTE1LjggNC0yNS41IDcuNS00LjUgMS43LTguMSAzLjctMTMuMSA1LTEuMS4zLTIuNi42LTMuOC44LS4xIDAtLjIuMS0uMy4xcy0uMiAwLS4yIDBjLTguNyAxLjktMTcuMS0yLjktMTguOS0xMC43czMuOC0xNS43IDEyLjQtMTcuOGMuMSAwIC4yIDAgLjItLjFoLjFjMS4yLS4zIDIuOC0uNyAzLjktLjkgNS4xLTEgOS4yLS43IDE0LTEuMSAxMC4yLTEuMSAxOC43LTEuOSAyNi4yLTQuMyAyLjQtMSA0LjctNC4zIDYuMy02LjNsNi4xLTEuOGMtNi45LTQ3LjUgNC44LTk0LjIgMjkuOC0xMzEuOWwtNC43LTQuMmMtLjMtMS44LS43LTYtMi45LTguNC01LjgtNS40LTEzLTkuOS0yMS44LTE1LjMtNC4yLTIuNC04LTQtMTIuMS03LjEtLjktLjctMi4xLTEuNy0zLTIuNC0uMS0uMS0uMS0uMS0uMi0uMi03LTUuNi04LjYtMTUuMi0zLjYtMjEuNiAyLjgtMy42IDcuMi01LjMgMTEuNy01LjIgMy41LjEgNy4xIDEuNCAxMC4yIDMuOCAxIC44IDIuNCAxLjggMy4yIDIuNiAzLjkgMy40IDYuMyA2LjcgOS42IDEwLjIgNy4yIDcuMyAxMy4yIDEzLjQgMTkuNyAxNy44IDMuNCAyIDYuMSAxLjIgOC43LjguOC42IDMuNyAyLjYgNS4zIDMuOCAyNC45LTI2LjQgNTcuNi00NiA5NS42LTU0LjYgOC44LTIgMTcuNy0zLjMgMjYuNC00LjFsLjMtNi4yYzEuOS0xLjkgNC4xLTQuNiA0LjgtNy42LjYtNy45LS40LTE2LjMtMS42LTI2LjUtLjctNC44LTEuOC04LjctMi0xMy45IDAtMS4xIDAtMi41IDAtMy44IDAtLjEgMC0uMyAwLS40IDAtOSA2LjUtMTYuMiAxNC42LTE2LjJzMTQuNiA3LjMgMTQuNiAxNi4yYzAgMS4zLjEgMyAwIDQuMi0uMiA1LjItMS4zIDkuMS0yIDEzLjktMS4yIDEwLjItMi4zIDE4LjctMS43IDI2LjUuNiAzLjkgMi45IDUuNSA0LjggNy4zIDAgMS4xLjIgNC42LjMgNi41IDQ2LjUgNC4xIDg5LjcgMjUuNCAxMjEuNCA1OC43bDUuNi00YzEuOS4xIDYgLjcgOC45LTEgNi41LTQuNCAxMi41LTEwLjUgMTkuNy0xNy44IDMuMy0zLjUgNS43LTYuOCA5LjctMTAuMi45LS44IDIuMy0xLjggMy4yLTIuNiA3LTUuNiAxNi44LTUgMjEuOCAxLjNzMy40IDE2LTMuNiAyMS42Yy0xIC44LTIuMyAxLjktMy4yIDIuNi00LjIgMy4xLTggNC43LTEyLjIgNy4xLTguNyA1LjQtMTYgOS45LTIxLjggMTUuMy0yLjcgMi45LTIuNSA1LjctMi44IDguMy0uOC43LTMuNyAzLjMtNS4yIDQuNyAxMi42IDE4LjggMjIuMSA0MC4xIDI3LjQgNjMuMyA1LjMgMjMuMSA2LjEgNDYuMSAzLjEgNjguM2w1LjkgMS43YzEuMSAxLjUgMy4yIDUuMiA2LjMgNi4zIDcuNSAyLjQgMTYgMy4yIDI2LjIgNC4zIDQuOC40IDguOS4yIDE0IDEuMSAxLjIuMiAzIC43IDQuMiAxIDguOSAyLjQgMTQuNCAxMC40IDEyLjYgMTguMnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTQyOCA0MDEuN2MtMS0uMi0yLS4zLTMtLjItMS43LjEtMy4zLjUtNC45IDEuMy02LjIgMy05IDEwLjQtNi4yIDE2LjdsLS4xLjEgMjkuNiA3MS40YzI4LjUtMTguMiA0OS44LTQ1LjMgNjEtNzYuNmwtNzYuMi0xMi45eiIvPgogICAgICAgICAgPC9nPgogICAgICAgIDwvc3ZnPg==);" + />
@@ -3450,44 +3217,11 @@ exports[`opening dock tab for installing helm chart given application is started class="TableCell icon" >
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
+ class="chartIcon intro-logo imageNotLoaded" + data-testid="image-container" + style="background-image: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNzIyLjggNzAyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogICAgICAgICAgPGcgZmlsbD0iIzhlOTI5NyI+CiAgICAgICAgICAgIDxwYXRoIGQ9Im0zMTggMjk5LjVjMi4xIDEuNiA0LjggMi41IDcuNiAyLjUgNi45IDAgMTIuNi01LjUgMTIuOS0xMi4zbC4zLS4yIDQuMy03Ni43Yy01LjIuNi0xMC40IDEuNS0xNS42IDIuNy0yOC41IDYuNS01My4yIDIwLjUtNzIuNiAzOS41bDYyLjkgNDQuNnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTMwOS41IDQxMS45Yy0xLjQtNS45LTYuNi05LjktMTIuNC0xMC0uOCAwLTEuNy4xLTIuNS4ybC0uMS0uMi03NS41IDEyLjhjMTEuNyAzMi4yIDMzLjQgNTguNSA2MC44IDc2LjFsMjkuMi03MC43LS4yLS4zYzEuMS0yLjQgMS40LTUuMi43LTcuOXoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTI4NC40IDM1Ny41YzIuNS0uNyA0LjktMi4yIDYuNy00LjQgNC4zLTUuNCAzLjYtMTMuMi0xLjYtMTcuOGwuMS0uMy01Ny40LTUxLjRjLTE3IDI3LjgtMjUuMSA2MS4xLTIxLjQgOTUuM2w3My42LTIxLjJ6Ii8+CiAgICAgICAgICAgIDxwYXRoIGQ9Im0zNDAuMiAzODAgMjEuMiAxMC4yIDIxLjEtMTAuMSA1LjMtMjIuOS0xNC42LTE4LjJoLTIzLjZsLTE0LjYgMTguMnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTM4NC4yIDI4OS40Yy4xIDIuNiAxIDUuMiAyLjggNy41IDQuMyA1LjQgMTIuMSA2LjQgMTcuNyAyLjRsLjIuMSA2Mi41LTQ0LjNjLTIzLjYtMjMuMS01NC40LTM4LjItODcuNi00Mi4yeiIvPgogICAgICAgICAgICA8cGF0aCBkPSJtNDkwLjMgMjgzLjctNTcuMSA1MS4xdi4yYy0yIDEuNy0zLjUgNC4xLTQuMSA2LjgtMS41IDYuOCAyLjUgMTMuNSA5LjIgMTUuM2wuMS4zIDc0IDIxLjNjMS42LTE2IC42LTMyLjUtMy4yLTQ5LTMuOS0xNi44LTEwLjQtMzIuMi0xOC45LTQ2eiIvPgogICAgICAgICAgICA8cGF0aCBkPSJtMzcyLjggNDM5LjZjLTEuMi0yLjMtMy4yLTQuMy01LjgtNS41LTItLjktNC0xLjQtNi0xLjMtNC41LjItOC43IDIuNi0xMC45IDYuOGgtLjFsLTM3LjEgNjcuMWMyNS43IDguOCA1NC4xIDEwLjcgODIuNSA0LjIgNS4xLTEuMiAxMC0yLjUgMTQuOS00LjJsLTM3LjMtNjcuMXoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTcxMS43IDQyNS02MC40LTI2Mi4yYy0zLjItMTMuNy0xMi41LTI1LjMtMjUuMy0zMS40bC0yNDQuNC0xMTYuOGMtNy4xLTMuNC0xNC44LTQuOS0yMi43LTQuNS02LjIuMy0xMi4zIDEuOS0xNy45IDQuNWwtMjQ0LjMgMTE2LjdjLTEyLjggNi4xLTIyLjEgMTcuNy0yNS4zIDMxLjRsLTYwLjIgMjYyLjNjLTIuOCAxMi4yLS41IDI1IDYuMyAzNS41LjggMS4zIDEuNyAyLjUgMi43IDMuN2wxNjkuMSAyMTAuM2M4LjkgMTEgMjIuMyAxNy40IDM2LjUgMTcuNGwyNzEuMi0uMWMxNC4yIDAgMjcuNy02LjQgMzYuNS0xNy40bDE2OS4xLTIxMC4zYzguOS0xMC45IDEyLjItMjUuNCA5LjEtMzkuMXptLTkzLTMuMmMtMS44IDcuOC0xMC4yIDEyLjYtMTguOSAxMC43LS4xIDAtLjIgMC0uMiAwLS4xIDAtLjItLjEtLjMtLjEtMS4yLS4zLTIuNy0uNS0zLjgtLjgtNS0xLjMtOC42LTMuMy0xMy4xLTUuMS05LjctMy41LTE3LjctNi40LTI1LjUtNy41LTQtLjMtNiAxLjYtOC4yIDMtMS4xLS4yLTQuNC0uOC02LjItMS4xLTE0IDQ0LTQzLjkgODIuMi04NC4zIDEwNi4xLjcgMS43IDEuOSA1LjMgMi40IDUuOS0uOSAyLjUtMi4zIDQuOC0xLjEgOC42IDIuOCA3LjQgNy40IDE0LjYgMTMgMjMuMiAyLjcgNCA1LjQgNy4xIDcuOCAxMS43LjYgMS4xIDEuMyAyLjggMS45IDMuOSAzLjggOCAxIDE3LjMtNi4yIDIwLjgtNy4zIDMuNS0xNi4zLS4yLTIwLjItOC4zLS42LTEuMS0xLjMtMi43LTEuOC0zLjgtMi4xLTQuNy0yLjgtOC44LTQuMi0xMy40LTMuMy05LjctNi0xNy44LTEwLTI0LjYtMi4yLTMuMy01LTMuNy03LjUtNC41LS41LS44LTIuMi00LTMuMS01LjYtOC4xIDMuMS0xNi40IDUuNi0yNS4xIDcuNi0zNy45IDguNi03NS45IDUuMS0xMDkuOS03LjlsLTMuMyA2Yy0yLjUuNy00LjggMS4zLTYuMyAzLjEtNS4zIDYuNC03LjUgMTYuNi0xMS4zIDI2LjMtMS41IDQuNi0yLjEgOC43LTQuMiAxMy40LS41IDEuMS0xLjMgMi42LTEuOCAzLjctMy45IDguMS0xMi45IDExLjctMjAuMiA4LjItNy4yLTMuNS0xMC0xMi43LTYuMi0yMC44LjYtMS4yIDEuMy0yLjggMS45LTMuOSAyLjQtNC42IDUuMi03LjcgNy44LTExLjcgNS41LTguNyAxMC40LTE2LjQgMTMuMi0yMy44LjctMi40LS4zLTUuOC0xLjMtOC4zbDIuNy02LjRjLTM4LjktMjMuMS02OS43LTU5LjgtODQuMy0xMDUuM2wtNi40IDEuMWMtMS43LTEtNS4xLTMuMi04LjQtMy03LjggMS4xLTE1LjggNC0yNS41IDcuNS00LjUgMS43LTguMSAzLjctMTMuMSA1LTEuMS4zLTIuNi42LTMuOC44LS4xIDAtLjIuMS0uMy4xcy0uMiAwLS4yIDBjLTguNyAxLjktMTcuMS0yLjktMTguOS0xMC43czMuOC0xNS43IDEyLjQtMTcuOGMuMSAwIC4yIDAgLjItLjFoLjFjMS4yLS4zIDIuOC0uNyAzLjktLjkgNS4xLTEgOS4yLS43IDE0LTEuMSAxMC4yLTEuMSAxOC43LTEuOSAyNi4yLTQuMyAyLjQtMSA0LjctNC4zIDYuMy02LjNsNi4xLTEuOGMtNi45LTQ3LjUgNC44LTk0LjIgMjkuOC0xMzEuOWwtNC43LTQuMmMtLjMtMS44LS43LTYtMi45LTguNC01LjgtNS40LTEzLTkuOS0yMS44LTE1LjMtNC4yLTIuNC04LTQtMTIuMS03LjEtLjktLjctMi4xLTEuNy0zLTIuNC0uMS0uMS0uMS0uMS0uMi0uMi03LTUuNi04LjYtMTUuMi0zLjYtMjEuNiAyLjgtMy42IDcuMi01LjMgMTEuNy01LjIgMy41LjEgNy4xIDEuNCAxMC4yIDMuOCAxIC44IDIuNCAxLjggMy4yIDIuNiAzLjkgMy40IDYuMyA2LjcgOS42IDEwLjIgNy4yIDcuMyAxMy4yIDEzLjQgMTkuNyAxNy44IDMuNCAyIDYuMSAxLjIgOC43LjguOC42IDMuNyAyLjYgNS4zIDMuOCAyNC45LTI2LjQgNTcuNi00NiA5NS42LTU0LjYgOC44LTIgMTcuNy0zLjMgMjYuNC00LjFsLjMtNi4yYzEuOS0xLjkgNC4xLTQuNiA0LjgtNy42LjYtNy45LS40LTE2LjMtMS42LTI2LjUtLjctNC44LTEuOC04LjctMi0xMy45IDAtMS4xIDAtMi41IDAtMy44IDAtLjEgMC0uMyAwLS40IDAtOSA2LjUtMTYuMiAxNC42LTE2LjJzMTQuNiA3LjMgMTQuNiAxNi4yYzAgMS4zLjEgMyAwIDQuMi0uMiA1LjItMS4zIDkuMS0yIDEzLjktMS4yIDEwLjItMi4zIDE4LjctMS43IDI2LjUuNiAzLjkgMi45IDUuNSA0LjggNy4zIDAgMS4xLjIgNC42LjMgNi41IDQ2LjUgNC4xIDg5LjcgMjUuNCAxMjEuNCA1OC43bDUuNi00YzEuOS4xIDYgLjcgOC45LTEgNi41LTQuNCAxMi41LTEwLjUgMTkuNy0xNy44IDMuMy0zLjUgNS43LTYuOCA5LjctMTAuMi45LS44IDIuMy0xLjggMy4yLTIuNiA3LTUuNiAxNi44LTUgMjEuOCAxLjNzMy40IDE2LTMuNiAyMS42Yy0xIC44LTIuMyAxLjktMy4yIDIuNi00LjIgMy4xLTggNC43LTEyLjIgNy4xLTguNyA1LjQtMTYgOS45LTIxLjggMTUuMy0yLjcgMi45LTIuNSA1LjctMi44IDguMy0uOC43LTMuNyAzLjMtNS4yIDQuNyAxMi42IDE4LjggMjIuMSA0MC4xIDI3LjQgNjMuMyA1LjMgMjMuMSA2LjEgNDYuMSAzLjEgNjguM2w1LjkgMS43YzEuMSAxLjUgMy4yIDUuMiA2LjMgNi4zIDcuNSAyLjQgMTYgMy4yIDI2LjIgNC4zIDQuOC40IDguOS4yIDE0IDEuMSAxLjIuMiAzIC43IDQuMiAxIDguOSAyLjQgMTQuNCAxMC40IDEyLjYgMTguMnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTQyOCA0MDEuN2MtMS0uMi0yLS4zLTMtLjItMS43LjEtMy4zLjUtNC45IDEuMy02LjIgMy05IDEwLjQtNi4yIDE2LjdsLS4xLjEgMjkuNiA3MS40YzI4LjUtMTguMiA0OS44LTQ1LjMgNjEtNzYuNmwtNzYuMi0xMi45eiIvPgogICAgICAgICAgPC9nPgogICAgICAgIDwvc3ZnPg==);" + />
@@ -4407,44 +4073,11 @@ exports[`opening dock tab for installing helm chart given application is started class="TableCell icon" >
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
+ class="chartIcon intro-logo imageNotLoaded" + data-testid="image-container" + style="background-image: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNzIyLjggNzAyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogICAgICAgICAgPGcgZmlsbD0iIzhlOTI5NyI+CiAgICAgICAgICAgIDxwYXRoIGQ9Im0zMTggMjk5LjVjMi4xIDEuNiA0LjggMi41IDcuNiAyLjUgNi45IDAgMTIuNi01LjUgMTIuOS0xMi4zbC4zLS4yIDQuMy03Ni43Yy01LjIuNi0xMC40IDEuNS0xNS42IDIuNy0yOC41IDYuNS01My4yIDIwLjUtNzIuNiAzOS41bDYyLjkgNDQuNnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTMwOS41IDQxMS45Yy0xLjQtNS45LTYuNi05LjktMTIuNC0xMC0uOCAwLTEuNy4xLTIuNS4ybC0uMS0uMi03NS41IDEyLjhjMTEuNyAzMi4yIDMzLjQgNTguNSA2MC44IDc2LjFsMjkuMi03MC43LS4yLS4zYzEuMS0yLjQgMS40LTUuMi43LTcuOXoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTI4NC40IDM1Ny41YzIuNS0uNyA0LjktMi4yIDYuNy00LjQgNC4zLTUuNCAzLjYtMTMuMi0xLjYtMTcuOGwuMS0uMy01Ny40LTUxLjRjLTE3IDI3LjgtMjUuMSA2MS4xLTIxLjQgOTUuM2w3My42LTIxLjJ6Ii8+CiAgICAgICAgICAgIDxwYXRoIGQ9Im0zNDAuMiAzODAgMjEuMiAxMC4yIDIxLjEtMTAuMSA1LjMtMjIuOS0xNC42LTE4LjJoLTIzLjZsLTE0LjYgMTguMnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTM4NC4yIDI4OS40Yy4xIDIuNiAxIDUuMiAyLjggNy41IDQuMyA1LjQgMTIuMSA2LjQgMTcuNyAyLjRsLjIuMSA2Mi41LTQ0LjNjLTIzLjYtMjMuMS01NC40LTM4LjItODcuNi00Mi4yeiIvPgogICAgICAgICAgICA8cGF0aCBkPSJtNDkwLjMgMjgzLjctNTcuMSA1MS4xdi4yYy0yIDEuNy0zLjUgNC4xLTQuMSA2LjgtMS41IDYuOCAyLjUgMTMuNSA5LjIgMTUuM2wuMS4zIDc0IDIxLjNjMS42LTE2IC42LTMyLjUtMy4yLTQ5LTMuOS0xNi44LTEwLjQtMzIuMi0xOC45LTQ2eiIvPgogICAgICAgICAgICA8cGF0aCBkPSJtMzcyLjggNDM5LjZjLTEuMi0yLjMtMy4yLTQuMy01LjgtNS41LTItLjktNC0xLjQtNi0xLjMtNC41LjItOC43IDIuNi0xMC45IDYuOGgtLjFsLTM3LjEgNjcuMWMyNS43IDguOCA1NC4xIDEwLjcgODIuNSA0LjIgNS4xLTEuMiAxMC0yLjUgMTQuOS00LjJsLTM3LjMtNjcuMXoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTcxMS43IDQyNS02MC40LTI2Mi4yYy0zLjItMTMuNy0xMi41LTI1LjMtMjUuMy0zMS40bC0yNDQuNC0xMTYuOGMtNy4xLTMuNC0xNC44LTQuOS0yMi43LTQuNS02LjIuMy0xMi4zIDEuOS0xNy45IDQuNWwtMjQ0LjMgMTE2LjdjLTEyLjggNi4xLTIyLjEgMTcuNy0yNS4zIDMxLjRsLTYwLjIgMjYyLjNjLTIuOCAxMi4yLS41IDI1IDYuMyAzNS41LjggMS4zIDEuNyAyLjUgMi43IDMuN2wxNjkuMSAyMTAuM2M4LjkgMTEgMjIuMyAxNy40IDM2LjUgMTcuNGwyNzEuMi0uMWMxNC4yIDAgMjcuNy02LjQgMzYuNS0xNy40bDE2OS4xLTIxMC4zYzguOS0xMC45IDEyLjItMjUuNCA5LjEtMzkuMXptLTkzLTMuMmMtMS44IDcuOC0xMC4yIDEyLjYtMTguOSAxMC43LS4xIDAtLjIgMC0uMiAwLS4xIDAtLjItLjEtLjMtLjEtMS4yLS4zLTIuNy0uNS0zLjgtLjgtNS0xLjMtOC42LTMuMy0xMy4xLTUuMS05LjctMy41LTE3LjctNi40LTI1LjUtNy41LTQtLjMtNiAxLjYtOC4yIDMtMS4xLS4yLTQuNC0uOC02LjItMS4xLTE0IDQ0LTQzLjkgODIuMi04NC4zIDEwNi4xLjcgMS43IDEuOSA1LjMgMi40IDUuOS0uOSAyLjUtMi4zIDQuOC0xLjEgOC42IDIuOCA3LjQgNy40IDE0LjYgMTMgMjMuMiAyLjcgNCA1LjQgNy4xIDcuOCAxMS43LjYgMS4xIDEuMyAyLjggMS45IDMuOSAzLjggOCAxIDE3LjMtNi4yIDIwLjgtNy4zIDMuNS0xNi4zLS4yLTIwLjItOC4zLS42LTEuMS0xLjMtMi43LTEuOC0zLjgtMi4xLTQuNy0yLjgtOC44LTQuMi0xMy40LTMuMy05LjctNi0xNy44LTEwLTI0LjYtMi4yLTMuMy01LTMuNy03LjUtNC41LS41LS44LTIuMi00LTMuMS01LjYtOC4xIDMuMS0xNi40IDUuNi0yNS4xIDcuNi0zNy45IDguNi03NS45IDUuMS0xMDkuOS03LjlsLTMuMyA2Yy0yLjUuNy00LjggMS4zLTYuMyAzLjEtNS4zIDYuNC03LjUgMTYuNi0xMS4zIDI2LjMtMS41IDQuNi0yLjEgOC43LTQuMiAxMy40LS41IDEuMS0xLjMgMi42LTEuOCAzLjctMy45IDguMS0xMi45IDExLjctMjAuMiA4LjItNy4yLTMuNS0xMC0xMi43LTYuMi0yMC44LjYtMS4yIDEuMy0yLjggMS45LTMuOSAyLjQtNC42IDUuMi03LjcgNy44LTExLjcgNS41LTguNyAxMC40LTE2LjQgMTMuMi0yMy44LjctMi40LS4zLTUuOC0xLjMtOC4zbDIuNy02LjRjLTM4LjktMjMuMS02OS43LTU5LjgtODQuMy0xMDUuM2wtNi40IDEuMWMtMS43LTEtNS4xLTMuMi04LjQtMy03LjggMS4xLTE1LjggNC0yNS41IDcuNS00LjUgMS43LTguMSAzLjctMTMuMSA1LTEuMS4zLTIuNi42LTMuOC44LS4xIDAtLjIuMS0uMy4xcy0uMiAwLS4yIDBjLTguNyAxLjktMTcuMS0yLjktMTguOS0xMC43czMuOC0xNS43IDEyLjQtMTcuOGMuMSAwIC4yIDAgLjItLjFoLjFjMS4yLS4zIDIuOC0uNyAzLjktLjkgNS4xLTEgOS4yLS43IDE0LTEuMSAxMC4yLTEuMSAxOC43LTEuOSAyNi4yLTQuMyAyLjQtMSA0LjctNC4zIDYuMy02LjNsNi4xLTEuOGMtNi45LTQ3LjUgNC44LTk0LjIgMjkuOC0xMzEuOWwtNC43LTQuMmMtLjMtMS44LS43LTYtMi45LTguNC01LjgtNS40LTEzLTkuOS0yMS44LTE1LjMtNC4yLTIuNC04LTQtMTIuMS03LjEtLjktLjctMi4xLTEuNy0zLTIuNC0uMS0uMS0uMS0uMS0uMi0uMi03LTUuNi04LjYtMTUuMi0zLjYtMjEuNiAyLjgtMy42IDcuMi01LjMgMTEuNy01LjIgMy41LjEgNy4xIDEuNCAxMC4yIDMuOCAxIC44IDIuNCAxLjggMy4yIDIuNiAzLjkgMy40IDYuMyA2LjcgOS42IDEwLjIgNy4yIDcuMyAxMy4yIDEzLjQgMTkuNyAxNy44IDMuNCAyIDYuMSAxLjIgOC43LjguOC42IDMuNyAyLjYgNS4zIDMuOCAyNC45LTI2LjQgNTcuNi00NiA5NS42LTU0LjYgOC44LTIgMTcuNy0zLjMgMjYuNC00LjFsLjMtNi4yYzEuOS0xLjkgNC4xLTQuNiA0LjgtNy42LjYtNy45LS40LTE2LjMtMS42LTI2LjUtLjctNC44LTEuOC04LjctMi0xMy45IDAtMS4xIDAtMi41IDAtMy44IDAtLjEgMC0uMyAwLS40IDAtOSA2LjUtMTYuMiAxNC42LTE2LjJzMTQuNiA3LjMgMTQuNiAxNi4yYzAgMS4zLjEgMyAwIDQuMi0uMiA1LjItMS4zIDkuMS0yIDEzLjktMS4yIDEwLjItMi4zIDE4LjctMS43IDI2LjUuNiAzLjkgMi45IDUuNSA0LjggNy4zIDAgMS4xLjIgNC42LjMgNi41IDQ2LjUgNC4xIDg5LjcgMjUuNCAxMjEuNCA1OC43bDUuNi00YzEuOS4xIDYgLjcgOC45LTEgNi41LTQuNCAxMi41LTEwLjUgMTkuNy0xNy44IDMuMy0zLjUgNS43LTYuOCA5LjctMTAuMi45LS44IDIuMy0xLjggMy4yLTIuNiA3LTUuNiAxNi44LTUgMjEuOCAxLjNzMy40IDE2LTMuNiAyMS42Yy0xIC44LTIuMyAxLjktMy4yIDIuNi00LjIgMy4xLTggNC43LTEyLjIgNy4xLTguNyA1LjQtMTYgOS45LTIxLjggMTUuMy0yLjcgMi45LTIuNSA1LjctMi44IDguMy0uOC43LTMuNyAzLjMtNS4yIDQuNyAxMi42IDE4LjggMjIuMSA0MC4xIDI3LjQgNjMuMyA1LjMgMjMuMSA2LjEgNDYuMSAzLjEgNjguM2w1LjkgMS43YzEuMSAxLjUgMy4yIDUuMiA2LjMgNi4zIDcuNSAyLjQgMTYgMy4yIDI2LjIgNC4zIDQuOC40IDguOS4yIDE0IDEuMSAxLjIuMiAzIC43IDQuMiAxIDguOSAyLjQgMTQuNCAxMC40IDEyLjYgMTguMnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTQyOCA0MDEuN2MtMS0uMi0yLS4zLTMtLjItMS43LjEtMy4zLjUtNC45IDEuMy02LjIgMy05IDEwLjQtNi4yIDE2LjdsLS4xLjEgMjkuNiA3MS40YzI4LjUtMTguMiA0OS44LTQ1LjMgNjEtNzYuNmwtNzYuMi0xMi45eiIvPgogICAgICAgICAgPC9nPgogICAgICAgIDwvc3ZnPg==);" + />
@@ -5354,44 +4919,11 @@ exports[`opening dock tab for installing helm chart given application is started class="TableCell icon" >
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
+ class="chartIcon intro-logo imageNotLoaded" + data-testid="image-container" + style="background-image: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNzIyLjggNzAyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogICAgICAgICAgPGcgZmlsbD0iIzhlOTI5NyI+CiAgICAgICAgICAgIDxwYXRoIGQ9Im0zMTggMjk5LjVjMi4xIDEuNiA0LjggMi41IDcuNiAyLjUgNi45IDAgMTIuNi01LjUgMTIuOS0xMi4zbC4zLS4yIDQuMy03Ni43Yy01LjIuNi0xMC40IDEuNS0xNS42IDIuNy0yOC41IDYuNS01My4yIDIwLjUtNzIuNiAzOS41bDYyLjkgNDQuNnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTMwOS41IDQxMS45Yy0xLjQtNS45LTYuNi05LjktMTIuNC0xMC0uOCAwLTEuNy4xLTIuNS4ybC0uMS0uMi03NS41IDEyLjhjMTEuNyAzMi4yIDMzLjQgNTguNSA2MC44IDc2LjFsMjkuMi03MC43LS4yLS4zYzEuMS0yLjQgMS40LTUuMi43LTcuOXoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTI4NC40IDM1Ny41YzIuNS0uNyA0LjktMi4yIDYuNy00LjQgNC4zLTUuNCAzLjYtMTMuMi0xLjYtMTcuOGwuMS0uMy01Ny40LTUxLjRjLTE3IDI3LjgtMjUuMSA2MS4xLTIxLjQgOTUuM2w3My42LTIxLjJ6Ii8+CiAgICAgICAgICAgIDxwYXRoIGQ9Im0zNDAuMiAzODAgMjEuMiAxMC4yIDIxLjEtMTAuMSA1LjMtMjIuOS0xNC42LTE4LjJoLTIzLjZsLTE0LjYgMTguMnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTM4NC4yIDI4OS40Yy4xIDIuNiAxIDUuMiAyLjggNy41IDQuMyA1LjQgMTIuMSA2LjQgMTcuNyAyLjRsLjIuMSA2Mi41LTQ0LjNjLTIzLjYtMjMuMS01NC40LTM4LjItODcuNi00Mi4yeiIvPgogICAgICAgICAgICA8cGF0aCBkPSJtNDkwLjMgMjgzLjctNTcuMSA1MS4xdi4yYy0yIDEuNy0zLjUgNC4xLTQuMSA2LjgtMS41IDYuOCAyLjUgMTMuNSA5LjIgMTUuM2wuMS4zIDc0IDIxLjNjMS42LTE2IC42LTMyLjUtMy4yLTQ5LTMuOS0xNi44LTEwLjQtMzIuMi0xOC45LTQ2eiIvPgogICAgICAgICAgICA8cGF0aCBkPSJtMzcyLjggNDM5LjZjLTEuMi0yLjMtMy4yLTQuMy01LjgtNS41LTItLjktNC0xLjQtNi0xLjMtNC41LjItOC43IDIuNi0xMC45IDYuOGgtLjFsLTM3LjEgNjcuMWMyNS43IDguOCA1NC4xIDEwLjcgODIuNSA0LjIgNS4xLTEuMiAxMC0yLjUgMTQuOS00LjJsLTM3LjMtNjcuMXoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTcxMS43IDQyNS02MC40LTI2Mi4yYy0zLjItMTMuNy0xMi41LTI1LjMtMjUuMy0zMS40bC0yNDQuNC0xMTYuOGMtNy4xLTMuNC0xNC44LTQuOS0yMi43LTQuNS02LjIuMy0xMi4zIDEuOS0xNy45IDQuNWwtMjQ0LjMgMTE2LjdjLTEyLjggNi4xLTIyLjEgMTcuNy0yNS4zIDMxLjRsLTYwLjIgMjYyLjNjLTIuOCAxMi4yLS41IDI1IDYuMyAzNS41LjggMS4zIDEuNyAyLjUgMi43IDMuN2wxNjkuMSAyMTAuM2M4LjkgMTEgMjIuMyAxNy40IDM2LjUgMTcuNGwyNzEuMi0uMWMxNC4yIDAgMjcuNy02LjQgMzYuNS0xNy40bDE2OS4xLTIxMC4zYzguOS0xMC45IDEyLjItMjUuNCA5LjEtMzkuMXptLTkzLTMuMmMtMS44IDcuOC0xMC4yIDEyLjYtMTguOSAxMC43LS4xIDAtLjIgMC0uMiAwLS4xIDAtLjItLjEtLjMtLjEtMS4yLS4zLTIuNy0uNS0zLjgtLjgtNS0xLjMtOC42LTMuMy0xMy4xLTUuMS05LjctMy41LTE3LjctNi40LTI1LjUtNy41LTQtLjMtNiAxLjYtOC4yIDMtMS4xLS4yLTQuNC0uOC02LjItMS4xLTE0IDQ0LTQzLjkgODIuMi04NC4zIDEwNi4xLjcgMS43IDEuOSA1LjMgMi40IDUuOS0uOSAyLjUtMi4zIDQuOC0xLjEgOC42IDIuOCA3LjQgNy40IDE0LjYgMTMgMjMuMiAyLjcgNCA1LjQgNy4xIDcuOCAxMS43LjYgMS4xIDEuMyAyLjggMS45IDMuOSAzLjggOCAxIDE3LjMtNi4yIDIwLjgtNy4zIDMuNS0xNi4zLS4yLTIwLjItOC4zLS42LTEuMS0xLjMtMi43LTEuOC0zLjgtMi4xLTQuNy0yLjgtOC44LTQuMi0xMy40LTMuMy05LjctNi0xNy44LTEwLTI0LjYtMi4yLTMuMy01LTMuNy03LjUtNC41LS41LS44LTIuMi00LTMuMS01LjYtOC4xIDMuMS0xNi40IDUuNi0yNS4xIDcuNi0zNy45IDguNi03NS45IDUuMS0xMDkuOS03LjlsLTMuMyA2Yy0yLjUuNy00LjggMS4zLTYuMyAzLjEtNS4zIDYuNC03LjUgMTYuNi0xMS4zIDI2LjMtMS41IDQuNi0yLjEgOC43LTQuMiAxMy40LS41IDEuMS0xLjMgMi42LTEuOCAzLjctMy45IDguMS0xMi45IDExLjctMjAuMiA4LjItNy4yLTMuNS0xMC0xMi43LTYuMi0yMC44LjYtMS4yIDEuMy0yLjggMS45LTMuOSAyLjQtNC42IDUuMi03LjcgNy44LTExLjcgNS41LTguNyAxMC40LTE2LjQgMTMuMi0yMy44LjctMi40LS4zLTUuOC0xLjMtOC4zbDIuNy02LjRjLTM4LjktMjMuMS02OS43LTU5LjgtODQuMy0xMDUuM2wtNi40IDEuMWMtMS43LTEtNS4xLTMuMi04LjQtMy03LjggMS4xLTE1LjggNC0yNS41IDcuNS00LjUgMS43LTguMSAzLjctMTMuMSA1LTEuMS4zLTIuNi42LTMuOC44LS4xIDAtLjIuMS0uMy4xcy0uMiAwLS4yIDBjLTguNyAxLjktMTcuMS0yLjktMTguOS0xMC43czMuOC0xNS43IDEyLjQtMTcuOGMuMSAwIC4yIDAgLjItLjFoLjFjMS4yLS4zIDIuOC0uNyAzLjktLjkgNS4xLTEgOS4yLS43IDE0LTEuMSAxMC4yLTEuMSAxOC43LTEuOSAyNi4yLTQuMyAyLjQtMSA0LjctNC4zIDYuMy02LjNsNi4xLTEuOGMtNi45LTQ3LjUgNC44LTk0LjIgMjkuOC0xMzEuOWwtNC43LTQuMmMtLjMtMS44LS43LTYtMi45LTguNC01LjgtNS40LTEzLTkuOS0yMS44LTE1LjMtNC4yLTIuNC04LTQtMTIuMS03LjEtLjktLjctMi4xLTEuNy0zLTIuNC0uMS0uMS0uMS0uMS0uMi0uMi03LTUuNi04LjYtMTUuMi0zLjYtMjEuNiAyLjgtMy42IDcuMi01LjMgMTEuNy01LjIgMy41LjEgNy4xIDEuNCAxMC4yIDMuOCAxIC44IDIuNCAxLjggMy4yIDIuNiAzLjkgMy40IDYuMyA2LjcgOS42IDEwLjIgNy4yIDcuMyAxMy4yIDEzLjQgMTkuNyAxNy44IDMuNCAyIDYuMSAxLjIgOC43LjguOC42IDMuNyAyLjYgNS4zIDMuOCAyNC45LTI2LjQgNTcuNi00NiA5NS42LTU0LjYgOC44LTIgMTcuNy0zLjMgMjYuNC00LjFsLjMtNi4yYzEuOS0xLjkgNC4xLTQuNiA0LjgtNy42LjYtNy45LS40LTE2LjMtMS42LTI2LjUtLjctNC44LTEuOC04LjctMi0xMy45IDAtMS4xIDAtMi41IDAtMy44IDAtLjEgMC0uMyAwLS40IDAtOSA2LjUtMTYuMiAxNC42LTE2LjJzMTQuNiA3LjMgMTQuNiAxNi4yYzAgMS4zLjEgMyAwIDQuMi0uMiA1LjItMS4zIDkuMS0yIDEzLjktMS4yIDEwLjItMi4zIDE4LjctMS43IDI2LjUuNiAzLjkgMi45IDUuNSA0LjggNy4zIDAgMS4xLjIgNC42LjMgNi41IDQ2LjUgNC4xIDg5LjcgMjUuNCAxMjEuNCA1OC43bDUuNi00YzEuOS4xIDYgLjcgOC45LTEgNi41LTQuNCAxMi41LTEwLjUgMTkuNy0xNy44IDMuMy0zLjUgNS43LTYuOCA5LjctMTAuMi45LS44IDIuMy0xLjggMy4yLTIuNiA3LTUuNiAxNi44LTUgMjEuOCAxLjNzMy40IDE2LTMuNiAyMS42Yy0xIC44LTIuMyAxLjktMy4yIDIuNi00LjIgMy4xLTggNC43LTEyLjIgNy4xLTguNyA1LjQtMTYgOS45LTIxLjggMTUuMy0yLjcgMi45LTIuNSA1LjctMi44IDguMy0uOC43LTMuNyAzLjMtNS4yIDQuNyAxMi42IDE4LjggMjIuMSA0MC4xIDI3LjQgNjMuMyA1LjMgMjMuMSA2LjEgNDYuMSAzLjEgNjguM2w1LjkgMS43YzEuMSAxLjUgMy4yIDUuMiA2LjMgNi4zIDcuNSAyLjQgMTYgMy4yIDI2LjIgNC4zIDQuOC40IDguOS4yIDE0IDEuMSAxLjIuMiAzIC43IDQuMiAxIDguOSAyLjQgMTQuNCAxMC40IDEyLjYgMTguMnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTQyOCA0MDEuN2MtMS0uMi0yLS4zLTMtLjItMS43LjEtMy4zLjUtNC45IDEuMy02LjIgMy05IDEwLjQtNi4yIDE2LjdsLS4xLjEgMjkuNiA3MS40YzI4LjUtMTguMiA0OS44LTQ1LjMgNjEtNzYuNmwtNzYuMi0xMi45eiIvPgogICAgICAgICAgPC9nPgogICAgICAgIDwvc3ZnPg==);" + />
@@ -6305,44 +5769,11 @@ exports[`opening dock tab for installing helm chart given application is started class="TableCell icon" >
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
+ class="chartIcon intro-logo imageNotLoaded" + data-testid="image-container" + style="background-image: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNzIyLjggNzAyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogICAgICAgICAgPGcgZmlsbD0iIzhlOTI5NyI+CiAgICAgICAgICAgIDxwYXRoIGQ9Im0zMTggMjk5LjVjMi4xIDEuNiA0LjggMi41IDcuNiAyLjUgNi45IDAgMTIuNi01LjUgMTIuOS0xMi4zbC4zLS4yIDQuMy03Ni43Yy01LjIuNi0xMC40IDEuNS0xNS42IDIuNy0yOC41IDYuNS01My4yIDIwLjUtNzIuNiAzOS41bDYyLjkgNDQuNnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTMwOS41IDQxMS45Yy0xLjQtNS45LTYuNi05LjktMTIuNC0xMC0uOCAwLTEuNy4xLTIuNS4ybC0uMS0uMi03NS41IDEyLjhjMTEuNyAzMi4yIDMzLjQgNTguNSA2MC44IDc2LjFsMjkuMi03MC43LS4yLS4zYzEuMS0yLjQgMS40LTUuMi43LTcuOXoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTI4NC40IDM1Ny41YzIuNS0uNyA0LjktMi4yIDYuNy00LjQgNC4zLTUuNCAzLjYtMTMuMi0xLjYtMTcuOGwuMS0uMy01Ny40LTUxLjRjLTE3IDI3LjgtMjUuMSA2MS4xLTIxLjQgOTUuM2w3My42LTIxLjJ6Ii8+CiAgICAgICAgICAgIDxwYXRoIGQ9Im0zNDAuMiAzODAgMjEuMiAxMC4yIDIxLjEtMTAuMSA1LjMtMjIuOS0xNC42LTE4LjJoLTIzLjZsLTE0LjYgMTguMnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTM4NC4yIDI4OS40Yy4xIDIuNiAxIDUuMiAyLjggNy41IDQuMyA1LjQgMTIuMSA2LjQgMTcuNyAyLjRsLjIuMSA2Mi41LTQ0LjNjLTIzLjYtMjMuMS01NC40LTM4LjItODcuNi00Mi4yeiIvPgogICAgICAgICAgICA8cGF0aCBkPSJtNDkwLjMgMjgzLjctNTcuMSA1MS4xdi4yYy0yIDEuNy0zLjUgNC4xLTQuMSA2LjgtMS41IDYuOCAyLjUgMTMuNSA5LjIgMTUuM2wuMS4zIDc0IDIxLjNjMS42LTE2IC42LTMyLjUtMy4yLTQ5LTMuOS0xNi44LTEwLjQtMzIuMi0xOC45LTQ2eiIvPgogICAgICAgICAgICA8cGF0aCBkPSJtMzcyLjggNDM5LjZjLTEuMi0yLjMtMy4yLTQuMy01LjgtNS41LTItLjktNC0xLjQtNi0xLjMtNC41LjItOC43IDIuNi0xMC45IDYuOGgtLjFsLTM3LjEgNjcuMWMyNS43IDguOCA1NC4xIDEwLjcgODIuNSA0LjIgNS4xLTEuMiAxMC0yLjUgMTQuOS00LjJsLTM3LjMtNjcuMXoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTcxMS43IDQyNS02MC40LTI2Mi4yYy0zLjItMTMuNy0xMi41LTI1LjMtMjUuMy0zMS40bC0yNDQuNC0xMTYuOGMtNy4xLTMuNC0xNC44LTQuOS0yMi43LTQuNS02LjIuMy0xMi4zIDEuOS0xNy45IDQuNWwtMjQ0LjMgMTE2LjdjLTEyLjggNi4xLTIyLjEgMTcuNy0yNS4zIDMxLjRsLTYwLjIgMjYyLjNjLTIuOCAxMi4yLS41IDI1IDYuMyAzNS41LjggMS4zIDEuNyAyLjUgMi43IDMuN2wxNjkuMSAyMTAuM2M4LjkgMTEgMjIuMyAxNy40IDM2LjUgMTcuNGwyNzEuMi0uMWMxNC4yIDAgMjcuNy02LjQgMzYuNS0xNy40bDE2OS4xLTIxMC4zYzguOS0xMC45IDEyLjItMjUuNCA5LjEtMzkuMXptLTkzLTMuMmMtMS44IDcuOC0xMC4yIDEyLjYtMTguOSAxMC43LS4xIDAtLjIgMC0uMiAwLS4xIDAtLjItLjEtLjMtLjEtMS4yLS4zLTIuNy0uNS0zLjgtLjgtNS0xLjMtOC42LTMuMy0xMy4xLTUuMS05LjctMy41LTE3LjctNi40LTI1LjUtNy41LTQtLjMtNiAxLjYtOC4yIDMtMS4xLS4yLTQuNC0uOC02LjItMS4xLTE0IDQ0LTQzLjkgODIuMi04NC4zIDEwNi4xLjcgMS43IDEuOSA1LjMgMi40IDUuOS0uOSAyLjUtMi4zIDQuOC0xLjEgOC42IDIuOCA3LjQgNy40IDE0LjYgMTMgMjMuMiAyLjcgNCA1LjQgNy4xIDcuOCAxMS43LjYgMS4xIDEuMyAyLjggMS45IDMuOSAzLjggOCAxIDE3LjMtNi4yIDIwLjgtNy4zIDMuNS0xNi4zLS4yLTIwLjItOC4zLS42LTEuMS0xLjMtMi43LTEuOC0zLjgtMi4xLTQuNy0yLjgtOC44LTQuMi0xMy40LTMuMy05LjctNi0xNy44LTEwLTI0LjYtMi4yLTMuMy01LTMuNy03LjUtNC41LS41LS44LTIuMi00LTMuMS01LjYtOC4xIDMuMS0xNi40IDUuNi0yNS4xIDcuNi0zNy45IDguNi03NS45IDUuMS0xMDkuOS03LjlsLTMuMyA2Yy0yLjUuNy00LjggMS4zLTYuMyAzLjEtNS4zIDYuNC03LjUgMTYuNi0xMS4zIDI2LjMtMS41IDQuNi0yLjEgOC43LTQuMiAxMy40LS41IDEuMS0xLjMgMi42LTEuOCAzLjctMy45IDguMS0xMi45IDExLjctMjAuMiA4LjItNy4yLTMuNS0xMC0xMi43LTYuMi0yMC44LjYtMS4yIDEuMy0yLjggMS45LTMuOSAyLjQtNC42IDUuMi03LjcgNy44LTExLjcgNS41LTguNyAxMC40LTE2LjQgMTMuMi0yMy44LjctMi40LS4zLTUuOC0xLjMtOC4zbDIuNy02LjRjLTM4LjktMjMuMS02OS43LTU5LjgtODQuMy0xMDUuM2wtNi40IDEuMWMtMS43LTEtNS4xLTMuMi04LjQtMy03LjggMS4xLTE1LjggNC0yNS41IDcuNS00LjUgMS43LTguMSAzLjctMTMuMSA1LTEuMS4zLTIuNi42LTMuOC44LS4xIDAtLjIuMS0uMy4xcy0uMiAwLS4yIDBjLTguNyAxLjktMTcuMS0yLjktMTguOS0xMC43czMuOC0xNS43IDEyLjQtMTcuOGMuMSAwIC4yIDAgLjItLjFoLjFjMS4yLS4zIDIuOC0uNyAzLjktLjkgNS4xLTEgOS4yLS43IDE0LTEuMSAxMC4yLTEuMSAxOC43LTEuOSAyNi4yLTQuMyAyLjQtMSA0LjctNC4zIDYuMy02LjNsNi4xLTEuOGMtNi45LTQ3LjUgNC44LTk0LjIgMjkuOC0xMzEuOWwtNC43LTQuMmMtLjMtMS44LS43LTYtMi45LTguNC01LjgtNS40LTEzLTkuOS0yMS44LTE1LjMtNC4yLTIuNC04LTQtMTIuMS03LjEtLjktLjctMi4xLTEuNy0zLTIuNC0uMS0uMS0uMS0uMS0uMi0uMi03LTUuNi04LjYtMTUuMi0zLjYtMjEuNiAyLjgtMy42IDcuMi01LjMgMTEuNy01LjIgMy41LjEgNy4xIDEuNCAxMC4yIDMuOCAxIC44IDIuNCAxLjggMy4yIDIuNiAzLjkgMy40IDYuMyA2LjcgOS42IDEwLjIgNy4yIDcuMyAxMy4yIDEzLjQgMTkuNyAxNy44IDMuNCAyIDYuMSAxLjIgOC43LjguOC42IDMuNyAyLjYgNS4zIDMuOCAyNC45LTI2LjQgNTcuNi00NiA5NS42LTU0LjYgOC44LTIgMTcuNy0zLjMgMjYuNC00LjFsLjMtNi4yYzEuOS0xLjkgNC4xLTQuNiA0LjgtNy42LjYtNy45LS40LTE2LjMtMS42LTI2LjUtLjctNC44LTEuOC04LjctMi0xMy45IDAtMS4xIDAtMi41IDAtMy44IDAtLjEgMC0uMyAwLS40IDAtOSA2LjUtMTYuMiAxNC42LTE2LjJzMTQuNiA3LjMgMTQuNiAxNi4yYzAgMS4zLjEgMyAwIDQuMi0uMiA1LjItMS4zIDkuMS0yIDEzLjktMS4yIDEwLjItMi4zIDE4LjctMS43IDI2LjUuNiAzLjkgMi45IDUuNSA0LjggNy4zIDAgMS4xLjIgNC42LjMgNi41IDQ2LjUgNC4xIDg5LjcgMjUuNCAxMjEuNCA1OC43bDUuNi00YzEuOS4xIDYgLjcgOC45LTEgNi41LTQuNCAxMi41LTEwLjUgMTkuNy0xNy44IDMuMy0zLjUgNS43LTYuOCA5LjctMTAuMi45LS44IDIuMy0xLjggMy4yLTIuNiA3LTUuNiAxNi44LTUgMjEuOCAxLjNzMy40IDE2LTMuNiAyMS42Yy0xIC44LTIuMyAxLjktMy4yIDIuNi00LjIgMy4xLTggNC43LTEyLjIgNy4xLTguNyA1LjQtMTYgOS45LTIxLjggMTUuMy0yLjcgMi45LTIuNSA1LjctMi44IDguMy0uOC43LTMuNyAzLjMtNS4yIDQuNyAxMi42IDE4LjggMjIuMSA0MC4xIDI3LjQgNjMuMyA1LjMgMjMuMSA2LjEgNDYuMSAzLjEgNjguM2w1LjkgMS43YzEuMSAxLjUgMy4yIDUuMiA2LjMgNi4zIDcuNSAyLjQgMTYgMy4yIDI2LjIgNC4zIDQuOC40IDguOS4yIDE0IDEuMSAxLjIuMiAzIC43IDQuMiAxIDguOSAyLjQgMTQuNCAxMC40IDEyLjYgMTguMnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTQyOCA0MDEuN2MtMS0uMi0yLS4zLTMtLjItMS43LjEtMy4zLjUtNC45IDEuMy02LjIgMy05IDEwLjQtNi4yIDE2LjdsLS4xLjEgMjkuNiA3MS40YzI4LjUtMTguMiA0OS44LTQ1LjMgNjEtNzYuNmwtNzYuMi0xMi45eiIvPgogICAgICAgICAgPC9nPgogICAgICAgIDwvc3ZnPg==);" + />
@@ -7262,44 +6625,11 @@ exports[`opening dock tab for installing helm chart given application is started class="TableCell icon" >
-
- - - - - - - - - - - - - -
+
-
- - - - - - - - - - - - - -
+
{ + it("renders the placeholder image by default", () => { + render(); + const imageContainer = screen.getByTestId("image-container"); + + expect(imageContainer.style.backgroundImage).toContain("data:image/svg+xml"); + }); + + it("renders img tag when image url is valid", () => { + render(); + const mainImage = screen.getByRole("img"); + + expect(mainImage).toBeInTheDocument(); + }); + + it("renders jpg image when its loaded", () => { + render(); + + const imageContainer = screen.getByTestId("image-container"); + const mainImage = screen.getByRole("img"); + + mainImage.dispatchEvent(new Event("load")); + expect(imageContainer.style.backgroundImage).toBe("url(https://example.com/main-picture.jpg)"); + }); + + it("renders png image when its loaded", () => { + render(); + + const imageContainer = screen.getByTestId("image-container"); + const mainImage = screen.getByRole("img"); + + mainImage.dispatchEvent(new Event("load")); + expect(imageContainer.style.backgroundImage).toBe("url(https://example.com/main-picture.png)"); + }); + + it("does not render invalid image url", () => { + render(); + + const mainImage = screen.queryByRole("img"); + + expect(mainImage).not.toBeInTheDocument(); + }); + + it("does not render svg image", () => { + render(); + + const mainImage = screen.queryByRole("img"); + + expect(mainImage).not.toBeInTheDocument(); + }); +}); diff --git a/packages/core/src/renderer/components/+helm-charts/helm-chart-details.scss b/packages/core/src/renderer/components/+helm-charts/helm-chart-details.scss index b82512dff4..80ddfb9f9c 100644 --- a/packages/core/src/renderer/components/+helm-charts/helm-chart-details.scss +++ b/packages/core/src/renderer/components/+helm-charts/helm-chart-details.scss @@ -5,17 +5,14 @@ .HelmChartDetails { .intro-logo { - margin-right: $margin * 2; - background: var(--helmLogoBackground); - border-radius: $radius; - max-width: 150px; - max-height: 100px; - padding: $padding; - box-sizing: content-box; - } - - div.intro-logo { + margin-right: calc(var(--margin) * 2); + background: var(--helmLogoBackground) center no-repeat; + border-radius: var(--border-radius); + padding: var(--padding); width: 100px; + height: 100px; + box-sizing: content-box; + background-size: contain; } .Select__option { diff --git a/packages/core/src/renderer/components/+helm-charts/helm-chart-details.tsx b/packages/core/src/renderer/components/+helm-charts/helm-chart-details.tsx index 2004a8704c..15add2c2ea 100644 --- a/packages/core/src/renderer/components/+helm-charts/helm-chart-details.tsx +++ b/packages/core/src/renderer/components/+helm-charts/helm-chart-details.tsx @@ -71,7 +71,7 @@ class NonInjectedHelmChartDetails extends Component
diff --git a/packages/core/src/renderer/components/+helm-charts/helm-charts.tsx b/packages/core/src/renderer/components/+helm-charts/helm-charts.tsx index a8367aac23..dff8025de5 100644 --- a/packages/core/src/renderer/components/+helm-charts/helm-charts.tsx +++ b/packages/core/src/renderer/components/+helm-charts/helm-charts.tsx @@ -121,7 +121,7 @@ class NonInjectedHelmCharts extends Component { ]} renderTableContents={chart => [
- +
, chart.getName(), chart.getDescription(), diff --git a/packages/core/src/renderer/components/+helm-charts/icon.module.css b/packages/core/src/renderer/components/+helm-charts/icon.module.css new file mode 100644 index 0000000000..a665648c83 --- /dev/null +++ b/packages/core/src/renderer/components/+helm-charts/icon.module.css @@ -0,0 +1,13 @@ +.chartIcon { + background-size: cover; + background-position: center; +} + +.imageNotLoaded { + width: 95%; + height: 95%; +} + +.img { + opacity: 0; +} \ No newline at end of file diff --git a/packages/core/src/renderer/components/+helm-charts/icon.tsx b/packages/core/src/renderer/components/+helm-charts/icon.tsx index 78d5be7ed3..12e3c8761b 100644 --- a/packages/core/src/renderer/components/+helm-charts/icon.tsx +++ b/packages/core/src/renderer/components/+helm-charts/icon.tsx @@ -3,47 +3,48 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ +import styles from "./icon.module.css"; + +import { cssNames } from "@k8slens/utilities"; import React, { useState } from "react"; -import type { HelmChart } from "../../../common/k8s-api/endpoints/helm-charts.api"; export interface HelmChartIconProps { className?: string; - chart: HelmChart; + imageUrl?: string; } export const HelmChartIcon = ({ - chart, + imageUrl = "", className, }: HelmChartIconProps) => { - const [failedToLoad, setFailedToLoad] = useState(false); - const icon = chart.getIcon(); + const [isImageLoaded, setIsImageLoaded] = useState(false); + const backgroundImage = `url(${imageUrl})`; + const placeholderImageUrl = "data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNzIyLjggNzAyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogICAgICAgICAgPGcgZmlsbD0iIzhlOTI5NyI+CiAgICAgICAgICAgIDxwYXRoIGQ9Im0zMTggMjk5LjVjMi4xIDEuNiA0LjggMi41IDcuNiAyLjUgNi45IDAgMTIuNi01LjUgMTIuOS0xMi4zbC4zLS4yIDQuMy03Ni43Yy01LjIuNi0xMC40IDEuNS0xNS42IDIuNy0yOC41IDYuNS01My4yIDIwLjUtNzIuNiAzOS41bDYyLjkgNDQuNnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTMwOS41IDQxMS45Yy0xLjQtNS45LTYuNi05LjktMTIuNC0xMC0uOCAwLTEuNy4xLTIuNS4ybC0uMS0uMi03NS41IDEyLjhjMTEuNyAzMi4yIDMzLjQgNTguNSA2MC44IDc2LjFsMjkuMi03MC43LS4yLS4zYzEuMS0yLjQgMS40LTUuMi43LTcuOXoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTI4NC40IDM1Ny41YzIuNS0uNyA0LjktMi4yIDYuNy00LjQgNC4zLTUuNCAzLjYtMTMuMi0xLjYtMTcuOGwuMS0uMy01Ny40LTUxLjRjLTE3IDI3LjgtMjUuMSA2MS4xLTIxLjQgOTUuM2w3My42LTIxLjJ6Ii8+CiAgICAgICAgICAgIDxwYXRoIGQ9Im0zNDAuMiAzODAgMjEuMiAxMC4yIDIxLjEtMTAuMSA1LjMtMjIuOS0xNC42LTE4LjJoLTIzLjZsLTE0LjYgMTguMnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTM4NC4yIDI4OS40Yy4xIDIuNiAxIDUuMiAyLjggNy41IDQuMyA1LjQgMTIuMSA2LjQgMTcuNyAyLjRsLjIuMSA2Mi41LTQ0LjNjLTIzLjYtMjMuMS01NC40LTM4LjItODcuNi00Mi4yeiIvPgogICAgICAgICAgICA8cGF0aCBkPSJtNDkwLjMgMjgzLjctNTcuMSA1MS4xdi4yYy0yIDEuNy0zLjUgNC4xLTQuMSA2LjgtMS41IDYuOCAyLjUgMTMuNSA5LjIgMTUuM2wuMS4zIDc0IDIxLjNjMS42LTE2IC42LTMyLjUtMy4yLTQ5LTMuOS0xNi44LTEwLjQtMzIuMi0xOC45LTQ2eiIvPgogICAgICAgICAgICA8cGF0aCBkPSJtMzcyLjggNDM5LjZjLTEuMi0yLjMtMy4yLTQuMy01LjgtNS41LTItLjktNC0xLjQtNi0xLjMtNC41LjItOC43IDIuNi0xMC45IDYuOGgtLjFsLTM3LjEgNjcuMWMyNS43IDguOCA1NC4xIDEwLjcgODIuNSA0LjIgNS4xLTEuMiAxMC0yLjUgMTQuOS00LjJsLTM3LjMtNjcuMXoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTcxMS43IDQyNS02MC40LTI2Mi4yYy0zLjItMTMuNy0xMi41LTI1LjMtMjUuMy0zMS40bC0yNDQuNC0xMTYuOGMtNy4xLTMuNC0xNC44LTQuOS0yMi43LTQuNS02LjIuMy0xMi4zIDEuOS0xNy45IDQuNWwtMjQ0LjMgMTE2LjdjLTEyLjggNi4xLTIyLjEgMTcuNy0yNS4zIDMxLjRsLTYwLjIgMjYyLjNjLTIuOCAxMi4yLS41IDI1IDYuMyAzNS41LjggMS4zIDEuNyAyLjUgMi43IDMuN2wxNjkuMSAyMTAuM2M4LjkgMTEgMjIuMyAxNy40IDM2LjUgMTcuNGwyNzEuMi0uMWMxNC4yIDAgMjcuNy02LjQgMzYuNS0xNy40bDE2OS4xLTIxMC4zYzguOS0xMC45IDEyLjItMjUuNCA5LjEtMzkuMXptLTkzLTMuMmMtMS44IDcuOC0xMC4yIDEyLjYtMTguOSAxMC43LS4xIDAtLjIgMC0uMiAwLS4xIDAtLjItLjEtLjMtLjEtMS4yLS4zLTIuNy0uNS0zLjgtLjgtNS0xLjMtOC42LTMuMy0xMy4xLTUuMS05LjctMy41LTE3LjctNi40LTI1LjUtNy41LTQtLjMtNiAxLjYtOC4yIDMtMS4xLS4yLTQuNC0uOC02LjItMS4xLTE0IDQ0LTQzLjkgODIuMi04NC4zIDEwNi4xLjcgMS43IDEuOSA1LjMgMi40IDUuOS0uOSAyLjUtMi4zIDQuOC0xLjEgOC42IDIuOCA3LjQgNy40IDE0LjYgMTMgMjMuMiAyLjcgNCA1LjQgNy4xIDcuOCAxMS43LjYgMS4xIDEuMyAyLjggMS45IDMuOSAzLjggOCAxIDE3LjMtNi4yIDIwLjgtNy4zIDMuNS0xNi4zLS4yLTIwLjItOC4zLS42LTEuMS0xLjMtMi43LTEuOC0zLjgtMi4xLTQuNy0yLjgtOC44LTQuMi0xMy40LTMuMy05LjctNi0xNy44LTEwLTI0LjYtMi4yLTMuMy01LTMuNy03LjUtNC41LS41LS44LTIuMi00LTMuMS01LjYtOC4xIDMuMS0xNi40IDUuNi0yNS4xIDcuNi0zNy45IDguNi03NS45IDUuMS0xMDkuOS03LjlsLTMuMyA2Yy0yLjUuNy00LjggMS4zLTYuMyAzLjEtNS4zIDYuNC03LjUgMTYuNi0xMS4zIDI2LjMtMS41IDQuNi0yLjEgOC43LTQuMiAxMy40LS41IDEuMS0xLjMgMi42LTEuOCAzLjctMy45IDguMS0xMi45IDExLjctMjAuMiA4LjItNy4yLTMuNS0xMC0xMi43LTYuMi0yMC44LjYtMS4yIDEuMy0yLjggMS45LTMuOSAyLjQtNC42IDUuMi03LjcgNy44LTExLjcgNS41LTguNyAxMC40LTE2LjQgMTMuMi0yMy44LjctMi40LS4zLTUuOC0xLjMtOC4zbDIuNy02LjRjLTM4LjktMjMuMS02OS43LTU5LjgtODQuMy0xMDUuM2wtNi40IDEuMWMtMS43LTEtNS4xLTMuMi04LjQtMy03LjggMS4xLTE1LjggNC0yNS41IDcuNS00LjUgMS43LTguMSAzLjctMTMuMSA1LTEuMS4zLTIuNi42LTMuOC44LS4xIDAtLjIuMS0uMy4xcy0uMiAwLS4yIDBjLTguNyAxLjktMTcuMS0yLjktMTguOS0xMC43czMuOC0xNS43IDEyLjQtMTcuOGMuMSAwIC4yIDAgLjItLjFoLjFjMS4yLS4zIDIuOC0uNyAzLjktLjkgNS4xLTEgOS4yLS43IDE0LTEuMSAxMC4yLTEuMSAxOC43LTEuOSAyNi4yLTQuMyAyLjQtMSA0LjctNC4zIDYuMy02LjNsNi4xLTEuOGMtNi45LTQ3LjUgNC44LTk0LjIgMjkuOC0xMzEuOWwtNC43LTQuMmMtLjMtMS44LS43LTYtMi45LTguNC01LjgtNS40LTEzLTkuOS0yMS44LTE1LjMtNC4yLTIuNC04LTQtMTIuMS03LjEtLjktLjctMi4xLTEuNy0zLTIuNC0uMS0uMS0uMS0uMS0uMi0uMi03LTUuNi04LjYtMTUuMi0zLjYtMjEuNiAyLjgtMy42IDcuMi01LjMgMTEuNy01LjIgMy41LjEgNy4xIDEuNCAxMC4yIDMuOCAxIC44IDIuNCAxLjggMy4yIDIuNiAzLjkgMy40IDYuMyA2LjcgOS42IDEwLjIgNy4yIDcuMyAxMy4yIDEzLjQgMTkuNyAxNy44IDMuNCAyIDYuMSAxLjIgOC43LjguOC42IDMuNyAyLjYgNS4zIDMuOCAyNC45LTI2LjQgNTcuNi00NiA5NS42LTU0LjYgOC44LTIgMTcuNy0zLjMgMjYuNC00LjFsLjMtNi4yYzEuOS0xLjkgNC4xLTQuNiA0LjgtNy42LjYtNy45LS40LTE2LjMtMS42LTI2LjUtLjctNC44LTEuOC04LjctMi0xMy45IDAtMS4xIDAtMi41IDAtMy44IDAtLjEgMC0uMyAwLS40IDAtOSA2LjUtMTYuMiAxNC42LTE2LjJzMTQuNiA3LjMgMTQuNiAxNi4yYzAgMS4zLjEgMyAwIDQuMi0uMiA1LjItMS4zIDkuMS0yIDEzLjktMS4yIDEwLjItMi4zIDE4LjctMS43IDI2LjUuNiAzLjkgMi45IDUuNSA0LjggNy4zIDAgMS4xLjIgNC42LjMgNi41IDQ2LjUgNC4xIDg5LjcgMjUuNCAxMjEuNCA1OC43bDUuNi00YzEuOS4xIDYgLjcgOC45LTEgNi41LTQuNCAxMi41LTEwLjUgMTkuNy0xNy44IDMuMy0zLjUgNS43LTYuOCA5LjctMTAuMi45LS44IDIuMy0xLjggMy4yLTIuNiA3LTUuNiAxNi44LTUgMjEuOCAxLjNzMy40IDE2LTMuNiAyMS42Yy0xIC44LTIuMyAxLjktMy4yIDIuNi00LjIgMy4xLTggNC43LTEyLjIgNy4xLTguNyA1LjQtMTYgOS45LTIxLjggMTUuMy0yLjcgMi45LTIuNSA1LjctMi44IDguMy0uOC43LTMuNyAzLjMtNS4yIDQuNyAxMi42IDE4LjggMjIuMSA0MC4xIDI3LjQgNjMuMyA1LjMgMjMuMSA2LjEgNDYuMSAzLjEgNjguM2w1LjkgMS43YzEuMSAxLjUgMy4yIDUuMiA2LjMgNi4zIDcuNSAyLjQgMTYgMy4yIDI2LjIgNC4zIDQuOC40IDguOS4yIDE0IDEuMSAxLjIuMiAzIC43IDQuMiAxIDguOSAyLjQgMTQuNCAxMC40IDEyLjYgMTguMnoiLz4KICAgICAgICAgICAgPHBhdGggZD0ibTQyOCA0MDEuN2MtMS0uMi0yLS4zLTMtLjItMS43LjEtMy4zLjUtNC45IDEuMy02LjIgMy05IDEwLjQtNi4yIDE2LjdsLS4xLjEgMjkuNiA3MS40YzI4LjUtMTguMiA0OS44LTQ1LjMgNjEtNzYuNmwtNzYuMi0xMi45eiIvPgogICAgICAgICAgPC9nPgogICAgICAgIDwvc3ZnPg=="; - if (!icon || failedToLoad) { - return ( -
- - - - - - - - - - - - - -
- ); - } + const handleImageLoad = () => { + setIsImageLoaded(true); + }; + + const isValidImage = () => { + return /^https?:\/\/.*(? evt.currentTarget.classList.add("visible")} - onError={() => setFailedToLoad(true)} - /> +
+ {isValidImage() && ( + + )} +
); }; From ecfe99480c9529c0c4b7e5e4107e1afaabd89f96 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 29 Mar 2023 07:40:11 -0400 Subject: [PATCH 08/35] Remove auto adding tickets to project board (#7424) Signed-off-by: Sebastian Malton --- .../actions/add-card-to-project/Dockerfile | 11 -- .../actions/add-card-to-project/action.yml | 23 --- .../actions/add-card-to-project/entrypoint.sh | 157 ------------------ .github/workflows/add-to-project-board.yaml | 33 ---- 4 files changed, 224 deletions(-) delete mode 100644 .github/actions/add-card-to-project/Dockerfile delete mode 100644 .github/actions/add-card-to-project/action.yml delete mode 100644 .github/actions/add-card-to-project/entrypoint.sh delete mode 100644 .github/workflows/add-to-project-board.yaml diff --git a/.github/actions/add-card-to-project/Dockerfile b/.github/actions/add-card-to-project/Dockerfile deleted file mode 100644 index 95c2fe1628..0000000000 --- a/.github/actions/add-card-to-project/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -# Container image that runs your code -FROM alpine:3.10 - -RUN apk add --no-cache --no-progress curl jq - -# Copies your code file from your action repository to the filesystem path `/` of the container -COPY entrypoint.sh /entrypoint.sh -RUN chmod +x /entrypoint.sh - -# Code file to execute when the docker container starts up (`entrypoint.sh`) -ENTRYPOINT ["/entrypoint.sh"] diff --git a/.github/actions/add-card-to-project/action.yml b/.github/actions/add-card-to-project/action.yml deleted file mode 100644 index e7fcba44c6..0000000000 --- a/.github/actions/add-card-to-project/action.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: 'add_card_to_project' -description: 'A GitHub Action to add a card to a project and set the card position' -author: 'Steve Richards' -branding: - icon: 'command' - color: 'blue' -inputs: - project: - description: 'The url of the project to be assigned to.' - required: true - column_name: - description: 'The column name of the project, defaults to "To do" for issues and "In progress" for pull requests.' - required: false - card_position: - description: 'The card position of the card in the column, defaults to "bottom". Valid values are "top", "bottom" and "after:".' - required: false -runs: - using: 'docker' - image: 'Dockerfile' - args: - - ${{ inputs.project }} - - ${{ inputs.column_name }} - - ${{ inputs.card_position }} diff --git a/.github/actions/add-card-to-project/entrypoint.sh b/.github/actions/add-card-to-project/entrypoint.sh deleted file mode 100644 index a67bfb1d96..0000000000 --- a/.github/actions/add-card-to-project/entrypoint.sh +++ /dev/null @@ -1,157 +0,0 @@ -#!/bin/sh -l - -PROJECT_URL="$INPUT_PROJECT" -if [ -z "$PROJECT_URL" ]; then - echo "PROJECT_URL is not defined." >&2 - exit 1 -fi - -get_project_type() { - _PROJECT_URL="$1" - - case "$_PROJECT_URL" in - https://github.com/orgs/*) - echo "org" - ;; - https://github.com/users/*) - echo "user" - ;; - https://github.com/*/projects/*) - echo "repo" - ;; - *) - echo "Invalid PROJECT_URL: $_PROJECT_URL" >&2 - exit 1 - ;; - esac - - unset _PROJECT_URL -} - -find_project_id() { - _PROJECT_TYPE="$1" - _PROJECT_URL="$2" - - case "$_PROJECT_TYPE" in - org) - _ORG_NAME=$(echo "$_PROJECT_URL" | sed -e 's@https://github.com/orgs/\([^/]\+\)/projects/[0-9]\+@\1@') - _ENDPOINT="https://api.github.com/orgs/$_ORG_NAME/projects" - ;; - user) - _USER_NAME=$(echo "$_PROJECT_URL" | sed -e 's@https://github.com/users/\([^/]\+\)/projects/[0-9]\+@\1@') - _ENDPOINT="https://api.github.com/users/$_USER_NAME/projects" - ;; - repo) - _ENDPOINT="https://api.github.com/repos/$GITHUB_REPOSITORY/projects" - ;; - esac - - _PROJECTS=$(curl -s -X GET -u "$GITHUB_ACTOR:$TOKEN" --retry 3 \ - -H 'Accept: application/vnd.github.inertia-preview+json' \ - "$_ENDPOINT") - - _PROJECTID=$(echo "$_PROJECTS" | jq -r ".[] | select(.html_url == \"$_PROJECT_URL\").id") - - if [ "$_PROJECTID" != "" ]; then - echo "$_PROJECTID" - else - echo "No project was found." >&2 - exit 1 - fi - - unset _PROJECT_TYPE _PROJECT_URL _ORG_NAME _USER_NAME _ENDPOINT _PROJECTS _PROJECTID -} - -find_column_id() { - _PROJECT_ID="$1" - _INITIAL_COLUMN_NAME="$2" - - _COLUMNS=$(curl -s -X GET -u "$GITHUB_ACTOR:$TOKEN" --retry 3 \ - -H 'Accept: application/vnd.github.inertia-preview+json' \ - "https://api.github.com/projects/$_PROJECT_ID/columns") - - - echo "$_COLUMNS" | jq -r ".[] | select(.name == \"$_INITIAL_COLUMN_NAME\").id" - unset _PROJECT_ID _INITIAL_COLUMN_NAME _COLUMNS -} - -PROJECT_TYPE=$(get_project_type "${PROJECT_URL:? required this environment variable}") - -if [ "$PROJECT_TYPE" = org ] || [ "$PROJECT_TYPE" = user ]; then - if [ -z "$MY_GITHUB_TOKEN" ]; then - echo "MY_GITHUB_TOKEN not defined" >&2 - exit 1 - fi - - TOKEN="$MY_GITHUB_TOKEN" # It's User's personal access token. It should be secret. -else - if [ -z "$GITHUB_TOKEN" ]; then - echo "GITHUB_TOKEN not defined" >&2 - exit 1 - fi - - TOKEN="$GITHUB_TOKEN" # GitHub sets. The scope in only the repository containing the workflow file. -fi - -INITIAL_COLUMN_NAME="$INPUT_COLUMN_NAME" -if [ -z "$INITIAL_COLUMN_NAME" ]; then - # assing the column name by default - INITIAL_COLUMN_NAME='To do' - if [ "$GITHUB_EVENT_NAME" == "pull_request" ] || [ "$GITHUB_EVENT_NAME" == "pull_request_target" ]; then - echo "changing col name for PR event" - INITIAL_COLUMN_NAME='In progress' - fi -fi - - -PROJECT_ID=$(find_project_id "$PROJECT_TYPE" "$PROJECT_URL") -INITIAL_COLUMN_ID=$(find_column_id "$PROJECT_ID" "${INITIAL_COLUMN_NAME:? required this environment variable}") - -if [ -z "$INITIAL_COLUMN_ID" ]; then - echo "INITIAL_COLUMN_ID is not found." >&2 - exit 1 -fi - -case "$GITHUB_EVENT_NAME" in - issues) - ISSUE_ID=$(jq -r '.issue.id' < "$GITHUB_EVENT_PATH") - - # Add this issue to the project column - _CARDS=$(curl -s -X POST -u "$GITHUB_ACTOR:$TOKEN" --retry 3 \ - -H 'Accept: application/vnd.github.inertia-preview+json' \ - -d "{\"content_type\": \"Issue\", \"content_id\": $ISSUE_ID}" \ - "https://api.github.com/projects/columns/$INITIAL_COLUMN_ID/cards") - ;; - pull_request|pull_request_target) - PULL_REQUEST_ID=$(jq -r '.pull_request.id' < "$GITHUB_EVENT_PATH") - - # Add this pull_request to the project column - _CARDS=$(curl -s -X POST -u "$GITHUB_ACTOR:$TOKEN" --retry 3 \ - -H 'Accept: application/vnd.github.inertia-preview+json' \ - -d "{\"content_type\": \"PullRequest\", \"content_id\": $PULL_REQUEST_ID}" \ - "https://api.github.com/projects/columns/$INITIAL_COLUMN_ID/cards") - ;; - *) - echo "Nothing to be done on this action: $GITHUB_EVENT_NAME" >&2 - exit 1 - ;; -esac - -CARDS_ID=$(echo "$_CARDS" | jq -r .id) -unset _CARDS - -if [ -z "$CARDS_ID" ]; then - echo "CARDS_ID is not found." >&2 - exit 1 -fi - -INITIAL_CARD_POSITION="$INPUT_CARD_POSITION" -if [ -z "$INITIAL_CARD_POSITION" ]; then - # assign the card position by default - INITIAL_CARD_POSITION='bottom' -fi - -_CARDS=$(curl -s -X POST -u "$GITHUB_ACTOR:$TOKEN" --retry 3 \ - -H 'Accept: application/vnd.github.inertia-preview+json' \ - -d "{\"position\": \"$INITIAL_CARD_POSITION\"}" \ - "https://api.github.com/projects/columns/cards/$CARDS_ID/moves") diff --git a/.github/workflows/add-to-project-board.yaml b/.github/workflows/add-to-project-board.yaml deleted file mode 100644 index 5ebb3de16e..0000000000 --- a/.github/workflows/add-to-project-board.yaml +++ /dev/null @@ -1,33 +0,0 @@ -name: Add Card to Project(s) -on: - issues: - types: [opened] - pull_request_target: - types: [opened] -env: - MY_GITHUB_TOKEN: ${{ secrets.PROJECT_GITHUB_TOKEN }} - EVENT_TYPE: $GITHUB_EVENT_NAME - -jobs: - add_card_to_project: - runs-on: ubuntu-latest - name: Add Card to Project(s) - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Get Event Type - run: echo $GITHUB_EVENT_NAME - - name: Assign NEW issues to project 1 - uses: ./.github/actions/add-card-to-project - if: github.event_name == 'issues' && github.event.action == 'opened' - with: - project: "https://github.com/orgs/lensapp/projects/1" - column_name: "Backlog" - card_position: "bottom" - - name: Assign NEW pull requests to project 1 - uses: ./.github/actions/add-card-to-project - if: github.event_name == 'pull_request_target' && github.event.action == 'opened' - with: - project: "https://github.com/orgs/lensapp/projects/1" - column_name: "PRs" - card_position: "bottom" From d8c485a79f42d05ffa61c1c235f57b7b8b80e6a5 Mon Sep 17 00:00:00 2001 From: Jim Ehrismann <40840436+jim-docker@users.noreply.github.com> Date: Wed, 29 Mar 2023 07:40:22 -0400 Subject: [PATCH 09/35] Restore disk metrics to PersistentVolumeClaim details page (#7427) Signed-off-by: Jim Ehrismann --- packages/core/src/common/cluster-types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/common/cluster-types.ts b/packages/core/src/common/cluster-types.ts index ba01489152..4095c3fc23 100644 --- a/packages/core/src/common/cluster-types.ts +++ b/packages/core/src/common/cluster-types.ts @@ -167,7 +167,7 @@ export enum ClusterMetricsResourceType { StatefulSet = "StatefulSet", Container = "Container", Ingress = "Ingress", - VolumeClaim = "VolumeClaim", + VolumeClaim = "PersistentVolumeClaim", ReplicaSet = "ReplicaSet", DaemonSet = "DaemonSet", Job = "Job", From a5d458bd9766168c1f9f01832fd5bb734e1b6175 Mon Sep 17 00:00:00 2001 From: steve richards Date: Wed, 29 Mar 2023 15:09:33 +0100 Subject: [PATCH 10/35] Remove Materials Insiders usage. (#7430) Signed-off-by: Steve Richards --- .github/workflows/main.yml | 2 +- .github/workflows/mkdocs-delete-version.yml | 2 +- .github/workflows/mkdocs-manual.yml | 2 +- .github/workflows/mkdocs-set-default-version.yml | 2 +- mkdocs.yml | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9eee6fbda9..4c63c78d36 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,7 +57,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install git+https://${{ secrets.GH_TOKEN }}@github.com/lensapp/mkdocs-material-insiders.git + pip install mkdocs-material pip install mike - name: Checkout Release from lens diff --git a/.github/workflows/mkdocs-delete-version.yml b/.github/workflows/mkdocs-delete-version.yml index a5ff72b8cb..aa0d0d0ccf 100644 --- a/.github/workflows/mkdocs-delete-version.yml +++ b/.github/workflows/mkdocs-delete-version.yml @@ -18,7 +18,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install git+https://${{ secrets.GH_TOKEN }}@github.com/lensapp/mkdocs-material-insiders.git + pip install mkdocs-material pip install mike - name: Checkout Release from lens diff --git a/.github/workflows/mkdocs-manual.yml b/.github/workflows/mkdocs-manual.yml index adb0094d62..5656cdce77 100644 --- a/.github/workflows/mkdocs-manual.yml +++ b/.github/workflows/mkdocs-manual.yml @@ -21,7 +21,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install git+https://${{ secrets.GH_TOKEN }}@github.com/lensapp/mkdocs-material-insiders.git + pip install mkdocs-material pip install mike - name: Checkout Version from lens diff --git a/.github/workflows/mkdocs-set-default-version.yml b/.github/workflows/mkdocs-set-default-version.yml index a4bcf5fbb2..509ddc785b 100644 --- a/.github/workflows/mkdocs-set-default-version.yml +++ b/.github/workflows/mkdocs-set-default-version.yml @@ -18,7 +18,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install git+https://${{ secrets.GH_TOKEN }}@github.com/lensapp/mkdocs-material-insiders.git + pip install mkdocs-material pip install mike - name: Checkout Release from lens diff --git a/mkdocs.yml b/mkdocs.yml index e0f1568b87..401bd7b12f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -53,6 +53,7 @@ theme: - toc.autohide - search.suggest - search.highlight + - content.code.copy extra_css: - stylesheets/extra.css From 962aa13de2d08574753bd8a44f9d1ddaeecd2ca7 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 29 Mar 2023 16:29:49 -0400 Subject: [PATCH 11/35] Add scenarios for namespace selector (#7431) * Add scenarios for namespace selector Signed-off-by: Sebastian Malton * Add scenarios about namespaces being created and deleted Signed-off-by: Sebastian Malton --------- Signed-off-by: Sebastian Malton --- scenarios/namespace-selector.md | 208 ++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 scenarios/namespace-selector.md diff --git a/scenarios/namespace-selector.md b/scenarios/namespace-selector.md new file mode 100644 index 0000000000..e30a708ce3 --- /dev/null +++ b/scenarios/namespace-selector.md @@ -0,0 +1,208 @@ +## Feature: Namespace-selector in "cluster frame" + +### Scenario: Options for namespaces +- Given I’m connected to a cluster for the first time +- And I see the Namespace selector somewhere +- When I mouse-click to select it +- Then I see a list of all the Namespaces in alphabetical order +- But a selection for "All namespaces" as first + +### Scenario: Selecting a single namespace with mouse +- Given I’ve opened namespace selector +- When I hover over a namespace +- Then a toggle appears next to the namespace +- When I click the namespace entry outside of the toggle +- Then the list of namespaces closes +- And the namespace is seen as selected +- When I reopen the list +- Then I see the selected namespace at the top, just below "All namespaces" +- And I see the namespace marked as selected +- And I see the remaining namespaces in previous order not marked as selected + +### Scenario: Selecting All Namespaces option explicitly +- Given I’ve opened namespace selector +- When I click the "All Namespaces" option +- Then I see just the "All Namespaces" option as selected + +### Scenario: Toggling a single namespace after selecting "All Namespaces" option explicitly +- Given I’ve opened namespace selector +- And the "All Namespaces" option is selected +- And the CTRL/CMD is pressed +- When I click a single namespace option +- Then the "All Namespaces" option is shown as not selected +- And that single namespace is shown as not selected +- And all other single namespace options are shown as selected + +### Scenario: Selecting all namespace options explicitly +- Given I’ve opened namespace selector +- When I have selected each of the individual namespace options +- Then the "All Namespaces" option is not shown as selected +- And then every namespace option is shown as selected +- When a new namespace appears +- Then that new namespace is not shown as selected + +### Scenario: An single explicitly selected namespace is deleted +- Given that a single namespace is selected +- When that namespace is deleted +- Then the "All Namespaces" option is selected +- When a new namespace with the same name is created +- The "All Namespaces" is still the option selected + +### Scenario: One of several explicitly selected namespaces is deleted +- Given that more than one namespaces are selected +- When one of those namespace is deleted +- Then the remaining namespaces are shown as selected +- When a new namespace with the same name is created +- Then that new namespace is shown as selected + +### Scenario: Selecting a different single namespace with mouse +- Given I’ve opened namespace selector +- And I have a single namespace selected +- When I select a different namespace with a mouse-click +- Then the list of namespaces closes +- And the namespace is seen as selected in the select control + +### Scenario: Toggling multiple namespaces with mouse +- Given I’ve opened namespace selector +- When I hover over a namespace that isn't selected +- Then a toggle appears next to only that namespace +- When I hover over a namespace that is selected +- Then a toggle replaces the selection marker next to only that namespace +- When I click the checkbox +- Then the list of namespaces does not close +- And the namespace is still seen in original order +- But the namespace is marked as selected +- When I click the select control the namespace selector closes + +### Scenario: Selecting single namespace after multiple namespaces with mouse +- Given I’ve opened namespace selector +- When I hover over a namespace +- Then a checkbox appears next to only that namespace +- When I click the checkbox +- Then the list of namespaces does not close +- And the namespace is still seen in original order +- But the namespace is marked as selected +- When I click any namespace +- Then the list of namespaces closes +- And the namespace is seen as selected in the select control + +### Scenario: Selecting multiple namespaces with CTRL/CMD and mouse +- Given I’ve opened namespace selector +- And CTRL/CMD is pressed +- When I hover a namespace +- Then a checkbox does not appear next to the namespace +- When I click the namespace anywhere +- Then the list of namespaces does not close +- And the namespace is still seen in original order +- But the namespace is marked as selected +- When I click the select control the namespace selector closes + +### Scenario: A new namespace is created while the selector is open +- Given that the namespace selector is open +- And a new namespace is created +- Then new namespace is now visible as an option +- And the new namespace is not shown as selected +- And the namespace is sorted alphabetically into the "never selected" section + +### Scenario: A non-selected namespace is deleted while the selector is open +- Given that the namespace selector is open +- And a namespace that is not selected is deleted +- Then the namespace is no longer visible as an option + +### Scenario: Closing dropdown after selecting multiple namespaces onKeyUp CTRL/CMD and mouse +- Given I’ve opened namespace selector +- And CTRL/CMD is pressed +- When I release CTRL/CMD key +- Then the namespace selector closes + +### Scenario: Closing the namespace selector with outside mouse click +- Given I’ve opened namespace selector +- When I click outside the selector the namespace selector closes + +### Scenario: Reopening namespace selection shows selections first +- Given I’ve already selected namespaces +- When I reopen namespace selector +- Then I see the selected namespaces at the top in alphabetical order, just below "All namespaces" +- And then I see the namespaces that I have ever selected in MRU order +- And then I see the namespaces that I have never selected in alphabetical order + +### Scenario: Default namespace is preselected when present +- Given this is the first time connecting to a cluster +- And a special namespace called "default" is among the namespaces +- Then "default" is selected instead of "All namespaces" + +### Scenario: All namespace is preselected when default is not present +- Given this is the first time connecting to a cluster +- And a special namespace called "default" is not among the namespaces +- Then "All namespaces" is selected + +### Scenario: Focusing namespace selector using keyboard +- Given that I have just opened page with the namespace selector +- Can press TAB +- Then focuses the namespace selector + +### Scenario: Opening namespace selector using keyboard +- Given that the namespace selector is focused and is closed +- Pressing the ENTER key +- Opens the namespace selector + +### Scenario: Closing namespace selector using keyboard +- Given that the namespace selector control is focused and the dropdown is open +- Pressing the ENTER key +- Closes the namespace selector + +### Scenario: Closing namespace selector using keyboard +- Given that the namespace selector is open and either the control or the dropdown is focuses +- Pressing the ESC key +- Closes the namespace selector + +### Scenario: Moving focus through namespace selector dropdown using the keyboard +- Given that the namespace selector is open and is focused +- Regardless of CTRL/CMD press state +- Pressing the DOWN-ARROW moves to the next option in the dropdown, without wrapping around, being sticky +- Pressing the UP-ARROW moves to the previous option in the dropdown, without wrapping around, being sticky +- Pressing the PAGE-DOWN moves to the bottom of the dropdown +- Pressing the PAGE-UP moves to the top of the dropdown + +### Scenario: Toggling namespace as selected using the keyboard +- Given that the namespace selector is open and is focused +- And that a namespace option is focused +- Pressing SPACE toggles the namespace as selected +- And the namespace selector closes + +### Scenario: Toggling multiple namespace as selected using the keyboard +- Given that the namespace selector is open and is focused +- And the CTRL/CMD is pressed +- And that a namespace option is focused +- Pressing SPACE toggles the namespace as selected +- And the namespace selector stays open + +### Scenario: Selecting a single namespace as selected using the keyboard +- Given that the namespace selector is open and is focused +- And that a namespace option is focused +- Pressing ENTER selects that single namespace +- And the namespace selector closes + +### Scenario: Filtering list of namespaces +- Given that the namespace selector is open and is focused +- Typing filters the visible namespace options in the dropdown via contains +- Focus returns to the filter text input field + +### Scenario: Toggling the first option after filtering list of namespace +- Given that the namespace selector is open, focused, and some filtering has been done +- Pressing ENTER toggles the first namespace option +- And the namespace selector closes + +### Scenario: Selecting multiple options after filtering list of namespace +- Given that the namespace selector is open, focused, and some filtering has been done +- And the CTRL/CMD is pressed +- And not all the visible options are selected +- Pressing ENTER selects all the visible namespace options +- And the namespace selector stays open + +### Scenario: Deselecting multiple options after filtering list of namespace +- Given that the namespace selector is open, focused, and some filtering has been done +- And the CTRL/CMD is pressed +- And all the visible options are selected +- Pressing ENTER deselects all the visible namespace options +- And the namespace selector stays open From 132c51018bc4227df4a935a8f89aa1b4ff83910d Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 30 Mar 2023 10:28:32 -0400 Subject: [PATCH 12/35] Remove requirement for JSON of messages (#7426) * Remove requirement for JSON of messages - Remove backhanded requirements of reactive contexts, overriding application configurations. Signed-off-by: Sebastian Malton * Fix type error Signed-off-by: Sebastian Malton --------- Signed-off-by: Sebastian Malton --- .../messaging/computed-channel/index.ts | 3 --- ...annel-administration-channel.injectable.ts | 6 ----- .../computed-channel.injectable.ts | 26 +++---------------- .../computed-channel.test.tsx | 16 ------------ 4 files changed, 3 insertions(+), 48 deletions(-) diff --git a/packages/technical-features/messaging/computed-channel/index.ts b/packages/technical-features/messaging/computed-channel/index.ts index 4516e0b9a6..dd72ecf71b 100644 --- a/packages/technical-features/messaging/computed-channel/index.ts +++ b/packages/technical-features/messaging/computed-channel/index.ts @@ -6,7 +6,4 @@ export { export type { ChannelObserver, ComputedChannelFactory, - JsonifiableObject, - JsonifiableArray, - Jsonifiable, } from "./src/computed-channel/computed-channel.injectable"; diff --git a/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel-administration-channel.injectable.ts b/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel-administration-channel.injectable.ts index b0fdb3c59f..da8dd4110a 100644 --- a/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel-administration-channel.injectable.ts +++ b/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel-administration-channel.injectable.ts @@ -1,15 +1,9 @@ import { reaction } from "mobx"; - import { getMessageChannelListenerInjectable } from "@k8slens/messaging"; import { sendMessageToChannelInjectionToken } from "@k8slens/messaging"; -import type { JsonPrimitive } from "type-fest"; import { computedChannelObserverInjectionToken } from "./computed-channel.injectable"; import { getMessageChannel } from "@k8slens/messaging"; -export type JsonifiableObject = { [Key in string]?: Jsonifiable } | { toJSON: () => Jsonifiable }; -export type JsonifiableArray = readonly Jsonifiable[]; -export type Jsonifiable = JsonPrimitive | JsonifiableObject | JsonifiableArray; - export type ComputedChannelAdminMessage = { channelId: string; status: "became-observed" | "became-unobserved"; diff --git a/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.injectable.ts b/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.injectable.ts index 03f5a16aab..b652a0c795 100644 --- a/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.injectable.ts +++ b/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.injectable.ts @@ -1,7 +1,6 @@ import { getInjectable, getInjectionToken } from "@ogre-tools/injectable"; import { - _getGlobalState, computed, IComputedValue, observable, @@ -13,13 +12,8 @@ import { import type { MessageChannel } from "@k8slens/messaging"; import { getMessageChannelListenerInjectable } from "@k8slens/messaging"; import { sendMessageToChannelInjectionToken } from "@k8slens/messaging"; -import type { JsonPrimitive } from "type-fest"; import { computedChannelAdministrationChannel } from "./computed-channel-administration-channel.injectable"; -export type JsonifiableObject = { [Key in string]?: Jsonifiable } | { toJSON: () => Jsonifiable }; -export type JsonifiableArray = readonly Jsonifiable[]; -export type Jsonifiable = JsonPrimitive | JsonifiableObject | JsonifiableArray; - export type ComputedChannelFactory = ( channel: MessageChannel, pendingValue: T, @@ -29,14 +23,12 @@ export const computedChannelInjectionToken = getInjectionToken = { +export type ChannelObserver = { channel: MessageChannel; observer: IComputedValue; }; -export const computedChannelObserverInjectionToken = getInjectionToken< - ChannelObserver ->({ +export const computedChannelObserverInjectionToken = getInjectionToken>({ id: "computed-channel-observer", }); @@ -49,19 +41,7 @@ const computedChannelInjectable = getInjectable({ return ((channel, pendingValue) => { const observableValue = observable.box(pendingValue); - const computedValue = computed(() => { - const { trackingDerivation } = _getGlobalState(); - - const contextIsReactive = !!trackingDerivation; - - if (!contextIsReactive) { - throw new Error( - `Tried to access value of computed channel "${channel.id}" outside of reactive context. This is not possible, as the value is acquired asynchronously sometime *after* being observed. Not respecting that, the value could be stale.`, - ); - } - - return observableValue.get(); - }); + const computedValue = computed(() => observableValue.get()); const valueReceiverInjectable = getMessageChannelListenerInjectable({ id: `computed-channel-value-receiver-for-${channel.id}`, diff --git a/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.test.tsx b/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.test.tsx index 4736fe22d4..b1c648176d 100644 --- a/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.test.tsx +++ b/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.test.tsx @@ -292,14 +292,6 @@ const TestComponent = observer(({ someComputed }: { someComputed: IComputedValue }); }); - it("when accessing the computed value outside of reactive context, throws", () => { - expect(() => { - computedTestChannel.get(); - }).toThrow( - 'Tried to access value of computed channel "some-channel-id" outside of reactive context. This is not possible, as the value is acquired asynchronously sometime *after* being observed. Not respecting that, the value could be stale.', - ); - }); - it("no value gets listened in di-1 anymore", () => { expect(latestValueMessage).toBeUndefined(); }); @@ -381,14 +373,6 @@ const TestComponent = observer(({ someComputed }: { someComputed: IComputedValue }); }); }); - - it("when accessing the computed value outside of reactive context, throws", () => { - expect(() => { - computedTestChannel.get(); - }).toThrow( - 'Tried to access value of computed channel "some-channel-id" outside of reactive context. This is not possible, as the value is acquired asynchronously sometime *after* being observed. Not respecting that, the value could be stale.', - ); - }); }); it("given observation of unrelated computed channel is stopped, observation of other computed channel still works", async () => { From 5b680e88702a8c9017a2ff3c8b4f0d41360dce8e Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 30 Mar 2023 13:58:18 -0400 Subject: [PATCH 13/35] Fix computed-channel tests Signed-off-by: Sebastian Malton --- .../src/computed-channel/computed-channel.test.tsx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.test.tsx b/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.test.tsx index b1c648176d..6bea2ca76d 100644 --- a/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.test.tsx +++ b/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.test.tsx @@ -493,14 +493,6 @@ const TestComponent = observer(({ someComputed }: { someComputed: IComputedValue }); }); - it("when accessing the computed value outside of reactive context, throws", () => { - expect(() => { - computedTestChannel.get(); - }).toThrow( - 'Tried to access value of computed channel "some-channel-id" outside of reactive context. This is not possible, as the value is acquired asynchronously sometime *after* being observed. Not respecting that, the value could be stale.', - ); - }); - it("given duplicate channel observer for the channel is registered, when the computed channel is observer, throws", () => { const duplicateChannelObserverInjectable = getInjectable({ id: "some-duplicate-channel-observer", From 5827fc9d9a391b5edc8cb12c720bd376007d0015 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Mar 2023 10:41:45 +0300 Subject: [PATCH 14/35] Bump webpack and @types/webpack (#7438) Bumps [webpack](https://github.com/webpack/webpack) and [@types/webpack](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/webpack). These dependencies needed to be updated together. Updates `webpack` from 5.76.1 to 5.77.0 - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.76.1...v5.77.0) Updates `@types/webpack` from 5.28.0 to 5.28.1 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/webpack) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: "@types/webpack" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 422 +++++++++++++++++- packages/core/package.json | 4 +- packages/extension-api/package.json | 4 +- packages/infrastructure/webpack/package.json | 2 +- .../legacy-extension-example/package.json | 2 +- packages/node-fetch/package.json | 2 +- packages/open-lens/package.json | 4 +- 7 files changed, 422 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index c06df90bc6..b0230bf37f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7814,6 +7814,8 @@ "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-5.28.0.tgz", "integrity": "sha512-8cP0CzcxUiFuA9xGJkfeVpqmWTk9nx6CWwamRGCj95ph1SmlRRk9KlCZ6avhCbZd4L68LvYT6l1kpdEnQXrF8w==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "@types/node": "*", "tapable": "^2.2.0", @@ -34469,7 +34471,7 @@ "@types/triple-beam": "^1.3.2", "@types/url-parse": "^1.4.8", "@types/uuid": "^8.3.4", - "@types/webpack": "^5.28.0", + "@types/webpack": "^5.28.1", "@types/webpack-dev-server": "^4.7.2", "@types/webpack-env": "^1.18.0", "@types/webpack-node-externals": "^2.5.3", @@ -34542,7 +34544,7 @@ "typedoc-plugin-markdown": "^3.13.6", "typescript": "^4.9.5", "typescript-plugin-css-modules": "^3.4.0", - "webpack": "^5.75.0", + "webpack": "^5.77.0", "webpack-cli": "^4.9.2", "webpack-dev-server": "^4.11.1", "webpack-node-externals": "^3.0.0", @@ -34840,6 +34842,12 @@ "@sinonjs/commons": "^2.0.0" } }, + "packages/core/node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, "packages/core/node_modules/@types/jest": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.0.tgz", @@ -34856,6 +34864,17 @@ "integrity": "sha512-ZOzvDRWp8dCVBmgnkIqYCArgdFOO9YzocZp8Ra25N/RStKiWvMOXHMz+GjSeVNe5TstaTmTWPucGJkDw0XXJWA==", "dev": true }, + "packages/core/node_modules/@types/webpack": { + "version": "5.28.1", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-5.28.1.tgz", + "integrity": "sha512-qw1MqGZclCoBrpiSe/hokSgQM/su8Ocpl3L/YHE0L6moyaypg4+5F7Uzq7NgaPKPxUxUbQ4fLPLpDWdR27bCZw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "tapable": "^2.2.0", + "webpack": "^5" + } + }, "packages/core/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -35521,6 +35540,62 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "packages/core/node_modules/webpack": { + "version": "5.77.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.77.0.tgz", + "integrity": "sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "packages/core/node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, "packages/ensure-binaries": { "name": "@k8slens/ensure-binaries", "version": "6.5.0-alpha.1", @@ -35562,7 +35637,7 @@ }, "devDependencies": { "@types/node": "^16.18.6", - "@types/webpack": "^5.28.0", + "@types/webpack": "^5.28.1", "@types/webpack-env": "^1.18.0", "@types/webpack-node-externals": "2.5.3", "css-loader": "^6.7.2", @@ -35576,16 +35651,33 @@ "typedoc-plugin-markdown": "^3.13.6", "typescript": "^4.9.5", "typescript-plugin-css-modules": "^4.1.1", - "webpack": "^5.75.0", + "webpack": "^5.77.0", "webpack-cli": "^5.0.1" } }, + "packages/extension-api/node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, "packages/extension-api/node_modules/@types/node": { "version": "16.18.16", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.16.tgz", "integrity": "sha512-ZOzvDRWp8dCVBmgnkIqYCArgdFOO9YzocZp8Ra25N/RStKiWvMOXHMz+GjSeVNe5TstaTmTWPucGJkDw0XXJWA==", "dev": true }, + "packages/extension-api/node_modules/@types/webpack": { + "version": "5.28.1", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-5.28.1.tgz", + "integrity": "sha512-qw1MqGZclCoBrpiSe/hokSgQM/su8Ocpl3L/YHE0L6moyaypg4+5F7Uzq7NgaPKPxUxUbQ4fLPLpDWdR27bCZw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "tapable": "^2.2.0", + "webpack": "^5" + } + }, "packages/extension-api/node_modules/@webpack-cli/configtest": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.1.tgz", @@ -35750,6 +35842,53 @@ "typescript": ">=3.9.0" } }, + "packages/extension-api/node_modules/webpack": { + "version": "5.77.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.77.0.tgz", + "integrity": "sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, "packages/extension-api/node_modules/webpack-cli": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", @@ -35795,6 +35934,15 @@ } } }, + "packages/extension-api/node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, "packages/generate-tray-icons": { "name": "@k8slens/generate-tray-icons", "version": "6.5.0-alpha.1", @@ -37227,11 +37375,16 @@ "sass-loader": "^13.2.0", "style-loader": "^3.3.1", "ts-loader": "^9.4.1", - "webpack": "^5.76.0", + "webpack": "^5.77.0", "webpack-cli": "^4.10.0", "webpack-node-externals": "^3.0.0" } }, + "packages/infrastructure/webpack/node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==" + }, "packages/infrastructure/webpack/node_modules/sass-loader": { "version": "13.2.0", "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.0.tgz", @@ -37269,6 +37422,60 @@ } } }, + "packages/infrastructure/webpack/node_modules/webpack": { + "version": "5.77.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.77.0.tgz", + "integrity": "sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q==", + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "packages/infrastructure/webpack/node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "engines": { + "node": ">=10.13.0" + } + }, "packages/legacy-extension-example": { "name": "@k8slens/legacy-extension-example", "version": "1.0.0-alpha.1", @@ -37277,13 +37484,19 @@ "@k8slens/extensions": "^6.5.0-alpha.3", "@types/node": "^16.18.16", "typescript": "^4.9.5", - "webpack": "^5.76.1", + "webpack": "^5.77.0", "webpack-cli": "^5.0.1" }, "engines": { "lens": "6.5" } }, + "packages/legacy-extension-example/node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, "packages/legacy-extension-example/node_modules/@types/node": { "version": "16.18.16", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.16.tgz", @@ -37364,6 +37577,53 @@ "node": ">= 10.13.0" } }, + "packages/legacy-extension-example/node_modules/webpack": { + "version": "5.77.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.77.0.tgz", + "integrity": "sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, "packages/legacy-extension-example/node_modules/webpack-cli": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", @@ -37409,6 +37669,15 @@ } } }, + "packages/legacy-extension-example/node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, "packages/node-fetch": { "name": "@k8slens/node-fetch", "version": "6.5.0-alpha.1", @@ -37422,10 +37691,16 @@ "ts-loader": "^9.4.2", "ts-node": "^10.9.1", "typescript": "^4.9.5", - "webpack": "^5.75.0", + "webpack": "^5.77.0", "webpack-cli": "^5.0.1" } }, + "packages/node-fetch/node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, "packages/node-fetch/node_modules/@webpack-cli/configtest": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.1.tgz", @@ -37500,6 +37775,53 @@ "node": ">= 10.13.0" } }, + "packages/node-fetch/node_modules/webpack": { + "version": "5.77.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.77.0.tgz", + "integrity": "sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, "packages/node-fetch/node_modules/webpack-cli": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", @@ -37545,6 +37867,15 @@ } } }, + "packages/node-fetch/node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, "packages/open-lens": { "version": "6.5.0-alpha.3", "hasInstallScript": true, @@ -37596,7 +37927,7 @@ "@types/tcp-port-used": "^1.0.1", "@types/url-parse": "^1.4.8", "@types/uuid": "^8.3.4", - "@types/webpack": "^5.28.0", + "@types/webpack": "^5.28.1", "@types/webpack-dev-server": "^4.7.2", "@types/webpack-env": "^1.18.0", "@types/webpack-node-externals": "2.5.3", @@ -37634,7 +37965,7 @@ "typed-emitter": "^1.4.0", "typescript": "^4.9.5", "typescript-plugin-css-modules": "^4.1.1", - "webpack": "^5.75.0", + "webpack": "^5.77.0", "webpack-cli": "^4.9.2", "webpack-dev-server": "^4.11.1", "webpack-node-externals": "^3.0.0", @@ -37901,12 +38232,29 @@ "@sinonjs/commons": "^2.0.0" } }, + "packages/open-lens/node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, "packages/open-lens/node_modules/@types/node": { "version": "16.18.16", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.16.tgz", "integrity": "sha512-ZOzvDRWp8dCVBmgnkIqYCArgdFOO9YzocZp8Ra25N/RStKiWvMOXHMz+GjSeVNe5TstaTmTWPucGJkDw0XXJWA==", "dev": true }, + "packages/open-lens/node_modules/@types/webpack": { + "version": "5.28.1", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-5.28.1.tgz", + "integrity": "sha512-qw1MqGZclCoBrpiSe/hokSgQM/su8Ocpl3L/YHE0L6moyaypg4+5F7Uzq7NgaPKPxUxUbQ4fLPLpDWdR27bCZw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "tapable": "^2.2.0", + "webpack": "^5" + } + }, "packages/open-lens/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -38653,6 +39001,62 @@ "typescript": ">=3.9.0" } }, + "packages/open-lens/node_modules/webpack": { + "version": "5.77.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.77.0.tgz", + "integrity": "sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "packages/open-lens/node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, "packages/release-tool": { "name": "@k8slens/release-tool", "version": "6.5.0-alpha.2", diff --git a/packages/core/package.json b/packages/core/package.json index b608493c38..b619871e5c 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -239,7 +239,7 @@ "@types/triple-beam": "^1.3.2", "@types/url-parse": "^1.4.8", "@types/uuid": "^8.3.4", - "@types/webpack": "^5.28.0", + "@types/webpack": "^5.28.1", "@types/webpack-dev-server": "^4.7.2", "@types/webpack-env": "^1.18.0", "@types/webpack-node-externals": "^2.5.3", @@ -312,7 +312,7 @@ "typedoc-plugin-markdown": "^3.13.6", "typescript": "^4.9.5", "typescript-plugin-css-modules": "^3.4.0", - "webpack": "^5.75.0", + "webpack": "^5.77.0", "webpack-cli": "^4.9.2", "webpack-dev-server": "^4.11.1", "webpack-node-externals": "^3.0.0", diff --git a/packages/extension-api/package.json b/packages/extension-api/package.json index a1b17c96e9..db2c221516 100644 --- a/packages/extension-api/package.json +++ b/packages/extension-api/package.json @@ -30,7 +30,7 @@ }, "devDependencies": { "@types/node": "^16.18.6", - "@types/webpack": "^5.28.0", + "@types/webpack": "^5.28.1", "@types/webpack-env": "^1.18.0", "@types/webpack-node-externals": "2.5.3", "css-loader": "^6.7.2", @@ -44,7 +44,7 @@ "typedoc-plugin-markdown": "^3.13.6", "typescript": "^4.9.5", "typescript-plugin-css-modules": "^4.1.1", - "webpack": "^5.75.0", + "webpack": "^5.77.0", "webpack-cli": "^5.0.1" } } diff --git a/packages/infrastructure/webpack/package.json b/packages/infrastructure/webpack/package.json index 3faa94494b..6b59746e9e 100644 --- a/packages/infrastructure/webpack/package.json +++ b/packages/infrastructure/webpack/package.json @@ -30,7 +30,7 @@ "sass-loader": "^13.2.0", "style-loader": "^3.3.1", "ts-loader": "^9.4.1", - "webpack": "^5.76.0", + "webpack": "^5.77.0", "webpack-cli": "^4.10.0", "webpack-node-externals": "^3.0.0" } diff --git a/packages/legacy-extension-example/package.json b/packages/legacy-extension-example/package.json index e175eeb1f1..e2fdde25e2 100644 --- a/packages/legacy-extension-example/package.json +++ b/packages/legacy-extension-example/package.json @@ -40,7 +40,7 @@ "@k8slens/extensions": "^6.5.0-alpha.3", "@types/node": "^16.18.16", "typescript": "^4.9.5", - "webpack": "^5.76.1", + "webpack": "^5.77.0", "webpack-cli": "^5.0.1" } } diff --git a/packages/node-fetch/package.json b/packages/node-fetch/package.json index df4f9f579a..40c542d335 100644 --- a/packages/node-fetch/package.json +++ b/packages/node-fetch/package.json @@ -30,7 +30,7 @@ "ts-loader": "^9.4.2", "ts-node": "^10.9.1", "typescript": "^4.9.5", - "webpack": "^5.75.0", + "webpack": "^5.77.0", "webpack-cli": "^5.0.1" } } diff --git a/packages/open-lens/package.json b/packages/open-lens/package.json index fb4fbc6616..630e51223c 100644 --- a/packages/open-lens/package.json +++ b/packages/open-lens/package.json @@ -241,7 +241,7 @@ "@types/tcp-port-used": "^1.0.1", "@types/url-parse": "^1.4.8", "@types/uuid": "^8.3.4", - "@types/webpack": "^5.28.0", + "@types/webpack": "^5.28.1", "@types/webpack-dev-server": "^4.7.2", "@types/webpack-env": "^1.18.0", "@types/webpack-node-externals": "2.5.3", @@ -279,7 +279,7 @@ "typed-emitter": "^1.4.0", "typescript": "^4.9.5", "typescript-plugin-css-modules": "^4.1.1", - "webpack": "^5.75.0", + "webpack": "^5.77.0", "webpack-cli": "^4.9.2", "webpack-dev-server": "^4.11.1", "webpack-node-externals": "^3.0.0", From b5e564271e866864426135c3c243192baed54813 Mon Sep 17 00:00:00 2001 From: Janne Savolainen Date: Fri, 31 Mar 2023 11:57:20 +0300 Subject: [PATCH 15/35] Extract React Application as a Feature (#7441) * Fix webpack config for react Signed-off-by: Janne Savolainen * Introduce package for discovering html elements in unit tests Signed-off-by: Janne Savolainen * Switch to using discovery of html elements from package Signed-off-by: Janne Savolainen * Introduce competition for starting react application inside the Feature Signed-off-by: Janne Savolainen * Move stuff in application start to earlier timeslot having no real need to be done so late Signed-off-by: Janne Savolainen * Switch to using react application root feature being more friendly to extending Signed-off-by: Janne Savolainen * Switch to using more familiar pattern of higher order components for wrapping react application Co-authored-by: Mikko Aspiala Signed-off-by: Janne Savolainen * Adapt to more familiar pattern for higher order components Signed-off-by: Janne Savolainen * Rename feature for clarity Signed-off-by: Janne Savolainen --------- Signed-off-by: Janne Savolainen --- package-lock.json | 235 ++++++++++++++++++ packages/core/package.json | 2 + .../extension-adding-preference-tabs.test.tsx | 4 +- .../hiding-of-empty-branches.test.tsx | 4 +- ...gation-to-application-preferences.test.tsx | 4 +- .../navigation-to-editor-preferences.test.ts | 4 +- ...to-extension-specific-preferences.test.tsx | 4 +- ...vigation-to-kubernetes-preferences.test.ts | 4 +- .../navigation-to-proxy-preferences.test.ts | 4 +- ...vigation-to-telemetry-preferences.test.tsx | 4 +- ...navigation-to-terminal-preferences.test.ts | 4 +- .../navigation-using-application-menu.test.ts | 4 +- .../preferences/navigation-using-tray.test.ts | 4 +- .../urls-of-legacy-extensions.test.tsx | 4 +- .../core/src/renderer/bootstrap.injectable.ts | 6 +- packages/core/src/renderer/bootstrap.tsx | 21 +- .../test-utils/discovery-of-html-elements.ts | 115 --------- .../test-utils/get-application-builder.tsx | 2 +- .../frame-application-root.injectable.ts | 31 +++ ...uting-react-application-hoc.injectable.tsx | 31 +++ ...vider-react-application-hoc.injectable.tsx | 22 ++ packages/core/src/renderer/mui-base-theme.tsx | 4 +- .../start-frame/start-frame.injectable.ts | 6 +- .../webpack/src/react-config.js | 2 +- packages/open-lens/package.json | 1 + packages/open-lens/src/renderer/index.ts | 9 +- .../react-application/.eslintrc.json | 6 + .../react-application/.prettierrc | 1 + .../react-application/README.md | 19 ++ .../react-application/index.ts | 10 + .../react-application/jest.config.js | 1 + .../react-application/package.json | 52 ++++ .../react-application.test.tsx.snap | 41 +++ .../react-application/src/feature.ts | 17 ++ .../src/react-application.test.tsx | 137 ++++++++++ ...ct-application-children-injection-token.ts | 13 + .../react-application-content.tsx | 29 +++ ...-higher-order-component-injection-token.ts | 11 + .../react-application/react-application.tsx | 37 +++ ...n-when-application-is-ready.injectable.tsx | 21 ++ .../render-application/render.injectable.tsx | 22 ++ .../react-application/tsconfig.json | 4 + .../react-application/webpack.config.js | 1 + .../.eslintrc.json | 6 + .../.prettierrc | 1 + .../react-testing-library-discovery/index.ts | 13 + .../package.json | 33 +++ .../src/discovery-of-html-elements.ts | 125 ++++++++++ .../tsconfig.json | 4 + .../webpack.config.js | 1 + 50 files changed, 968 insertions(+), 172 deletions(-) delete mode 100644 packages/core/src/renderer/components/test-utils/discovery-of-html-elements.ts create mode 100644 packages/core/src/renderer/frames/frame-application-root.injectable.ts create mode 100644 packages/core/src/renderer/frames/routing-react-application-hoc.injectable.tsx create mode 100644 packages/core/src/renderer/frames/theme-provider-react-application-hoc.injectable.tsx create mode 100644 packages/technical-features/react-application/.eslintrc.json create mode 100644 packages/technical-features/react-application/.prettierrc create mode 100644 packages/technical-features/react-application/README.md create mode 100644 packages/technical-features/react-application/index.ts create mode 100644 packages/technical-features/react-application/jest.config.js create mode 100644 packages/technical-features/react-application/package.json create mode 100644 packages/technical-features/react-application/src/__snapshots__/react-application.test.tsx.snap create mode 100644 packages/technical-features/react-application/src/feature.ts create mode 100644 packages/technical-features/react-application/src/react-application.test.tsx create mode 100644 packages/technical-features/react-application/src/react-application/react-application-children-injection-token.ts create mode 100644 packages/technical-features/react-application/src/react-application/react-application-content.tsx create mode 100644 packages/technical-features/react-application/src/react-application/react-application-higher-order-component-injection-token.ts create mode 100644 packages/technical-features/react-application/src/react-application/react-application.tsx create mode 100644 packages/technical-features/react-application/src/render-application/render-application-when-application-is-ready.injectable.tsx create mode 100644 packages/technical-features/react-application/src/render-application/render.injectable.tsx create mode 100644 packages/technical-features/react-application/tsconfig.json create mode 100644 packages/technical-features/react-application/webpack.config.js create mode 100644 packages/utility-features/react-testing-library-discovery/.eslintrc.json create mode 100644 packages/utility-features/react-testing-library-discovery/.prettierrc create mode 100644 packages/utility-features/react-testing-library-discovery/index.ts create mode 100644 packages/utility-features/react-testing-library-discovery/package.json create mode 100644 packages/utility-features/react-testing-library-discovery/src/discovery-of-html-elements.ts create mode 100644 packages/utility-features/react-testing-library-discovery/tsconfig.json create mode 100644 packages/utility-features/react-testing-library-discovery/webpack.config.js diff --git a/package-lock.json b/package-lock.json index b0230bf37f..60e1c5dc69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4634,6 +4634,14 @@ "resolved": "packages/node-fetch", "link": true }, + "node_modules/@k8slens/react-application": { + "resolved": "packages/technical-features/react-application", + "link": true + }, + "node_modules/@k8slens/react-testing-library-discovery": { + "resolved": "packages/utility-features/react-testing-library-discovery", + "link": true + }, "node_modules/@k8slens/release-tool": { "resolved": "packages/release-tool", "link": true @@ -34325,6 +34333,57 @@ "integrity": "sha512-ZOzvDRWp8dCVBmgnkIqYCArgdFOO9YzocZp8Ra25N/RStKiWvMOXHMz+GjSeVNe5TstaTmTWPucGJkDw0XXJWA==", "dev": true }, + "packages/business-features/dock": { + "name": "@k8slens/dock", + "version": "1.0.0-alpha.0", + "extraneous": true, + "license": "MIT", + "devDependencies": { + "@async-fn/jest": "^1.6.4", + "@k8slens/eslint-config": "6.5.0-alpha.1", + "@k8slens/react-testing-library-discovery": "^1.0.0-alpha.0" + }, + "peerDependencies": { + "@k8slens/feature-core": "^6.5.0-alpha.0", + "@ogre-tools/fp": "^15.1.2", + "@ogre-tools/injectable": "^15.1.2", + "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", + "lodash": "^4.17.21" + } + }, + "packages/business-features/dock/agnostic": { + "version": "1.0.0-alpha.0", + "extraneous": true, + "license": "MIT", + "devDependencies": { + "@async-fn/jest": "^1.6.4", + "@k8slens/eslint-config": "6.5.0-alpha.1" + }, + "peerDependencies": { + "@k8slens/feature-core": "^6.5.0-alpha.0", + "@ogre-tools/injectable": "^15.1.2", + "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2" + } + }, + "packages/business-features/keyboard-shortcuts": { + "name": "@k8slens/keyboard-shortcuts", + "version": "1.0.0-alpha.0", + "extraneous": true, + "license": "MIT", + "devDependencies": { + "@async-fn/jest": "^1.6.4", + "@k8slens/eslint-config": "6.5.0-alpha.1", + "@k8slens/react-testing-library-discovery": "^1.0.0-alpha.0" + }, + "peerDependencies": { + "@k8slens/feature-core": "^6.5.0-alpha.0", + "@k8slens/react-application": "^1.0.0-alpha.0", + "@ogre-tools/fp": "^15.1.2", + "@ogre-tools/injectable": "^15.1.2", + "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", + "lodash": "^4.17.21" + } + }, "packages/cluster-settings": { "name": "@k8slens/cluster-settings", "version": "6.5.0-alpha.1", @@ -34354,6 +34413,7 @@ "@hapi/subtext": "^7.1.0", "@k8slens/cluster-settings": "^6.5.0-alpha.1", "@k8slens/node-fetch": "^6.5.0-alpha.1", + "@k8slens/react-application": "^1.0.0-alpha.0", "@kubernetes/client-node": "^0.18.1", "@material-ui/styles": "^4.11.5", "@ogre-tools/fp": "^15.1.2", @@ -34422,6 +34482,7 @@ "devDependencies": { "@async-fn/jest": "1.6.4", "@k8slens/messaging-fake-bridge": "^1.0.0-alpha.1", + "@k8slens/react-testing-library-discovery": "^1.0.0-alpha.0", "@material-ui/core": "^4.12.3", "@material-ui/icons": "^4.11.2", "@material-ui/lab": "^4.0.0-alpha.60", @@ -37892,6 +37953,7 @@ "@k8slens/messaging": "^1.0.0-alpha.1", "@k8slens/messaging-for-main": "^1.0.0-alpha.1", "@k8slens/messaging-for-renderer": "^1.0.0-alpha.1", + "@k8slens/react-application": "^1.0.0-alpha.0", "@k8slens/run-many": "^1.0.0-alpha.1", "@k8slens/startable-stoppable": "^1.0.0-alpha.1", "@k8slens/test-utils": "^1.0.0-alpha.1", @@ -39543,6 +39605,179 @@ "lodash": "^4.17.21" } }, + "packages/technical-features/react-application": { + "name": "@k8slens/react-application", + "version": "1.0.0-alpha.0", + "license": "MIT", + "devDependencies": { + "@async-fn/jest": "^1.6.4", + "@k8slens/eslint-config": "6.5.0-alpha.1", + "@k8slens/react-testing-library-discovery": "*", + "@testing-library/react": "^12.1.5" + }, + "peerDependencies": { + "@k8slens/application": "^6.5.0-alpha.2", + "@k8slens/feature-core": "^6.5.0-alpha.0", + "@ogre-tools/fp": "^15.1.2", + "@ogre-tools/injectable": "^15.1.2", + "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", + "@ogre-tools/injectable-extension-for-mobx": "^15.1.2", + "@ogre-tools/injectable-react": "^15.1.2", + "lodash": "^4.17.15", + "mobx": "^6.8.0", + "react": "^17.0.2", + "react-dom": "^17.0.2" + } + }, + "packages/technical-features/react-application-root": { + "name": "@k8slens/react-application-root", + "version": "1.0.0-alpha.0", + "extraneous": true, + "license": "MIT", + "devDependencies": { + "@async-fn/jest": "^1.6.4", + "@k8slens/eslint-config": "6.5.0-alpha.1", + "@k8slens/react-testing-library-discovery": "*", + "@testing-library/react": "^12.1.5" + }, + "peerDependencies": { + "@k8slens/application": "^6.5.0-alpha.2", + "@k8slens/feature-core": "^6.5.0-alpha.0", + "@ogre-tools/fp": "^15.1.2", + "@ogre-tools/injectable": "^15.1.2", + "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", + "@ogre-tools/injectable-extension-for-mobx": "^15.1.2", + "@ogre-tools/injectable-react": "^15.1.2", + "lodash": "^4.17.15", + "mobx": "^6.8.0", + "react": "^17.0.2", + "react-dom": "^17.0.2" + } + }, + "packages/utility-features/react-testing-library-discovery": { + "name": "@k8slens/react-testing-library-discovery", + "version": "1.0.0-alpha.0", + "license": "MIT", + "dependencies": { + "@testing-library/dom": "^8.19.0", + "@testing-library/jest-dom": "^5.16.5", + "@testing-library/react": "^13.4.0" + } + }, + "packages/utility-features/react-testing-library-discovery/node_modules/@testing-library/dom": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.0.tgz", + "integrity": "sha512-d9ULIT+a4EXLX3UU8FBjauG9NnsZHkHztXoIcTsOKoOw030fyjheN9svkTULjJxtYag9DZz5Jz5qkWZDPxTFwA==", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "^5.0.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.4.4", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=12" + } + }, + "packages/utility-features/react-testing-library-discovery/node_modules/@testing-library/react": { + "version": "13.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-13.4.0.tgz", + "integrity": "sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^8.5.0", + "@types/react-dom": "^18.0.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "packages/utility-features/react-testing-library-discovery/node_modules/@types/aria-query": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==" + }, + "packages/utility-features/react-testing-library-discovery/node_modules/@types/react-dom": { + "version": "18.0.11", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", + "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", + "dependencies": { + "@types/react": "*" + } + }, + "packages/utility-features/react-testing-library-discovery/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "packages/utility-features/react-testing-library-discovery/node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "packages/utility-features/react-testing-library-discovery/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "packages/utility-features/react-testing-library-discovery/node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "packages/utility-features/react-testing-library-discovery/node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "packages/utility-features/react-testing-library-discovery/node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, "packages/utility-features/run-many": { "name": "@k8slens/run-many", "version": "1.0.0-alpha.1", diff --git a/packages/core/package.json b/packages/core/package.json index b619871e5c..8c7d22ee2c 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -122,6 +122,7 @@ "@hapi/subtext": "^7.1.0", "@k8slens/cluster-settings": "^6.5.0-alpha.1", "@k8slens/node-fetch": "^6.5.0-alpha.1", + "@k8slens/react-application": "^1.0.0-alpha.0", "@kubernetes/client-node": "^0.18.1", "@material-ui/styles": "^4.11.5", "@ogre-tools/fp": "^15.1.2", @@ -190,6 +191,7 @@ "devDependencies": { "@async-fn/jest": "1.6.4", "@k8slens/messaging-fake-bridge": "^1.0.0-alpha.1", + "@k8slens/react-testing-library-discovery": "^1.0.0-alpha.0", "@material-ui/core": "^4.12.3", "@material-ui/icons": "^4.11.2", "@material-ui/lab": "^4.0.0-alpha.60", diff --git a/packages/core/src/features/preferences/extension-adding-preference-tabs.test.tsx b/packages/core/src/features/preferences/extension-adding-preference-tabs.test.tsx index a68f39f547..4631a6415d 100644 --- a/packages/core/src/features/preferences/extension-adding-preference-tabs.test.tsx +++ b/packages/core/src/features/preferences/extension-adding-preference-tabs.test.tsx @@ -7,8 +7,8 @@ import type { IObservableValue } from "mobx"; import { runInAction, computed, observable } from "mobx"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; -import type { Discover } from "../../renderer/components/test-utils/discovery-of-html-elements"; -import { discoverFor } from "../../renderer/components/test-utils/discovery-of-html-elements"; +import type { Discover } from "@k8slens/react-testing-library-discovery"; +import { discoverFor } from "@k8slens/react-testing-library-discovery"; import React from "react"; describe("preferences: extension adding preference tabs", () => { diff --git a/packages/core/src/features/preferences/hiding-of-empty-branches.test.tsx b/packages/core/src/features/preferences/hiding-of-empty-branches.test.tsx index 0bc2d67d24..9e4ef01a5c 100644 --- a/packages/core/src/features/preferences/hiding-of-empty-branches.test.tsx +++ b/packages/core/src/features/preferences/hiding-of-empty-branches.test.tsx @@ -10,8 +10,8 @@ import { runInAction } from "mobx"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { preferenceItemInjectionToken } from "./renderer/preference-items/preference-item-injection-token"; -import type { Discover } from "../../renderer/components/test-utils/discovery-of-html-elements"; -import { discoverFor } from "../../renderer/components/test-utils/discovery-of-html-elements"; +import type { Discover } from "@k8slens/react-testing-library-discovery"; +import { discoverFor } from "@k8slens/react-testing-library-discovery"; describe("preferences - hiding-of-empty-branches, given in preferences page", () => { let builder: ApplicationBuilder; diff --git a/packages/core/src/features/preferences/navigation-to-application-preferences.test.tsx b/packages/core/src/features/preferences/navigation-to-application-preferences.test.tsx index bcb4db587d..47673b4637 100644 --- a/packages/core/src/features/preferences/navigation-to-application-preferences.test.tsx +++ b/packages/core/src/features/preferences/navigation-to-application-preferences.test.tsx @@ -7,8 +7,8 @@ import type { RenderResult } from "@testing-library/react"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import navigateToProxyPreferencesInjectable from "./common/navigate-to-proxy-preferences.injectable"; -import type { Discover } from "../../renderer/components/test-utils/discovery-of-html-elements"; -import { discoverFor } from "../../renderer/components/test-utils/discovery-of-html-elements"; +import type { Discover } from "@k8slens/react-testing-library-discovery"; +import { discoverFor } from "@k8slens/react-testing-library-discovery"; import type { FakeExtensionOptions } from "../../renderer/components/test-utils/get-extension-fake"; describe("preferences - navigation to application preferences", () => { diff --git a/packages/core/src/features/preferences/navigation-to-editor-preferences.test.ts b/packages/core/src/features/preferences/navigation-to-editor-preferences.test.ts index 018a27210a..51f93afa3f 100644 --- a/packages/core/src/features/preferences/navigation-to-editor-preferences.test.ts +++ b/packages/core/src/features/preferences/navigation-to-editor-preferences.test.ts @@ -5,8 +5,8 @@ import type { RenderResult } from "@testing-library/react"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; -import type { Discover } from "../../renderer/components/test-utils/discovery-of-html-elements"; -import { discoverFor } from "../../renderer/components/test-utils/discovery-of-html-elements"; +import type { Discover } from "@k8slens/react-testing-library-discovery"; +import { discoverFor } from "@k8slens/react-testing-library-discovery"; describe("preferences - navigation to editor preferences", () => { let applicationBuilder: ApplicationBuilder; diff --git a/packages/core/src/features/preferences/navigation-to-extension-specific-preferences.test.tsx b/packages/core/src/features/preferences/navigation-to-extension-specific-preferences.test.tsx index 84c8f4e395..e7a04a4b04 100644 --- a/packages/core/src/features/preferences/navigation-to-extension-specific-preferences.test.tsx +++ b/packages/core/src/features/preferences/navigation-to-extension-specific-preferences.test.tsx @@ -8,8 +8,8 @@ import { getApplicationBuilder } from "../../renderer/components/test-utils/get- import React from "react"; import "@testing-library/jest-dom/extend-expect"; import type { FakeExtensionOptions } from "../../renderer/components/test-utils/get-extension-fake"; -import type { Discover } from "../../renderer/components/test-utils/discovery-of-html-elements"; -import { discoverFor } from "../../renderer/components/test-utils/discovery-of-html-elements"; +import type { Discover } from "@k8slens/react-testing-library-discovery"; +import { discoverFor } from "@k8slens/react-testing-library-discovery"; import logErrorInjectable from "../../common/log-error.injectable"; describe("preferences - navigation to extension specific preferences", () => { diff --git a/packages/core/src/features/preferences/navigation-to-kubernetes-preferences.test.ts b/packages/core/src/features/preferences/navigation-to-kubernetes-preferences.test.ts index 15c853d3c3..06c1fda87e 100644 --- a/packages/core/src/features/preferences/navigation-to-kubernetes-preferences.test.ts +++ b/packages/core/src/features/preferences/navigation-to-kubernetes-preferences.test.ts @@ -7,8 +7,8 @@ import type { ApplicationBuilder } from "../../renderer/components/test-utils/ge import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import requestPublicHelmRepositoriesInjectable from "../helm-charts/child-features/preferences/renderer/adding-of-public-helm-repository/public-helm-repositories/request-public-helm-repositories.injectable"; import getActiveHelmRepositoriesInjectable from "../../main/helm/repositories/get-active-helm-repositories/get-active-helm-repositories.injectable"; -import type { Discover } from "../../renderer/components/test-utils/discovery-of-html-elements"; -import { discoverFor } from "../../renderer/components/test-utils/discovery-of-html-elements"; +import type { Discover } from "@k8slens/react-testing-library-discovery"; +import { discoverFor } from "@k8slens/react-testing-library-discovery"; describe("preferences - navigation to kubernetes preferences", () => { let builder: ApplicationBuilder; diff --git a/packages/core/src/features/preferences/navigation-to-proxy-preferences.test.ts b/packages/core/src/features/preferences/navigation-to-proxy-preferences.test.ts index 2372b78187..fa22e15d17 100644 --- a/packages/core/src/features/preferences/navigation-to-proxy-preferences.test.ts +++ b/packages/core/src/features/preferences/navigation-to-proxy-preferences.test.ts @@ -5,8 +5,8 @@ import type { RenderResult } from "@testing-library/react"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; -import type { Discover } from "../../renderer/components/test-utils/discovery-of-html-elements"; -import { discoverFor } from "../../renderer/components/test-utils/discovery-of-html-elements"; +import type { Discover } from "@k8slens/react-testing-library-discovery"; +import { discoverFor } from "@k8slens/react-testing-library-discovery"; describe("preferences - navigation to proxy preferences", () => { let applicationBuilder: ApplicationBuilder; diff --git a/packages/core/src/features/preferences/navigation-to-telemetry-preferences.test.tsx b/packages/core/src/features/preferences/navigation-to-telemetry-preferences.test.tsx index 58d0121a9e..ce8158cc4c 100644 --- a/packages/core/src/features/preferences/navigation-to-telemetry-preferences.test.tsx +++ b/packages/core/src/features/preferences/navigation-to-telemetry-preferences.test.tsx @@ -9,8 +9,8 @@ import { getApplicationBuilder } from "../../renderer/components/test-utils/get- import navigateToTelemetryPreferencesInjectable from "./common/navigate-to-telemetry-preferences.injectable"; import sentryDataSourceNameInjectable from "../../common/vars/sentry-dsn-url.injectable"; import type { FakeExtensionOptions } from "../../renderer/components/test-utils/get-extension-fake"; -import type { Discover } from "../../renderer/components/test-utils/discovery-of-html-elements"; -import { discoverFor } from "../../renderer/components/test-utils/discovery-of-html-elements"; +import type { Discover } from "@k8slens/react-testing-library-discovery"; +import { discoverFor } from "@k8slens/react-testing-library-discovery"; describe("preferences - navigation to telemetry preferences", () => { let builder: ApplicationBuilder; diff --git a/packages/core/src/features/preferences/navigation-to-terminal-preferences.test.ts b/packages/core/src/features/preferences/navigation-to-terminal-preferences.test.ts index 3023852481..1542659d17 100644 --- a/packages/core/src/features/preferences/navigation-to-terminal-preferences.test.ts +++ b/packages/core/src/features/preferences/navigation-to-terminal-preferences.test.ts @@ -5,8 +5,8 @@ import type { RenderResult } from "@testing-library/react"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; -import type { Discover } from "../../renderer/components/test-utils/discovery-of-html-elements"; -import { discoverFor } from "../../renderer/components/test-utils/discovery-of-html-elements"; +import type { Discover } from "@k8slens/react-testing-library-discovery"; +import { discoverFor } from "@k8slens/react-testing-library-discovery"; describe("preferences - navigation to terminal preferences", () => { let applicationBuilder: ApplicationBuilder; diff --git a/packages/core/src/features/preferences/navigation-using-application-menu.test.ts b/packages/core/src/features/preferences/navigation-using-application-menu.test.ts index ae143fe468..020bc25259 100644 --- a/packages/core/src/features/preferences/navigation-using-application-menu.test.ts +++ b/packages/core/src/features/preferences/navigation-using-application-menu.test.ts @@ -6,8 +6,8 @@ import type { RenderResult } from "@testing-library/react"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; -import type { Discover } from "../../renderer/components/test-utils/discovery-of-html-elements"; -import { discoverFor } from "../../renderer/components/test-utils/discovery-of-html-elements"; +import type { Discover } from "@k8slens/react-testing-library-discovery"; +import { discoverFor } from "@k8slens/react-testing-library-discovery"; describe("preferences - navigation using application menu", () => { let applicationBuilder: ApplicationBuilder; diff --git a/packages/core/src/features/preferences/navigation-using-tray.test.ts b/packages/core/src/features/preferences/navigation-using-tray.test.ts index e48dba482e..63d2bd5290 100644 --- a/packages/core/src/features/preferences/navigation-using-tray.test.ts +++ b/packages/core/src/features/preferences/navigation-using-tray.test.ts @@ -5,8 +5,8 @@ import type { RenderResult } from "@testing-library/react"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; -import type { Discover } from "../../renderer/components/test-utils/discovery-of-html-elements"; -import { discoverFor } from "../../renderer/components/test-utils/discovery-of-html-elements"; +import type { Discover } from "@k8slens/react-testing-library-discovery"; +import { discoverFor } from "@k8slens/react-testing-library-discovery"; describe("show-about-using-tray", () => { let applicationBuilder: ApplicationBuilder; diff --git a/packages/core/src/features/preferences/urls-of-legacy-extensions.test.tsx b/packages/core/src/features/preferences/urls-of-legacy-extensions.test.tsx index 1eba04c683..4b04e5500f 100644 --- a/packages/core/src/features/preferences/urls-of-legacy-extensions.test.tsx +++ b/packages/core/src/features/preferences/urls-of-legacy-extensions.test.tsx @@ -5,8 +5,8 @@ import type { RenderResult } from "@testing-library/react"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; -import type { Discover } from "../../renderer/components/test-utils/discovery-of-html-elements"; -import { discoverFor } from "../../renderer/components/test-utils/discovery-of-html-elements"; +import type { Discover } from "@k8slens/react-testing-library-discovery"; +import { discoverFor } from "@k8slens/react-testing-library-discovery"; import React from "react"; import type { Navigate } from "../../renderer/navigation/navigate.injectable"; import navigateInjectable from "../../renderer/navigation/navigate.injectable"; diff --git a/packages/core/src/renderer/bootstrap.injectable.ts b/packages/core/src/renderer/bootstrap.injectable.ts index 7cc172e3f1..24c01deecc 100644 --- a/packages/core/src/renderer/bootstrap.injectable.ts +++ b/packages/core/src/renderer/bootstrap.injectable.ts @@ -3,9 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { - afterApplicationIsLoadedInjectionToken, -} from "@k8slens/application"; +import { onLoadOfApplicationInjectionToken } from "@k8slens/application"; import { bootstrap } from "./bootstrap"; import startFrameInjectable from "./start-frame/start-frame.injectable"; @@ -22,7 +20,7 @@ const bootstrapInjectable = getInjectable({ causesSideEffects: true, - injectionToken: afterApplicationIsLoadedInjectionToken, + injectionToken: onLoadOfApplicationInjectionToken, }); export default bootstrapInjectable; diff --git a/packages/core/src/renderer/bootstrap.tsx b/packages/core/src/renderer/bootstrap.tsx index a811f07d5c..fcd2dc7415 100644 --- a/packages/core/src/renderer/bootstrap.tsx +++ b/packages/core/src/renderer/bootstrap.tsx @@ -5,10 +5,7 @@ import "./components/app.scss"; -import React from "react"; -import { render, unmountComponentAtNode } from "react-dom"; -import { DefaultProps } from "./mui-base-theme"; -import { DiContextProvider } from "@ogre-tools/injectable-react"; +import { unmountComponentAtNode } from "react-dom"; import type { DiContainerForInjection, } from "@ogre-tools/injectable"; @@ -17,8 +14,6 @@ import extensionDiscoveryInjectable from "../extensions/extension-discovery/exte import extensionInstallationStateStoreInjectable from "../extensions/extension-installation-state-store/extension-installation-state-store.injectable"; import initRootFrameInjectable from "./frames/root-frame/init-root-frame.injectable"; import initClusterFrameInjectable from "./frames/cluster-frame/init-cluster-frame/init-cluster-frame.injectable"; -import { Router } from "react-router"; -import historyInjectable from "./navigation/history.injectable"; import assert from "assert"; export async function bootstrap(di: DiContainerForInjection) { @@ -30,16 +25,13 @@ export async function bootstrap(di: DiContainerForInjection) { await di.inject(extensionDiscoveryInjectable).init(); di.inject(extensionInstallationStateStoreInjectable).bindIpcListeners(); - let App; let initializeApp; // TODO: Introduce proper architectural boundaries between root and cluster iframes if (process.isMainFrame) { initializeApp = di.inject(initRootFrameInjectable); - App = (await import("./frames/root-frame/root-frame")).RootFrame; } else { initializeApp = di.inject(initClusterFrameInjectable); - App = (await import("./frames/cluster-frame/cluster-frame")).ClusterFrame; } try { @@ -50,15 +42,4 @@ export async function bootstrap(di: DiContainerForInjection) { isTopFrameView: process.isMainFrame, }); } - - const history = di.inject(historyInjectable); - - render( - - - {DefaultProps(App)} - - , - rootElem, - ); } diff --git a/packages/core/src/renderer/components/test-utils/discovery-of-html-elements.ts b/packages/core/src/renderer/components/test-utils/discovery-of-html-elements.ts deleted file mode 100644 index 472199fc60..0000000000 --- a/packages/core/src/renderer/components/test-utils/discovery-of-html-elements.ts +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import type { RenderResult } from "@testing-library/react"; - -type DiscoverySourceTypes = RenderResult | Element; - -export type QuerySingleElement = ( - attributeName: string, - attributeValue?: string -) => { discovered: Element | null } & Discover; - -export type GetSingleElement = ( - attributeName: string, - attributeValue?: string -) => { discovered: Element } & Discover; - -export type QueryAllElements = (attributeName: string) => { - discovered: Element[]; - attributeValues: (string | null)[]; -}; - -export interface Discover { - querySingleElement: QuerySingleElement; - queryAllElements: QueryAllElements; - getSingleElement: GetSingleElement; -} - -export const discoverFor = (getSource: () => DiscoverySourceTypes): Discover => ({ - querySingleElement: querySingleElement(getSource), - queryAllElements: queryAllElements(getSource), - getSingleElement: getSingleElement(getSource), -}); - -export const querySingleElement = - (getSource: () => DiscoverySourceTypes): QuerySingleElement => - (attributeName, attributeValue) => { - const source = getSource(); - - const dataAttribute = `data-${attributeName}-test`; - - const selector = attributeValue - ? `[${dataAttribute}="${attributeValue}"]` - : `[${dataAttribute}]`; - - const discovered = getBaseElement(source).querySelector(selector); - - const nestedDiscover = discoverFor(() => { - if (!discovered) { - throw new Error("Tried to do nested discover using source that does not exist"); - } - - return discovered; - }); - - return { - discovered, - - ...nestedDiscover, - }; - }; - -export const queryAllElements = - (getSource: () => DiscoverySourceTypes): QueryAllElements => - (attributeName) => { - const source = getSource(); - - const dataAttribute = `data-${attributeName}-test`; - - const results = [ - ...getBaseElement(source).querySelectorAll(`[${dataAttribute}]`), - ]; - - return { - discovered: results, - - attributeValues: results.map((result) => - result.getAttribute(dataAttribute), - ), - }; - }; - -export const getSingleElement = - (getSource: () => DiscoverySourceTypes): GetSingleElement => - (attributeName, attributeValue) => { - const dataAttribute = `data-${attributeName}-test`; - - const { discovered, ...nestedDiscover } = querySingleElement(getSource)( - attributeName, - attributeValue, - ); - - if (!discovered) { - const validValues = - queryAllElements(getSource)(attributeName).attributeValues; - - if (attributeValue) { - throw new Error( - `Couldn't find HTML-element with attribute "${dataAttribute}" with value "${attributeValue}". Present values are:\n\n"${validValues.join( - '",\n"', - )}"`, - ); - } - - throw new Error( - `Couldn't find HTML-element with attribute "${dataAttribute}"`, - ); - } - - return { discovered, ...nestedDiscover }; - }; - -const getBaseElement = (source: DiscoverySourceTypes) => - "baseElement" in source ? source.baseElement : source; diff --git a/packages/core/src/renderer/components/test-utils/get-application-builder.tsx b/packages/core/src/renderer/components/test-utils/get-application-builder.tsx index 731c5ba8c7..ce103d7a83 100644 --- a/packages/core/src/renderer/components/test-utils/get-application-builder.tsx +++ b/packages/core/src/renderer/components/test-utils/get-application-builder.tsx @@ -59,7 +59,7 @@ import { Namespace } from "../../../common/k8s-api/endpoints"; import { getOverrideFsWithFakes } from "../../../test-utils/override-fs-with-fakes"; import applicationMenuItemCompositeInjectable from "../../../features/application-menu/main/application-menu-item-composite.injectable"; import { getCompositePaths } from "../../../common/utils/composite/get-composite-paths/get-composite-paths"; -import { discoverFor } from "./discovery-of-html-elements"; +import { discoverFor } from "@k8slens/react-testing-library-discovery"; import { findComposite } from "../../../common/utils/composite/find-composite/find-composite"; import shouldStartHiddenInjectable from "../../../main/electron-app/features/should-start-hidden.injectable"; import fsInjectable from "../../../common/fs/fs.injectable"; diff --git a/packages/core/src/renderer/frames/frame-application-root.injectable.ts b/packages/core/src/renderer/frames/frame-application-root.injectable.ts new file mode 100644 index 0000000000..afae5a5fb3 --- /dev/null +++ b/packages/core/src/renderer/frames/frame-application-root.injectable.ts @@ -0,0 +1,31 @@ +/** + * 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 { + reactApplicationChildrenInjectionToken, +} from "@k8slens/react-application"; +import { computed } from "mobx"; + +const frameApplicationRootInjectable = getInjectable({ + id: "frame-application-root", + + instantiate: () => { + const Frame = process.isMainFrame + ? require("./root-frame/root-frame").RootFrame + : require("./cluster-frame/cluster-frame").ClusterFrame; + + return { + id: "frame-application-root", + Component: Frame, + enabled: computed(() => true), + }; + }, + + causesSideEffects: true, + + injectionToken: reactApplicationChildrenInjectionToken, +}); + +export default frameApplicationRootInjectable; diff --git a/packages/core/src/renderer/frames/routing-react-application-hoc.injectable.tsx b/packages/core/src/renderer/frames/routing-react-application-hoc.injectable.tsx new file mode 100644 index 0000000000..6853b0eaed --- /dev/null +++ b/packages/core/src/renderer/frames/routing-react-application-hoc.injectable.tsx @@ -0,0 +1,31 @@ +/** + * 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 { Router } from "react-router"; +import historyInjectable from "../navigation/history.injectable"; +import React from "react"; + +import { + reactApplicationHigherOrderComponentInjectionToken, +} from "@k8slens/react-application"; + +const routingReactApplicationHocInjectable = getInjectable({ + id: "routing-react-application-hoc", + + instantiate: (di) => { + const history = di.inject(historyInjectable); + + return ({ children }) => + ( + + {children} + + ); + }, + + injectionToken: reactApplicationHigherOrderComponentInjectionToken, +}); + +export default routingReactApplicationHocInjectable; diff --git a/packages/core/src/renderer/frames/theme-provider-react-application-hoc.injectable.tsx b/packages/core/src/renderer/frames/theme-provider-react-application-hoc.injectable.tsx new file mode 100644 index 0000000000..45f94c6404 --- /dev/null +++ b/packages/core/src/renderer/frames/theme-provider-react-application-hoc.injectable.tsx @@ -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 React from "react"; +import { reactApplicationHigherOrderComponentInjectionToken } from "@k8slens/react-application"; +import { ThemeProvider } from "@material-ui/core"; +import { defaultMuiBaseTheme } from "../mui-base-theme"; + +const themeProviderReactApplicationHocInjectable = getInjectable({ + id: "theme-provider-react-application-hoc", + + instantiate: + () => + ({ children }) => + {children}, + + injectionToken: reactApplicationHigherOrderComponentInjectionToken, +}); + +export default themeProviderReactApplicationHocInjectable; diff --git a/packages/core/src/renderer/mui-base-theme.tsx b/packages/core/src/renderer/mui-base-theme.tsx index c32374cf58..7238462172 100644 --- a/packages/core/src/renderer/mui-base-theme.tsx +++ b/packages/core/src/renderer/mui-base-theme.tsx @@ -6,7 +6,7 @@ import React from "react"; import { createTheme, ThemeProvider } from "@material-ui/core"; -const defaultTheme = createTheme({ +export const defaultMuiBaseTheme = createTheme({ props: { MuiIconButton: { color: "inherit", @@ -32,7 +32,7 @@ const defaultTheme = createTheme({ export function DefaultProps(App: React.ComponentType | React.FunctionComponent) { return ( - + ); diff --git a/packages/core/src/renderer/start-frame/start-frame.injectable.ts b/packages/core/src/renderer/start-frame/start-frame.injectable.ts index b4bddc9c30..668419191c 100644 --- a/packages/core/src/renderer/start-frame/start-frame.injectable.ts +++ b/packages/core/src/renderer/start-frame/start-frame.injectable.ts @@ -6,9 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import { runManyFor } from "@k8slens/run-many"; import * as tokens from "../before-frame-starts/tokens"; import currentlyInClusterFrameInjectable from "../routes/currently-in-cluster-frame.injectable"; -import { - afterApplicationIsLoadedInjectionToken, -} from "@k8slens/application"; +import { onLoadOfApplicationInjectionToken } from "@k8slens/application"; const startFrameInjectable = getInjectable({ id: "start-frame", @@ -44,7 +42,7 @@ const startFrameInjectable = getInjectable({ }; }, - injectionToken: afterApplicationIsLoadedInjectionToken, + injectionToken: onLoadOfApplicationInjectionToken, }); export default startFrameInjectable; diff --git a/packages/infrastructure/webpack/src/react-config.js b/packages/infrastructure/webpack/src/react-config.js index 3b25515208..201a3c9a6b 100644 --- a/packages/infrastructure/webpack/src/react-config.js +++ b/packages/infrastructure/webpack/src/react-config.js @@ -1,7 +1,7 @@ const path = require("path"); const getReactConfig = require("./get-react-config"); -module.exports = getReactConfig({ +module.exports = getReactConfig()({ entrypointFilePath: "./index.ts", outputDirectory: path.resolve(process.cwd(), "dist"), }); diff --git a/packages/open-lens/package.json b/packages/open-lens/package.json index 630e51223c..34d259ed9c 100644 --- a/packages/open-lens/package.json +++ b/packages/open-lens/package.json @@ -206,6 +206,7 @@ "@k8slens/messaging": "^1.0.0-alpha.1", "@k8slens/messaging-for-main": "^1.0.0-alpha.1", "@k8slens/messaging-for-renderer": "^1.0.0-alpha.1", + "@k8slens/react-application": "^1.0.0-alpha.0", "@k8slens/run-many": "^1.0.0-alpha.1", "@k8slens/startable-stoppable": "^1.0.0-alpha.1", "@k8slens/test-utils": "^1.0.0-alpha.1", diff --git a/packages/open-lens/src/renderer/index.ts b/packages/open-lens/src/renderer/index.ts index 207fc2265c..2d5dda2f04 100644 --- a/packages/open-lens/src/renderer/index.ts +++ b/packages/open-lens/src/renderer/index.ts @@ -15,6 +15,7 @@ import { createContainer } from "@ogre-tools/injectable"; import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx"; import { registerInjectableReact } from "@ogre-tools/injectable-react"; import { messagingFeatureForRenderer } from "@k8slens/messaging-for-renderer"; +import { reactApplicationFeature } from "@k8slens/react-application"; const environment = "renderer"; @@ -24,7 +25,13 @@ runInAction(() => { registerMobX(di); registerInjectableReact(di); registerLensCore(di, environment); - registerFeature(di, applicationFeature, messagingFeatureForRenderer); + + registerFeature( + di, + applicationFeature, + messagingFeatureForRenderer, + reactApplicationFeature + ); autoRegister({ di, diff --git a/packages/technical-features/react-application/.eslintrc.json b/packages/technical-features/react-application/.eslintrc.json new file mode 100644 index 0000000000..b15115cb69 --- /dev/null +++ b/packages/technical-features/react-application/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "@k8slens/eslint-config/eslint", + "parserOptions": { + "project": "./tsconfig.json" + } +} diff --git a/packages/technical-features/react-application/.prettierrc b/packages/technical-features/react-application/.prettierrc new file mode 100644 index 0000000000..edd47b479e --- /dev/null +++ b/packages/technical-features/react-application/.prettierrc @@ -0,0 +1 @@ +"@k8slens/eslint-config/prettier" diff --git a/packages/technical-features/react-application/README.md b/packages/technical-features/react-application/README.md new file mode 100644 index 0000000000..2650d6f527 --- /dev/null +++ b/packages/technical-features/react-application/README.md @@ -0,0 +1,19 @@ +# @k8slens/react-application + +# Usage + +```bash +$ npm install @k8slens/react-application +``` + +```typescript +import { reactApplicationFeature } from "@k8slens/react-application"; +import { registerFeature } from "@k8slens/feature-core"; +import { createContainer } from "@ogre-tools/injectable"; + +const di = createContainer("some-container"); + +registerFeature(di, reactApplicationRootFeature); +``` + +## Extendability diff --git a/packages/technical-features/react-application/index.ts b/packages/technical-features/react-application/index.ts new file mode 100644 index 0000000000..e3f5236d54 --- /dev/null +++ b/packages/technical-features/react-application/index.ts @@ -0,0 +1,10 @@ +export { renderInjectionToken } from "./src/render-application/render.injectable"; +export type { Render } from "./src/render-application/render.injectable"; + +export { reactApplicationChildrenInjectionToken } from "./src/react-application/react-application-children-injection-token"; +export type { ReactApplicationChildren } from "./src/react-application/react-application-children-injection-token"; + +export { reactApplicationHigherOrderComponentInjectionToken } from "./src/react-application/react-application-higher-order-component-injection-token"; +export type { ReactApplicationHigherOrderComponent } from "./src/react-application/react-application-higher-order-component-injection-token"; + +export { reactApplicationFeature } from "./src/feature"; diff --git a/packages/technical-features/react-application/jest.config.js b/packages/technical-features/react-application/jest.config.js new file mode 100644 index 0000000000..38d54ab7b6 --- /dev/null +++ b/packages/technical-features/react-application/jest.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/jest").monorepoPackageConfig(__dirname).configForReact; diff --git a/packages/technical-features/react-application/package.json b/packages/technical-features/react-application/package.json new file mode 100644 index 0000000000..e3ca7956a8 --- /dev/null +++ b/packages/technical-features/react-application/package.json @@ -0,0 +1,52 @@ +{ + "name": "@k8slens/react-application", + "private": false, + "version": "1.0.0-alpha.0", + "description": "Package for React Application", + "type": "commonjs", + "files": [ + "dist" + ], + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/lensapp/lens.git" + }, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "author": { + "name": "OpenLens Authors", + "email": "info@k8slens.dev" + }, + "license": "MIT", + "homepage": "https://github.com/lensapp/lens", + "scripts": { + "build": "webpack", + "dev": "webpack --mode=development --watch", + "test:unit": "jest --coverage --runInBand", + "lint": "lens-lint", + "lint:fix": "lens-lint --fix" + }, + "peerDependencies": { + "@k8slens/feature-core": "^6.5.0-alpha.0", + "@k8slens/application": "^6.5.0-alpha.2", + "@ogre-tools/fp": "^15.1.2", + "@ogre-tools/injectable": "^15.1.2", + "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", + "@ogre-tools/injectable-extension-for-mobx": "^15.1.2", + "@ogre-tools/injectable-react": "^15.1.2", + "lodash": "^4.17.15", + "mobx": "^6.8.0", + "react": "^17.0.2", + "react-dom": "^17.0.2" + }, + "devDependencies": { + "@async-fn/jest": "^1.6.4", + "@k8slens/eslint-config": "6.5.0-alpha.1", + "@testing-library/react": "^12.1.5", + "@k8slens/react-testing-library-discovery": "*" + } +} diff --git a/packages/technical-features/react-application/src/__snapshots__/react-application.test.tsx.snap b/packages/technical-features/react-application/src/__snapshots__/react-application.test.tsx.snap new file mode 100644 index 0000000000..a029ece5f9 --- /dev/null +++ b/packages/technical-features/react-application/src/__snapshots__/react-application.test.tsx.snap @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`react-application renders 1`] = ` + +
+ +`; + +exports[`react-application when content is registered and enabled renders 1`] = ` + +
+
+ Some children +
+
+ +`; + +exports[`react-application when content is registered and enabled when content is disabled renders 1`] = ` + +
+ +`; + +exports[`react-application when content is registered and enabled when higher order component is registered renders 1`] = ` + +
+
+
+ Some children +
+
+
+ +`; diff --git a/packages/technical-features/react-application/src/feature.ts b/packages/technical-features/react-application/src/feature.ts new file mode 100644 index 0000000000..96860c90df --- /dev/null +++ b/packages/technical-features/react-application/src/feature.ts @@ -0,0 +1,17 @@ +import { getFeature } from "@k8slens/feature-core"; +import { autoRegister } from "@ogre-tools/injectable-extension-for-auto-registration"; +import { applicationFeature } from "@k8slens/application"; + +export const reactApplicationFeature = getFeature({ + id: "react-application", + + register: (di) => { + autoRegister({ + di, + targetModule: module, + getRequireContexts: () => [require.context("./", true, /\.injectable\.(ts|tsx)$/)], + }); + }, + + dependencies: [applicationFeature], +}); diff --git a/packages/technical-features/react-application/src/react-application.test.tsx b/packages/technical-features/react-application/src/react-application.test.tsx new file mode 100644 index 0000000000..12fcdb6bac --- /dev/null +++ b/packages/technical-features/react-application/src/react-application.test.tsx @@ -0,0 +1,137 @@ +import { registerFeature } from "@k8slens/feature-core"; +import { createContainer, DiContainer, getInjectable } from "@ogre-tools/injectable"; +import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx"; +import { registerInjectableReact } from "@ogre-tools/injectable-react"; +import { reactApplicationFeature } from "./feature"; +import { runInAction, computed, observable, IObservableValue } from "mobx"; +import { startApplicationInjectionToken } from "@k8slens/application"; +import type { RenderResult } from "@testing-library/react"; +import { render, act } from "@testing-library/react"; +import renderInjectable from "./render-application/render.injectable"; +import { reactApplicationChildrenInjectionToken } from "./react-application/react-application-children-injection-token"; +import React from "react"; +import { Discover, discoverFor } from "@k8slens/react-testing-library-discovery"; +import { + ReactApplicationHigherOrderComponent, + reactApplicationHigherOrderComponentInjectionToken, +} from "./react-application/react-application-higher-order-component-injection-token"; + +const SomeContent = () =>
Some children
; + +describe("react-application", () => { + let rendered: RenderResult; + let di: DiContainer; + let discover: Discover; + + beforeEach(async () => { + di = createContainer("some-container"); + + registerInjectableReact(di); + + registerMobX(di); + + runInAction(() => { + registerFeature(di, reactApplicationFeature); + }); + + di.override(renderInjectable, () => (application) => { + rendered = render(application); + }); + + const startApplication = di.inject(startApplicationInjectionToken); + + await startApplication(); + + discover = discoverFor(() => rendered); + }); + + it("renders", () => { + expect(rendered.baseElement).toMatchSnapshot(); + }); + + describe("when content is registered and enabled", () => { + let someObservable: IObservableValue; + + beforeEach(() => { + someObservable = observable.box(true); + + const someContentInjectable = getInjectable({ + id: "some-content", + + instantiate: () => ({ + id: "some-content", + Component: SomeContent, + enabled: computed(() => someObservable.get()), + }), + + injectionToken: reactApplicationChildrenInjectionToken, + }); + + runInAction(() => { + di.register(someContentInjectable); + }); + }); + + it("renders", () => { + expect(rendered.baseElement).toMatchSnapshot(); + }); + + it("renders the content", () => { + const { discovered } = discover.getSingleElement("some-content"); + + expect(discovered).not.toBeNull(); + }); + + describe("when higher order component is registered", () => { + beforeEach(() => { + const SomeHigherOrderComponent: ReactApplicationHigherOrderComponent = ({ children }) => ( +
{children}
+ ); + + const someHigherOrderComponentInjectable = getInjectable({ + id: "some-higher-order-component", + + instantiate: () => SomeHigherOrderComponent, + + injectionToken: reactApplicationHigherOrderComponentInjectionToken, + }); + + runInAction(() => { + di.register(someHigherOrderComponentInjectable); + }); + }); + + it("renders", () => { + expect(rendered.baseElement).toMatchSnapshot(); + }); + + it("renders the content inside the higher order component", () => { + const { discovered } = discover + .getSingleElement("some-higher-order-component") + .getSingleElement("some-content"); + + expect(discovered).not.toBeNull(); + }); + }); + + describe("when content is disabled", () => { + beforeEach(() => { + act(() => { + runInAction(() => { + someObservable.set(false); + }); + }); + }); + + it("renders", () => { + expect(rendered.baseElement).toMatchSnapshot(); + }); + + it("does not render the content", () => { + const { discovered } = discover.querySingleElement("some-content"); + + expect(discovered).toBeNull(); + }); + }); + }); +}); diff --git a/packages/technical-features/react-application/src/react-application/react-application-children-injection-token.ts b/packages/technical-features/react-application/src/react-application/react-application-children-injection-token.ts new file mode 100644 index 0000000000..398f55d89a --- /dev/null +++ b/packages/technical-features/react-application/src/react-application/react-application-children-injection-token.ts @@ -0,0 +1,13 @@ +import { getInjectionToken } from "@ogre-tools/injectable"; +import type React from "react"; +import type { IComputedValue } from "mobx"; + +export interface ReactApplicationChildren { + id: string; + Component: React.ComponentType; + enabled: IComputedValue; +} + +export const reactApplicationChildrenInjectionToken = getInjectionToken({ + id: "react-application-children-injection-token", +}); diff --git a/packages/technical-features/react-application/src/react-application/react-application-content.tsx b/packages/technical-features/react-application/src/react-application/react-application-content.tsx new file mode 100644 index 0000000000..2307969542 --- /dev/null +++ b/packages/technical-features/react-application/src/react-application/react-application-content.tsx @@ -0,0 +1,29 @@ +import { withInjectables } from "@ogre-tools/injectable-react"; +import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-for-mobx"; +import React from "react"; +import { + ReactApplicationChildren, + reactApplicationChildrenInjectionToken, +} from "./react-application-children-injection-token"; +import type { IComputedValue } from "mobx"; +import { observer, Observer } from "mobx-react"; + +type Dependencies = { contents: IComputedValue }; + +const NonInjectedContent = observer(({ contents }: Dependencies) => ( + <> + {contents.get().map((child) => ( + {() => (child.enabled.get() ? : null)} + ))} + +)); + +export const ReactApplicationContent = withInjectables( + NonInjectedContent, + + { + getProps: (di) => ({ + contents: di.inject(computedInjectManyInjectable)(reactApplicationChildrenInjectionToken), + }), + }, +); diff --git a/packages/technical-features/react-application/src/react-application/react-application-higher-order-component-injection-token.ts b/packages/technical-features/react-application/src/react-application/react-application-higher-order-component-injection-token.ts new file mode 100644 index 0000000000..cae1a6b468 --- /dev/null +++ b/packages/technical-features/react-application/src/react-application/react-application-higher-order-component-injection-token.ts @@ -0,0 +1,11 @@ +import { getInjectionToken } from "@ogre-tools/injectable"; +import type React from "react"; + +export type ReactApplicationHigherOrderComponent = React.ComponentType<{ + children: React.ReactNode; +}>; + +export const reactApplicationHigherOrderComponentInjectionToken = + getInjectionToken({ + id: "react-application-higher-order-component-injection-token", + }); diff --git a/packages/technical-features/react-application/src/react-application/react-application.tsx b/packages/technical-features/react-application/src/react-application/react-application.tsx new file mode 100644 index 0000000000..933d0ad389 --- /dev/null +++ b/packages/technical-features/react-application/src/react-application/react-application.tsx @@ -0,0 +1,37 @@ +import type { DiContainerForInjection } from "@ogre-tools/injectable"; +import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-for-mobx"; +import { DiContextProvider } from "@ogre-tools/injectable-react"; +import { observer } from "mobx-react"; +import React from "react"; +import { + ReactApplicationHigherOrderComponent, + reactApplicationHigherOrderComponentInjectionToken, +} from "./react-application-higher-order-component-injection-token"; + +import { ReactApplicationContent } from "./react-application-content"; + +interface ReactApplicationProps { + di: DiContainerForInjection; +} + +const render = (components: ReactApplicationHigherOrderComponent[]) => { + const [Component, ...rest] = components; + + if (!Component) { + return null; + } + + return {render(rest)}; +}; + +export const ReactApplication = observer(({ di }: ReactApplicationProps) => { + const computedInjectMany = di.inject(computedInjectManyInjectable); + + const higherOrderComponents = computedInjectMany( + reactApplicationHigherOrderComponentInjectionToken, + ); + + const Components = [...higherOrderComponents.get(), ReactApplicationContent]; + + return {render(Components)}; +}); diff --git a/packages/technical-features/react-application/src/render-application/render-application-when-application-is-ready.injectable.tsx b/packages/technical-features/react-application/src/render-application/render-application-when-application-is-ready.injectable.tsx new file mode 100644 index 0000000000..c18f18fc5f --- /dev/null +++ b/packages/technical-features/react-application/src/render-application/render-application-when-application-is-ready.injectable.tsx @@ -0,0 +1,21 @@ +import { getInjectable } from "@ogre-tools/injectable"; +import { afterApplicationIsLoadedInjectionToken } from "@k8slens/application"; +import renderInjectable from "./render.injectable"; +import { ReactApplication } from "../react-application/react-application"; +import React from "react"; + +export const renderApplicationWhenApplicationIsReadyInjectable = getInjectable({ + id: "render-application-when-application-is-ready", + + instantiate: (di) => { + const render = di.inject(renderInjectable); + + return { + run: () => { + render(); + }, + }; + }, + + injectionToken: afterApplicationIsLoadedInjectionToken, +}); diff --git a/packages/technical-features/react-application/src/render-application/render.injectable.tsx b/packages/technical-features/react-application/src/render-application/render.injectable.tsx new file mode 100644 index 0000000000..944823f10a --- /dev/null +++ b/packages/technical-features/react-application/src/render-application/render.injectable.tsx @@ -0,0 +1,22 @@ +import { getInjectable, getInjectionToken } from "@ogre-tools/injectable"; +import { render } from "react-dom"; +import type React from "react"; + +export type Render = (application: React.ReactElement) => void; + +export const renderInjectionToken = getInjectionToken({ + id: "render-injection-token", +}); + +const renderInjectable = getInjectable({ + id: "render", + + /* c8 ignore next */ + instantiate: () => (application) => render(application, document.getElementById("app")), + + causesSideEffects: true, + + injectionToken: renderInjectionToken, +}); + +export default renderInjectable; diff --git a/packages/technical-features/react-application/tsconfig.json b/packages/technical-features/react-application/tsconfig.json new file mode 100644 index 0000000000..ec29a8f75f --- /dev/null +++ b/packages/technical-features/react-application/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "@k8slens/typescript/config/base.json", + "include": ["**/*.ts", "**/*.tsx"] +} diff --git a/packages/technical-features/react-application/webpack.config.js b/packages/technical-features/react-application/webpack.config.js new file mode 100644 index 0000000000..1cda407f5a --- /dev/null +++ b/packages/technical-features/react-application/webpack.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/webpack").configForReact; diff --git a/packages/utility-features/react-testing-library-discovery/.eslintrc.json b/packages/utility-features/react-testing-library-discovery/.eslintrc.json new file mode 100644 index 0000000000..b15115cb69 --- /dev/null +++ b/packages/utility-features/react-testing-library-discovery/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "@k8slens/eslint-config/eslint", + "parserOptions": { + "project": "./tsconfig.json" + } +} diff --git a/packages/utility-features/react-testing-library-discovery/.prettierrc b/packages/utility-features/react-testing-library-discovery/.prettierrc new file mode 100644 index 0000000000..edd47b479e --- /dev/null +++ b/packages/utility-features/react-testing-library-discovery/.prettierrc @@ -0,0 +1 @@ +"@k8slens/eslint-config/prettier" diff --git a/packages/utility-features/react-testing-library-discovery/index.ts b/packages/utility-features/react-testing-library-discovery/index.ts new file mode 100644 index 0000000000..109c6af90f --- /dev/null +++ b/packages/utility-features/react-testing-library-discovery/index.ts @@ -0,0 +1,13 @@ +export type { + Discover, + GetSingleElement, + QueryAllElements, + QuerySingleElement, +} from "./src/discovery-of-html-elements"; + +export { + discoverFor, + getSingleElement, + queryAllElements, + querySingleElement, +} from "./src/discovery-of-html-elements"; diff --git a/packages/utility-features/react-testing-library-discovery/package.json b/packages/utility-features/react-testing-library-discovery/package.json new file mode 100644 index 0000000000..489549a187 --- /dev/null +++ b/packages/utility-features/react-testing-library-discovery/package.json @@ -0,0 +1,33 @@ +{ + "name": "@k8slens/react-testing-library-discovery", + "private": false, + "version": "1.0.0-alpha.0", + "description": "A way to discover HTML-elements using react-testing-library", + "type": "commonjs", + "files": [ + "dist" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/lensapp/lens.git" + }, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "author": { + "name": "OpenLens Authors", + "email": "info@k8slens.dev" + }, + "license": "MIT", + "homepage": "https://github.com/lensapp/lens", + "scripts": { + "build": "webpack", + "dev": "webpack --mode=development --watch", + "lint": "lens-lint", + "lint:fix": "lens-lint --fix" + }, + "dependencies": { + "@testing-library/dom": "^8.19.0", + "@testing-library/jest-dom": "^5.16.5", + "@testing-library/react": "^13.4.0" + } +} diff --git a/packages/utility-features/react-testing-library-discovery/src/discovery-of-html-elements.ts b/packages/utility-features/react-testing-library-discovery/src/discovery-of-html-elements.ts new file mode 100644 index 0000000000..0df7d9202d --- /dev/null +++ b/packages/utility-features/react-testing-library-discovery/src/discovery-of-html-elements.ts @@ -0,0 +1,125 @@ +import type { RenderResult } from "@testing-library/react"; +import { prettyDOM as prettyDom } from "@testing-library/dom"; + +type DiscoverySourceTypes = RenderResult | Element; + +export type QuerySingleElement = ( + attributeName: string, + attributeValue?: string, +) => { discovered: Element | null } & Discover; + +type Clickable = { click: () => void }; + +export type GetSingleElement = ( + attributeName: string, + attributeValue?: string, +) => { discovered: Element } & Discover & Clickable; + +export type QueryAllElements = (attributeName: string) => { + discovered: Element[]; + attributeValues: (string | null)[]; +}; + +export interface Discover { + querySingleElement: QuerySingleElement; + queryAllElements: QueryAllElements; + getSingleElement: GetSingleElement; +} + +const getBaseElement = (source: DiscoverySourceTypes) => + "baseElement" in source ? source.baseElement : source; + +export function querySingleElement(getSource: () => DiscoverySourceTypes): QuerySingleElement { + return (attributeName, attributeValue) => { + const source = getSource(); + + const dataAttribute = `data-${attributeName}-test`; + + const selector = attributeValue + ? `[${dataAttribute}="${attributeValue}"]` + : `[${dataAttribute}]`; + + const discovered = getBaseElement(source).querySelector(selector); + + // eslint-disable-next-line @typescript-eslint/no-use-before-define + const nestedDiscover = discoverFor(() => { + if (!discovered) { + throw new Error("Tried to do nested discover using source that does not exist"); + } + + return discovered; + }); + + return { + discovered, + + ...nestedDiscover, + }; + }; +} + +export function queryAllElements(getSource: () => DiscoverySourceTypes): QueryAllElements { + return (attributeName) => { + const source = getSource(); + + const dataAttribute = `data-${attributeName}-test`; + + const results = [...getBaseElement(source).querySelectorAll(`[${dataAttribute}]`)]; + + return { + discovered: results, + + attributeValues: results.map((result) => result.getAttribute(dataAttribute)), + }; + }; +} + +export function getSingleElement(getSource: () => DiscoverySourceTypes): GetSingleElement { + return (attributeName, attributeValue) => { + const dataAttribute = `data-${attributeName}-test`; + + const { discovered, ...nestedDiscover } = querySingleElement(getSource)( + attributeName, + attributeValue, + ); + + if (!discovered) { + // eslint-disable-next-line xss/no-mixed-html + const html = prettyDom(getBaseElement(getSource())); + + if (attributeValue) { + const validValues = queryAllElements(getSource)(attributeName).attributeValues; + + throw new Error( + `Couldn't find HTML-element with attribute "${dataAttribute}" with value "${attributeValue}".\n\nPresent values are:\n\n"${validValues.join( + '",\n"', + )}"\n\nHTML is:\n\n${html}`, + ); + } + + throw new Error( + `Couldn't find HTML-element with attribute "${dataAttribute}"\n\nHTML is:\n\n${html}`, + ); + } + + const click = () => { + if ("click" in discovered && typeof discovered.click === "function") { + discovered.click(); + } else { + throw new Error( + `Tried to click something that was not clickable:\n\n${prettyDom(discovered)}`, + ); + } + }; + + return { discovered, click, ...nestedDiscover }; + }; +} + +export function discoverFor(getSource: () => DiscoverySourceTypes): Discover { + return { + querySingleElement: querySingleElement(getSource), + queryAllElements: queryAllElements(getSource), + getSingleElement: getSingleElement(getSource), + }; +} diff --git a/packages/utility-features/react-testing-library-discovery/tsconfig.json b/packages/utility-features/react-testing-library-discovery/tsconfig.json new file mode 100644 index 0000000000..1819203dc1 --- /dev/null +++ b/packages/utility-features/react-testing-library-discovery/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "@k8slens/typescript/config/base.json", + "include": ["**/*.ts"] +} diff --git a/packages/utility-features/react-testing-library-discovery/webpack.config.js b/packages/utility-features/react-testing-library-discovery/webpack.config.js new file mode 100644 index 0000000000..3183f30179 --- /dev/null +++ b/packages/utility-features/react-testing-library-discovery/webpack.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/webpack").configForNode; From 7bae7127032425487e9a1dc3509d2a5cb3e60668 Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Fri, 31 Mar 2023 13:33:13 +0300 Subject: [PATCH 16/35] wait app to be ready before creating a BrowserWindow for system proxy resolver (#7443) Signed-off-by: Jari Kolehmainen --- ...esolve-system-proxy-from-electron.injectable.ts | 3 ++- .../resolve-system-proxy-from-electron.test.ts | 4 ++-- ...-proxy-window.global-override-for-injectable.ts | 4 ++-- .../resolve-system-proxy-window.injectable.ts | 14 +++++++++++--- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.injectable.ts b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.injectable.ts index 4ad2da39b8..1a111f7dd7 100644 --- a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.injectable.ts +++ b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.injectable.ts @@ -10,11 +10,12 @@ const resolveSystemProxyFromElectronInjectable = getInjectable({ id: "resolve-system-proxy-from-electron", instantiate: (di) => { - const helperWindow = di.inject(resolveSystemProxyWindowInjectable); const withErrorLoggingFor = di.inject(withErrorLoggingInjectable); const withErrorLogging = withErrorLoggingFor(() => "Error resolving proxy"); return withErrorLogging(async (url: string) => { + const helperWindow = await di.inject(resolveSystemProxyWindowInjectable); + return await helperWindow.webContents.session.resolveProxy(url); }); }, diff --git a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.test.ts b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.test.ts index a2e6d01627..9ee9c86459 100644 --- a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.test.ts +++ b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.test.ts @@ -32,7 +32,7 @@ describe("technical: resolve-system-proxy-from-electron", () => { di.override( resolveSystemProxyWindowInjectable, - () => ({ + async () => ({ webContents: { session: { resolveProxy: resolveSystemProxyMock, @@ -73,7 +73,7 @@ describe("technical: resolve-system-proxy-from-electron", () => { di.override( resolveSystemProxyWindowInjectable, - () => ({ + async () => ({ webContents: { session: { resolveProxy: () => { diff --git a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.global-override-for-injectable.ts b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.global-override-for-injectable.ts index 4bf1ada952..680101b998 100644 --- a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.global-override-for-injectable.ts +++ b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.global-override-for-injectable.ts @@ -8,8 +8,8 @@ import type { BrowserWindow, Session, WebContents } from "electron"; import resolveSystemProxyWindowInjectable from "./resolve-system-proxy-window.injectable"; export default getGlobalOverride( - resolveSystemProxyWindowInjectable, - () => ({ + resolveSystemProxyWindowInjectable, + async () => ({ webContents: { session: { resolveProxy: () => "DIRECT", diff --git a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.injectable.ts b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.injectable.ts index baa0da6c39..9dcfed4edf 100644 --- a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.injectable.ts +++ b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.injectable.ts @@ -4,13 +4,21 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { BrowserWindow } from "electron"; +import electronAppInjectable from "../../electron-app/electron-app.injectable"; const resolveSystemProxyWindowInjectable = getInjectable({ id: "resolve-system-proxy-window", - instantiate: () => { - const window = new BrowserWindow({ show: false }); + instantiate: async (di) => { + const app = di.inject(electronAppInjectable); - window.hide(); + await app.whenReady(); + + const window = new BrowserWindow({ + show: false, + paintWhenInitiallyHidden: false, + }); + + window.hide(); return window; }, From 67dc74530b28826e6cd8c4f6ffcce31bed8f2f38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Mar 2023 14:14:04 +0300 Subject: [PATCH 17/35] Bump @swc/core from 1.3.40 to 1.3.44 (#7439) Bumps [@swc/core](https://github.com/swc-project/swc) from 1.3.40 to 1.3.44. - [Release notes](https://github.com/swc-project/swc/releases) - [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md) - [Commits](https://github.com/swc-project/swc/compare/v1.3.40...v1.3.44) --- updated-dependencies: - dependency-name: "@swc/core" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 1692 ++++++++++++++++++- packages/bump-version-for-cron/package.json | 2 +- packages/cluster-settings/package.json | 2 +- packages/core/package.json | 2 +- packages/ensure-binaries/package.json | 2 +- packages/generate-tray-icons/package.json | 2 +- packages/infrastructure/jest/package.json | 2 +- packages/open-lens/package.json | 2 +- packages/release-tool/package.json | 2 +- packages/semver/package.json | 2 +- 10 files changed, 1692 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 60e1c5dc69..ccbc543df9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6542,6 +6542,7 @@ "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.40.tgz", "integrity": "sha512-ZQJ+NID24PQkPIHnbO2B68YNQ6aMEyDz6dcsZucpRK4r7+aPqQ2yVLaqFcQU9VcGMyo4JJydmokzyTr1roWPIQ==", "hasInstallScript": true, + "peer": true, "engines": { "node": ">=10" }, @@ -6573,6 +6574,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=10" } @@ -6588,6 +6590,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=10" } @@ -6603,6 +6606,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=10" } @@ -6618,6 +6622,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=10" } @@ -6633,6 +6638,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=10" } @@ -6648,6 +6654,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=10" } @@ -6663,6 +6670,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=10" } @@ -6678,6 +6686,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=10" } @@ -6693,6 +6702,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=10" } @@ -6708,6 +6718,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=10" } @@ -34321,12 +34332,198 @@ }, "devDependencies": { "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.37", + "@swc/core": "^1.3.44", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", "rimraf": "^4.1.2" } }, + "packages/bump-version-for-cron/node_modules/@swc/core": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.44.tgz", + "integrity": "sha512-RC25C8nxOCdfGS//F9Q8aHKx4XoCsxvgO+sSUhvt7zDz1Y2ruVUTu2UOH0VeE0WkA8j6oEZH+xH2SUfDUkxXdA==", + "dev": true, + "hasInstallScript": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.44", + "@swc/core-darwin-x64": "1.3.44", + "@swc/core-linux-arm-gnueabihf": "1.3.44", + "@swc/core-linux-arm64-gnu": "1.3.44", + "@swc/core-linux-arm64-musl": "1.3.44", + "@swc/core-linux-x64-gnu": "1.3.44", + "@swc/core-linux-x64-musl": "1.3.44", + "@swc/core-win32-arm64-msvc": "1.3.44", + "@swc/core-win32-ia32-msvc": "1.3.44", + "@swc/core-win32-x64-msvc": "1.3.44" + } + }, + "packages/bump-version-for-cron/node_modules/@swc/core-darwin-arm64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.44.tgz", + "integrity": "sha512-Y+oVsCjXUPvr3D9YLuB1gjP84TseM/CRkbPNrf+3JXQhsPEkgxdIdFP1cl/obeqMQrRgPpvSfK+TOvGuOuV22g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/bump-version-for-cron/node_modules/@swc/core-darwin-x64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.44.tgz", + "integrity": "sha512-bM0IKBjlSD0yHJbd7bE3il5fTu3oUjUO2zjLkzfIx6tiqbmDyvOX8adaSqse9N+d8Ip9p26b5Vo7pMHq0POGkg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/bump-version-for-cron/node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.44.tgz", + "integrity": "sha512-D4lfVwCbkWscDTb6btb89+bN0kgvjGBPfOmcvih7nY5hxaorwvp+PefkYAhFw8vKmL92lrnWUFNiTemVFN4bxg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/bump-version-for-cron/node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.44.tgz", + "integrity": "sha512-muExPTrN26MFmtO+5uffkH5v4lmd8GdmyWvlC2tL95h7o9genTIQyr7kcSepGZrDe4fM9G6++5YfENhUpXHo+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/bump-version-for-cron/node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.44.tgz", + "integrity": "sha512-MY1wY3kSIosjJKKCfFGniJFFVkt3oPvJLN4Dlj+bMgAt3O7anm8lGbyLqUpJ1Ep4rTsJj7ObO06DQiSWp4Fhcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/bump-version-for-cron/node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.44.tgz", + "integrity": "sha512-xV4pDxJM06g0yUDTA22ZHgonzGqf/poIlgADRmEkx9cWWm5qLRhmWrrkVX1xZVvdlcXj1ERnia/UkvrDux96lg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/bump-version-for-cron/node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.44.tgz", + "integrity": "sha512-NJnnlE8vCkKHoo/wIaoywNN/01vNsvhKUjBgUx865sUM/XWAIanpbV41yfdEkC+Iwd+/zB3ZZnOYql3b+Nn8aQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/bump-version-for-cron/node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.44.tgz", + "integrity": "sha512-/xOtjZhX25GEOPLN55icjj9E061DDH7G0A9HfUAEilURgBbvm6bIlqK+t8mOKK0tOsDoHftdTBRkYhTAqUtakQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/bump-version-for-cron/node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.44.tgz", + "integrity": "sha512-uKTAWQuMEW1gJnl8F3eiz3kdk8CiaR5dMWWlGbHIq6dRbur2hoKaEnINR4UqkvvAhhY1YB0Xr5DV1H986Xu2EA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/bump-version-for-cron/node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.44.tgz", + "integrity": "sha512-D9fBRhr44cK4YIKFikpktyUDLkZgVj0ISaSl8IjiTvjqTrE/9+E+dzTNHULn5tc3lHVLLxyVwMjJRr2G0D4O6w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, "packages/bump-version-for-cron/node_modules/@types/node": { "version": "16.18.16", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.16.tgz", @@ -34391,12 +34588,198 @@ "devDependencies": { "@ogre-tools/injectable": "^15.1.2", "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.37", + "@swc/core": "^1.3.44", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", "rimraf": "^4.1.2" } }, + "packages/cluster-settings/node_modules/@swc/core": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.44.tgz", + "integrity": "sha512-RC25C8nxOCdfGS//F9Q8aHKx4XoCsxvgO+sSUhvt7zDz1Y2ruVUTu2UOH0VeE0WkA8j6oEZH+xH2SUfDUkxXdA==", + "dev": true, + "hasInstallScript": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.44", + "@swc/core-darwin-x64": "1.3.44", + "@swc/core-linux-arm-gnueabihf": "1.3.44", + "@swc/core-linux-arm64-gnu": "1.3.44", + "@swc/core-linux-arm64-musl": "1.3.44", + "@swc/core-linux-x64-gnu": "1.3.44", + "@swc/core-linux-x64-musl": "1.3.44", + "@swc/core-win32-arm64-msvc": "1.3.44", + "@swc/core-win32-ia32-msvc": "1.3.44", + "@swc/core-win32-x64-msvc": "1.3.44" + } + }, + "packages/cluster-settings/node_modules/@swc/core-darwin-arm64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.44.tgz", + "integrity": "sha512-Y+oVsCjXUPvr3D9YLuB1gjP84TseM/CRkbPNrf+3JXQhsPEkgxdIdFP1cl/obeqMQrRgPpvSfK+TOvGuOuV22g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/cluster-settings/node_modules/@swc/core-darwin-x64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.44.tgz", + "integrity": "sha512-bM0IKBjlSD0yHJbd7bE3il5fTu3oUjUO2zjLkzfIx6tiqbmDyvOX8adaSqse9N+d8Ip9p26b5Vo7pMHq0POGkg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/cluster-settings/node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.44.tgz", + "integrity": "sha512-D4lfVwCbkWscDTb6btb89+bN0kgvjGBPfOmcvih7nY5hxaorwvp+PefkYAhFw8vKmL92lrnWUFNiTemVFN4bxg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/cluster-settings/node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.44.tgz", + "integrity": "sha512-muExPTrN26MFmtO+5uffkH5v4lmd8GdmyWvlC2tL95h7o9genTIQyr7kcSepGZrDe4fM9G6++5YfENhUpXHo+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/cluster-settings/node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.44.tgz", + "integrity": "sha512-MY1wY3kSIosjJKKCfFGniJFFVkt3oPvJLN4Dlj+bMgAt3O7anm8lGbyLqUpJ1Ep4rTsJj7ObO06DQiSWp4Fhcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/cluster-settings/node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.44.tgz", + "integrity": "sha512-xV4pDxJM06g0yUDTA22ZHgonzGqf/poIlgADRmEkx9cWWm5qLRhmWrrkVX1xZVvdlcXj1ERnia/UkvrDux96lg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/cluster-settings/node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.44.tgz", + "integrity": "sha512-NJnnlE8vCkKHoo/wIaoywNN/01vNsvhKUjBgUx865sUM/XWAIanpbV41yfdEkC+Iwd+/zB3ZZnOYql3b+Nn8aQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/cluster-settings/node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.44.tgz", + "integrity": "sha512-/xOtjZhX25GEOPLN55icjj9E061DDH7G0A9HfUAEilURgBbvm6bIlqK+t8mOKK0tOsDoHftdTBRkYhTAqUtakQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/cluster-settings/node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.44.tgz", + "integrity": "sha512-uKTAWQuMEW1gJnl8F3eiz3kdk8CiaR5dMWWlGbHIq6dRbur2hoKaEnINR4UqkvvAhhY1YB0Xr5DV1H986Xu2EA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/cluster-settings/node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.44.tgz", + "integrity": "sha512-D9fBRhr44cK4YIKFikpktyUDLkZgVj0ISaSl8IjiTvjqTrE/9+E+dzTNHULn5tc3lHVLLxyVwMjJRr2G0D4O6w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, "packages/cluster-settings/node_modules/@types/node": { "version": "16.18.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.18.tgz", @@ -34488,7 +34871,7 @@ "@material-ui/lab": "^4.0.0-alpha.60", "@sentry/types": "^6.19.7", "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.37", + "@swc/core": "^1.3.44", "@swc/jest": "^0.2.24", "@testing-library/dom": "^7.31.2", "@testing-library/jest-dom": "^5.16.5", @@ -34903,6 +35286,192 @@ "@sinonjs/commons": "^2.0.0" } }, + "packages/core/node_modules/@swc/core": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.44.tgz", + "integrity": "sha512-RC25C8nxOCdfGS//F9Q8aHKx4XoCsxvgO+sSUhvt7zDz1Y2ruVUTu2UOH0VeE0WkA8j6oEZH+xH2SUfDUkxXdA==", + "dev": true, + "hasInstallScript": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.44", + "@swc/core-darwin-x64": "1.3.44", + "@swc/core-linux-arm-gnueabihf": "1.3.44", + "@swc/core-linux-arm64-gnu": "1.3.44", + "@swc/core-linux-arm64-musl": "1.3.44", + "@swc/core-linux-x64-gnu": "1.3.44", + "@swc/core-linux-x64-musl": "1.3.44", + "@swc/core-win32-arm64-msvc": "1.3.44", + "@swc/core-win32-ia32-msvc": "1.3.44", + "@swc/core-win32-x64-msvc": "1.3.44" + } + }, + "packages/core/node_modules/@swc/core-darwin-arm64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.44.tgz", + "integrity": "sha512-Y+oVsCjXUPvr3D9YLuB1gjP84TseM/CRkbPNrf+3JXQhsPEkgxdIdFP1cl/obeqMQrRgPpvSfK+TOvGuOuV22g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/core/node_modules/@swc/core-darwin-x64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.44.tgz", + "integrity": "sha512-bM0IKBjlSD0yHJbd7bE3il5fTu3oUjUO2zjLkzfIx6tiqbmDyvOX8adaSqse9N+d8Ip9p26b5Vo7pMHq0POGkg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/core/node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.44.tgz", + "integrity": "sha512-D4lfVwCbkWscDTb6btb89+bN0kgvjGBPfOmcvih7nY5hxaorwvp+PefkYAhFw8vKmL92lrnWUFNiTemVFN4bxg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/core/node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.44.tgz", + "integrity": "sha512-muExPTrN26MFmtO+5uffkH5v4lmd8GdmyWvlC2tL95h7o9genTIQyr7kcSepGZrDe4fM9G6++5YfENhUpXHo+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/core/node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.44.tgz", + "integrity": "sha512-MY1wY3kSIosjJKKCfFGniJFFVkt3oPvJLN4Dlj+bMgAt3O7anm8lGbyLqUpJ1Ep4rTsJj7ObO06DQiSWp4Fhcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/core/node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.44.tgz", + "integrity": "sha512-xV4pDxJM06g0yUDTA22ZHgonzGqf/poIlgADRmEkx9cWWm5qLRhmWrrkVX1xZVvdlcXj1ERnia/UkvrDux96lg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/core/node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.44.tgz", + "integrity": "sha512-NJnnlE8vCkKHoo/wIaoywNN/01vNsvhKUjBgUx865sUM/XWAIanpbV41yfdEkC+Iwd+/zB3ZZnOYql3b+Nn8aQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/core/node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.44.tgz", + "integrity": "sha512-/xOtjZhX25GEOPLN55icjj9E061DDH7G0A9HfUAEilURgBbvm6bIlqK+t8mOKK0tOsDoHftdTBRkYhTAqUtakQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/core/node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.44.tgz", + "integrity": "sha512-uKTAWQuMEW1gJnl8F3eiz3kdk8CiaR5dMWWlGbHIq6dRbur2hoKaEnINR4UqkvvAhhY1YB0Xr5DV1H986Xu2EA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/core/node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.44.tgz", + "integrity": "sha512-D9fBRhr44cK4YIKFikpktyUDLkZgVj0ISaSl8IjiTvjqTrE/9+E+dzTNHULn5tc3lHVLLxyVwMjJRr2G0D4O6w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, "packages/core/node_modules/@types/estree": { "version": "0.0.51", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", @@ -35674,7 +36243,7 @@ }, "devDependencies": { "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.37", + "@swc/core": "^1.3.44", "@types/cli-progress": "^3.11.0", "@types/gunzip-maybe": "^1.4.0", "@types/node": "^16.18.11", @@ -35683,6 +36252,192 @@ "rimraf": "^4.1.2" } }, + "packages/ensure-binaries/node_modules/@swc/core": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.44.tgz", + "integrity": "sha512-RC25C8nxOCdfGS//F9Q8aHKx4XoCsxvgO+sSUhvt7zDz1Y2ruVUTu2UOH0VeE0WkA8j6oEZH+xH2SUfDUkxXdA==", + "dev": true, + "hasInstallScript": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.44", + "@swc/core-darwin-x64": "1.3.44", + "@swc/core-linux-arm-gnueabihf": "1.3.44", + "@swc/core-linux-arm64-gnu": "1.3.44", + "@swc/core-linux-arm64-musl": "1.3.44", + "@swc/core-linux-x64-gnu": "1.3.44", + "@swc/core-linux-x64-musl": "1.3.44", + "@swc/core-win32-arm64-msvc": "1.3.44", + "@swc/core-win32-ia32-msvc": "1.3.44", + "@swc/core-win32-x64-msvc": "1.3.44" + } + }, + "packages/ensure-binaries/node_modules/@swc/core-darwin-arm64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.44.tgz", + "integrity": "sha512-Y+oVsCjXUPvr3D9YLuB1gjP84TseM/CRkbPNrf+3JXQhsPEkgxdIdFP1cl/obeqMQrRgPpvSfK+TOvGuOuV22g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/ensure-binaries/node_modules/@swc/core-darwin-x64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.44.tgz", + "integrity": "sha512-bM0IKBjlSD0yHJbd7bE3il5fTu3oUjUO2zjLkzfIx6tiqbmDyvOX8adaSqse9N+d8Ip9p26b5Vo7pMHq0POGkg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/ensure-binaries/node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.44.tgz", + "integrity": "sha512-D4lfVwCbkWscDTb6btb89+bN0kgvjGBPfOmcvih7nY5hxaorwvp+PefkYAhFw8vKmL92lrnWUFNiTemVFN4bxg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/ensure-binaries/node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.44.tgz", + "integrity": "sha512-muExPTrN26MFmtO+5uffkH5v4lmd8GdmyWvlC2tL95h7o9genTIQyr7kcSepGZrDe4fM9G6++5YfENhUpXHo+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/ensure-binaries/node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.44.tgz", + "integrity": "sha512-MY1wY3kSIosjJKKCfFGniJFFVkt3oPvJLN4Dlj+bMgAt3O7anm8lGbyLqUpJ1Ep4rTsJj7ObO06DQiSWp4Fhcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/ensure-binaries/node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.44.tgz", + "integrity": "sha512-xV4pDxJM06g0yUDTA22ZHgonzGqf/poIlgADRmEkx9cWWm5qLRhmWrrkVX1xZVvdlcXj1ERnia/UkvrDux96lg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/ensure-binaries/node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.44.tgz", + "integrity": "sha512-NJnnlE8vCkKHoo/wIaoywNN/01vNsvhKUjBgUx865sUM/XWAIanpbV41yfdEkC+Iwd+/zB3ZZnOYql3b+Nn8aQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/ensure-binaries/node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.44.tgz", + "integrity": "sha512-/xOtjZhX25GEOPLN55icjj9E061DDH7G0A9HfUAEilURgBbvm6bIlqK+t8mOKK0tOsDoHftdTBRkYhTAqUtakQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/ensure-binaries/node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.44.tgz", + "integrity": "sha512-uKTAWQuMEW1gJnl8F3eiz3kdk8CiaR5dMWWlGbHIq6dRbur2hoKaEnINR4UqkvvAhhY1YB0Xr5DV1H986Xu2EA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/ensure-binaries/node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.44.tgz", + "integrity": "sha512-D9fBRhr44cK4YIKFikpktyUDLkZgVj0ISaSl8IjiTvjqTrE/9+E+dzTNHULn5tc3lHVLLxyVwMjJRr2G0D4O6w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, "packages/ensure-binaries/node_modules/@types/node": { "version": "16.18.16", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.16.tgz", @@ -36019,13 +36774,199 @@ }, "devDependencies": { "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.37", + "@swc/core": "^1.3.44", "@types/jsdom": "^20.0.1", "@types/node": "^18.11.18", "@types/sharp": "^0.31.1", "rimraf": "^4.1.2" } }, + "packages/generate-tray-icons/node_modules/@swc/core": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.44.tgz", + "integrity": "sha512-RC25C8nxOCdfGS//F9Q8aHKx4XoCsxvgO+sSUhvt7zDz1Y2ruVUTu2UOH0VeE0WkA8j6oEZH+xH2SUfDUkxXdA==", + "dev": true, + "hasInstallScript": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.44", + "@swc/core-darwin-x64": "1.3.44", + "@swc/core-linux-arm-gnueabihf": "1.3.44", + "@swc/core-linux-arm64-gnu": "1.3.44", + "@swc/core-linux-arm64-musl": "1.3.44", + "@swc/core-linux-x64-gnu": "1.3.44", + "@swc/core-linux-x64-musl": "1.3.44", + "@swc/core-win32-arm64-msvc": "1.3.44", + "@swc/core-win32-ia32-msvc": "1.3.44", + "@swc/core-win32-x64-msvc": "1.3.44" + } + }, + "packages/generate-tray-icons/node_modules/@swc/core-darwin-arm64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.44.tgz", + "integrity": "sha512-Y+oVsCjXUPvr3D9YLuB1gjP84TseM/CRkbPNrf+3JXQhsPEkgxdIdFP1cl/obeqMQrRgPpvSfK+TOvGuOuV22g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/generate-tray-icons/node_modules/@swc/core-darwin-x64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.44.tgz", + "integrity": "sha512-bM0IKBjlSD0yHJbd7bE3il5fTu3oUjUO2zjLkzfIx6tiqbmDyvOX8adaSqse9N+d8Ip9p26b5Vo7pMHq0POGkg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/generate-tray-icons/node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.44.tgz", + "integrity": "sha512-D4lfVwCbkWscDTb6btb89+bN0kgvjGBPfOmcvih7nY5hxaorwvp+PefkYAhFw8vKmL92lrnWUFNiTemVFN4bxg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/generate-tray-icons/node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.44.tgz", + "integrity": "sha512-muExPTrN26MFmtO+5uffkH5v4lmd8GdmyWvlC2tL95h7o9genTIQyr7kcSepGZrDe4fM9G6++5YfENhUpXHo+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/generate-tray-icons/node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.44.tgz", + "integrity": "sha512-MY1wY3kSIosjJKKCfFGniJFFVkt3oPvJLN4Dlj+bMgAt3O7anm8lGbyLqUpJ1Ep4rTsJj7ObO06DQiSWp4Fhcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/generate-tray-icons/node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.44.tgz", + "integrity": "sha512-xV4pDxJM06g0yUDTA22ZHgonzGqf/poIlgADRmEkx9cWWm5qLRhmWrrkVX1xZVvdlcXj1ERnia/UkvrDux96lg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/generate-tray-icons/node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.44.tgz", + "integrity": "sha512-NJnnlE8vCkKHoo/wIaoywNN/01vNsvhKUjBgUx865sUM/XWAIanpbV41yfdEkC+Iwd+/zB3ZZnOYql3b+Nn8aQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/generate-tray-icons/node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.44.tgz", + "integrity": "sha512-/xOtjZhX25GEOPLN55icjj9E061DDH7G0A9HfUAEilURgBbvm6bIlqK+t8mOKK0tOsDoHftdTBRkYhTAqUtakQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/generate-tray-icons/node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.44.tgz", + "integrity": "sha512-uKTAWQuMEW1gJnl8F3eiz3kdk8CiaR5dMWWlGbHIq6dRbur2hoKaEnINR4UqkvvAhhY1YB0Xr5DV1H986Xu2EA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/generate-tray-icons/node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.44.tgz", + "integrity": "sha512-D9fBRhr44cK4YIKFikpktyUDLkZgVj0ISaSl8IjiTvjqTrE/9+E+dzTNHULn5tc3lHVLLxyVwMjJRr2G0D4O6w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, "packages/generate-tray-icons/node_modules/color": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", @@ -36097,7 +37038,7 @@ "version": "6.5.0-alpha.1", "license": "MIT", "dependencies": { - "@swc/core": "^1.3.38", + "@swc/core": "^1.3.44", "@swc/jest": "^0.2.23", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", @@ -36330,6 +37271,181 @@ "@sinonjs/commons": "^2.0.0" } }, + "packages/infrastructure/jest/node_modules/@swc/core": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.44.tgz", + "integrity": "sha512-RC25C8nxOCdfGS//F9Q8aHKx4XoCsxvgO+sSUhvt7zDz1Y2ruVUTu2UOH0VeE0WkA8j6oEZH+xH2SUfDUkxXdA==", + "hasInstallScript": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.44", + "@swc/core-darwin-x64": "1.3.44", + "@swc/core-linux-arm-gnueabihf": "1.3.44", + "@swc/core-linux-arm64-gnu": "1.3.44", + "@swc/core-linux-arm64-musl": "1.3.44", + "@swc/core-linux-x64-gnu": "1.3.44", + "@swc/core-linux-x64-musl": "1.3.44", + "@swc/core-win32-arm64-msvc": "1.3.44", + "@swc/core-win32-ia32-msvc": "1.3.44", + "@swc/core-win32-x64-msvc": "1.3.44" + } + }, + "packages/infrastructure/jest/node_modules/@swc/core-darwin-arm64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.44.tgz", + "integrity": "sha512-Y+oVsCjXUPvr3D9YLuB1gjP84TseM/CRkbPNrf+3JXQhsPEkgxdIdFP1cl/obeqMQrRgPpvSfK+TOvGuOuV22g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/infrastructure/jest/node_modules/@swc/core-darwin-x64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.44.tgz", + "integrity": "sha512-bM0IKBjlSD0yHJbd7bE3il5fTu3oUjUO2zjLkzfIx6tiqbmDyvOX8adaSqse9N+d8Ip9p26b5Vo7pMHq0POGkg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/infrastructure/jest/node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.44.tgz", + "integrity": "sha512-D4lfVwCbkWscDTb6btb89+bN0kgvjGBPfOmcvih7nY5hxaorwvp+PefkYAhFw8vKmL92lrnWUFNiTemVFN4bxg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/infrastructure/jest/node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.44.tgz", + "integrity": "sha512-muExPTrN26MFmtO+5uffkH5v4lmd8GdmyWvlC2tL95h7o9genTIQyr7kcSepGZrDe4fM9G6++5YfENhUpXHo+g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/infrastructure/jest/node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.44.tgz", + "integrity": "sha512-MY1wY3kSIosjJKKCfFGniJFFVkt3oPvJLN4Dlj+bMgAt3O7anm8lGbyLqUpJ1Ep4rTsJj7ObO06DQiSWp4Fhcw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/infrastructure/jest/node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.44.tgz", + "integrity": "sha512-xV4pDxJM06g0yUDTA22ZHgonzGqf/poIlgADRmEkx9cWWm5qLRhmWrrkVX1xZVvdlcXj1ERnia/UkvrDux96lg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/infrastructure/jest/node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.44.tgz", + "integrity": "sha512-NJnnlE8vCkKHoo/wIaoywNN/01vNsvhKUjBgUx865sUM/XWAIanpbV41yfdEkC+Iwd+/zB3ZZnOYql3b+Nn8aQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/infrastructure/jest/node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.44.tgz", + "integrity": "sha512-/xOtjZhX25GEOPLN55icjj9E061DDH7G0A9HfUAEilURgBbvm6bIlqK+t8mOKK0tOsDoHftdTBRkYhTAqUtakQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/infrastructure/jest/node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.44.tgz", + "integrity": "sha512-uKTAWQuMEW1gJnl8F3eiz3kdk8CiaR5dMWWlGbHIq6dRbur2hoKaEnINR4UqkvvAhhY1YB0Xr5DV1H986Xu2EA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/infrastructure/jest/node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.44.tgz", + "integrity": "sha512-D9fBRhr44cK4YIKFikpktyUDLkZgVj0ISaSl8IjiTvjqTrE/9+E+dzTNHULn5tc3lHVLLxyVwMjJRr2G0D4O6w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, "packages/infrastructure/jest/node_modules/@testing-library/dom": { "version": "8.20.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.0.tgz", @@ -37971,7 +39087,7 @@ "@k8slens/node-fetch": "^6.5.0-alpha.1", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.10", "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.37", + "@swc/core": "^1.3.44", "@swc/jest": "^0.2.24", "@types/byline": "^4.2.33", "@types/chart.js": "^2.9.36", @@ -38294,6 +39410,192 @@ "@sinonjs/commons": "^2.0.0" } }, + "packages/open-lens/node_modules/@swc/core": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.44.tgz", + "integrity": "sha512-RC25C8nxOCdfGS//F9Q8aHKx4XoCsxvgO+sSUhvt7zDz1Y2ruVUTu2UOH0VeE0WkA8j6oEZH+xH2SUfDUkxXdA==", + "dev": true, + "hasInstallScript": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.44", + "@swc/core-darwin-x64": "1.3.44", + "@swc/core-linux-arm-gnueabihf": "1.3.44", + "@swc/core-linux-arm64-gnu": "1.3.44", + "@swc/core-linux-arm64-musl": "1.3.44", + "@swc/core-linux-x64-gnu": "1.3.44", + "@swc/core-linux-x64-musl": "1.3.44", + "@swc/core-win32-arm64-msvc": "1.3.44", + "@swc/core-win32-ia32-msvc": "1.3.44", + "@swc/core-win32-x64-msvc": "1.3.44" + } + }, + "packages/open-lens/node_modules/@swc/core-darwin-arm64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.44.tgz", + "integrity": "sha512-Y+oVsCjXUPvr3D9YLuB1gjP84TseM/CRkbPNrf+3JXQhsPEkgxdIdFP1cl/obeqMQrRgPpvSfK+TOvGuOuV22g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/open-lens/node_modules/@swc/core-darwin-x64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.44.tgz", + "integrity": "sha512-bM0IKBjlSD0yHJbd7bE3il5fTu3oUjUO2zjLkzfIx6tiqbmDyvOX8adaSqse9N+d8Ip9p26b5Vo7pMHq0POGkg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/open-lens/node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.44.tgz", + "integrity": "sha512-D4lfVwCbkWscDTb6btb89+bN0kgvjGBPfOmcvih7nY5hxaorwvp+PefkYAhFw8vKmL92lrnWUFNiTemVFN4bxg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/open-lens/node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.44.tgz", + "integrity": "sha512-muExPTrN26MFmtO+5uffkH5v4lmd8GdmyWvlC2tL95h7o9genTIQyr7kcSepGZrDe4fM9G6++5YfENhUpXHo+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/open-lens/node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.44.tgz", + "integrity": "sha512-MY1wY3kSIosjJKKCfFGniJFFVkt3oPvJLN4Dlj+bMgAt3O7anm8lGbyLqUpJ1Ep4rTsJj7ObO06DQiSWp4Fhcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/open-lens/node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.44.tgz", + "integrity": "sha512-xV4pDxJM06g0yUDTA22ZHgonzGqf/poIlgADRmEkx9cWWm5qLRhmWrrkVX1xZVvdlcXj1ERnia/UkvrDux96lg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/open-lens/node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.44.tgz", + "integrity": "sha512-NJnnlE8vCkKHoo/wIaoywNN/01vNsvhKUjBgUx865sUM/XWAIanpbV41yfdEkC+Iwd+/zB3ZZnOYql3b+Nn8aQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/open-lens/node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.44.tgz", + "integrity": "sha512-/xOtjZhX25GEOPLN55icjj9E061DDH7G0A9HfUAEilURgBbvm6bIlqK+t8mOKK0tOsDoHftdTBRkYhTAqUtakQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/open-lens/node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.44.tgz", + "integrity": "sha512-uKTAWQuMEW1gJnl8F3eiz3kdk8CiaR5dMWWlGbHIq6dRbur2hoKaEnINR4UqkvvAhhY1YB0Xr5DV1H986Xu2EA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/open-lens/node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.44.tgz", + "integrity": "sha512-D9fBRhr44cK4YIKFikpktyUDLkZgVj0ISaSl8IjiTvjqTrE/9+E+dzTNHULn5tc3lHVLLxyVwMjJRr2G0D4O6w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, "packages/open-lens/node_modules/@types/estree": { "version": "0.0.51", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", @@ -39133,13 +40435,199 @@ }, "devDependencies": { "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.37", + "@swc/core": "^1.3.44", "@types/inquirer": "^9.0.3", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", "rimraf": "^4.1.2" } }, + "packages/release-tool/node_modules/@swc/core": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.44.tgz", + "integrity": "sha512-RC25C8nxOCdfGS//F9Q8aHKx4XoCsxvgO+sSUhvt7zDz1Y2ruVUTu2UOH0VeE0WkA8j6oEZH+xH2SUfDUkxXdA==", + "dev": true, + "hasInstallScript": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.44", + "@swc/core-darwin-x64": "1.3.44", + "@swc/core-linux-arm-gnueabihf": "1.3.44", + "@swc/core-linux-arm64-gnu": "1.3.44", + "@swc/core-linux-arm64-musl": "1.3.44", + "@swc/core-linux-x64-gnu": "1.3.44", + "@swc/core-linux-x64-musl": "1.3.44", + "@swc/core-win32-arm64-msvc": "1.3.44", + "@swc/core-win32-ia32-msvc": "1.3.44", + "@swc/core-win32-x64-msvc": "1.3.44" + } + }, + "packages/release-tool/node_modules/@swc/core-darwin-arm64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.44.tgz", + "integrity": "sha512-Y+oVsCjXUPvr3D9YLuB1gjP84TseM/CRkbPNrf+3JXQhsPEkgxdIdFP1cl/obeqMQrRgPpvSfK+TOvGuOuV22g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/release-tool/node_modules/@swc/core-darwin-x64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.44.tgz", + "integrity": "sha512-bM0IKBjlSD0yHJbd7bE3il5fTu3oUjUO2zjLkzfIx6tiqbmDyvOX8adaSqse9N+d8Ip9p26b5Vo7pMHq0POGkg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/release-tool/node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.44.tgz", + "integrity": "sha512-D4lfVwCbkWscDTb6btb89+bN0kgvjGBPfOmcvih7nY5hxaorwvp+PefkYAhFw8vKmL92lrnWUFNiTemVFN4bxg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/release-tool/node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.44.tgz", + "integrity": "sha512-muExPTrN26MFmtO+5uffkH5v4lmd8GdmyWvlC2tL95h7o9genTIQyr7kcSepGZrDe4fM9G6++5YfENhUpXHo+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/release-tool/node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.44.tgz", + "integrity": "sha512-MY1wY3kSIosjJKKCfFGniJFFVkt3oPvJLN4Dlj+bMgAt3O7anm8lGbyLqUpJ1Ep4rTsJj7ObO06DQiSWp4Fhcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/release-tool/node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.44.tgz", + "integrity": "sha512-xV4pDxJM06g0yUDTA22ZHgonzGqf/poIlgADRmEkx9cWWm5qLRhmWrrkVX1xZVvdlcXj1ERnia/UkvrDux96lg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/release-tool/node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.44.tgz", + "integrity": "sha512-NJnnlE8vCkKHoo/wIaoywNN/01vNsvhKUjBgUx865sUM/XWAIanpbV41yfdEkC+Iwd+/zB3ZZnOYql3b+Nn8aQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/release-tool/node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.44.tgz", + "integrity": "sha512-/xOtjZhX25GEOPLN55icjj9E061DDH7G0A9HfUAEilURgBbvm6bIlqK+t8mOKK0tOsDoHftdTBRkYhTAqUtakQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/release-tool/node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.44.tgz", + "integrity": "sha512-uKTAWQuMEW1gJnl8F3eiz3kdk8CiaR5dMWWlGbHIq6dRbur2hoKaEnINR4UqkvvAhhY1YB0Xr5DV1H986Xu2EA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/release-tool/node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.44.tgz", + "integrity": "sha512-D9fBRhr44cK4YIKFikpktyUDLkZgVj0ISaSl8IjiTvjqTrE/9+E+dzTNHULn5tc3lHVLLxyVwMjJRr2G0D4O6w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, "packages/release-tool/node_modules/@types/node": { "version": "16.18.16", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.16.tgz", @@ -39445,13 +40933,199 @@ }, "devDependencies": { "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.37", + "@swc/core": "^1.3.44", "@types/command-line-args": "^5.2.0", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", "rimraf": "^4.1.2" } }, + "packages/semver/node_modules/@swc/core": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.44.tgz", + "integrity": "sha512-RC25C8nxOCdfGS//F9Q8aHKx4XoCsxvgO+sSUhvt7zDz1Y2ruVUTu2UOH0VeE0WkA8j6oEZH+xH2SUfDUkxXdA==", + "dev": true, + "hasInstallScript": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.44", + "@swc/core-darwin-x64": "1.3.44", + "@swc/core-linux-arm-gnueabihf": "1.3.44", + "@swc/core-linux-arm64-gnu": "1.3.44", + "@swc/core-linux-arm64-musl": "1.3.44", + "@swc/core-linux-x64-gnu": "1.3.44", + "@swc/core-linux-x64-musl": "1.3.44", + "@swc/core-win32-arm64-msvc": "1.3.44", + "@swc/core-win32-ia32-msvc": "1.3.44", + "@swc/core-win32-x64-msvc": "1.3.44" + } + }, + "packages/semver/node_modules/@swc/core-darwin-arm64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.44.tgz", + "integrity": "sha512-Y+oVsCjXUPvr3D9YLuB1gjP84TseM/CRkbPNrf+3JXQhsPEkgxdIdFP1cl/obeqMQrRgPpvSfK+TOvGuOuV22g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/semver/node_modules/@swc/core-darwin-x64": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.44.tgz", + "integrity": "sha512-bM0IKBjlSD0yHJbd7bE3il5fTu3oUjUO2zjLkzfIx6tiqbmDyvOX8adaSqse9N+d8Ip9p26b5Vo7pMHq0POGkg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "packages/semver/node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.44.tgz", + "integrity": "sha512-D4lfVwCbkWscDTb6btb89+bN0kgvjGBPfOmcvih7nY5hxaorwvp+PefkYAhFw8vKmL92lrnWUFNiTemVFN4bxg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/semver/node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.44.tgz", + "integrity": "sha512-muExPTrN26MFmtO+5uffkH5v4lmd8GdmyWvlC2tL95h7o9genTIQyr7kcSepGZrDe4fM9G6++5YfENhUpXHo+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/semver/node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.44.tgz", + "integrity": "sha512-MY1wY3kSIosjJKKCfFGniJFFVkt3oPvJLN4Dlj+bMgAt3O7anm8lGbyLqUpJ1Ep4rTsJj7ObO06DQiSWp4Fhcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/semver/node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.44.tgz", + "integrity": "sha512-xV4pDxJM06g0yUDTA22ZHgonzGqf/poIlgADRmEkx9cWWm5qLRhmWrrkVX1xZVvdlcXj1ERnia/UkvrDux96lg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/semver/node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.44.tgz", + "integrity": "sha512-NJnnlE8vCkKHoo/wIaoywNN/01vNsvhKUjBgUx865sUM/XWAIanpbV41yfdEkC+Iwd+/zB3ZZnOYql3b+Nn8aQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "packages/semver/node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.44.tgz", + "integrity": "sha512-/xOtjZhX25GEOPLN55icjj9E061DDH7G0A9HfUAEilURgBbvm6bIlqK+t8mOKK0tOsDoHftdTBRkYhTAqUtakQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/semver/node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.44.tgz", + "integrity": "sha512-uKTAWQuMEW1gJnl8F3eiz3kdk8CiaR5dMWWlGbHIq6dRbur2hoKaEnINR4UqkvvAhhY1YB0Xr5DV1H986Xu2EA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "packages/semver/node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.44.tgz", + "integrity": "sha512-D9fBRhr44cK4YIKFikpktyUDLkZgVj0ISaSl8IjiTvjqTrE/9+E+dzTNHULn5tc3lHVLLxyVwMjJRr2G0D4O6w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, "packages/semver/node_modules/@types/node": { "version": "16.18.16", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.16.tgz", diff --git a/packages/bump-version-for-cron/package.json b/packages/bump-version-for-cron/package.json index cba08964d2..78781c6b58 100644 --- a/packages/bump-version-for-cron/package.json +++ b/packages/bump-version-for-cron/package.json @@ -23,7 +23,7 @@ }, "devDependencies": { "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.37", + "@swc/core": "^1.3.44", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", "rimraf": "^4.1.2" diff --git a/packages/cluster-settings/package.json b/packages/cluster-settings/package.json index f71236a0df..eb9719ae02 100644 --- a/packages/cluster-settings/package.json +++ b/packages/cluster-settings/package.json @@ -25,7 +25,7 @@ "devDependencies": { "@ogre-tools/injectable": "^15.1.2", "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.37", + "@swc/core": "^1.3.44", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", "rimraf": "^4.1.2" diff --git a/packages/core/package.json b/packages/core/package.json index 8c7d22ee2c..a585d71a18 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -197,7 +197,7 @@ "@material-ui/lab": "^4.0.0-alpha.60", "@sentry/types": "^6.19.7", "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.37", + "@swc/core": "^1.3.44", "@swc/jest": "^0.2.24", "@testing-library/dom": "^7.31.2", "@testing-library/jest-dom": "^5.16.5", diff --git a/packages/ensure-binaries/package.json b/packages/ensure-binaries/package.json index af8c7b12f3..a3100d3b9f 100644 --- a/packages/ensure-binaries/package.json +++ b/packages/ensure-binaries/package.json @@ -32,7 +32,7 @@ }, "devDependencies": { "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.37", + "@swc/core": "^1.3.44", "@types/cli-progress": "^3.11.0", "@types/gunzip-maybe": "^1.4.0", "@types/node": "^16.18.11", diff --git a/packages/generate-tray-icons/package.json b/packages/generate-tray-icons/package.json index f659fabcf1..bf0b1b49e1 100644 --- a/packages/generate-tray-icons/package.json +++ b/packages/generate-tray-icons/package.json @@ -23,7 +23,7 @@ }, "devDependencies": { "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.37", + "@swc/core": "^1.3.44", "@types/jsdom": "^20.0.1", "@types/node": "^18.11.18", "@types/sharp": "^0.31.1", diff --git a/packages/infrastructure/jest/package.json b/packages/infrastructure/jest/package.json index 6f75802b77..ffac66dd81 100644 --- a/packages/infrastructure/jest/package.json +++ b/packages/infrastructure/jest/package.json @@ -20,7 +20,7 @@ "license": "MIT", "homepage": "https://github.com/lensapp/lens", "dependencies": { - "@swc/core": "^1.3.38", + "@swc/core": "^1.3.44", "@swc/jest": "^0.2.23", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", diff --git a/packages/open-lens/package.json b/packages/open-lens/package.json index 34d259ed9c..6c6dd30998 100644 --- a/packages/open-lens/package.json +++ b/packages/open-lens/package.json @@ -224,7 +224,7 @@ "@k8slens/node-fetch": "^6.5.0-alpha.1", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.10", "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.37", + "@swc/core": "^1.3.44", "@swc/jest": "^0.2.24", "@types/byline": "^4.2.33", "@types/chart.js": "^2.9.36", diff --git a/packages/release-tool/package.json b/packages/release-tool/package.json index b98aa84153..8e03906d72 100644 --- a/packages/release-tool/package.json +++ b/packages/release-tool/package.json @@ -15,7 +15,7 @@ "type": "module", "devDependencies": { "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.37", + "@swc/core": "^1.3.44", "@types/inquirer": "^9.0.3", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", diff --git a/packages/semver/package.json b/packages/semver/package.json index 78ba4e3ae9..a27fe449bf 100644 --- a/packages/semver/package.json +++ b/packages/semver/package.json @@ -15,7 +15,7 @@ }, "devDependencies": { "@swc/cli": "^0.1.61", - "@swc/core": "^1.3.37", + "@swc/core": "^1.3.44", "@types/command-line-args": "^5.2.0", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", From 799c12040792d46f38207c95dd45b525271e1387 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Mar 2023 09:09:58 -0400 Subject: [PATCH 18/35] Bump rimraf from 4.4.0 to 4.4.1 (#7406) Bumps [rimraf](https://github.com/isaacs/rimraf) from 4.4.0 to 4.4.1. - [Release notes](https://github.com/isaacs/rimraf/releases) - [Changelog](https://github.com/isaacs/rimraf/blob/main/CHANGELOG.md) - [Commits](https://github.com/isaacs/rimraf/compare/v4.4.0...v4.4.1) --- updated-dependencies: - dependency-name: rimraf dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 34 ++++++++++----------- package.json | 2 +- packages/bump-version-for-cron/package.json | 2 +- packages/cluster-settings/package.json | 2 +- packages/core/package.json | 2 +- packages/ensure-binaries/package.json | 2 +- packages/extension-api/package.json | 2 +- packages/generate-tray-icons/package.json | 4 +-- packages/node-fetch/package.json | 4 +-- packages/open-lens/package.json | 4 +-- packages/release-tool/package.json | 2 +- packages/semver/package.json | 2 +- 12 files changed, 31 insertions(+), 31 deletions(-) diff --git a/package-lock.json b/package-lock.json index ccbc543df9..d9a38696c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "adr": "^1.4.3", "cross-env": "^7.0.3", "lerna": "^6.5.1", - "rimraf": "^4.4.0" + "rimraf": "^4.4.1" } }, "node_modules/@adobe/css-tools": { @@ -30108,9 +30108,9 @@ "integrity": "sha512-tYGfLpKIq9X7lrt4o3IkD9w9bpeAtsejfAqWNR98AoxfTsZqCepKa8eDlRiX8QMiCOD9vMx0/YbKLx0G1nPi5w==" }, "node_modules/rimraf": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.0.tgz", - "integrity": "sha512-X36S+qpCUR0HjXlkDe4NAOhS//aHH0Z+h8Ckf2auGJk3PTnx5rLmrHkwNdbVQuCSUhOyFrlRvFEllZOYE+yZGQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.1.tgz", + "integrity": "sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==", "dev": true, "dependencies": { "glob": "^9.2.0" @@ -34335,7 +34335,7 @@ "@swc/core": "^1.3.44", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", - "rimraf": "^4.1.2" + "rimraf": "^4.4.1" } }, "packages/bump-version-for-cron/node_modules/@swc/core": { @@ -34591,7 +34591,7 @@ "@swc/core": "^1.3.44", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", - "rimraf": "^4.1.2" + "rimraf": "^4.4.1" } }, "packages/cluster-settings/node_modules/@swc/core": { @@ -34975,7 +34975,7 @@ "react-select-event": "^5.5.1", "react-table": "^7.8.0", "react-window": "^1.8.8", - "rimraf": "^4.1.2", + "rimraf": "^4.4.1", "sass": "^1.58.2", "sass-loader": "^12.6.0", "style-loader": "^3.3.1", @@ -36249,7 +36249,7 @@ "@types/node": "^16.18.11", "@types/semver": "^7.3.13", "@types/tar-stream": "^2.2.2", - "rimraf": "^4.1.2" + "rimraf": "^4.4.1" } }, "packages/ensure-binaries/node_modules/@swc/core": { @@ -36458,7 +36458,7 @@ "@types/webpack-node-externals": "2.5.3", "css-loader": "^6.7.2", "node-loader": "^2.0.0", - "rimraf": "^4.1.2", + "rimraf": "^4.4.1", "style-loader": "^3.3.1", "ts-loader": "^9.4.2", "ts-node": "^10.9.1", @@ -36766,7 +36766,7 @@ "dependencies": { "arg": "^5.0.2", "jsdom": "^21.1.0", - "rimraf": "^4.1.2", + "rimraf": "^4.4.1", "sharp": "^0.31.3" }, "bin": { @@ -36778,7 +36778,7 @@ "@types/jsdom": "^20.0.1", "@types/node": "^18.11.18", "@types/sharp": "^0.31.1", - "rimraf": "^4.1.2" + "rimraf": "^4.4.1" } }, "packages/generate-tray-icons/node_modules/@swc/core": { @@ -38861,10 +38861,10 @@ "license": "MIT", "dependencies": { "node-fetch": "^3.3.0", - "rimraf": "^4.1.2" + "rimraf": "^4.4.1" }, "devDependencies": { - "rimraf": "^4.1.2", + "rimraf": "^4.4.1", "ts-loader": "^9.4.2", "ts-node": "^10.9.1", "typescript": "^4.9.5", @@ -39080,7 +39080,7 @@ "@ogre-tools/injectable-extension-for-mobx": "^15.1.2", "@ogre-tools/injectable-react": "^15.1.2", "mobx": "^6.8.0", - "rimraf": "^4.1.2" + "rimraf": "^4.4.1" }, "devDependencies": { "@electron/rebuild": "^3.2.10", @@ -39133,7 +39133,7 @@ "react-refresh": "^0.14.0", "react-refresh-typescript": "^2.0.7", "react-select": "^5.7.0", - "rimraf": "^4.1.2", + "rimraf": "^4.4.1", "run-script-os": "^1.1.6", "style-loader": "^3.3.1", "tailwindcss": "^3.2.4", @@ -40439,7 +40439,7 @@ "@types/inquirer": "^9.0.3", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", - "rimraf": "^4.1.2" + "rimraf": "^4.4.1" } }, "packages/release-tool/node_modules/@swc/core": { @@ -40937,7 +40937,7 @@ "@types/command-line-args": "^5.2.0", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", - "rimraf": "^4.1.2" + "rimraf": "^4.4.1" } }, "packages/semver/node_modules/@swc/core": { diff --git a/package.json b/package.json index 0a9f693adb..2bb6ef9f70 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,6 @@ "adr": "^1.4.3", "cross-env": "^7.0.3", "lerna": "^6.5.1", - "rimraf": "^4.4.0" + "rimraf": "^4.4.1" } } diff --git a/packages/bump-version-for-cron/package.json b/packages/bump-version-for-cron/package.json index 78781c6b58..efb3a3f786 100644 --- a/packages/bump-version-for-cron/package.json +++ b/packages/bump-version-for-cron/package.json @@ -26,6 +26,6 @@ "@swc/core": "^1.3.44", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", - "rimraf": "^4.1.2" + "rimraf": "^4.4.1" } } diff --git a/packages/cluster-settings/package.json b/packages/cluster-settings/package.json index eb9719ae02..aa9b8d6725 100644 --- a/packages/cluster-settings/package.json +++ b/packages/cluster-settings/package.json @@ -28,6 +28,6 @@ "@swc/core": "^1.3.44", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", - "rimraf": "^4.1.2" + "rimraf": "^4.4.1" } } diff --git a/packages/core/package.json b/packages/core/package.json index a585d71a18..7b04d2ce06 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -301,7 +301,7 @@ "react-select-event": "^5.5.1", "react-table": "^7.8.0", "react-window": "^1.8.8", - "rimraf": "^4.1.2", + "rimraf": "^4.4.1", "sass": "^1.58.2", "sass-loader": "^12.6.0", "style-loader": "^3.3.1", diff --git a/packages/ensure-binaries/package.json b/packages/ensure-binaries/package.json index a3100d3b9f..e12d4a0432 100644 --- a/packages/ensure-binaries/package.json +++ b/packages/ensure-binaries/package.json @@ -38,6 +38,6 @@ "@types/node": "^16.18.11", "@types/semver": "^7.3.13", "@types/tar-stream": "^2.2.2", - "rimraf": "^4.1.2" + "rimraf": "^4.4.1" } } diff --git a/packages/extension-api/package.json b/packages/extension-api/package.json index db2c221516..ab1156a70b 100644 --- a/packages/extension-api/package.json +++ b/packages/extension-api/package.json @@ -35,7 +35,7 @@ "@types/webpack-node-externals": "2.5.3", "css-loader": "^6.7.2", "node-loader": "^2.0.0", - "rimraf": "^4.1.2", + "rimraf": "^4.4.1", "style-loader": "^3.3.1", "ts-loader": "^9.4.2", "ts-node": "^10.9.1", diff --git a/packages/generate-tray-icons/package.json b/packages/generate-tray-icons/package.json index bf0b1b49e1..ce85daf62f 100644 --- a/packages/generate-tray-icons/package.json +++ b/packages/generate-tray-icons/package.json @@ -27,12 +27,12 @@ "@types/jsdom": "^20.0.1", "@types/node": "^18.11.18", "@types/sharp": "^0.31.1", - "rimraf": "^4.1.2" + "rimraf": "^4.4.1" }, "dependencies": { "arg": "^5.0.2", "jsdom": "^21.1.0", - "rimraf": "^4.1.2", + "rimraf": "^4.4.1", "sharp": "^0.31.3" } } diff --git a/packages/node-fetch/package.json b/packages/node-fetch/package.json index 40c542d335..0634ee5448 100644 --- a/packages/node-fetch/package.json +++ b/packages/node-fetch/package.json @@ -23,10 +23,10 @@ }, "dependencies": { "node-fetch": "^3.3.0", - "rimraf": "^4.1.2" + "rimraf": "^4.4.1" }, "devDependencies": { - "rimraf": "^4.1.2", + "rimraf": "^4.4.1", "ts-loader": "^9.4.2", "ts-node": "^10.9.1", "typescript": "^4.9.5", diff --git a/packages/open-lens/package.json b/packages/open-lens/package.json index 6c6dd30998..03be08828f 100644 --- a/packages/open-lens/package.json +++ b/packages/open-lens/package.json @@ -217,7 +217,7 @@ "@ogre-tools/injectable-extension-for-mobx": "^15.1.2", "@ogre-tools/injectable-react": "^15.1.2", "mobx": "^6.8.0", - "rimraf": "^4.1.2" + "rimraf": "^4.4.1" }, "devDependencies": { "@electron/rebuild": "^3.2.10", @@ -270,7 +270,7 @@ "react-refresh": "^0.14.0", "react-refresh-typescript": "^2.0.7", "react-select": "^5.7.0", - "rimraf": "^4.1.2", + "rimraf": "^4.4.1", "run-script-os": "^1.1.6", "style-loader": "^3.3.1", "tailwindcss": "^3.2.4", diff --git a/packages/release-tool/package.json b/packages/release-tool/package.json index 8e03906d72..b1c475aed2 100644 --- a/packages/release-tool/package.json +++ b/packages/release-tool/package.json @@ -19,7 +19,7 @@ "@types/inquirer": "^9.0.3", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", - "rimraf": "^4.1.2" + "rimraf": "^4.4.1" }, "dependencies": { "chalk": "^5.2.0", diff --git a/packages/semver/package.json b/packages/semver/package.json index a27fe449bf..25ed955b4b 100644 --- a/packages/semver/package.json +++ b/packages/semver/package.json @@ -19,6 +19,6 @@ "@types/command-line-args": "^5.2.0", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", - "rimraf": "^4.1.2" + "rimraf": "^4.4.1" } } From de0ee4e6f43b05a53e90ee65479d53f63743c397 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Mar 2023 09:23:05 -0400 Subject: [PATCH 19/35] Bump lerna from 6.5.1 to 6.6.1 (#7411) Bumps [lerna](https://github.com/lerna/lerna/tree/HEAD/packages/lerna) from 6.5.1 to 6.6.1. - [Release notes](https://github.com/lerna/lerna/releases) - [Changelog](https://github.com/lerna/lerna/blob/main/packages/lerna/CHANGELOG.md) - [Commits](https://github.com/lerna/lerna/commits/6.6.1/packages/lerna) --- updated-dependencies: - dependency-name: lerna dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 3785 +++++++++++++++++++++++++++++++++++++++++---- package.json | 2 +- 2 files changed, 3526 insertions(+), 261 deletions(-) diff --git a/package-lock.json b/package-lock.json index d9a38696c1..9cd17c91fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "devDependencies": { "adr": "^1.4.3", "cross-env": "^7.0.3", - "lerna": "^6.5.1", + "lerna": "^6.6.1", "rimraf": "^4.4.1" } }, @@ -4712,9 +4712,9 @@ "dev": true }, "node_modules/@lerna/child-process": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@lerna/child-process/-/child-process-6.5.1.tgz", - "integrity": "sha512-QfyleXSD9slh4qM54wDaqKVPvtUH1NJMgsFc9BabqSHO1Ttpandv1EAvTCN9Lu73RbCX3LJpn+BfJmnjHbjCyw==", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/@lerna/child-process/-/child-process-6.6.1.tgz", + "integrity": "sha512-yUCDCcRNNbI9UUsUB6FYEmDHpo5Tn/f0q5D7vhDP4i6Or8kBj82y7+e31hwfLvK2ykOYlDVs2MxAluH/+QUBOQ==", "dev": true, "dependencies": { "chalk": "^4.1.0", @@ -4785,12 +4785,12 @@ } }, "node_modules/@lerna/create": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@lerna/create/-/create-6.5.1.tgz", - "integrity": "sha512-ejERJnfA36jEuKrfM+94feLiyf2/hF2NoG923N0rE4rsmvRFPr1XLVPvAKleXW+Gdi/t1p410lJ7NKaLRMYCYw==", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/@lerna/create/-/create-6.6.1.tgz", + "integrity": "sha512-GDmHFhQ0mr0RcXWXrsLyfMV6ch/dZV/Ped1e6sFVQhsLL9P+FFXX1ZWxa/dQQ90VWF2qWcmK0+S/L3kUz2xvTA==", "dev": true, "dependencies": { - "@lerna/child-process": "6.5.1", + "@lerna/child-process": "6.6.1", "dedent": "^0.7.0", "fs-extra": "^9.1.0", "init-package-json": "^3.0.2", @@ -4820,6 +4820,716 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@lerna/legacy-package-management": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/@lerna/legacy-package-management/-/legacy-package-management-6.6.1.tgz", + "integrity": "sha512-0EYxSFr34VgeudA5rvjGJSY7s4seITMVB7AJ9LRFv9QDUk6jpvapV13ZAaKnhDTxX5vNCfnJuWHXXWq0KyPF/Q==", + "dev": true, + "dependencies": { + "@npmcli/arborist": "6.2.3", + "@npmcli/run-script": "4.1.7", + "@nrwl/devkit": ">=15.5.2 < 16", + "@octokit/rest": "19.0.3", + "byte-size": "7.0.0", + "chalk": "4.1.0", + "clone-deep": "4.0.1", + "cmd-shim": "5.0.0", + "columnify": "1.6.0", + "config-chain": "1.1.12", + "conventional-changelog-core": "4.2.4", + "conventional-recommended-bump": "6.1.0", + "cosmiconfig": "7.0.0", + "dedent": "0.7.0", + "dot-prop": "6.0.1", + "execa": "5.0.0", + "file-url": "3.0.0", + "find-up": "5.0.0", + "fs-extra": "9.1.0", + "get-port": "5.1.1", + "get-stream": "6.0.0", + "git-url-parse": "13.1.0", + "glob-parent": "5.1.2", + "globby": "11.1.0", + "graceful-fs": "4.2.10", + "has-unicode": "2.0.1", + "inquirer": "8.2.4", + "is-ci": "2.0.0", + "is-stream": "2.0.0", + "libnpmpublish": "6.0.4", + "load-json-file": "6.2.0", + "make-dir": "3.1.0", + "minimatch": "3.0.5", + "multimatch": "5.0.0", + "node-fetch": "2.6.7", + "npm-package-arg": "8.1.1", + "npm-packlist": "5.1.1", + "npm-registry-fetch": "14.0.3", + "npmlog": "6.0.2", + "p-map": "4.0.0", + "p-map-series": "2.1.0", + "p-queue": "6.6.2", + "p-waterfall": "2.1.1", + "pacote": "13.6.2", + "pify": "5.0.0", + "pretty-format": "29.4.3", + "read-cmd-shim": "3.0.0", + "read-package-json": "5.0.1", + "resolve-from": "5.0.0", + "semver": "7.3.8", + "signal-exit": "3.0.7", + "slash": "3.0.0", + "ssri": "9.0.1", + "strong-log-transformer": "2.1.0", + "tar": "6.1.11", + "temp-dir": "1.0.0", + "tempy": "1.0.0", + "upath": "2.0.1", + "uuid": "8.3.2", + "write-file-atomic": "4.0.1", + "write-pkg": "4.0.0", + "yargs": "16.2.0" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/cacache": { + "version": "17.0.5", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.5.tgz", + "integrity": "sha512-Y/PRQevNSsjAPWykl9aeGz8Pr+OI6BYM9fYDNMvOkuUiG9IhG4LEmaYrZZZvioMUEQ+cBCxT0v8wrnCURccyKA==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^9.3.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/cacache/node_modules/fs-minipass": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.1.tgz", + "integrity": "sha512-MhaJDcFRTuLidHrIttu0RDGyyXs/IYHVmlcxfLAEFIWjc1vdLAkdwT7Ace2u7DbitWC0toKMl5eJZRYNVreIMw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/cacache/node_modules/ssri": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.1.tgz", + "integrity": "sha512-WVy6di9DlPOeBWEjMScpNipeSX2jIZBGEn5Uuo8Q7aIuFEuDX0pw8RxcOjlD1TWP4obi24ki7m/13+nFpcbXrw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/@lerna/legacy-package-management/node_modules/cosmiconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", + "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/execa": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", + "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/get-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", + "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/glob": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", + "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^7.4.1", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/glob/node_modules/minimatch": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", + "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/make-fetch-happen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", + "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/make-fetch-happen/node_modules/ssri": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.1.tgz", + "integrity": "sha512-WVy6di9DlPOeBWEjMScpNipeSX2jIZBGEn5Uuo8Q7aIuFEuDX0pw8RxcOjlD1TWP4obi24ki7m/13+nFpcbXrw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/npm-registry-fetch": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.3.tgz", + "integrity": "sha512-YaeRbVNpnWvsGOjX2wk5s85XJ7l1qQBGAp724h8e2CZFFhMSuw9enom7K1mWVUtvXO1uUSFIAPofQK0pPN0ZcA==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^11.0.0", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^10.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/npm-registry-fetch/node_modules/npm-package-arg": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", + "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/pretty-format": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.4.3.tgz", + "integrity": "sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/@lerna/legacy-package-management/node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/tar/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/tempy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.0.tgz", + "integrity": "sha512-eLXG5B1G0mRPHmgH2WydPl5v4jH35qEn3y/rA/aahKhIa91Pn119SsU7n7v/433gtT9ONzC8ISvNHIh2JSTm0w==", + "dev": true, + "dependencies": { + "del": "^6.0.0", + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/tempy/node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/@lerna/legacy-package-management/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/@lerna/legacy-package-management/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/write-file-atomic": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + } + }, + "node_modules/@lerna/legacy-package-management/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@lerna/legacy-package-management/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@malept/cross-spawn-promise": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", @@ -5104,63 +5814,304 @@ } }, "node_modules/@npmcli/arborist": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-5.3.0.tgz", - "integrity": "sha512-+rZ9zgL1lnbl8Xbb1NQdMjveOMwj4lIYfcDtyJHHi5x4X8jtR6m8SXooJMZy5vmFVZ8w7A2Bnd/oX9eTuU8w5A==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-6.2.3.tgz", + "integrity": "sha512-lpGOC2ilSJXcc2zfW9QtukcCTcMbl3fVI0z4wvFB2AFIl0C+Q6Wv7ccrpdrQa8rvJ1ZVuc6qkX7HVTyKlzGqKA==", "dev": true, "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/installed-package-contents": "^1.0.7", - "@npmcli/map-workspaces": "^2.0.3", - "@npmcli/metavuln-calculator": "^3.0.1", - "@npmcli/move-file": "^2.0.0", - "@npmcli/name-from-folder": "^1.0.1", - "@npmcli/node-gyp": "^2.0.0", - "@npmcli/package-json": "^2.0.0", - "@npmcli/run-script": "^4.1.3", - "bin-links": "^3.0.0", - "cacache": "^16.0.6", + "@npmcli/fs": "^3.1.0", + "@npmcli/installed-package-contents": "^2.0.0", + "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/metavuln-calculator": "^5.0.0", + "@npmcli/name-from-folder": "^2.0.0", + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^3.0.0", + "@npmcli/query": "^3.0.0", + "@npmcli/run-script": "^6.0.0", + "bin-links": "^4.0.1", + "cacache": "^17.0.4", "common-ancestor-path": "^1.0.1", - "json-parse-even-better-errors": "^2.3.1", + "hosted-git-info": "^6.1.1", + "json-parse-even-better-errors": "^3.0.0", "json-stringify-nice": "^1.1.4", - "mkdirp": "^1.0.4", - "mkdirp-infer-owner": "^2.0.0", - "nopt": "^5.0.0", - "npm-install-checks": "^5.0.0", - "npm-package-arg": "^9.0.0", - "npm-pick-manifest": "^7.0.0", - "npm-registry-fetch": "^13.0.0", - "npmlog": "^6.0.2", - "pacote": "^13.6.1", - "parse-conflict-json": "^2.0.1", - "proc-log": "^2.0.0", + "minimatch": "^6.1.6", + "nopt": "^7.0.0", + "npm-install-checks": "^6.0.0", + "npm-package-arg": "^10.1.0", + "npm-pick-manifest": "^8.0.1", + "npm-registry-fetch": "^14.0.3", + "npmlog": "^7.0.1", + "pacote": "^15.0.8", + "parse-conflict-json": "^3.0.0", + "proc-log": "^3.0.0", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^1.0.1", - "read-package-json-fast": "^2.0.2", - "readdir-scoped-modules": "^1.1.0", - "rimraf": "^3.0.2", + "read-package-json-fast": "^3.0.2", "semver": "^7.3.7", - "ssri": "^9.0.0", - "treeverse": "^2.0.0", + "ssri": "^10.0.1", + "treeverse": "^3.0.0", "walk-up-path": "^1.0.0" }, "bin": { "arborist": "bin/index.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/@npmcli/git": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.0.4.tgz", + "integrity": "sha512-5yZghx+u5M47LghaybLCkdSyFzV/w4OuH12d96HO389Ik9CDsLaDZJVynSGGVJOLn6gy/k7Dz5XYcplM3uxXRg==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^6.0.0", + "lru-cache": "^7.4.4", + "npm-pick-manifest": "^8.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/@npmcli/git/node_modules/which": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", + "integrity": "sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/@npmcli/promise-spawn": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz", + "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==", + "dev": true, + "dependencies": { + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", + "integrity": "sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/@npmcli/run-script": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.0.tgz", + "integrity": "sha512-ql+AbRur1TeOdl1FY+RAwGW9fcr4ZwiVKabdvm93mujGREVuVLbdkXRJDrkTXSdCjaxYydr1wlA2v67jxWG5BQ==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^6.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/@npmcli/run-script/node_modules/which": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", + "integrity": "sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/@npmcli/arborist/node_modules/cacache": { + "version": "17.0.5", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.5.tgz", + "integrity": "sha512-Y/PRQevNSsjAPWykl9aeGz8Pr+OI6BYM9fYDNMvOkuUiG9IhG4LEmaYrZZZvioMUEQ+cBCxT0v8wrnCURccyKA==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^9.3.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/cacache/node_modules/glob": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", + "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^7.4.1", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/arborist/node_modules/cacache/node_modules/minimatch": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", + "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/arborist/node_modules/fs-minipass": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.1.tgz", + "integrity": "sha512-MhaJDcFRTuLidHrIttu0RDGyyXs/IYHVmlcxfLAEFIWjc1vdLAkdwT7Ace2u7DbitWC0toKMl5eJZRYNVreIMw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@npmcli/arborist/node_modules/hosted-git-info": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", - "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/ignore-walk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.2.tgz", + "integrity": "sha512-ezmQ1Dg2b3jVZh2Dh+ar6Eu2MqNSTkyb32HU2MAQQQX9tKM3q/UQ/9lf03lQ5hW+fOeoMnwxwkleZ0xcNp0/qg==", + "dev": true, + "dependencies": { + "minimatch": "^7.4.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/ignore-walk/node_modules/minimatch": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", + "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/arborist/node_modules/json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@npmcli/arborist/node_modules/lru-cache": { @@ -5172,21 +6123,542 @@ "node": ">=12" } }, - "node_modules/@npmcli/arborist/node_modules/npm-package-arg": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", - "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "node_modules/@npmcli/arborist/node_modules/make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", "dev": true, "dependencies": { - "hosted-git-info": "^5.0.0", - "proc-log": "^2.0.1", - "semver": "^7.3.5", - "validate-npm-package-name": "^4.0.0" + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" }, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/@npmcli/arborist/node_modules/make-fetch-happen/node_modules/@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dev": true, + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/make-fetch-happen/node_modules/cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/make-fetch-happen/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/arborist/node_modules/make-fetch-happen/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/arborist/node_modules/make-fetch-happen/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/arborist/node_modules/make-fetch-happen/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@npmcli/arborist/node_modules/make-fetch-happen/node_modules/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/make-fetch-happen/node_modules/unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "dev": true, + "dependencies": { + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/make-fetch-happen/node_modules/unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/minimatch": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-6.2.0.tgz", + "integrity": "sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/arborist/node_modules/minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/@npmcli/arborist/node_modules/minipass-fetch/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@npmcli/arborist/node_modules/node-gyp": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz", + "integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/@npmcli/arborist/node_modules/node-gyp/node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/node-gyp/node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/nopt": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.1.0.tgz", + "integrity": "sha512-ZFPLe9Iu0tnx7oWhFxAo4s7QTn8+NNDDxYNaKLjE7Dp0tbakQ3M1QhQzsnzXHQBTUO3K9BmwaxnyO8Ayn2I95Q==", + "dev": true, + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/nopt/node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/normalize-package-data": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", + "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "dev": true, + "dependencies": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/npm-package-arg": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", + "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/npm-packlist": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-7.0.4.tgz", + "integrity": "sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==", + "dev": true, + "dependencies": { + "ignore-walk": "^6.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/npm-registry-fetch": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.3.tgz", + "integrity": "sha512-YaeRbVNpnWvsGOjX2wk5s85XJ7l1qQBGAp724h8e2CZFFhMSuw9enom7K1mWVUtvXO1uUSFIAPofQK0pPN0ZcA==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^11.0.0", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^10.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", + "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/npm-registry-fetch/node_modules/minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/@npmcli/arborist/node_modules/npmlog": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-7.0.1.tgz", + "integrity": "sha512-uJ0YFk/mCQpLBt+bxN88AKd+gyqZvZDbtiNxk6Waqcj2aPRyfVx8ITawkyQynxUagInjdYT1+qj4NfA5KJJUxg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^4.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^5.0.0", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/npmlog/node_modules/are-we-there-yet": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-4.0.0.tgz", + "integrity": "sha512-nSXlV+u3vtVjRgihdTzbfWYzxPWGo424zPgQbHD0ZqIla3jqYAewDcvee0Ua2hjS5IfTAmjGlx1Jf0PKwjZDEw==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^4.1.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/npmlog/node_modules/gauge": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-5.0.0.tgz", + "integrity": "sha512-0s5T5eciEG7Q3ugkxAkFtaDhrrhXsCRivA5y8C9WMHWuI8UlMOJg7+Iwf7Mccii+Dfs3H5jHepU0joPVyQU0Lw==", + "dev": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/pacote": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.1.1.tgz", + "integrity": "sha512-eeqEe77QrA6auZxNHIp+1TzHQ0HBKf5V6c8zcaYZ134EJe1lCi+fjXATkNiEEfbG+e50nu02GLvUtmZcGOYabQ==", + "dev": true, + "dependencies": { + "@npmcli/git": "^4.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^6.0.1", + "@npmcli/run-script": "^6.0.0", + "cacache": "^17.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^4.0.0", + "npm-package-arg": "^10.0.0", + "npm-packlist": "^7.0.0", + "npm-pick-manifest": "^8.0.0", + "npm-registry-fetch": "^14.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^6.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^1.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/read-package-json": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.1.tgz", + "integrity": "sha512-AaHqXxfAVa+fNL07x8iAghfKOds/XXsu7zoouIVsbm7PEbQ3nMWXlvjcbrNLjElnUHWQtAo4QEa0RXuvD4XlpA==", + "dev": true, + "dependencies": { + "glob": "^9.3.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/read-package-json/node_modules/glob": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", + "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^7.4.1", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/arborist/node_modules/read-package-json/node_modules/minimatch": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", + "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/arborist/node_modules/readable-stream": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.3.0.tgz", + "integrity": "sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ==", + "dev": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@npmcli/arborist/node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -5202,6 +6674,74 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@npmcli/arborist/node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@npmcli/arborist/node_modules/ssri": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.1.tgz", + "integrity": "sha512-WVy6di9DlPOeBWEjMScpNipeSX2jIZBGEn5Uuo8Q7aIuFEuDX0pw8RxcOjlD1TWP4obi24ki7m/13+nFpcbXrw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/@npmcli/fs": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", @@ -5235,6 +6775,18 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/@npmcli/git/node_modules/hosted-git-info": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/@npmcli/git/node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -5244,37 +6796,88 @@ "node": ">=12" } }, - "node_modules/@npmcli/installed-package-contents": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", - "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "node_modules/@npmcli/git/node_modules/npm-install-checks": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", + "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", "dev": true, "dependencies": { - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - }, - "bin": { - "installed-package-contents": "index.js" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@npmcli/map-workspaces": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-2.0.4.tgz", - "integrity": "sha512-bMo0aAfwhVwqoVM5UzX1DJnlvVvzDCHae821jv48L1EsrYwfOZChlqWYXEtto/+BkBXetPbEWgau++/brh4oVg==", - "dev": true, - "dependencies": { - "@npmcli/name-from-folder": "^1.0.1", - "glob": "^8.0.1", - "minimatch": "^5.0.1", - "read-package-json-fast": "^2.0.3" + "semver": "^7.1.1" }, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/@npmcli/git/node_modules/npm-normalize-package-bin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/npm-package-arg": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^5.0.0", + "proc-log": "^2.0.1", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/npm-pick-manifest": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-7.0.2.tgz", + "integrity": "sha512-gk37SyRmlIjvTfcYl6RzDbSmS9Y4TOBXfsPnoYqTHARNgWbyDiCSMLUpmALDj4jjcTZpURiEfsSHJj9k7EV4Rw==", + "dev": true, + "dependencies": { + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^2.0.0", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "dev": true, + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/map-workspaces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-3.0.3.tgz", + "integrity": "sha512-HlCvFuTzw4UNoKyZdqiNrln+qMF71QJkxy2dsusV8QQdoa89e2TF4dATCzBxbl4zzRzdDoWWyP5ADVrNAH9cRQ==", + "dev": true, + "dependencies": { + "@npmcli/name-from-folder": "^2.0.0", + "glob": "^9.3.1", + "minimatch": "^7.4.2", + "read-package-json-fast": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/@npmcli/map-workspaces/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -5285,6 +6888,299 @@ } }, "node_modules/@npmcli/map-workspaces/node_modules/glob": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", + "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^7.4.1", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/map-workspaces/node_modules/minimatch": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", + "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/metavuln-calculator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-5.0.0.tgz", + "integrity": "sha512-BBFQx4M12wiEuVwCgtX/Depx0B/+NHMwDWOlXT41/Pdy5W/1Fenk+hibUlMSrFWwASbX+fY90UbILAEIYH02/A==", + "dev": true, + "dependencies": { + "cacache": "^17.0.0", + "json-parse-even-better-errors": "^3.0.0", + "pacote": "^15.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/git": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.0.4.tgz", + "integrity": "sha512-5yZghx+u5M47LghaybLCkdSyFzV/w4OuH12d96HO389Ik9CDsLaDZJVynSGGVJOLn6gy/k7Dz5XYcplM3uxXRg==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^6.0.0", + "lru-cache": "^7.4.4", + "npm-pick-manifest": "^8.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/promise-spawn": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz", + "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==", + "dev": true, + "dependencies": { + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/@npmcli/run-script": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.0.tgz", + "integrity": "sha512-ql+AbRur1TeOdl1FY+RAwGW9fcr4ZwiVKabdvm93mujGREVuVLbdkXRJDrkTXSdCjaxYydr1wlA2v67jxWG5BQ==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^6.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/cacache": { + "version": "17.0.5", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.5.tgz", + "integrity": "sha512-Y/PRQevNSsjAPWykl9aeGz8Pr+OI6BYM9fYDNMvOkuUiG9IhG4LEmaYrZZZvioMUEQ+cBCxT0v8wrnCURccyKA==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^9.3.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/fs-minipass": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.1.tgz", + "integrity": "sha512-MhaJDcFRTuLidHrIttu0RDGyyXs/IYHVmlcxfLAEFIWjc1vdLAkdwT7Ace2u7DbitWC0toKMl5eJZRYNVreIMw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/glob": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", + "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^7.4.1", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/ignore-walk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.2.tgz", + "integrity": "sha512-ezmQ1Dg2b3jVZh2Dh+ar6Eu2MqNSTkyb32HU2MAQQQX9tKM3q/UQ/9lf03lQ5hW+fOeoMnwxwkleZ0xcNp0/qg==", + "dev": true, + "dependencies": { + "minimatch": "^7.4.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/make-fetch-happen/node_modules/@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dev": true, + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/make-fetch-happen/node_modules/cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/make-fetch-happen/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/make-fetch-happen/node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", @@ -5303,7 +7199,7 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@npmcli/map-workspaces/node_modules/minimatch": { + "node_modules/@npmcli/metavuln-calculator/node_modules/make-fetch-happen/node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", @@ -5315,21 +7211,493 @@ "node": ">=10" } }, - "node_modules/@npmcli/metavuln-calculator": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-3.1.1.tgz", - "integrity": "sha512-n69ygIaqAedecLeVH3KnO39M6ZHiJ2dEv5A7DGvcqCB8q17BGUgW8QaanIkbWUo2aYGZqJaOORTLAlIvKjNDKA==", + "node_modules/@npmcli/metavuln-calculator/node_modules/make-fetch-happen/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, "dependencies": { - "cacache": "^16.0.0", - "json-parse-even-better-errors": "^2.3.1", - "pacote": "^13.0.3", - "semver": "^7.3.5" + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/make-fetch-happen/node_modules/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" }, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/@npmcli/metavuln-calculator/node_modules/make-fetch-happen/node_modules/unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "dev": true, + "dependencies": { + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/make-fetch-happen/node_modules/unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/minimatch": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", + "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/minipass-fetch/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/node-gyp": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz", + "integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/node-gyp/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/node-gyp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/node-gyp/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/node-gyp/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/normalize-package-data": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", + "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "dev": true, + "dependencies": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/npm-package-arg": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", + "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/npm-packlist": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-7.0.4.tgz", + "integrity": "sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==", + "dev": true, + "dependencies": { + "ignore-walk": "^6.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/npm-registry-fetch": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.3.tgz", + "integrity": "sha512-YaeRbVNpnWvsGOjX2wk5s85XJ7l1qQBGAp724h8e2CZFFhMSuw9enom7K1mWVUtvXO1uUSFIAPofQK0pPN0ZcA==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^11.0.0", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^10.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", + "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/npm-registry-fetch/node_modules/minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/pacote": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.1.1.tgz", + "integrity": "sha512-eeqEe77QrA6auZxNHIp+1TzHQ0HBKf5V6c8zcaYZ134EJe1lCi+fjXATkNiEEfbG+e50nu02GLvUtmZcGOYabQ==", + "dev": true, + "dependencies": { + "@npmcli/git": "^4.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^6.0.1", + "@npmcli/run-script": "^6.0.0", + "cacache": "^17.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^4.0.0", + "npm-package-arg": "^10.0.0", + "npm-packlist": "^7.0.0", + "npm-pick-manifest": "^8.0.0", + "npm-registry-fetch": "^14.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^6.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^1.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/read-package-json": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.1.tgz", + "integrity": "sha512-AaHqXxfAVa+fNL07x8iAghfKOds/XXsu7zoouIVsbm7PEbQ3nMWXlvjcbrNLjElnUHWQtAo4QEa0RXuvD4XlpA==", + "dev": true, + "dependencies": { + "glob": "^9.3.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/ssri": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.1.tgz", + "integrity": "sha512-WVy6di9DlPOeBWEjMScpNipeSX2jIZBGEn5Uuo8Q7aIuFEuDX0pw8RxcOjlD1TWP4obi24ki7m/13+nFpcbXrw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/which": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", + "integrity": "sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/metavuln-calculator/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/@npmcli/move-file": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", @@ -5360,30 +7728,42 @@ } }, "node_modules/@npmcli/name-from-folder": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-1.0.1.tgz", - "integrity": "sha512-qq3oEfcLFwNfEYOQ8HLimRGKlD8WSeGEdtUa7hmzpR8Sa7haL1KVQrvgO6wqMjhWFFVjgtrh1gIxDz+P8sjUaA==", - "dev": true - }, - "node_modules/@npmcli/node-gyp": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz", - "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", + "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-2.0.0.tgz", + "integrity": "sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==", "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@npmcli/package-json": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-2.0.0.tgz", - "integrity": "sha512-42jnZ6yl16GzjWSH7vtrmWyJDGVa/LXPdpN2rcUWolFjc9ON2N3uz0qdBbQACfmhuJZ2lbKYtmK5qx68ZPLHMA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-3.0.0.tgz", + "integrity": "sha512-NnuPuM97xfiCpbTEJYtEuKz6CFbpUHtaT0+5via5pQeI25omvQDFbp1GcGJ/c4zvL/WX0qbde6YiLgfZbWFgvg==", "dev": true, "dependencies": { - "json-parse-even-better-errors": "^2.3.1" + "json-parse-even-better-errors": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@npmcli/promise-spawn": { @@ -5398,6 +7778,18 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/@npmcli/query": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/query/-/query-3.0.0.tgz", + "integrity": "sha512-MFNDSJNgsLZIEBVZ0Q9w9K7o07j5N4o4yjtdz2uEpuCZlXGMuPENiRaFYk0vRqAA64qVuUQwC05g27fRtfUgnA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/@npmcli/run-script": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-4.1.7.tgz", @@ -5414,6 +7806,15 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/@npmcli/run-script/node_modules/@npmcli/node-gyp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz", + "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/@npmcli/run-script/node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -5518,6 +7919,25 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/@npmcli/run-script/node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "node_modules/@npmcli/run-script/node_modules/read-package-json-fast": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", + "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@npmcli/run-script/node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -6465,6 +8885,15 @@ "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.1.0.tgz", + "integrity": "sha512-a31EnjuIDSX8IXBUib3cYLDRlPMU36AWX4xS8ysLaNu4ZzUesDiPt83pgrW2X1YLMe5L2HbDyaKK5BrL4cNKaQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/@sinclair/typebox": { "version": "0.25.24", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", @@ -6935,6 +9364,42 @@ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "devOptional": true }, + "node_modules/@tufjs/models": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.1.tgz", + "integrity": "sha512-AY0VoG/AXdlSOocuREfPoEW4SNhOPp/7fw6mpAxfVIny1uZ+0fEtMoCi7NhELSlqQIRLMu7RgfKhkxT+AJ+EXg==", + "dev": true, + "dependencies": { + "minimatch": "^7.4.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/minimatch": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", + "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@types/aria-query": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", @@ -8962,12 +11427,6 @@ "node": ">=0.10.0" } }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true - }, "node_modules/asar": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/asar/-/asar-3.2.0.tgz", @@ -9564,44 +12023,49 @@ } }, "node_modules/bin-links": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-3.0.3.tgz", - "integrity": "sha512-zKdnMPWEdh4F5INR07/eBrodC7QrF5JKvqskjz/ZZRXg5YSAZIbn8zGhbhUrElzHBZ2fvEQdOU59RHcTG3GiwA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-4.0.1.tgz", + "integrity": "sha512-bmFEM39CyX336ZGGRsGPlc6jZHriIoHacOQcTt72MktIjpPhZoP4te2jOyUXF3BLILmJ8aNLncoPVeIIFlrDeA==", "dev": true, "dependencies": { - "cmd-shim": "^5.0.0", - "mkdirp-infer-owner": "^2.0.0", - "npm-normalize-package-bin": "^2.0.0", - "read-cmd-shim": "^3.0.0", - "rimraf": "^3.0.0", - "write-file-atomic": "^4.0.0" + "cmd-shim": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "read-cmd-shim": "^4.0.0", + "write-file-atomic": "^5.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/bin-links/node_modules/npm-normalize-package-bin": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", - "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "node_modules/bin-links/node_modules/cmd-shim": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-6.0.1.tgz", + "integrity": "sha512-S9iI9y0nKR4hwEQsVWpyxld/6kRfGepGfzff83FcaiEBpmvlbA2nnGe7Cylgrx2f/p1P5S5wpRm9oL8z1PbS3Q==", "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/bin-links/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "node_modules/bin-links/node_modules/read-cmd-shim": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz", + "integrity": "sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/bin-links/node_modules/write-file-atomic": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.0.tgz", + "integrity": "sha512-R7NYMnHSlV42K54lwY9lvW6MnSm1HSJqZL3xiSgi9E7//FYaI74r2G0rd+/X6VAMkHEdzxQaU5HUOXWUz5kA/w==", "dev": true, "dependencies": { - "glob": "^7.1.3" + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/bin-version": { @@ -11860,15 +14324,6 @@ } } }, - "node_modules/debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -12249,16 +14704,6 @@ "node": ">=0.8.0" } }, - "node_modules/dezalgo": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", - "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", - "dev": true, - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, "node_modules/diacritics-map": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/diacritics-map/-/diacritics-map-0.1.0.tgz", @@ -15196,6 +17641,15 @@ "url": "https://github.com/sindresorhus/file-type?sponsor=1" } }, + "node_modules/file-url": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/file-url/-/file-url-3.0.0.tgz", + "integrity": "sha512-g872QGsHexznxkIAdK8UiZRe7SkE6kvylShU4Nsj8NvfvZag7S0QuQ4IgvPDkk75HxgjIVDwycFTDAgIiO4nDA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/filehound": { "version": "1.17.6", "resolved": "https://registry.npmjs.org/filehound/-/filehound-1.17.6.tgz", @@ -21263,9 +23717,9 @@ } }, "node_modules/just-diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-5.2.0.tgz", - "integrity": "sha512-6ufhP9SHjb7jibNFrNxyFZ6od3g+An6Ai9mhGRvcYe8UJlH0prseN64M+6ZBBUoKYHZsitDP42gAJ8+eVWr3lw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-6.0.2.tgz", + "integrity": "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA==", "dev": true }, "node_modules/just-diff-apply": { @@ -21344,14 +23798,15 @@ "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==" }, "node_modules/lerna": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/lerna/-/lerna-6.5.1.tgz", - "integrity": "sha512-Va1bysubwWdoWZ1ncKcoTGBXNAu/10/TwELb550TTivXmEWjCCdek4eX0BNLTEYKxu3tpV2UEeqVisUiWGn4WA==", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/lerna/-/lerna-6.6.1.tgz", + "integrity": "sha512-WJtrvmbmR+6hMB9b5pvsxJzew0lRL6hARgW/My9BM4vYaxwPIA2I0riv3qQu5Zd7lYse7FEqJkTnl9Kn1bXhLA==", "dev": true, "dependencies": { - "@lerna/child-process": "6.5.1", - "@lerna/create": "6.5.1", - "@npmcli/arborist": "5.3.0", + "@lerna/child-process": "6.6.1", + "@lerna/create": "6.6.1", + "@lerna/legacy-package-management": "6.6.1", + "@npmcli/arborist": "6.2.3", "@npmcli/run-script": "4.1.7", "@nrwl/devkit": ">=15.5.2 < 16", "@octokit/plugin-enterprise-rest": "6.0.1", @@ -21393,7 +23848,7 @@ "node-fetch": "2.6.7", "npm-package-arg": "8.1.1", "npm-packlist": "5.1.1", - "npm-registry-fetch": "13.3.0", + "npm-registry-fetch": "^14.0.3", "npmlog": "^6.0.2", "nx": ">=15.5.2 < 16", "p-map": "4.0.0", @@ -21402,14 +23857,13 @@ "p-queue": "6.6.2", "p-reduce": "2.1.0", "p-waterfall": "2.1.1", - "pacote": "13.6.1", - "path-exists": "4.0.0", + "pacote": "13.6.2", "pify": "5.0.0", "read-cmd-shim": "3.0.0", "read-package-json": "5.0.1", "resolve-from": "5.0.0", - "rimraf": "^3.0.2", - "semver": "7.3.4", + "rimraf": "^4.4.1", + "semver": "^7.3.8", "signal-exit": "3.0.7", "slash": "3.0.0", "ssri": "9.0.1", @@ -21433,6 +23887,75 @@ "node": "^14.15.0 || >=16.0.0" } }, + "node_modules/lerna/node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/lerna/node_modules/cacache": { + "version": "17.0.5", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.5.tgz", + "integrity": "sha512-Y/PRQevNSsjAPWykl9aeGz8Pr+OI6BYM9fYDNMvOkuUiG9IhG4LEmaYrZZZvioMUEQ+cBCxT0v8wrnCURccyKA==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^9.3.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/lerna/node_modules/cacache/node_modules/fs-minipass": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.1.tgz", + "integrity": "sha512-MhaJDcFRTuLidHrIttu0RDGyyXs/IYHVmlcxfLAEFIWjc1vdLAkdwT7Ace2u7DbitWC0toKMl5eJZRYNVreIMw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/lerna/node_modules/cacache/node_modules/minipass": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", + "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/lerna/node_modules/cacache/node_modules/ssri": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.1.tgz", + "integrity": "sha512-WVy6di9DlPOeBWEjMScpNipeSX2jIZBGEn5Uuo8Q7aIuFEuDX0pw8RxcOjlD1TWP4obi24ki7m/13+nFpcbXrw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/lerna/node_modules/chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -21521,6 +24044,69 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lerna/node_modules/glob": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", + "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^7.4.1", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/lerna/node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/lerna/node_modules/glob/node_modules/minimatch": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", + "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/lerna/node_modules/glob/node_modules/minipass": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", + "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/lerna/node_modules/hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/lerna/node_modules/inquirer": { "version": "8.2.5", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", @@ -21585,15 +24171,59 @@ } }, "node_modules/lerna/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/lerna/node_modules/make-fetch-happen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", + "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/lerna/node_modules/make-fetch-happen/node_modules/minipass": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", + "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/lerna/node_modules/make-fetch-happen/node_modules/ssri": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.1.tgz", + "integrity": "sha512-WVy6di9DlPOeBWEjMScpNipeSX2jIZBGEn5Uuo8Q7aIuFEuDX0pw8RxcOjlD1TWP4obi24ki7m/13+nFpcbXrw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/lerna/node_modules/minimatch": { @@ -21620,6 +24250,32 @@ "node": ">=8" } }, + "node_modules/lerna/node_modules/minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/lerna/node_modules/minipass-fetch/node_modules/minipass": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", + "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/lerna/node_modules/node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", @@ -21640,6 +24296,60 @@ } } }, + "node_modules/lerna/node_modules/npm-registry-fetch": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.3.tgz", + "integrity": "sha512-YaeRbVNpnWvsGOjX2wk5s85XJ7l1qQBGAp724h8e2CZFFhMSuw9enom7K1mWVUtvXO1uUSFIAPofQK0pPN0ZcA==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^11.0.0", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^10.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/lerna/node_modules/npm-registry-fetch/node_modules/minipass": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", + "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/lerna/node_modules/npm-registry-fetch/node_modules/npm-package-arg": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", + "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/lerna/node_modules/npm-registry-fetch/node_modules/validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/lerna/node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -21664,34 +24374,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lerna/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "node_modules/lerna/node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/lerna/node_modules/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "node_modules/lerna/node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" }, "engines": { - "node": ">=10" + "node": ">= 10" } }, "node_modules/lerna/node_modules/tar": { @@ -21717,6 +24420,30 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, + "node_modules/lerna/node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/lerna/node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/lerna/node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -24111,31 +26838,37 @@ } }, "node_modules/npm-bundled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", - "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", + "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", "dev": true, "dependencies": { - "npm-normalize-package-bin": "^1.0.1" + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm-install-checks": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", - "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.1.0.tgz", + "integrity": "sha512-udSGENih/5xKh3Ex+L0PtZcOt0Pa+6ppDLnpG5D49/EhMja3LupaY9E/DtJTxyFBwE09ot7Fc+H4DywnZNWTVA==", "dev": true, "dependencies": { "semver": "^7.1.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "dev": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.0.tgz", + "integrity": "sha512-g+DPQSkusnk7HYXr75NtzkIP4+N81i3RPsGFidF3DzHd9MT9wWngmqoeg/fnHFz5MNdtG4w03s+QnhewSLTT2Q==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, "node_modules/npm-package-arg": { "version": "8.1.1", @@ -24254,31 +26987,46 @@ "node": ">=10" } }, - "node_modules/npm-pick-manifest": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-7.0.2.tgz", - "integrity": "sha512-gk37SyRmlIjvTfcYl6RzDbSmS9Y4TOBXfsPnoYqTHARNgWbyDiCSMLUpmALDj4jjcTZpURiEfsSHJj9k7EV4Rw==", + "node_modules/npm-packlist/node_modules/npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", "dev": true, "dependencies": { - "npm-install-checks": "^5.0.0", - "npm-normalize-package-bin": "^2.0.0", - "npm-package-arg": "^9.0.0", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm-packlist/node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "node_modules/npm-pick-manifest": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.1.tgz", + "integrity": "sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA==", + "dev": true, + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^10.0.0", "semver": "^7.3.5" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm-pick-manifest/node_modules/hosted-git-info": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", - "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm-pick-manifest/node_modules/lru-cache": { @@ -24290,28 +27038,40 @@ "node": ">=12" } }, - "node_modules/npm-pick-manifest/node_modules/npm-normalize-package-bin": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", - "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/npm-pick-manifest/node_modules/npm-package-arg": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", - "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", + "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", "dev": true, "dependencies": { - "hosted-git-info": "^5.0.0", - "proc-log": "^2.0.1", + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", "semver": "^7.3.5", - "validate-npm-package-name": "^4.0.0" + "validate-npm-package-name": "^5.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-pick-manifest/node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-pick-manifest/node_modules/validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm-registry-fetch": { @@ -27462,9 +30222,9 @@ } }, "node_modules/pacote": { - "version": "13.6.1", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.6.1.tgz", - "integrity": "sha512-L+2BI1ougAPsFjXRyBhcKmfT016NscRFLv6Pz5EiNf1CCFJFU0pSKKQwsZTyAQB+sTuUL4TyFyp6J1Ork3dOqw==", + "version": "13.6.2", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.6.2.tgz", + "integrity": "sha512-Gu8fU3GsvOPkak2CkbojR7vjs3k3P9cA6uazKTHdsdV0gpCEQq2opelnEv30KRQWgVzP5Vd/5umjcedma3MKtg==", "dev": true, "dependencies": { "@npmcli/git": "^3.0.0", @@ -27496,6 +30256,22 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/pacote/node_modules/@npmcli/installed-package-contents": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", + "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, + "dependencies": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "installed-package-contents": "index.js" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/pacote/node_modules/hosted-git-info": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", @@ -27529,6 +30305,33 @@ "node": ">=8" } }, + "node_modules/pacote/node_modules/npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/pacote/node_modules/npm-install-checks": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", + "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/pacote/node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, "node_modules/pacote/node_modules/npm-package-arg": { "version": "9.1.2", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", @@ -27544,6 +30347,43 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/pacote/node_modules/npm-pick-manifest": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-7.0.2.tgz", + "integrity": "sha512-gk37SyRmlIjvTfcYl6RzDbSmS9Y4TOBXfsPnoYqTHARNgWbyDiCSMLUpmALDj4jjcTZpURiEfsSHJj9k7EV4Rw==", + "dev": true, + "dependencies": { + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^2.0.0", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/pacote/node_modules/npm-pick-manifest/node_modules/npm-normalize-package-bin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/pacote/node_modules/read-package-json-fast": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", + "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/pacote/node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -27592,17 +30432,26 @@ } }, "node_modules/parse-conflict-json": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-2.0.2.tgz", - "integrity": "sha512-jDbRGb00TAPFsKWCpZZOT93SxVP9nONOSgES3AevqRq/CHvavEBvKAjxX9p5Y5F0RZLxH9Ufd9+RwtCsa+lFDA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-3.0.1.tgz", + "integrity": "sha512-01TvEktc68vwbJOtWZluyWeVGWjP+bZwXtPDMQVbBKzbJ/vZBif0L69KH1+cHv1SZ6e0FKLvjyHe8mqsIqYOmw==", "dev": true, "dependencies": { - "json-parse-even-better-errors": "^2.3.1", - "just-diff": "^5.0.1", + "json-parse-even-better-errors": "^3.0.0", + "just-diff": "^6.0.0", "just-diff-apply": "^5.2.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/parse-conflict-json/node_modules/json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/parse-json": { @@ -29378,16 +32227,25 @@ } }, "node_modules/read-package-json-fast": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", - "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", "dev": true, "dependencies": { - "json-parse-even-better-errors": "^2.3.0", - "npm-normalize-package-bin": "^1.0.1" + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/read-package-json/node_modules/brace-expansion": { @@ -29466,6 +32324,12 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/read-package-json/node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, "node_modules/read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -29674,19 +32538,6 @@ "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/readdir-scoped-modules": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, - "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -30797,6 +33648,215 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/sigstore": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.2.0.tgz", + "integrity": "sha512-Fr9+W1nkBSIZCkJQR7jDn/zI0UXNsVpp+7mDQkCnZOIxG9p6yNXBx9xntHsfUyYHE55XDkkVV3+rYbrkzAeesA==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.1.0", + "make-fetch-happen": "^11.0.1", + "tuf-js": "^1.0.0" + }, + "bin": { + "sigstore": "bin/sigstore.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/sigstore/node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/sigstore/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/sigstore/node_modules/cacache": { + "version": "17.0.5", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.5.tgz", + "integrity": "sha512-Y/PRQevNSsjAPWykl9aeGz8Pr+OI6BYM9fYDNMvOkuUiG9IhG4LEmaYrZZZvioMUEQ+cBCxT0v8wrnCURccyKA==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^9.3.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/sigstore/node_modules/fs-minipass": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.1.tgz", + "integrity": "sha512-MhaJDcFRTuLidHrIttu0RDGyyXs/IYHVmlcxfLAEFIWjc1vdLAkdwT7Ace2u7DbitWC0toKMl5eJZRYNVreIMw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/sigstore/node_modules/glob": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", + "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^7.4.1", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sigstore/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/sigstore/node_modules/make-fetch-happen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", + "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/sigstore/node_modules/minimatch": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", + "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sigstore/node_modules/minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/sigstore/node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sigstore/node_modules/ssri": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.1.tgz", + "integrity": "sha512-WVy6di9DlPOeBWEjMScpNipeSX2jIZBGEn5Uuo8Q7aIuFEuDX0pw8RxcOjlD1TWP4obi24ki7m/13+nFpcbXrw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/sigstore/node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/sigstore/node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/simple-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", @@ -32564,12 +35624,12 @@ } }, "node_modules/treeverse": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/treeverse/-/treeverse-2.0.0.tgz", - "integrity": "sha512-N5gJCkLu1aXccpOTtqV6ddSEi6ZmGkh3hjmbu1IjcavJK4qyOVQmi0myQKM7z5jVGmD68SJoliaVrMmVObhj6A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/treeverse/-/treeverse-3.0.0.tgz", + "integrity": "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ==", "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/trim-newlines": { @@ -32749,6 +35809,211 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, + "node_modules/tuf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.2.tgz", + "integrity": "sha512-gBfbnS6khluxjvoFCpRV0fhWT265xNfpiNXOcBX0Ze6HGbPhe93UG5V5DdKcgm/aXsMadnY76l/h6j63GmJS5g==", + "dev": true, + "dependencies": { + "@tufjs/models": "1.0.1", + "make-fetch-happen": "^11.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/tuf-js/node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/tuf-js/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/tuf-js/node_modules/cacache": { + "version": "17.0.5", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.5.tgz", + "integrity": "sha512-Y/PRQevNSsjAPWykl9aeGz8Pr+OI6BYM9fYDNMvOkuUiG9IhG4LEmaYrZZZvioMUEQ+cBCxT0v8wrnCURccyKA==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^9.3.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/tuf-js/node_modules/fs-minipass": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.1.tgz", + "integrity": "sha512-MhaJDcFRTuLidHrIttu0RDGyyXs/IYHVmlcxfLAEFIWjc1vdLAkdwT7Ace2u7DbitWC0toKMl5eJZRYNVreIMw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/tuf-js/node_modules/glob": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", + "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "minimatch": "^7.4.1", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tuf-js/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/tuf-js/node_modules/make-fetch-happen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", + "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^4.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/tuf-js/node_modules/minimatch": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", + "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tuf-js/node_modules/minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/tuf-js/node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/tuf-js/node_modules/ssri": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.1.tgz", + "integrity": "sha512-WVy6di9DlPOeBWEjMScpNipeSX2jIZBGEn5Uuo8Q7aIuFEuDX0pw8RxcOjlD1TWP4obi24ki7m/13+nFpcbXrw==", + "dev": true, + "dependencies": { + "minipass": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/tuf-js/node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/tuf-js/node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", diff --git a/package.json b/package.json index 2bb6ef9f70..00b7c62388 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "devDependencies": { "adr": "^1.4.3", "cross-env": "^7.0.3", - "lerna": "^6.5.1", + "lerna": "^6.6.1", "rimraf": "^4.4.1" } } From 37c92c8fd1448027d0e4f6af898d4ddda033ef52 Mon Sep 17 00:00:00 2001 From: Jim Ehrismann <40840436+jim-docker@users.noreply.github.com> Date: Fri, 31 Mar 2023 10:37:59 -0400 Subject: [PATCH 20/35] Make ServiceAccount kubeconfig context name differ from cluster context name (#7433) Signed-off-by: Jim Ehrismann --- .../kubeconfig-route/get-service-account-route.injectable.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/main/routes/kubeconfig-route/get-service-account-route.injectable.ts b/packages/core/src/main/routes/kubeconfig-route/get-service-account-route.injectable.ts index b6b77d5a40..08aef8da1d 100644 --- a/packages/core/src/main/routes/kubeconfig-route/get-service-account-route.injectable.ts +++ b/packages/core/src/main/routes/kubeconfig-route/get-service-account-route.injectable.ts @@ -84,7 +84,7 @@ function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster ], "contexts": [ { - "name": cluster.contextName.get(), + "name": [cluster.contextName.get(), username].join("-"), "context": { "user": username, "cluster": cluster.contextName.get(), From a0fea203004f1a98399e0ca18b8217df8f9d453d Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 31 Mar 2023 13:37:29 -0400 Subject: [PATCH 21/35] Stop all extensions before quitting app (#7450) Signed-off-by: Sebastian Malton --- .../stopping/main/stop-all.injectable.ts | 25 +++++++++++++++++++ .../stop-services-and-exit-app.injectable.ts | 5 +++- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 packages/core/src/features/extensions/stopping/main/stop-all.injectable.ts diff --git a/packages/core/src/features/extensions/stopping/main/stop-all.injectable.ts b/packages/core/src/features/extensions/stopping/main/stop-all.injectable.ts new file mode 100644 index 0000000000..ce3d69d723 --- /dev/null +++ b/packages/core/src/features/extensions/stopping/main/stop-all.injectable.ts @@ -0,0 +1,25 @@ +/** + * 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 extensionInjectable from "../../../../extensions/extension-loader/extension/extension.injectable"; +import extensionsInjectable from "../../../../extensions/extensions.injectable"; + +const stopAllExtensionsInjectable = getInjectable({ + id: "stop-all-extensions", + instantiate: (di) => { + const extensionInstances = di.inject(extensionsInjectable); + + return async () => { + for (const instance of extensionInstances.get()) { + const extension = di.inject(extensionInjectable, instance); + + await instance.disable(); + extension.deregister(); + } + }; + }, +}); + +export default stopAllExtensionsInjectable; diff --git a/packages/core/src/main/stop-services-and-exit-app.injectable.ts b/packages/core/src/main/stop-services-and-exit-app.injectable.ts index 402862b462..f9bd436818 100644 --- a/packages/core/src/main/stop-services-and-exit-app.injectable.ts +++ b/packages/core/src/main/stop-services-and-exit-app.injectable.ts @@ -8,6 +8,7 @@ import clusterManagerInjectable from "./cluster/manager.injectable"; import loggerInjectable from "../common/logger.injectable"; import closeAllWindowsInjectable from "./start-main-application/lens-window/hide-all-windows/close-all-windows.injectable"; import emitAppEventInjectable from "../common/app-event-bus/emit-event.injectable"; +import stopAllExtensionsInjectable from "../features/extensions/stopping/main/stop-all.injectable"; const stopServicesAndExitAppInjectable = getInjectable({ id: "stop-services-and-exit-app", @@ -18,11 +19,13 @@ const stopServicesAndExitAppInjectable = getInjectable({ const logger = di.inject(loggerInjectable); const closeAllWindows = di.inject(closeAllWindowsInjectable); const emitAppEvent = di.inject(emitAppEventInjectable); + const stopAllExtensions = di.inject(stopAllExtensionsInjectable); - return () => { + return async () => { emitAppEvent({ name: "service", action: "close" }); closeAllWindows(); clusterManager.stop(); + await stopAllExtensions(); logger.info("SERVICE:QUIT"); setTimeout(exitApp, 1000); }; From c48b53fd5e5364db2efcc043996ccdb398b77153 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 31 Mar 2023 13:49:46 -0400 Subject: [PATCH 22/35] Correct dependencies of open-lens (#7451) Signed-off-by: Sebastian Malton --- package-lock.json | 6 +++--- packages/open-lens/package.json | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9cd17c91fd..539916d8a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42328,16 +42328,15 @@ "@k8slens/core": "^6.5.0-alpha.3", "@k8slens/ensure-binaries": "^6.5.0-alpha.1", "@k8slens/feature-core": "^6.5.0-alpha.1", - "@k8slens/generate-tray-icons": "^6.5.0-alpha.1", "@k8slens/legacy-extension-example": "^1.0.0-alpha.1", "@k8slens/legacy-extensions": "^1.0.0-alpha.1", "@k8slens/messaging": "^1.0.0-alpha.1", "@k8slens/messaging-for-main": "^1.0.0-alpha.1", "@k8slens/messaging-for-renderer": "^1.0.0-alpha.1", + "@k8slens/node-fetch": "^6.5.0-alpha.1", "@k8slens/react-application": "^1.0.0-alpha.0", "@k8slens/run-many": "^1.0.0-alpha.1", "@k8slens/startable-stoppable": "^1.0.0-alpha.1", - "@k8slens/test-utils": "^1.0.0-alpha.1", "@k8slens/utilities": "^1.0.0-alpha.1", "@ogre-tools/fp": "^15.1.2", "@ogre-tools/injectable": "^15.1.2", @@ -42349,7 +42348,8 @@ }, "devDependencies": { "@electron/rebuild": "^3.2.10", - "@k8slens/node-fetch": "^6.5.0-alpha.1", + "@k8slens/generate-tray-icons": "^6.5.0-alpha.1", + "@k8slens/test-utils": "^1.0.0-alpha.1", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.10", "@swc/cli": "^0.1.61", "@swc/core": "^1.3.44", diff --git a/packages/open-lens/package.json b/packages/open-lens/package.json index 03be08828f..950b0d2648 100644 --- a/packages/open-lens/package.json +++ b/packages/open-lens/package.json @@ -200,16 +200,15 @@ "@k8slens/core": "^6.5.0-alpha.3", "@k8slens/ensure-binaries": "^6.5.0-alpha.1", "@k8slens/feature-core": "^6.5.0-alpha.1", - "@k8slens/generate-tray-icons": "^6.5.0-alpha.1", "@k8slens/legacy-extension-example": "^1.0.0-alpha.1", "@k8slens/legacy-extensions": "^1.0.0-alpha.1", "@k8slens/messaging": "^1.0.0-alpha.1", "@k8slens/messaging-for-main": "^1.0.0-alpha.1", "@k8slens/messaging-for-renderer": "^1.0.0-alpha.1", + "@k8slens/node-fetch": "^6.5.0-alpha.1", "@k8slens/react-application": "^1.0.0-alpha.0", "@k8slens/run-many": "^1.0.0-alpha.1", "@k8slens/startable-stoppable": "^1.0.0-alpha.1", - "@k8slens/test-utils": "^1.0.0-alpha.1", "@k8slens/utilities": "^1.0.0-alpha.1", "@ogre-tools/fp": "^15.1.2", "@ogre-tools/injectable": "^15.1.2", @@ -221,7 +220,8 @@ }, "devDependencies": { "@electron/rebuild": "^3.2.10", - "@k8slens/node-fetch": "^6.5.0-alpha.1", + "@k8slens/generate-tray-icons": "^6.5.0-alpha.1", + "@k8slens/test-utils": "^1.0.0-alpha.1", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.10", "@swc/cli": "^0.1.61", "@swc/core": "^1.3.44", From 2884dea195edb524b80087e7b55de0c6584316a5 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 31 Mar 2023 14:21:07 -0400 Subject: [PATCH 23/35] Fix app crash on quit (#7407) (#7452) * Fix app crash on quit (#7407) * Fix app crash on quit Signed-off-by: Sebastian Malton * Back out disabling extensions on quit Signed-off-by: Sebastian Malton --------- Signed-off-by: Sebastian Malton * Fixup cherry-pick Signed-off-by: Sebastian Malton --------- Signed-off-by: Sebastian Malton --- ...efore-closing-of-application.injectable.ts | 45 +++++++++++++++---- .../create-lens-window.injectable.ts | 4 +- .../runnable-tokens/phases.ts | 2 +- .../resolve-system-proxy-window.injectable.ts | 4 +- 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/packages/core/src/main/electron-app/runnables/setup-runnables-before-closing-of-application.injectable.ts b/packages/core/src/main/electron-app/runnables/setup-runnables-before-closing-of-application.injectable.ts index 0ba1b68137..9843d2c223 100644 --- a/packages/core/src/main/electron-app/runnables/setup-runnables-before-closing-of-application.injectable.ts +++ b/packages/core/src/main/electron-app/runnables/setup-runnables-before-closing-of-application.injectable.ts @@ -8,7 +8,7 @@ import { beforeQuitOfFrontEndInjectionToken, beforeQuitOfBackEndInjectionToken } import electronAppInjectable from "../electron-app.injectable"; import isIntegrationTestingInjectable from "../../../common/vars/is-integration-testing.injectable"; import autoUpdaterInjectable from "../features/auto-updater.injectable"; -import { runManySyncFor } from "@k8slens/run-many"; +import { runManySyncFor, runManyFor } from "@k8slens/run-many"; const setupRunnablesBeforeClosingOfApplicationInjectable = getInjectable({ id: "setup-closing-of-application", @@ -16,8 +16,9 @@ const setupRunnablesBeforeClosingOfApplicationInjectable = getInjectable({ instantiate: (di) => ({ run: () => { const runManySync = runManySyncFor(di); + const runMany = runManyFor(di); const runRunnablesBeforeQuitOfFrontEnd = runManySync(beforeQuitOfFrontEndInjectionToken); - const runRunnablesBeforeQuitOfBackEnd = runManySync(beforeQuitOfBackEndInjectionToken); + const runRunnablesBeforeQuitOfBackEnd = runMany(beforeQuitOfBackEndInjectionToken); const app = di.inject(electronAppInjectable); const isIntegrationTesting = di.inject(isIntegrationTestingInjectable); const autoUpdater = di.inject(autoUpdaterInjectable); @@ -27,17 +28,43 @@ const setupRunnablesBeforeClosingOfApplicationInjectable = getInjectable({ isAutoUpdating = true; }); - app.on("will-quit", (event) => { + app.on("will-quit", () => { runRunnablesBeforeQuitOfFrontEnd(); - const shouldQuitBackEnd = isIntegrationTesting || isAutoUpdating; + let isAsyncQuitting = false; - if (shouldQuitBackEnd) { - runRunnablesBeforeQuitOfBackEnd(); - } else { - // IMPORTANT: This cannot be destructured as it would break binding of "this" for the Electron event + const doAsyncQuit = (event: Electron.Event, exitCode = 0) => { + if (isAsyncQuitting) { + return; + } + + isAsyncQuitting = true; + + void (async () => { + try { + await runRunnablesBeforeQuitOfBackEnd(); + } catch (error) { + console.error("A beforeQuitOfBackEnd failed!!!!", error); + exitCode = 1; + } + + app.exit(exitCode); + })(); + }; + + app.on("will-quit", (event) => { + runRunnablesBeforeQuitOfFrontEnd(); event.preventDefault(); - } + + if (isIntegrationTesting || isAutoUpdating) { + doAsyncQuit(event); + } + }); + + app.on("quit", (event, exitCode) => { + event.preventDefault(); + doAsyncQuit(event, exitCode); + }); }); return undefined; diff --git a/packages/core/src/main/start-main-application/lens-window/application-window/create-lens-window.injectable.ts b/packages/core/src/main/start-main-application/lens-window/application-window/create-lens-window.injectable.ts index e3854f6df6..3d6e636c8a 100644 --- a/packages/core/src/main/start-main-application/lens-window/application-window/create-lens-window.injectable.ts +++ b/packages/core/src/main/start-main-application/lens-window/application-window/create-lens-window.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import type { ContentSource, ElectronWindowTitleBarStyle } from "./create-electron-window.injectable"; -import createElectronWindowForInjectable from "./create-electron-window.injectable"; +import createElectronWindowInjectable from "./create-electron-window.injectable"; import type { ClusterFrameInfo } from "../../../../common/cluster-frames.injectable"; export interface ElectronWindow { @@ -59,7 +59,7 @@ const createLensWindowInjectable = getInjectable({ id: "create-lens-window", instantiate: (di) => { - const createElectronWindow = di.inject(createElectronWindowForInjectable); + const createElectronWindow = di.inject(createElectronWindowInjectable); return (configuration: LensWindowConfiguration): LensWindow => { let browserWindow: ElectronWindow | undefined; diff --git a/packages/core/src/main/start-main-application/runnable-tokens/phases.ts b/packages/core/src/main/start-main-application/runnable-tokens/phases.ts index 5808062fb2..b5844436e1 100644 --- a/packages/core/src/main/start-main-application/runnable-tokens/phases.ts +++ b/packages/core/src/main/start-main-application/runnable-tokens/phases.ts @@ -10,7 +10,7 @@ export const beforeQuitOfFrontEndInjectionToken = getInjectionToken({ +export const beforeQuitOfBackEndInjectionToken = getInjectionToken({ id: "before-quit-of-back-end", }); diff --git a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.injectable.ts b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.injectable.ts index 9dcfed4edf..91536c8204 100644 --- a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.injectable.ts +++ b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.injectable.ts @@ -12,13 +12,13 @@ const resolveSystemProxyWindowInjectable = getInjectable({ const app = di.inject(electronAppInjectable); await app.whenReady(); - + const window = new BrowserWindow({ show: false, paintWhenInitiallyHidden: false, }); - window.hide(); + window.hide(); return window; }, From 908a3cabe17b088a22589457b1f7a9b31e9c23bd Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 31 Mar 2023 14:21:31 -0400 Subject: [PATCH 24/35] Close Lens Proxy on quit of backend (#7453) - Extract global shared state of shell sessions Signed-off-by: Sebastian Malton --- .../lens-proxy/close-on-quit.injectable.ts | 21 +++++++++++ .../core/src/main/lens-proxy/lens-proxy.ts | 13 +++++-- .../local-shell-session/open.injectable.ts | 4 +++ .../node-shell-session/open.injectable.ts | 4 +++ .../shell-session/processes.injectable.ts | 15 ++++++++ .../shell-session/shell-envs.injectable.ts | 14 ++++++++ .../src/main/shell-session/shell-session.ts | 35 ++++++------------- .../clean-up-shell-sessions.injectable.ts | 24 +++++++++++-- 8 files changed, 99 insertions(+), 31 deletions(-) create mode 100644 packages/core/src/main/lens-proxy/close-on-quit.injectable.ts create mode 100644 packages/core/src/main/shell-session/processes.injectable.ts create mode 100644 packages/core/src/main/shell-session/shell-envs.injectable.ts diff --git a/packages/core/src/main/lens-proxy/close-on-quit.injectable.ts b/packages/core/src/main/lens-proxy/close-on-quit.injectable.ts new file mode 100644 index 0000000000..2ff22d6cf6 --- /dev/null +++ b/packages/core/src/main/lens-proxy/close-on-quit.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 { beforeQuitOfBackEndInjectionToken } from "../start-main-application/runnable-tokens/phases"; +import lensProxyInjectable from "./lens-proxy.injectable"; + +const closeLensProxyOnQuitInjectable = getInjectable({ + id: "close-lens-proxy-on-quit", + instantiate: (di) => ({ + run: async () => { + const lensProxy = di.inject(lensProxyInjectable); + + await lensProxy.close(); + }, + }), + injectionToken: beforeQuitOfBackEndInjectionToken, +}); + +export default closeLensProxyOnQuitInjectable; diff --git a/packages/core/src/main/lens-proxy/lens-proxy.ts b/packages/core/src/main/lens-proxy/lens-proxy.ts index 629e6a0f12..ce5a54bdf1 100644 --- a/packages/core/src/main/lens-proxy/lens-proxy.ts +++ b/packages/core/src/main/lens-proxy/lens-proxy.ts @@ -48,7 +48,7 @@ export function isLongRunningRequest(reqUrl: string) { /** * This is the list of ports that chrome considers unsafe to allow HTTP - * conntections to. Because they are the standard ports for processes that are + * connections to. Because they are the standard ports for processes that are * too forgiving in the connection types they accept. * * If we get one of these ports, the easiest thing to do is to just try again. @@ -166,10 +166,17 @@ export class LensProxy { } close() { + if (this.closed) { + return; + } + + // mark as closed immediately + this.closed = true; this.dependencies.logger.info("[LENS-PROXY]: Closing server"); - this.proxyServer.close(); - this.closed = true; + return new Promise((resolve) => { + this.proxyServer.close(() => resolve()); + }); } protected configureProxy(proxy: httpProxy): httpProxy { diff --git a/packages/core/src/main/shell-session/local-shell-session/open.injectable.ts b/packages/core/src/main/shell-session/local-shell-session/open.injectable.ts index c7d396b41a..29cf79e63a 100644 --- a/packages/core/src/main/shell-session/local-shell-session/open.injectable.ts +++ b/packages/core/src/main/shell-session/local-shell-session/open.injectable.ts @@ -25,6 +25,8 @@ import statInjectable from "../../../common/fs/stat.injectable"; import kubeconfigManagerInjectable from "../../kubeconfig-manager/kubeconfig-manager.injectable"; import userPreferencesStateInjectable from "../../../features/user-preferences/common/state.injectable"; import userShellSettingInjectable from "../../../features/user-preferences/common/shell-setting.injectable"; +import shellSessionEnvsInjectable from "../shell-envs.injectable"; +import shellSessionProcessesInjectable from "../processes.injectable"; export interface OpenLocalShellSessionArgs { websocket: WebSocket; @@ -48,6 +50,8 @@ const openLocalShellSessionInjectable = getInjectable({ userShellSetting: di.inject(userShellSettingInjectable), appName: di.inject(appNameInjectable), buildVersion: di.inject(buildVersionInjectable), + shellSessionEnvs: di.inject(shellSessionEnvsInjectable), + shellSessionProcesses: di.inject(shellSessionProcessesInjectable), modifyTerminalShellEnv: di.inject(modifyTerminalShellEnvInjectable), emitAppEvent: di.inject(emitAppEventInjectable), getDirnameOfPath: di.inject(getDirnameOfPathInjectable), diff --git a/packages/core/src/main/shell-session/node-shell-session/open.injectable.ts b/packages/core/src/main/shell-session/node-shell-session/open.injectable.ts index d2ce8ffb17..bdff572b12 100644 --- a/packages/core/src/main/shell-session/node-shell-session/open.injectable.ts +++ b/packages/core/src/main/shell-session/node-shell-session/open.injectable.ts @@ -22,6 +22,8 @@ import createKubeApiInjectable from "../../../common/k8s-api/create-kube-api.inj import loadProxyKubeconfigInjectable from "../../cluster/load-proxy-kubeconfig.injectable"; import kubeconfigManagerInjectable from "../../kubeconfig-manager/kubeconfig-manager.injectable"; import userShellSettingInjectable from "../../../features/user-preferences/common/shell-setting.injectable"; +import shellSessionEnvsInjectable from "../shell-envs.injectable"; +import shellSessionProcessesInjectable from "../processes.injectable"; export interface NodeShellSessionArgs { websocket: WebSocket; @@ -43,6 +45,8 @@ const openNodeShellSessionInjectable = getInjectable({ userShellSetting: di.inject(userShellSettingInjectable), appName: di.inject(appNameInjectable), buildVersion: di.inject(buildVersionInjectable), + shellSessionEnvs: di.inject(shellSessionEnvsInjectable), + shellSessionProcesses: di.inject(shellSessionProcessesInjectable), createKubeJsonApiForCluster: di.inject(createKubeJsonApiForClusterInjectable), computeShellEnvironment: di.inject(computeShellEnvironmentInjectable), spawnPty: di.inject(spawnPtyInjectable), diff --git a/packages/core/src/main/shell-session/processes.injectable.ts b/packages/core/src/main/shell-session/processes.injectable.ts new file mode 100644 index 0000000000..ffe9934401 --- /dev/null +++ b/packages/core/src/main/shell-session/processes.injectable.ts @@ -0,0 +1,15 @@ +/** + * 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 { IPty } from "node-pty"; + +export type ShellSessionProcesses = Map; + +const shellSessionProcessesInjectable = getInjectable({ + id: "shell-session-processes", + instantiate: (): ShellSessionProcesses => new Map(), +}); + +export default shellSessionProcessesInjectable; diff --git a/packages/core/src/main/shell-session/shell-envs.injectable.ts b/packages/core/src/main/shell-session/shell-envs.injectable.ts new file mode 100644 index 0000000000..4b866c825b --- /dev/null +++ b/packages/core/src/main/shell-session/shell-envs.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"; + +export type ShellSessionEnvs = Map>; + +const shellSessionEnvsInjectable = getInjectable({ + id: "shell-session-envs", + instantiate: (): ShellSessionEnvs => new Map(), +}); + +export default shellSessionEnvsInjectable; diff --git a/packages/core/src/main/shell-session/shell-session.ts b/packages/core/src/main/shell-session/shell-session.ts index ae1434287a..90c8e80297 100644 --- a/packages/core/src/main/shell-session/shell-session.ts +++ b/packages/core/src/main/shell-session/shell-session.ts @@ -19,6 +19,8 @@ import type { InitializableState } from "../../common/initializable-state/create import type { EmitAppEvent } from "../../common/app-event-bus/emit-event.injectable"; import type { Stat } from "../../common/fs/stat.injectable"; import type { IComputedValue } from "mobx"; +import type { ShellSessionEnvs } from "./shell-envs.injectable"; +import type { ShellSessionProcesses } from "./processes.injectable"; export class ShellOpenError extends Error { constructor(message: string, options?: ErrorOptions) { @@ -113,6 +115,8 @@ export interface ShellSessionDependencies { readonly buildVersion: InitializableState; readonly proxyKubeconfigPath: string; readonly directoryContainingKubectl: string; + readonly shellSessionEnvs: ShellSessionEnvs; + readonly shellSessionProcesses: ShellSessionProcesses; computeShellEnvironment: ComputeShellEnvironment; spawnPty: SpawnPty; emitAppEvent: EmitAppEvent; @@ -129,25 +133,6 @@ export interface ShellSessionArgs { export abstract class ShellSession { abstract readonly ShellType: string; - private static readonly shellEnvs = new Map>(); - private static readonly processes = new Map(); - - /** - * Kill all remaining shell backing processes. Should be called when about to - * quit - */ - public static cleanup(): void { - for (const shellProcess of this.processes.values()) { - try { - process.kill(shellProcess.pid); - } catch { - // ignore error - } - } - - this.processes.clear(); - } - protected running = false; protected readonly terminalId: string; protected readonly kubectl: Kubectl; @@ -157,8 +142,8 @@ export abstract class ShellSession { protected abstract get cwd(): string | undefined; protected ensureShellProcess(shell: string, args: string[], env: Partial>, cwd: string): { shellProcess: pty.IPty; resume: boolean } { - const resume = ShellSession.processes.has(this.terminalId); - const shellProcess = getOrInsertWith(ShellSession.processes, this.terminalId, () => ( + const resume = this.dependencies.shellSessionProcesses.has(this.terminalId); + const shellProcess = getOrInsertWith(this.dependencies.shellSessionProcesses, this.terminalId, () => ( this.dependencies.spawnPty(shell, args, { rows: 30, cols: 80, @@ -304,7 +289,7 @@ export abstract class ShellSession { try { this.dependencies.logger.info(`[SHELL-SESSION]: Killing shell process (pid=${shellProcess.pid}) for ${this.terminalId}`); shellProcess.kill(); - ShellSession.processes.delete(this.terminalId); + this.dependencies.shellSessionProcesses.delete(this.terminalId); } catch (error) { this.dependencies.logger.warn(`[SHELL-SESSION]: failed to kill shell process (pid=${shellProcess.pid}) for ${this.terminalId}`, error); } @@ -321,15 +306,15 @@ export abstract class ShellSession { protected async getCachedShellEnv() { const { id: clusterId } = this.cluster; - let env = ShellSession.shellEnvs.get(clusterId); + let env = this.dependencies.shellSessionEnvs.get(clusterId); if (!env) { env = await this.getShellEnv(); - ShellSession.shellEnvs.set(clusterId, env); + this.dependencies.shellSessionEnvs.set(clusterId, env); } else { // refresh env in the background this.getShellEnv().then((shellEnv: any) => { - ShellSession.shellEnvs.set(clusterId, shellEnv); + this.dependencies.shellSessionEnvs.set(clusterId, shellEnv); }); } diff --git a/packages/core/src/main/start-main-application/runnables/clean-up-shell-sessions.injectable.ts b/packages/core/src/main/start-main-application/runnables/clean-up-shell-sessions.injectable.ts index 2388f0fa73..fd428dd1fe 100644 --- a/packages/core/src/main/start-main-application/runnables/clean-up-shell-sessions.injectable.ts +++ b/packages/core/src/main/start-main-application/runnables/clean-up-shell-sessions.injectable.ts @@ -4,13 +4,31 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { beforeQuitOfBackEndInjectionToken } from "../runnable-tokens/phases"; -import { ShellSession } from "../../shell-session/shell-session"; +import shellSessionProcessesInjectable from "../../shell-session/processes.injectable"; +import prefixedLoggerInjectable from "../../../common/logger/prefixed-logger.injectable"; const cleanUpShellSessionsInjectable = getInjectable({ id: "clean-up-shell-sessions", - instantiate: () => ({ - run: () => void ShellSession.cleanup(), + instantiate: (di) => ({ + run: () => { + const shellSessionProcesses = di.inject(shellSessionProcessesInjectable); + const logger = di.inject(prefixedLoggerInjectable, "SHELL-SESSIONS"); + + logger.info("Killing all remaining shell sessions"); + + for (const { pid } of shellSessionProcesses.values()) { + try { + process.kill(pid); + } catch { + // ignore error + } + } + + shellSessionProcesses.clear(); + + return undefined; + }, }), injectionToken: beforeQuitOfBackEndInjectionToken, From 9b8d6e4e442bc6796cc41e8424a524982d59c947 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 31 Mar 2023 14:21:40 -0400 Subject: [PATCH 25/35] Fix crash due to non base64 encoded secrets (#7448) * Fix crash due to non base64 encoded secrets Signed-off-by: Sebastian Malton * Update snapshot Signed-off-by: Sebastian Malton --------- Signed-off-by: Sebastian Malton --- .../__snapshots__/secret-key.test.tsx.snap | 92 ++++++++ .../pod-container-env.test.tsx.snap | 7 +- .../+workloads-pods/pod-container-env.tsx | 64 +----- .../+workloads-pods/secret-key.test.tsx | 205 ++++++++++++++++++ .../components/+workloads-pods/secret-key.tsx | 85 ++++++++ 5 files changed, 395 insertions(+), 58 deletions(-) create mode 100644 packages/core/src/renderer/components/+workloads-pods/__snapshots__/secret-key.test.tsx.snap create mode 100644 packages/core/src/renderer/components/+workloads-pods/secret-key.test.tsx create mode 100644 packages/core/src/renderer/components/+workloads-pods/secret-key.tsx diff --git a/packages/core/src/renderer/components/+workloads-pods/__snapshots__/secret-key.test.tsx.snap b/packages/core/src/renderer/components/+workloads-pods/__snapshots__/secret-key.test.tsx.snap new file mode 100644 index 0000000000..3d1c8368ad --- /dev/null +++ b/packages/core/src/renderer/components/+workloads-pods/__snapshots__/secret-key.test.tsx.snap @@ -0,0 +1,92 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SecretKey technical tests renders 1`] = ` + +
+ secret(some-secret-name)[some-key] +   + + + visibility + + +
+ Show +
+
+ +`; + +exports[`SecretKey technical tests when the show secret button is clicked renders 1`] = ` + +
+ secret(some-secret-name)[some-key] +   + + + visibility + + +
+ Show +
+
+ +`; + +exports[`SecretKey technical tests when the show secret button is clicked when the secret fails to load with a primitive renders 1`] = ` + +
+ Error: some-other-error +
+ +`; + +exports[`SecretKey technical tests when the show secret button is clicked when the secret fails to load with an error renders 1`] = ` + +
+ Error: some-error +
+ +`; + +exports[`SecretKey technical tests when the show secret button is clicked when the secret fails to load with an object renders 1`] = ` + +
+ Error: {"message":"some-error"} +
+ +`; + +exports[`SecretKey technical tests when the show secret button is clicked when the secret loads with base64 encoded data renders 1`] = ` + +
+ some-data-for-some-key +
+ +`; + +exports[`SecretKey technical tests when the show secret button is clicked when the secret loads with non base64 encoded data renders 1`] = ` + +
+ some-data-for-some-key +
+ +`; diff --git a/packages/core/src/renderer/components/+workloads-pods/__tests__/__snapshots__/pod-container-env.test.tsx.snap b/packages/core/src/renderer/components/+workloads-pods/__tests__/__snapshots__/pod-container-env.test.tsx.snap index 1183ce4309..1a243d6fa8 100644 --- a/packages/core/src/renderer/components/+workloads-pods/__tests__/__snapshots__/pod-container-env.test.tsx.snap +++ b/packages/core/src/renderer/components/+workloads-pods/__tests__/__snapshots__/pod-container-env.test.tsx.snap @@ -158,10 +158,11 @@ exports[` renders envFrom when given a secretRef 1`] = ` bar : - secretKeyRef(my-secret.bar) + secret(my-secret)[bar]   renders envFrom when given a secretRef 1`] = ` visibility -
+
Show
diff --git a/packages/core/src/renderer/components/+workloads-pods/pod-container-env.tsx b/packages/core/src/renderer/components/+workloads-pods/pod-container-env.tsx index 977c945f18..00d13fa833 100644 --- a/packages/core/src/renderer/components/+workloads-pods/pod-container-env.tsx +++ b/packages/core/src/renderer/components/+workloads-pods/pod-container-env.tsx @@ -5,19 +5,19 @@ import "./pod-container-env.scss"; -import React, { useEffect, useState } from "react"; +import React, { useEffect } from "react"; import { observer } from "mobx-react"; -import type { Container, EnvVarKeySelector, Secret } from "../../../common/k8s-api/endpoints"; +import type { Container } from "../../../common/k8s-api/endpoints"; import { DrawerItem } from "../drawer"; import { autorun } from "mobx"; -import { Icon } from "../icon"; -import { base64, cssNames, object } from "@k8slens/utilities"; +import { object } from "@k8slens/utilities"; import _ from "lodash"; import { withInjectables } from "@ogre-tools/injectable-react"; import type { ConfigMapStore } from "../+config-maps/store"; import type { SecretStore } from "../+config-secrets/store"; import configMapStoreInjectable from "../+config-maps/store.injectable"; import secretStoreInjectable from "../+config-secrets/store.injectable"; +import { SecretKey } from "./secret-key"; export interface ContainerEnvironmentProps { container: Container; @@ -74,9 +74,11 @@ const NonInjectedContainerEnvironment = observer((props: Dependencies & Containe } else if (secretKeyRef?.name) { secretValue = ( ); } else if (configMapKeyRef?.name) { @@ -151,7 +153,6 @@ const NonInjectedContainerEnvironment = observer((props: Dependencies & Containe key, }} namespace={namespace} - secretStore={secretStore} />
)); @@ -172,52 +173,3 @@ export const ContainerEnvironment = withInjectables { - const { - reference: { name, key }, - namespace, - secretStore, - } = props; - - const [loading, setLoading] = useState(false); - const [secret, setSecret] = useState(); - - if (!name) { - return null; - } - - const showKey = async (evt: React.MouseEvent) => { - evt.preventDefault(); - setLoading(true); - const secret = await secretStore.load({ name, namespace }); - - setLoading(false); - setSecret(secret); - }; - - const value = secret?.data?.[key]; - - if (value) { - return <>{base64.decode(value)}; - } - - return ( - <> - {`secretKeyRef(${name}.${key})`} -   - - - ); -}; diff --git a/packages/core/src/renderer/components/+workloads-pods/secret-key.test.tsx b/packages/core/src/renderer/components/+workloads-pods/secret-key.test.tsx new file mode 100644 index 0000000000..035bf158df --- /dev/null +++ b/packages/core/src/renderer/components/+workloads-pods/secret-key.test.tsx @@ -0,0 +1,205 @@ +/** + * 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 { base64 } from "@k8slens/utilities"; +import type { RenderResult } from "@testing-library/react"; +import { act } from "@testing-library/react"; +import React from "react"; +import type { SecretStore } from "../+config-secrets/store"; +import secretStoreInjectable from "../+config-secrets/store.injectable"; +import { Secret, SecretType } from "../../../common/k8s-api/endpoints"; +import { getDiForUnitTesting } from "../../getDiForUnitTesting"; +import { renderFor } from "../test-utils/renderFor"; +import { SecretKey } from "./secret-key"; + +describe("SecretKey technical tests", () => { + let loadSecretMock: AsyncFnMock; + let result: RenderResult; + + beforeEach(() => { + const di = getDiForUnitTesting(); + const render = renderFor(di); + + loadSecretMock = asyncFn(); + di.override(secretStoreInjectable, () => ({ + load: loadSecretMock, + } as Partial as SecretStore)); + + result = render(( + + )); + }); + + it("renders", () => { + expect(result.baseElement).toMatchSnapshot(); + }); + + it("should not try to load secret", () => { + expect(loadSecretMock).not.toBeCalled(); + }); + + it("should show the 'show secret' button", () => { + expect(result.queryByTestId("show-secret-button-for-some-namespace/some-secret-name:some-key")).toBeInTheDocument(); + }); + + describe("when the show secret button is clicked", () => { + beforeEach(() => { + result + .getByTestId("show-secret-button-for-some-namespace/some-secret-name:some-key") + .click(); + }); + + it("renders", () => { + expect(result.baseElement).toMatchSnapshot(); + }); + + it("should try to load secret", () => { + expect(loadSecretMock).toBeCalledWith({ + name: "some-secret-name", + namespace: "some-namespace", + }); + }); + + it("should mark icon as disabled", () => { + expect(result.queryByTestId("show-secret-button-for-some-namespace/some-secret-name:some-key")).toHaveClass("disabled"); + }); + + describe("when the secret loads with base64 encoded data", () => { + beforeEach(async () => { + await act(async () => { + await loadSecretMock.resolve(new Secret({ + apiVersion: Secret.apiBase, + kind: Secret.kind, + metadata: { + name: "some-secret-name", + namespace: "some-namespace", + resourceVersion: "some-resource-version", + selfLink: "some-self-link", + uid: "some-uid", + }, + type: SecretType.Opaque, + data: { + "some-key": base64.encode("some-data-for-some-key"), + }, + })); + }); + }); + + it("renders", () => { + expect(result.baseElement).toMatchSnapshot(); + }); + + it("should not show the 'show secret' button", () => { + expect(result.queryByTestId("show-secret-button-for-some-namespace/some-secret-name:some-key")).not.toBeInTheDocument(); + }); + + it("should show the decoded secret data", () => { + expect(result.queryByText("some-data-for-some-key")).toBeInTheDocument(); + }); + }); + + describe("when the secret loads with non base64 encoded data", () => { + beforeEach(async () => { + await act(async () => { + await loadSecretMock.resolve(new Secret({ + apiVersion: Secret.apiBase, + kind: Secret.kind, + metadata: { + name: "some-secret-name", + namespace: "some-namespace", + resourceVersion: "some-resource-version", + selfLink: "some-self-link", + uid: "some-uid", + }, + type: SecretType.Opaque, + data: { + "some-key": "some-data-for-some-key", + }, + })); + }); + }); + + it("renders", () => { + expect(result.baseElement).toMatchSnapshot(); + }); + + it("should not show the 'show secret' button", () => { + expect(result.queryByTestId("show-secret-button-for-some-namespace/some-secret-name:some-key")).not.toBeInTheDocument(); + }); + + it("should show the non decoded secret data", () => { + expect(result.queryByText("some-data-for-some-key")).toBeInTheDocument(); + }); + }); + + describe("when the secret fails to load with an error", () => { + beforeEach(async () => { + await act(async () => { + await loadSecretMock.reject(new Error("some-error")); + }); + }); + + it("renders", () => { + expect(result.baseElement).toMatchSnapshot(); + }); + + it("should not show the 'show secret' button", () => { + expect(result.queryByTestId("show-secret-button-for-some-namespace/some-secret-name:some-key")).not.toBeInTheDocument(); + }); + + it("should show the loading error", () => { + expect(result.queryByText("Error: some-error")).toBeInTheDocument(); + }); + }); + + describe("when the secret fails to load with an object", () => { + beforeEach(async () => { + await act(async () => { + await loadSecretMock.reject({ message: "some-error" }); + }); + }); + + it("renders", () => { + expect(result.baseElement).toMatchSnapshot(); + }); + + it("should not show the 'show secret' button", () => { + expect(result.queryByTestId("show-secret-button-for-some-namespace/some-secret-name:some-key")).not.toBeInTheDocument(); + }); + + it("should show the loading error as JSON", () => { + expect(result.queryByText(`Error: {"message":"some-error"}`)).toBeInTheDocument(); + }); + }); + + describe("when the secret fails to load with a primitive", () => { + beforeEach(async () => { + await act(async () => { + await loadSecretMock.reject("some-other-error"); + }); + }); + + it("renders", () => { + expect(result.baseElement).toMatchSnapshot(); + }); + + it("should not show the 'show secret' button", () => { + expect(result.queryByTestId("show-secret-button-for-some-namespace/some-secret-name:some-key")).not.toBeInTheDocument(); + }); + + it("should show the loading error as JSON", () => { + expect(result.queryByText("Error: some-other-error")).toBeInTheDocument(); + }); + }); + }); +}); diff --git a/packages/core/src/renderer/components/+workloads-pods/secret-key.tsx b/packages/core/src/renderer/components/+workloads-pods/secret-key.tsx new file mode 100644 index 0000000000..ada6e9c3a2 --- /dev/null +++ b/packages/core/src/renderer/components/+workloads-pods/secret-key.tsx @@ -0,0 +1,85 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import React, { useState } from "react"; +import type { EnvVarKeySelector } from "../../../common/k8s-api/endpoints"; +import { Icon } from "../icon"; +import { base64, cssNames, isObject } from "@k8slens/utilities"; +import type { SecretStore } from "../+config-secrets/store"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import secretStoreInjectable from "../+config-secrets/store.injectable"; +import type { SetRequired } from "type-fest"; + +export interface SecretKeyProps { + reference: SetRequired; + namespace: string; +} + +interface Dependencies { + secretStore: SecretStore; +} + +const NonInjectedSecretKey = (props: SecretKeyProps & Dependencies) => { + const { + reference: { name, key }, namespace, secretStore, + } = props; + + const [loading, setLoading] = useState(false); + const [secretData, setSecretData] = useState(); + + if (!name) { + return null; + } + + const showKey = async (evt: React.MouseEvent) => { + evt.preventDefault(); + setLoading(true); + + try { + const secret = await secretStore.load({ name, namespace }); + + try { + setSecretData(base64.decode(secret.data[key] ?? "")); + } catch { + setSecretData(secret.data[key]); + } + } catch (error) { + if (error instanceof Error) { + setSecretData(`${error}`); + } else if (isObject(error)) { + setSecretData(`Error: ${JSON.stringify(error)}`); + } else { + setSecretData(`Error: ${error}`); + } + } finally { + setLoading(false); + } + }; + + if (secretData) { + return <>{secretData}; + } + + return ( + <> + {`secret(${name})[${key}]`} +   + + + ); +}; + +export const SecretKey = withInjectables(NonInjectedSecretKey, { + getProps: (di, props) => ({ + ...props, + secretStore: di.inject(secretStoreInjectable), + }), +}); From 18d660ea7791b59fef0da8dc56451c147330068d Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 31 Mar 2023 14:33:05 -0400 Subject: [PATCH 26/35] Add temporal dependency to initializeExtensions (#7454) - So that extensions can ensure that the shell env is up to date Signed-off-by: Sebastian Malton --- .../runnables/initialize-extensions.injectable.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/core/src/main/start-main-application/runnables/initialize-extensions.injectable.ts b/packages/core/src/main/start-main-application/runnables/initialize-extensions.injectable.ts index a986bea2ef..cf89992ade 100644 --- a/packages/core/src/main/start-main-application/runnables/initialize-extensions.injectable.ts +++ b/packages/core/src/main/start-main-application/runnables/initialize-extensions.injectable.ts @@ -8,6 +8,7 @@ import extensionDiscoveryInjectable from "../../../extensions/extension-discover import extensionLoaderInjectable from "../../../extensions/extension-loader/extension-loader.injectable"; import showErrorPopupInjectable from "../../electron-app/features/show-error-popup.injectable"; import { onLoadOfApplicationInjectionToken } from "@k8slens/application"; +import setupShellInjectable from "../../../features/shell-sync/main/setup-shell.injectable"; const initializeExtensionsInjectable = getInjectable({ id: "initialize-extensions", @@ -51,6 +52,7 @@ const initializeExtensionsInjectable = getInjectable({ console.trace(); } }, + runAfter: setupShellInjectable, }), causesSideEffects: true, From fe2fd4c1fd002d894f9a14695adae51cd9893728 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 31 Mar 2023 15:28:14 -0400 Subject: [PATCH 27/35] Move Cluster.apiUrl to seperate injectable (#7354) * Refactor out Cluster.apiUrl to direct reading - Should help prevent using stale data - Removes some uses of synchronous FS operations Signed-off-by: Sebastian Malton * Fix type errors Signed-off-by: Sebastian Malton * Rename helper function to better communicate intent Signed-off-by: Sebastian Malton * Improve prometheus handler tests to override less things Signed-off-by: Sebastian Malton --------- Signed-off-by: Sebastian Malton --- package-lock.json | 2 +- packages/core/package.json | 2 +- packages/core/src/common/cluster-types.ts | 1 - packages/core/src/common/cluster/cluster.ts | 12 +- .../k8s-api/__tests__/api-manager.test.ts | 2 - .../kube-api-version-detection.test.ts | 2 - .../common/k8s-api/__tests__/kube-api.test.ts | 4 - packages/core/src/common/kube-helpers.ts | 10 + ...d-validated-config-from-file.injectable.ts | 28 +++ .../connections/main/api-url.injectable.ts | 48 +++++ .../delete-cluster-dialog.test.tsx | 8 - .../cluster/storage/cluster-storage.test.ts | 75 +------- .../cluster/storage/common/add.injectable.ts | 18 +- .../common/read-cluster-config.injectable.ts | 31 ---- .../storage/common/storage.injectable.ts | 9 +- .../core/src/main/__test__/cluster.test.ts | 42 +++-- .../src/main/__test__/kube-auth-proxy.test.ts | 51 ++--- .../main/__test__/kubeconfig-manager.test.ts | 2 - .../main/__test__/prometheus-handler.test.ts | 63 ++++--- .../__test__/kubeconfig-sync.test.ts | 4 +- .../compute-diff.injectable.ts | 17 +- .../config-to-models.injectable.ts | 17 +- ...luster-distribution-detector.injectable.ts | 32 ++-- .../cluster-id-detector.injectable.ts | 3 +- .../detect-cluster-metadata.test.ts | 2 - .../kube-auth-proxy-server.injectable.ts | 36 ++-- packages/core/src/main/cluster/manager.ts | 19 +- .../cluster/update-entity-metadata.test.ts | 2 - .../main/cluster/update-entity-spec.test.ts | 2 - .../create-kube-auth-proxy.injectable.ts | 174 +++++++++++++++--- .../main/kube-auth-proxy/kube-auth-proxy.ts | 168 ----------------- .../kube-api-upgrade-request.injectable.ts | 10 +- .../get-service-account-route.injectable.ts | 97 ++++------ .../local-shell-session/techincal.test.ts | 2 - .../hpa-details.test.tsx | 2 - .../__tests__/secret-details.test.tsx | 2 - .../namespace-select-filter.test.tsx | 2 - .../+namespaces/namespace-store.test.ts | 2 - .../__tests__/dialog.test.tsx | 2 - .../+role-bindings/__tests__/dialog.test.tsx | 2 - .../__tests__/cronjob.store.test.ts | 2 - .../__tests__/daemonset.store.test.ts | 2 - .../__tests__/deployments.store.test.ts | 2 - .../components/__tests__/job.store.test.ts | 2 - .../components/__tests__/pods.store.test.ts | 2 - .../__tests__/replicaset.store.test.ts | 2 - .../__tests__/statefulset.store.test.ts | 2 - .../cluster-local-terminal-settings.test.tsx | 10 - .../__tests__/icon-settings.test.tsx | 53 +++--- .../kube-object-list-layout.test.tsx | 2 - .../test-utils/get-application-builder.tsx | 2 - .../cluster-frame/cluster-frame.test.tsx | 15 +- .../utilities/src/collection-functions.ts | 9 + 53 files changed, 472 insertions(+), 640 deletions(-) create mode 100644 packages/core/src/common/kube-helpers/load-validated-config-from-file.injectable.ts create mode 100644 packages/core/src/features/cluster/connections/main/api-url.injectable.ts delete mode 100644 packages/core/src/features/cluster/storage/common/read-cluster-config.injectable.ts delete mode 100644 packages/core/src/main/kube-auth-proxy/kube-auth-proxy.ts diff --git a/package-lock.json b/package-lock.json index 539916d8a3..d398f4aef3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38059,7 +38059,6 @@ "@astronautlabs/jsonpath": "^1.1.0", "@hapi/call": "^9.0.1", "@hapi/subtext": "^7.1.0", - "@k8slens/cluster-settings": "^6.5.0-alpha.1", "@k8slens/node-fetch": "^6.5.0-alpha.1", "@k8slens/react-application": "^1.0.0-alpha.0", "@kubernetes/client-node": "^0.18.1", @@ -38266,6 +38265,7 @@ "peerDependencies": { "@k8slens/application": "^6.5.0-alpha.0", "@k8slens/application-for-electron-main": "^6.5.0-alpha.0", + "@k8slens/cluster-settings": "^6.5.0-alpha.1", "@k8slens/legacy-extensions": "^1.0.0-alpha.0", "@k8slens/messaging": "^1.0.0-alpha.1", "@k8slens/messaging-for-main": "^1.0.0-alpha.1", diff --git a/packages/core/package.json b/packages/core/package.json index 7b04d2ce06..be81f74f14 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -120,7 +120,6 @@ "@astronautlabs/jsonpath": "^1.1.0", "@hapi/call": "^9.0.1", "@hapi/subtext": "^7.1.0", - "@k8slens/cluster-settings": "^6.5.0-alpha.1", "@k8slens/node-fetch": "^6.5.0-alpha.1", "@k8slens/react-application": "^1.0.0-alpha.0", "@kubernetes/client-node": "^0.18.1", @@ -324,6 +323,7 @@ "peerDependencies": { "@k8slens/application": "^6.5.0-alpha.0", "@k8slens/application-for-electron-main": "^6.5.0-alpha.0", + "@k8slens/cluster-settings": "^6.5.0-alpha.1", "@k8slens/legacy-extensions": "^1.0.0-alpha.0", "@k8slens/messaging": "^1.0.0-alpha.1", "@k8slens/messaging-for-main": "^1.0.0-alpha.1", diff --git a/packages/core/src/common/cluster-types.ts b/packages/core/src/common/cluster-types.ts index 4095c3fc23..a8ce7da912 100644 --- a/packages/core/src/common/cluster-types.ts +++ b/packages/core/src/common/cluster-types.ts @@ -183,7 +183,6 @@ export const initialNodeShellImage = "docker.io/alpine:3.13"; * The data representing a cluster's state, for passing between main and renderer */ export interface ClusterState { - apiUrl: string; online: boolean; disconnected: boolean; accessible: boolean; diff --git a/packages/core/src/common/cluster/cluster.ts b/packages/core/src/common/cluster/cluster.ts index fc66d9aa29..f703ebc336 100644 --- a/packages/core/src/common/cluster/cluster.ts +++ b/packages/core/src/common/cluster/cluster.ts @@ -5,7 +5,7 @@ import { computed, observable, toJS, runInAction } from "mobx"; import type { KubeApiResource } from "../rbac"; -import type { ClusterState, ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel, ClusterConfigData } from "../cluster-types"; +import type { ClusterState, ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel } from "../cluster-types"; import { ClusterMetadataKey, clusterModelIdChecker, updateClusterModelChecker } from "../cluster-types"; import type { IObservableValue } from "mobx"; import { replaceObservableObject } from "../utils/replace-observable-object"; @@ -27,11 +27,6 @@ export class Cluster { */ readonly kubeConfigPath = observable.box() as IObservableValue; - /** - * Kubernetes API server URL - */ - readonly apiUrl: IObservableValue; - /** * Describes if we can detect that cluster is online */ @@ -122,7 +117,7 @@ export class Cluster { */ readonly prometheusPreferences = computed(() => pick(toJS(this.preferences), "prometheus", "prometheusProvider") as ClusterPrometheusPreferences); - constructor({ id, ...model }: ClusterModel, configData: ClusterConfigData) { + constructor({ id, ...model }: ClusterModel) { const { error } = clusterModelIdChecker.validate({ id }); if (error) { @@ -131,7 +126,6 @@ export class Cluster { this.id = id; this.updateModel(model); - this.apiUrl = observable.box(configData.clusterServerUrl); } /** @@ -187,7 +181,6 @@ export class Cluster { */ getState(): ClusterState { return { - apiUrl: this.apiUrl.get(), online: this.online.get(), ready: this.ready.get(), disconnected: this.disconnected.get(), @@ -207,7 +200,6 @@ export class Cluster { this.accessible.set(state.accessible); this.allowedNamespaces.replace(state.allowedNamespaces); this.resourcesToShow.replace(state.resourcesToShow); - this.apiUrl.set(state.apiUrl); this.disconnected.set(state.disconnected); this.isAdmin.set(state.isAdmin); this.isGlobalWatchEnabled.set(state.isGlobalWatchEnabled); diff --git a/packages/core/src/common/k8s-api/__tests__/api-manager.test.ts b/packages/core/src/common/k8s-api/__tests__/api-manager.test.ts index 48fdb3e544..ce117d9475 100644 --- a/packages/core/src/common/k8s-api/__tests__/api-manager.test.ts +++ b/packages/core/src/common/k8s-api/__tests__/api-manager.test.ts @@ -51,8 +51,6 @@ describe("ApiManager", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); apiManager = di.inject(apiManagerInjectable); diff --git a/packages/core/src/common/k8s-api/__tests__/kube-api-version-detection.test.ts b/packages/core/src/common/k8s-api/__tests__/kube-api-version-detection.test.ts index e3bcd70a81..e6efa606b9 100644 --- a/packages/core/src/common/k8s-api/__tests__/kube-api-version-detection.test.ts +++ b/packages/core/src/common/k8s-api/__tests__/kube-api-version-detection.test.ts @@ -43,8 +43,6 @@ describe("KubeApi", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); apiManager = di.inject(apiManagerInjectable); diff --git a/packages/core/src/common/k8s-api/__tests__/kube-api.test.ts b/packages/core/src/common/k8s-api/__tests__/kube-api.test.ts index e7240895cf..a5cce9f02c 100644 --- a/packages/core/src/common/k8s-api/__tests__/kube-api.test.ts +++ b/packages/core/src/common/k8s-api/__tests__/kube-api.test.ts @@ -62,8 +62,6 @@ describe("createKubeApiForRemoteCluster", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); fetchMock = asyncFn(); @@ -168,8 +166,6 @@ describe("KubeApi", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); di.override(apiKubeInjectable, () => createKubeJsonApi({ diff --git a/packages/core/src/common/kube-helpers.ts b/packages/core/src/common/kube-helpers.ts index 6deb9ab8a1..0e42425f1c 100644 --- a/packages/core/src/common/kube-helpers.ts +++ b/packages/core/src/common/kube-helpers.ts @@ -130,6 +130,16 @@ export function loadConfigFromString(content: string): ConfigResult { }; } +export function loadValidatedConfig(content: string, contextName: string): ValidateKubeConfigResult { + const { options, error } = loadToOptions(content); + + if (error) { + return { error }; + } + + return validateKubeConfig(loadFromOptions(options), contextName); +} + export interface SplitConfigEntry { config: KubeConfig; validationResult: ValidateKubeConfigResult; diff --git a/packages/core/src/common/kube-helpers/load-validated-config-from-file.injectable.ts b/packages/core/src/common/kube-helpers/load-validated-config-from-file.injectable.ts new file mode 100644 index 0000000000..ee0b9ed9b0 --- /dev/null +++ b/packages/core/src/common/kube-helpers/load-validated-config-from-file.injectable.ts @@ -0,0 +1,28 @@ +/** + * 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 { Cluster } from "../cluster/cluster"; +import readFileInjectable from "../fs/read-file.injectable"; +import type { ValidateKubeConfigResult } from "../kube-helpers"; +import { loadValidatedConfig } from "../kube-helpers"; +import resolveTildeInjectable from "../path/resolve-tilde.injectable"; + +export type LoadValidatedClusterConfig = (cluster: Cluster) => Promise; + +const loadValidatedClusterConfigInjectable = getInjectable({ + id: "load-validated-cluster-config", + instantiate: (di): LoadValidatedClusterConfig => { + const readFile = di.inject(readFileInjectable); + const resolveTilde = di.inject(resolveTildeInjectable); + + return async (cluster) => { + const data = await readFile(resolveTilde(cluster.kubeConfigPath.get())); + + return loadValidatedConfig(data, cluster.contextName.get()); + }; + }, +}); + +export default loadValidatedClusterConfigInjectable; diff --git a/packages/core/src/features/cluster/connections/main/api-url.injectable.ts b/packages/core/src/features/cluster/connections/main/api-url.injectable.ts new file mode 100644 index 0000000000..5cb0b761ec --- /dev/null +++ b/packages/core/src/features/cluster/connections/main/api-url.injectable.ts @@ -0,0 +1,48 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable"; +import { URL } from "url"; +import type { Cluster } from "../../../../common/cluster/cluster"; +import statInjectable from "../../../../common/fs/stat.injectable"; +import loadValidatedClusterConfigInjectable from "../../../../common/kube-helpers/load-validated-config-from-file.injectable"; + +interface ClusterApiUrlState { + url: URL; + lastReadMtimeMs: number; +} + +const clusterApiUrlInjectable = getInjectable({ + id: "cluster-api-url", + instantiate: (di, cluster): () => Promise => { + const loadValidatedClusterConfig = di.inject(loadValidatedClusterConfigInjectable); + const stat = di.inject(statInjectable); + + let state: ClusterApiUrlState | undefined; + + return async () => { + const stats = await stat(cluster.kubeConfigPath.get()); + + if (!state || state.lastReadMtimeMs >= stats.mtimeMs) { + const result = await loadValidatedClusterConfig(cluster); + + if (result.error) { + throw result.error; + } + + state = { + url: new URL(result.cluster.server), + lastReadMtimeMs: stats.mtimeMs, + }; + } + + return state.url; + }; + }, + lifecycle: lifecycleEnum.keyedSingleton({ + getInstanceKey: (di, cluster: Cluster) => cluster.id, + }), +}); + +export default clusterApiUrlInjectable; diff --git a/packages/core/src/features/cluster/delete-dialog/delete-cluster-dialog.test.tsx b/packages/core/src/features/cluster/delete-dialog/delete-cluster-dialog.test.tsx index 255f545769..1ffad5df97 100644 --- a/packages/core/src/features/cluster/delete-dialog/delete-cluster-dialog.test.tsx +++ b/packages/core/src/features/cluster/delete-dialog/delete-cluster-dialog.test.tsx @@ -109,8 +109,6 @@ describe("Deleting a cluster", () => { clusterName: "some-current-context-cluster", }, kubeConfigPath: "./temp-kube-config", - }, { - clusterServerUrl: currentClusterServerUrl, }); nonCurrentCluster = new Cluster({ id: "some-non-current-context-cluster", @@ -119,8 +117,6 @@ describe("Deleting a cluster", () => { clusterName: "some-non-current-context-cluster", }, kubeConfigPath: "./temp-kube-config", - }, { - clusterServerUrl: currentClusterServerUrl, }); }); @@ -197,8 +193,6 @@ describe("Deleting a cluster", () => { clusterName: "some-cluster", }, kubeConfigPath: joinPaths(directoryForKubeConfigs, "some-cluster.json"), - }, { - clusterServerUrl: singleClusterServerUrl, }); }); @@ -233,8 +227,6 @@ describe("Deleting a cluster", () => { clusterName: "some-cluster", }, kubeConfigPath: "./temp-kube-config", - }, { - clusterServerUrl: singleClusterServerUrl, }); }); diff --git a/packages/core/src/features/cluster/storage/cluster-storage.test.ts b/packages/core/src/features/cluster/storage/cluster-storage.test.ts index f11ae3a4c5..4178b3e7d4 100644 --- a/packages/core/src/features/cluster/storage/cluster-storage.test.ts +++ b/packages/core/src/features/cluster/storage/cluster-storage.test.ts @@ -23,7 +23,6 @@ import type { WriteFileSync } from "../../../common/fs/write-file-sync.injectabl import writeFileSyncInjectable from "../../../common/fs/write-file-sync.injectable"; import type { WriteBufferSync } from "../../../common/fs/write-buffer-sync.injectable"; import writeBufferSyncInjectable from "../../../common/fs/write-buffer-sync.injectable"; -import { Cluster } from "../../../common/cluster/cluster"; import clustersPersistentStorageInjectable from "./common/storage.injectable"; import type { PersistentStorage } from "../../../common/persistent-storage/create.injectable"; import type { AddCluster } from "./common/add.injectable"; @@ -32,6 +31,7 @@ import type { GetClusterById } from "./common/get-by-id.injectable"; import getClusterByIdInjectable from "./common/get-by-id.injectable"; import type { IComputedValue } from "mobx"; import clustersInjectable from "./common/clusters.injectable"; +import type { Cluster } from "../../../common/cluster/cluster"; // NOTE: this is intended to read the actual file system const testDataIcon = readFileSync("test-data/cluster-store-migration-icon.png"); @@ -102,7 +102,7 @@ describe("cluster storage technical tests", () => { describe("with foo cluster added", () => { beforeEach(() => { - const cluster = new Cluster({ + addCluster({ id: "foo", contextName: "foo", preferences: { @@ -114,11 +114,7 @@ describe("cluster storage technical tests", () => { getCustomKubeConfigFilePath("foo"), kubeconfig, ), - }, { - clusterServerUrl, }); - - addCluster(cluster); }); it("adds new cluster to store", async () => { @@ -232,47 +228,6 @@ describe("cluster storage technical tests", () => { }); }); - describe("config with invalid cluster kubeconfig", () => { - beforeEach(() => { - writeFileSync("/invalid-kube-config", invalidKubeconfig); - writeFileSync("/valid-kube-config", kubeconfig); - writeJsonSync("/some-directory-for-user-data/lens-cluster-store.json", { - __internal__: { - migrations: { - version: "99.99.99", - }, - }, - clusters: [ - { - id: "cluster1", - kubeConfigPath: "/invalid-kube-config", - contextName: "test", - preferences: { terminalCWD: "/foo" }, - workspace: "foo", - }, - { - id: "cluster2", - kubeConfigPath: "/valid-kube-config", - contextName: "foo", - preferences: { terminalCWD: "/foo" }, - workspace: "default", - }, - ], - }); - - getCustomKubeConfigFilePath = di.inject(getCustomKubeConfigFilePathInjectable); - - clustersPersistentStorage = di.inject(clustersPersistentStorageInjectable); - clustersPersistentStorage.loadAndStartSyncing(); - }); - - it("does not enable clusters with invalid kubeconfig", () => { - const storedClusters = clusters.get(); - - expect(storedClusters.length).toBe(1); - }); - }); - describe("pre 3.6.0-beta.1 config with an existing cluster", () => { beforeEach(() => { di.override(storeMigrationVersionInjectable, () => "3.6.0"); @@ -315,32 +270,6 @@ describe("cluster storage technical tests", () => { }); }); -const invalidKubeconfig = JSON.stringify({ - apiVersion: "v1", - clusters: [{ - cluster: { - server: "https://localhost", - }, - name: "test2", - }], - contexts: [{ - context: { - cluster: "test", - user: "test", - }, - name: "test", - }], - "current-context": "test", - kind: "Config", - preferences: {}, - users: [{ - user: { - token: "kubeconfig-user-q4lm4:xxxyyyy", - }, - name: "test", - }], -}); - const minimalValidKubeConfig = JSON.stringify({ apiVersion: "v1", clusters: [ diff --git a/packages/core/src/features/cluster/storage/common/add.injectable.ts b/packages/core/src/features/cluster/storage/common/add.injectable.ts index 051aa6d23b..ff4ad8d828 100644 --- a/packages/core/src/features/cluster/storage/common/add.injectable.ts +++ b/packages/core/src/features/cluster/storage/common/add.injectable.ts @@ -5,33 +5,23 @@ import { getInjectable } from "@ogre-tools/injectable"; import { action } from "mobx"; import emitAppEventInjectable from "../../../../common/app-event-bus/emit-event.injectable"; -import readClusterConfigSyncInjectable from "./read-cluster-config.injectable"; import type { ClusterModel } from "../../../../common/cluster-types"; import { Cluster } from "../../../../common/cluster/cluster"; import clustersStateInjectable from "./state.injectable"; +import { setAndGet } from "@k8slens/utilities"; -export type AddCluster = (clusterOrModel: ClusterModel | Cluster) => Cluster; +export type AddCluster = (clusterModel: ClusterModel) => Cluster; const addClusterInjectable = getInjectable({ id: "add-cluster", instantiate: (di): AddCluster => { const clustersState = di.inject(clustersStateInjectable); const emitAppEvent = di.inject(emitAppEventInjectable); - const readClusterConfigSync = di.inject(readClusterConfigSyncInjectable); - return action((clusterOrModel) => { + return action((clusterModel) => { emitAppEvent({ name: "cluster", action: "add" }); - const cluster = clusterOrModel instanceof Cluster - ? clusterOrModel - : new Cluster( - clusterOrModel, - readClusterConfigSync(clusterOrModel), - ); - - clustersState.set(cluster.id, cluster); - - return cluster; + return setAndGet(clustersState, clusterModel.id, new Cluster(clusterModel)); }); }, }); diff --git a/packages/core/src/features/cluster/storage/common/read-cluster-config.injectable.ts b/packages/core/src/features/cluster/storage/common/read-cluster-config.injectable.ts deleted file mode 100644 index 9b3be7733e..0000000000 --- a/packages/core/src/features/cluster/storage/common/read-cluster-config.injectable.ts +++ /dev/null @@ -1,31 +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 type { ClusterConfigData, ClusterModel } from "../../../../common/cluster-types"; -import readFileSyncInjectable from "../../../../common/fs/read-file-sync.injectable"; -import { loadConfigFromString, validateKubeConfig } from "../../../../common/kube-helpers"; - -export type ReadClusterConfigSync = (model: ClusterModel) => ClusterConfigData; - -const readClusterConfigSyncInjectable = getInjectable({ - id: "read-cluster-config-sync", - instantiate: (di): ReadClusterConfigSync => { - const readFileSync = di.inject(readFileSyncInjectable); - - return ({ kubeConfigPath, contextName }) => { - const kubeConfigData = readFileSync(kubeConfigPath); - const { config } = loadConfigFromString(kubeConfigData); - const result = validateKubeConfig(config, contextName); - - if (result.error) { - throw result.error; - } - - return { clusterServerUrl: result.cluster.server }; - }; - }, -}); - -export default readClusterConfigSyncInjectable; diff --git a/packages/core/src/features/cluster/storage/common/storage.injectable.ts b/packages/core/src/features/cluster/storage/common/storage.injectable.ts index eaac8376cf..eb11d4b4e4 100644 --- a/packages/core/src/features/cluster/storage/common/storage.injectable.ts +++ b/packages/core/src/features/cluster/storage/common/storage.injectable.ts @@ -6,7 +6,6 @@ import { iter } from "@k8slens/utilities"; import { getInjectable } from "@ogre-tools/injectable"; import { comparer, action } from "mobx"; import { clusterStoreMigrationInjectionToken } from "./migration-token"; -import readClusterConfigSyncInjectable from "./read-cluster-config.injectable"; import type { ClusterId, ClusterModel } from "../../../../common/cluster-types"; import { Cluster } from "../../../../common/cluster/cluster"; import loggerInjectable from "../../../../common/logger.injectable"; @@ -23,7 +22,6 @@ const clustersPersistentStorageInjectable = getInjectable({ id: "clusters-persistent-storage", instantiate: (di) => { const createPersistentStorage = di.inject(createPersistentStorageInjectable); - const readClusterConfigSync = di.inject(readClusterConfigSyncInjectable); const clustersState = di.inject(clustersStateInjectable); const logger = di.inject(loggerInjectable); @@ -39,7 +37,6 @@ const clustersPersistentStorageInjectable = getInjectable({ const currentClusters = new Map(clustersState); const newClusters = new Map(); - // update new clusters for (const clusterModel of clusters) { try { let cluster = currentClusters.get(clusterModel.id); @@ -47,11 +44,9 @@ const clustersPersistentStorageInjectable = getInjectable({ if (cluster) { cluster.updateModel(clusterModel); } else { - cluster = new Cluster( - clusterModel, - readClusterConfigSync(clusterModel), - ); + cluster = new Cluster(clusterModel); } + newClusters.set(clusterModel.id, cluster); } catch (error) { logger.warn(`[CLUSTER-STORE]: Failed to update/create a cluster: ${error}`); diff --git a/packages/core/src/main/__test__/cluster.test.ts b/packages/core/src/main/__test__/cluster.test.ts index 205a23d5ab..dcc028afd6 100644 --- a/packages/core/src/main/__test__/cluster.test.ts +++ b/packages/core/src/main/__test__/cluster.test.ts @@ -2,7 +2,7 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { Cluster } from "../../common/cluster/cluster"; +import type { Cluster } from "../../common/cluster/cluster"; import { Kubectl } from "../kubectl/kubectl"; import { getDiForUnitTesting } from "../getDiForUnitTesting"; import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; @@ -19,6 +19,8 @@ import createCanIInjectable from "../../common/cluster/create-can-i.injectable"; import createRequestNamespaceListPermissionsInjectable from "../../common/cluster/create-request-namespace-list-permissions.injectable"; import createListNamespacesInjectable from "../../common/cluster/list-namespaces.injectable"; import prometheusHandlerInjectable from "../cluster/prometheus-handler/prometheus-handler.injectable"; +import writeJsonSyncInjectable from "../../common/fs/write-json-sync.injectable"; +import addClusterInjectable from "../../features/cluster/storage/common/add.injectable"; describe("create clusters", () => { let cluster: Cluster; @@ -26,7 +28,7 @@ describe("create clusters", () => { beforeEach(() => { const di = getDiForUnitTesting(); - const clusterServerUrl = "https://192.168.64.3:8443"; + const writeJsonSync = di.inject(writeJsonSyncInjectable); di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data"); di.override(directoryForTempInjectable, () => "some-directory-for-temp"); @@ -42,27 +44,45 @@ describe("create clusters", () => { setupPrometheus: jest.fn(), })); + writeJsonSync("/minikube-config.yml", { + apiVersion: "v1", + clusters: [{ + name: "minikube", + cluster: { + server: "https://192.168.64.3:8443", + }, + }], + "current-context": "minikube", + contexts: [{ + context: { + cluster: "minikube", + user: "minikube", + }, + name: "minikube", + }], + users: [{ + name: "minikube", + }], + kind: "Config", + preferences: {}, + }); + di.override(kubeconfigManagerInjectable, () => ({ ensurePath: async () => "/some-proxy-kubeconfig-file", } as Partial as KubeconfigManager)); jest.spyOn(Kubectl.prototype, "ensureKubectl").mockReturnValue(Promise.resolve(true)); - cluster = new Cluster({ + const addCluster = di.inject(addClusterInjectable); + + cluster = addCluster({ id: "foo", contextName: "minikube", - kubeConfigPath: "minikube-config.yml", - }, { - clusterServerUrl, + kubeConfigPath: "/minikube-config.yml", }); - clusterConnection = di.inject(clusterConnectionInjectable, cluster); }); - it("should be able to create a cluster from a cluster model and apiURL should be decoded", () => { - expect(cluster.apiUrl.get()).toBe("https://192.168.64.3:8443"); - }); - it("reconnect should not throw if contextHandler is missing", () => { expect(() => clusterConnection.reconnect()).not.toThrowError(); }); diff --git a/packages/core/src/main/__test__/kube-auth-proxy.test.ts b/packages/core/src/main/__test__/kube-auth-proxy.test.ts index dc4878f806..35de680e77 100644 --- a/packages/core/src/main/__test__/kube-auth-proxy.test.ts +++ b/packages/core/src/main/__test__/kube-auth-proxy.test.ts @@ -3,8 +3,6 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import waitUntilPortIsUsedInjectable from "../kube-auth-proxy/wait-until-port-is-used/wait-until-port-is-used.injectable"; -import { Cluster } from "../../common/cluster/cluster"; import type { ChildProcess } from "child_process"; import { Kubectl } from "../kubectl/kubectl"; import type { DeepMockProxy } from "jest-mock-extended"; @@ -12,7 +10,7 @@ import { mockDeep, mock } from "jest-mock-extended"; import type { Readable } from "stream"; import { EventEmitter } from "stream"; import { getDiForUnitTesting } from "../getDiForUnitTesting"; -import type { CreateKubeAuthProxy, KubeAuthProxy } from "../kube-auth-proxy/create-kube-auth-proxy.injectable"; +import type { KubeAuthProxy } from "../kube-auth-proxy/create-kube-auth-proxy.injectable"; import createKubeAuthProxyInjectable from "../kube-auth-proxy/create-kube-auth-proxy.injectable"; import spawnInjectable from "../child-process/spawn.injectable"; import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; @@ -25,15 +23,17 @@ import writeJsonSyncInjectable from "../../common/fs/write-json-sync.injectable" import ensureDirInjectable from "../../common/fs/ensure-dir.injectable"; import type { GetBasenameOfPath } from "../../common/path/get-basename.injectable"; import getBasenameOfPathInjectable from "../../common/path/get-basename.injectable"; - -const clusterServerUrl = "https://192.168.64.3:8443"; +import type { Cluster } from "../../common/cluster/cluster"; +import waitUntilPortIsUsedInjectable from "../kube-auth-proxy/wait-until-port-is-used/wait-until-port-is-used.injectable"; +import addClusterInjectable from "../../features/cluster/storage/common/add.injectable"; describe("kube auth proxy tests", () => { - let createKubeAuthProxy: CreateKubeAuthProxy; let spawnMock: jest.Mock; let waitUntilPortIsUsedMock: jest.Mock; let broadcastMessageMock: jest.Mock; let getBasenameOfPath: GetBasenameOfPath; + let cluster: Cluster; + let kubeAuthProxy: KubeAuthProxy; beforeEach(async () => { const di = getDiForUnitTesting(); @@ -51,7 +51,7 @@ describe("kube auth proxy tests", () => { clusters: [{ name: "minikube", cluster: { - server: clusterServerUrl, + server: "https://192.168.64.3:8443", }, }], "current-context": "minikube", @@ -83,29 +83,25 @@ describe("kube auth proxy tests", () => { di.override(kubectlDownloadingNormalizedArchInjectable, () => "amd64"); di.override(normalizedPlatformInjectable, () => "darwin"); - createKubeAuthProxy = di.inject(createKubeAuthProxyInjectable); + const addCluster = di.inject(addClusterInjectable); + + cluster = addCluster({ + id: "foobar", + kubeConfigPath: "/minikube-config.yml", + contextName: "minikube", + }); + kubeAuthProxy = di.inject(createKubeAuthProxyInjectable, cluster)({}); }); it("calling exit multiple times shouldn't throw", async () => { - const cluster = new Cluster({ - id: "foobar", - kubeConfigPath: "minikube-config.yml", - contextName: "minikube", - }, { - clusterServerUrl, - }); - - const kap = createKubeAuthProxy(cluster, {}); - - kap.exit(); - kap.exit(); - kap.exit(); + kubeAuthProxy.exit(); + kubeAuthProxy.exit(); + kubeAuthProxy.exit(); }); describe("spawn tests", () => { let mockedCP: DeepMockProxy; let listeners: EventEmitter; - let proxy: KubeAuthProxy; beforeEach(async () => { mockedCP = mockDeep(); @@ -184,16 +180,7 @@ describe("kube auth proxy tests", () => { }); waitUntilPortIsUsedMock.mockReturnValueOnce(Promise.resolve()); - const cluster = new Cluster({ - id: "foobar", - kubeConfigPath: "minikube-config.yml", - contextName: "minikube", - }, { - clusterServerUrl, - }); - - proxy = createKubeAuthProxy(cluster, {}); - await proxy.run(); + await kubeAuthProxy.run(); }); it("should call spawn and broadcast errors", () => { diff --git a/packages/core/src/main/__test__/kubeconfig-manager.test.ts b/packages/core/src/main/__test__/kubeconfig-manager.test.ts index 1205ba4f8f..fb9b329b69 100644 --- a/packages/core/src/main/__test__/kubeconfig-manager.test.ts +++ b/packages/core/src/main/__test__/kubeconfig-manager.test.ts @@ -89,8 +89,6 @@ describe("kubeconfig manager tests", () => { id: "foo", contextName: "minikube", kubeConfigPath: "/minikube-config.yml", - }, { - clusterServerUrl, }); kubeConfManager = di.inject(kubeconfigManagerInjectable, clusterFake); diff --git a/packages/core/src/main/__test__/prometheus-handler.test.ts b/packages/core/src/main/__test__/prometheus-handler.test.ts index 74cab1ea74..df0e1b37c9 100644 --- a/packages/core/src/main/__test__/prometheus-handler.test.ts +++ b/packages/core/src/main/__test__/prometheus-handler.test.ts @@ -13,8 +13,8 @@ import { runInAction } from "mobx"; import prometheusHandlerInjectable from "../cluster/prometheus-handler/prometheus-handler.injectable"; import directoryForTempInjectable from "../../common/app-paths/directory-for-temp/directory-for-temp.injectable"; import lensProxyPortInjectable from "../lens-proxy/lens-proxy-port.injectable"; -import loadProxyKubeconfigInjectable from "../cluster/load-proxy-kubeconfig.injectable"; -import { KubeConfig } from "@kubernetes/client-node"; +import createKubeAuthProxyInjectable from "../kube-auth-proxy/create-kube-auth-proxy.injectable"; +import writeJsonFileInjectable from "../../common/fs/write-json-file.injectable"; enum ServiceResult { Success, @@ -47,37 +47,46 @@ describe("PrometheusHandler", () => { let di: DiContainer; let cluster: Cluster; - beforeEach(() => { + beforeEach(async () => { di = getDiForUnitTesting(); - di.override(loadProxyKubeconfigInjectable, (di, cluster) => async () => { - const res = new KubeConfig(); - - res.addCluster({ - name: "some-cluster-name", - server: cluster.apiUrl.get(), - skipTLSVerify: false, - }); - res.addContext({ - cluster: "some-cluster-name", - name: "some-context-name", - user: "some-user-name", - }); - res.addUser({ - name: "some-user-name", - }); - res.setCurrentContext("some-context-name"); - - return res; - }); + di.override(createKubeAuthProxyInjectable, () => () => ({ + apiPrefix: "/some-api-prefix", + exit: () => {}, + run: async () => {}, + port: 9191, + })); di.override(directoryForTempInjectable, () => "/some-temp-dir"); di.inject(lensProxyPortInjectable).set(12345); + const writeJsonFile = di.inject(writeJsonFileInjectable); + const kubeConfigPath = "/some/path-to-a-config"; + const contextName = "some-context-name"; + + await writeJsonFile(kubeConfigPath, { + apiVersion: "v1", + kind: "Config", + clusters: [{ + name: "some-cluster-name", + cluster: { + server: "https://localhost:8989", + }, + }], + users: [{ + name: "some-user-name", + }], + contexts: [{ + name: contextName, + context: { + user: "some-user-name", + cluster: "some-cluster-name", + }, + }], + }); + cluster = new Cluster({ - contextName: "some-context-name", + contextName, id: "some-cluster-id", - kubeConfigPath: "/some/path", - }, { - clusterServerUrl: "http://localhost:81", + kubeConfigPath, }); }); diff --git a/packages/core/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts b/packages/core/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts index 6d23610e79..6cc651f7e5 100644 --- a/packages/core/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts +++ b/packages/core/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts @@ -97,8 +97,8 @@ describe("kubeconfig-sync.source tests", () => { const models = configToModels(config, "/bar"); expect(models.length).toBe(1); - expect(models[0][0].contextName).toBe("context-name"); - expect(models[0][0].kubeConfigPath).toBe("/bar"); + expect(models[0].contextName).toBe("context-name"); + expect(models[0].kubeConfigPath).toBe("/bar"); }); }); diff --git a/packages/core/src/main/catalog-sources/kubeconfig-sync/compute-diff.injectable.ts b/packages/core/src/main/catalog-sources/kubeconfig-sync/compute-diff.injectable.ts index 87475931fe..d1e8f0daab 100644 --- a/packages/core/src/main/catalog-sources/kubeconfig-sync/compute-diff.injectable.ts +++ b/packages/core/src/main/catalog-sources/kubeconfig-sync/compute-diff.injectable.ts @@ -38,15 +38,15 @@ const computeKubeconfigDiffInjectable = getInjectable({ } const rawModels = configToModels(config, filePath); - const models = new Map(rawModels.map(([model, configData]) => [model.contextName, [model, configData] as const])); + const models = new Map(rawModels.map((model) => [model.contextName, model])); logger.debug(`File now has ${models.size} entries`, { filePath }); for (const [contextName, value] of source) { - const data = models.get(contextName); + const model = models.get(contextName); // remove and disconnect clusters that were removed from the config - if (!data) { + if (!model) { // remove from the deleting set, so that if a new context of the same name is added, it isn't marked as deleting clustersThatAreBeingDeleted.delete(value[0].id); @@ -63,21 +63,16 @@ const computeKubeconfigDiffInjectable = getInjectable({ // diff against that // or update the model and mark it as not needed to be added - value[0].updateModel(data[0]); + value[0].updateModel(model); models.delete(contextName); logger.debug(`Updated old cluster from sync`, { filePath, contextName }); } - for (const [contextName, [model, configData]] of models) { + for (const [contextName, model] of models) { // add new clusters to the source try { const clusterId = createHash("md5").update(`${filePath}:${contextName}`).digest("hex"); - const cluster = getClusterById(clusterId) ?? new Cluster({ ...model, id: clusterId }, configData); - - if (!cluster.apiUrl.get()) { - throw new Error("Cluster constructor failed, see above error"); - } - + const cluster = getClusterById(clusterId) ?? new Cluster({ ...model, id: clusterId }); const entity = catalogEntityFromCluster(cluster); if (!filePath.startsWith(directoryForKubeConfigs)) { diff --git a/packages/core/src/main/catalog-sources/kubeconfig-sync/config-to-models.injectable.ts b/packages/core/src/main/catalog-sources/kubeconfig-sync/config-to-models.injectable.ts index 8240d4e914..6baad196cf 100644 --- a/packages/core/src/main/catalog-sources/kubeconfig-sync/config-to-models.injectable.ts +++ b/packages/core/src/main/catalog-sources/kubeconfig-sync/config-to-models.injectable.ts @@ -4,11 +4,11 @@ */ import type { KubeConfig } from "@kubernetes/client-node"; import { getInjectable } from "@ogre-tools/injectable"; -import type { ClusterConfigData, UpdateClusterModel } from "../../../common/cluster-types"; +import type { UpdateClusterModel } from "../../../common/cluster-types"; import { splitConfig } from "../../../common/kube-helpers"; import kubeconfigSyncLoggerInjectable from "./logger.injectable"; -export type ConfigToModels = (rootConfig: KubeConfig, filePath: string) => [UpdateClusterModel, ClusterConfigData][]; +export type ConfigToModels = (rootConfig: KubeConfig, filePath: string) => UpdateClusterModel[]; const configToModelsInjectable = getInjectable({ id: "config-to-models", @@ -22,15 +22,10 @@ const configToModelsInjectable = getInjectable({ if (validationResult.error) { logger.debug(`context failed validation: ${validationResult.error}`, { context: config.currentContext, filePath }); } else { - validConfigs.push([ - { - kubeConfigPath: filePath, - contextName: config.currentContext, - }, - { - clusterServerUrl: validationResult.cluster.server, - }, - ]); + validConfigs.push({ + kubeConfigPath: filePath, + contextName: config.currentContext, + }); } } diff --git a/packages/core/src/main/cluster-detectors/cluster-distribution-detector.injectable.ts b/packages/core/src/main/cluster-detectors/cluster-distribution-detector.injectable.ts index 44f1c88102..673cb3cf8d 100644 --- a/packages/core/src/main/cluster-detectors/cluster-distribution-detector.injectable.ts +++ b/packages/core/src/main/cluster-detectors/cluster-distribution-detector.injectable.ts @@ -9,22 +9,24 @@ import { getInjectable } from "@ogre-tools/injectable"; import k8SRequestInjectable from "../k8s-request.injectable"; import type { Cluster } from "../../common/cluster/cluster"; import requestClusterVersionInjectable from "./request-cluster-version.injectable"; +import type { URL } from "url"; +import clusterApiUrlInjectable from "../../features/cluster/connections/main/api-url.injectable"; const isGKE = (version: string) => version.includes("gke"); const isEKS = (version: string) => version.includes("eks"); const isIKS = (version: string) => version.includes("IKS"); -const isAKS = (cluster: Cluster) => cluster.apiUrl.get().includes("azmk8s.io"); +const isAKS = (apiUrl: URL) => apiUrl.hostname.includes("azmk8s.io"); const isMirantis = (version: string) => version.includes("-mirantis-") || version.includes("-docker-"); -const isDigitalOcean = (cluster: Cluster) => cluster.apiUrl.get().endsWith("k8s.ondigitalocean.com"); -const isMinikube = (cluster: Cluster) => cluster.contextName.get().startsWith("minikube"); -const isMicrok8s = (cluster: Cluster) => cluster.contextName.get().startsWith("microk8s"); -const isKind = (cluster: Cluster) => cluster.contextName.get().startsWith("kubernetes-admin@kind-"); -const isDockerDesktop = (cluster: Cluster) => cluster.contextName.get() === "docker-desktop"; +const isDigitalOcean = (apiUrl: URL) => apiUrl.hostname.endsWith("k8s.ondigitalocean.com"); +const isMinikube = (contextName: string) => contextName.startsWith("minikube"); +const isMicrok8s = (contextName: string) => contextName.startsWith("microk8s"); +const isKind = (contextName: string) => contextName.startsWith("kubernetes-admin@kind-"); +const isDockerDesktop = (contextName: string) => contextName === "docker-desktop"; const isTke = (version: string) => version.includes("-tke."); const isCustom = (version: string) => version.includes("+"); const isVMWare = (version: string) => version.includes("+vmware"); const isRke = (version: string) => version.includes("-rancher"); -const isRancherDesktop = (cluster: Cluster) => cluster.contextName.get() === "rancher-desktop"; +const isRancherDesktop = (contextName: string) => contextName === "rancher-desktop"; const isK3s = (version: string) => version.includes("+k3s"); const isK0s = (version: string) => version.includes("-k0s") || version.includes("+k0s"); const isAlibaba = (version: string) => version.includes("-aliyun"); @@ -49,12 +51,14 @@ const clusterDistributionDetectorInjectable = getInjectable({ key: ClusterMetadataKey.DISTRIBUTION, detect: async (cluster) => { const version = await requestClusterVersion(cluster); + const apiUrl = await di.inject(clusterApiUrlInjectable, cluster)(); + const contextName = cluster.contextName.get(); if (isRke(version)) { return { value: "rke", accuracy: 80 }; } - if (isRancherDesktop(cluster)) { + if (isRancherDesktop(contextName)) { return { value: "rancher-desktop", accuracy: 80 }; } @@ -74,11 +78,11 @@ const clusterDistributionDetectorInjectable = getInjectable({ return { value: "iks", accuracy: 80 }; } - if (isAKS(cluster)) { + if (isAKS(apiUrl)) { return { value: "aks", accuracy: 80 }; } - if (isDigitalOcean(cluster)) { + if (isDigitalOcean(apiUrl)) { return { value: "digitalocean", accuracy: 90 }; } @@ -106,19 +110,19 @@ const clusterDistributionDetectorInjectable = getInjectable({ return { value: "tencent", accuracy: 90 }; } - if (isMinikube(cluster)) { + if (isMinikube(contextName)) { return { value: "minikube", accuracy: 80 }; } - if (isMicrok8s(cluster)) { + if (isMicrok8s(contextName)) { return { value: "microk8s", accuracy: 80 }; } - if (isKind(cluster)) { + if (isKind(contextName)) { return { value: "kind", accuracy: 70 }; } - if (isDockerDesktop(cluster)) { + if (isDockerDesktop(contextName)) { return { value: "docker-desktop", accuracy: 80 }; } diff --git a/packages/core/src/main/cluster-detectors/cluster-id-detector.injectable.ts b/packages/core/src/main/cluster-detectors/cluster-id-detector.injectable.ts index 6699986805..51b65f0d90 100644 --- a/packages/core/src/main/cluster-detectors/cluster-id-detector.injectable.ts +++ b/packages/core/src/main/cluster-detectors/cluster-id-detector.injectable.ts @@ -9,6 +9,7 @@ import { ClusterMetadataKey } from "../../common/cluster-types"; import { getInjectable } from "@ogre-tools/injectable"; import k8SRequestInjectable from "../k8s-request.injectable"; import type { Cluster } from "../../common/cluster/cluster"; +import clusterApiUrlInjectable from "../../features/cluster/connections/main/api-url.injectable"; const clusterIdDetectorFactoryInjectable = getInjectable({ id: "cluster-id-detector-factory", @@ -28,7 +29,7 @@ const clusterIdDetectorFactoryInjectable = getInjectable({ try { id = await getDefaultNamespaceId(cluster); } catch(_) { - id = cluster.apiUrl.get(); + id = (await di.inject(clusterApiUrlInjectable, cluster)()).toString(); } const value = createHash("sha256").update(id).digest("hex"); diff --git a/packages/core/src/main/cluster-detectors/detect-cluster-metadata.test.ts b/packages/core/src/main/cluster-detectors/detect-cluster-metadata.test.ts index 9582b386c1..833b468738 100644 --- a/packages/core/src/main/cluster-detectors/detect-cluster-metadata.test.ts +++ b/packages/core/src/main/cluster-detectors/detect-cluster-metadata.test.ts @@ -67,8 +67,6 @@ describe("detect-cluster-metadata", () => { id: "some-id", contextName: "some-context", kubeConfigPath: "minikube-config.yml", - }, { - clusterServerUrl: "foo", }); }); diff --git a/packages/core/src/main/cluster/kube-auth-proxy-server.injectable.ts b/packages/core/src/main/cluster/kube-auth-proxy-server.injectable.ts index ff70af3a7b..df14cf3f93 100644 --- a/packages/core/src/main/cluster/kube-auth-proxy-server.injectable.ts +++ b/packages/core/src/main/cluster/kube-auth-proxy-server.injectable.ts @@ -9,6 +9,7 @@ import type { Cluster } from "../../common/cluster/cluster"; import createKubeAuthProxyInjectable from "../kube-auth-proxy/create-kube-auth-proxy.injectable"; import kubeAuthProxyCertificateInjectable from "../kube-auth-proxy/kube-auth-proxy-certificate.injectable"; import type { KubeAuthProxy } from "../kube-auth-proxy/create-kube-auth-proxy.injectable"; +import clusterApiUrlInjectable from "../../features/cluster/connections/main/api-url.injectable"; export interface KubeAuthProxyServer { getApiTarget(isLongRunningRequest?: boolean): Promise; @@ -24,23 +25,23 @@ const thirtySecondsInMs = 30 * 1000; const kubeAuthProxyServerInjectable = getInjectable({ id: "kube-auth-proxy-server", instantiate: (di, cluster): KubeAuthProxyServer => { - const clusterUrl = new URL(cluster.apiUrl.get()); - - const createKubeAuthProxy = di.inject(createKubeAuthProxyInjectable); - const certificate = di.inject(kubeAuthProxyCertificateInjectable, clusterUrl.hostname); + const clusterApiUrl = di.inject(clusterApiUrlInjectable, cluster); + const createKubeAuthProxy = di.inject(createKubeAuthProxyInjectable, cluster); let kubeAuthProxy: KubeAuthProxy | undefined = undefined; let apiTarget: ServerOptions | undefined = undefined; const ensureServerHelper = async (): Promise => { if (!kubeAuthProxy) { - const proxyEnv = Object.assign({}, process.env); + const proxyEnv = { + ...process.env, + }; if (cluster.preferences.httpsProxy) { proxyEnv.HTTPS_PROXY = cluster.preferences.httpsProxy; } - kubeAuthProxy = createKubeAuthProxy(cluster, proxyEnv); + kubeAuthProxy = createKubeAuthProxy(proxyEnv); } await kubeAuthProxy.run(); @@ -49,31 +50,24 @@ const kubeAuthProxyServerInjectable = getInjectable({ }; const newApiTarget = async (timeout: number): Promise => { - const kubeAuthProxy = await ensureServerHelper(); - const headers: Record = {}; - - if (clusterUrl.hostname) { - headers.Host = clusterUrl.hostname; - - // fix current IPv6 inconsistency in url.Parse() and httpProxy. - // with url.Parse the IPv6 Hostname has no Square brackets but httpProxy needs the Square brackets to work. - if (headers.Host.includes(":")) { - headers.Host = `[${headers.Host}]`; - } - } + const { hostname } = await clusterApiUrl(); + const certificate = di.inject(kubeAuthProxyCertificateInjectable, hostname); + const { port, apiPrefix: path } = await ensureServerHelper(); return { target: { protocol: "https:", host: "127.0.0.1", - port: kubeAuthProxy.port, - path: kubeAuthProxy.apiPrefix, + port, + path, ca: certificate.cert, }, changeOrigin: true, timeout, secure: true, - headers, + headers: { + Host: hostname, + }, }; }; diff --git a/packages/core/src/main/cluster/manager.ts b/packages/core/src/main/cluster/manager.ts index f9f844bd9f..800f981372 100644 --- a/packages/core/src/main/cluster/manager.ts +++ b/packages/core/src/main/cluster/manager.ts @@ -7,7 +7,6 @@ import "../../common/ipc/cluster"; import type { IComputedValue, IObservableValue, ObservableSet } from "mobx"; import { action, makeObservable, observe, reaction, toJS } from "mobx"; import type { Cluster } from "../../common/cluster/cluster"; -import { isErrnoException } from "@k8slens/utilities"; import { isKubernetesCluster, KubernetesCluster, LensKubernetesClusterStatus } from "../../common/catalog-entities/kubernetes-cluster"; import { ipcMainOn } from "../../common/ipc"; import { once } from "lodash"; @@ -158,26 +157,12 @@ export class ClusterManager { const cluster = this.dependencies.getClusterById(entity.getId()); if (!cluster) { - const model = { + this.dependencies.addCluster({ id: entity.getId(), kubeConfigPath: entity.spec.kubeconfigPath, contextName: entity.spec.kubeconfigContext, accessibleNamespaces: entity.spec.accessibleNamespaces ?? [], - }; - - try { - /** - * Add the bare minimum of data to ClusterStore. And especially no - * preferences, as those might be configured by the entity's source - */ - this.dependencies.addCluster(model); - } catch (error) { - if (isErrnoException(error) && error.code === "ENOENT" && error.path === entity.spec.kubeconfigPath) { - this.dependencies.logger.warn(`${logPrefix} kubeconfig file disappeared`, model); - } else { - this.dependencies.logger.error(`${logPrefix} failed to add cluster: ${error}`, model); - } - } + }); } else { cluster.kubeConfigPath.set(entity.spec.kubeconfigPath); cluster.contextName.set(entity.spec.kubeconfigContext); diff --git a/packages/core/src/main/cluster/update-entity-metadata.test.ts b/packages/core/src/main/cluster/update-entity-metadata.test.ts index 13683196bb..eca53c238e 100644 --- a/packages/core/src/main/cluster/update-entity-metadata.test.ts +++ b/packages/core/src/main/cluster/update-entity-metadata.test.ts @@ -34,8 +34,6 @@ describe("update-entity-metadata", () => { id: "some-id", contextName: "some-context", kubeConfigPath: "minikube-config.yml", - }, { - clusterServerUrl: "foo", }); detectedMetadata = { diff --git a/packages/core/src/main/cluster/update-entity-spec.test.ts b/packages/core/src/main/cluster/update-entity-spec.test.ts index a21e1fae46..fa2c14bb5a 100644 --- a/packages/core/src/main/cluster/update-entity-spec.test.ts +++ b/packages/core/src/main/cluster/update-entity-spec.test.ts @@ -31,8 +31,6 @@ describe("update-entity-spec", () => { id: "some-id", contextName: "some-context", kubeConfigPath: "minikube-config.yml", - }, { - clusterServerUrl: "foo", }); entity = new KubernetesCluster({ diff --git a/packages/core/src/main/kube-auth-proxy/create-kube-auth-proxy.injectable.ts b/packages/core/src/main/kube-auth-proxy/create-kube-auth-proxy.injectable.ts index fd4acf0d7a..df7108d8f1 100644 --- a/packages/core/src/main/kube-auth-proxy/create-kube-auth-proxy.injectable.ts +++ b/packages/core/src/main/kube-auth-proxy/create-kube-auth-proxy.injectable.ts @@ -2,18 +2,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 type { KubeAuthProxyDependencies } from "./kube-auth-proxy"; -import { KubeAuthProxyImpl } from "./kube-auth-proxy"; +import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable"; import type { Cluster } from "../../common/cluster/cluster"; import spawnInjectable from "../child-process/spawn.injectable"; -import kubeAuthProxyCertificateInjectable from "./kube-auth-proxy-certificate.injectable"; import loggerInjectable from "../../common/logger.injectable"; import waitUntilPortIsUsedInjectable from "./wait-until-port-is-used/wait-until-port-is-used.injectable"; import lensK8sProxyPathInjectable from "./lens-k8s-proxy-path.injectable"; import getPortFromStreamInjectable from "../utils/get-port-from-stream.injectable"; import getDirnameOfPathInjectable from "../../common/path/get-dirname.injectable"; +import randomBytesInjectable from "../../common/utils/random-bytes.injectable"; +import type { ChildProcess } from "child_process"; +import { observable, when } from "mobx"; +import assert from "assert"; +import clusterApiUrlInjectable from "../../features/cluster/connections/main/api-url.injectable"; +import kubeAuthProxyCertificateInjectable from "./kube-auth-proxy-certificate.injectable"; import broadcastConnectionUpdateInjectable from "../cluster/broadcast-connection-update.injectable"; +import { TypedRegEx } from "typed-regex"; export interface KubeAuthProxy { readonly apiPrefix: string; @@ -22,31 +26,159 @@ export interface KubeAuthProxy { exit: () => void; } -export type CreateKubeAuthProxy = (cluster: Cluster, env: NodeJS.ProcessEnv) => KubeAuthProxy; +export type CreateKubeAuthProxy = (env: NodeJS.ProcessEnv) => KubeAuthProxy; + +const startingServeMatcher = "starting to serve on (?
.+)"; +const startingServeRegex = Object.assign(TypedRegEx(startingServeMatcher, "i"), { + rawMatcher: startingServeMatcher, +}); const createKubeAuthProxyInjectable = getInjectable({ id: "create-kube-auth-proxy", - instantiate: (di): CreateKubeAuthProxy => { - const dependencies: Omit = { - proxyBinPath: di.inject(lensK8sProxyPathInjectable), - spawn: di.inject(spawnInjectable), - logger: di.inject(loggerInjectable), - waitUntilPortIsUsed: di.inject(waitUntilPortIsUsedInjectable), - getPortFromStream: di.inject(getPortFromStreamInjectable), - dirname: di.inject(getDirnameOfPathInjectable), - }; + instantiate: (di, cluster): CreateKubeAuthProxy => { + const lensK8sProxyPath = di.inject(lensK8sProxyPathInjectable); + const spawn = di.inject(spawnInjectable); + const logger = di.inject(loggerInjectable); + const waitUntilPortIsUsed = di.inject(waitUntilPortIsUsedInjectable); + const getPortFromStream = di.inject(getPortFromStreamInjectable); + const getDirnameOfPath = di.inject(getDirnameOfPathInjectable); + const randomBytes = di.inject(randomBytesInjectable); + const clusterApiUrl = di.inject(clusterApiUrlInjectable, cluster); + const broadcastConnectionUpdate = di.inject(broadcastConnectionUpdateInjectable, cluster); - return (cluster, env) => { - const clusterUrl = new URL(cluster.apiUrl.get()); + return (env) => { + let port: number | undefined; + let proxyProcess: ChildProcess | undefined; + const ready = observable.box(false); + const apiPrefix = `/${randomBytes(8).toString("hex")}`; - return new KubeAuthProxyImpl({ - ...dependencies, - proxyCert: di.inject(kubeAuthProxyCertificateInjectable, clusterUrl.hostname), - broadcastConnectionUpdate: di.inject(broadcastConnectionUpdateInjectable, cluster), - }, cluster, env); + const exit = () => { + ready.set(false); + + if (proxyProcess) { + logger.debug("[KUBE-AUTH]: stopping local proxy", cluster.getMeta()); + proxyProcess.removeAllListeners(); + proxyProcess.stderr?.removeAllListeners(); + proxyProcess.stdout?.removeAllListeners(); + proxyProcess.kill(); + proxyProcess = undefined; + } + }; + + const run = async (): Promise => { + if (proxyProcess) { + return when(() => ready.get()); + } + + const apiUrl = await clusterApiUrl(); + const certificate = di.inject(kubeAuthProxyCertificateInjectable, apiUrl.hostname); + + proxyProcess = spawn(lensK8sProxyPath, [], { + env: { + ...env, + KUBECONFIG: cluster.kubeConfigPath.get(), + KUBECONFIG_CONTEXT: cluster.contextName.get(), + API_PREFIX: apiPrefix, + PROXY_KEY: certificate.private, + PROXY_CERT: certificate.cert, + }, + cwd: getDirnameOfPath(cluster.kubeConfigPath.get()), + }); + proxyProcess.on("error", (error) => { + broadcastConnectionUpdate({ + level: "error", + message: error.message, + }); + exit(); + }); + + proxyProcess.on("exit", (code) => { + if (code) { + broadcastConnectionUpdate({ + level: "error", + message: `proxy exited with code: ${code}`, + }); + } else { + broadcastConnectionUpdate({ + level: "info", + message: "proxy exited successfully", + }); + } + exit(); + }); + + proxyProcess.on("disconnect", () => { + broadcastConnectionUpdate({ + level: "error", + message: "Proxy disconnected communications", + }); + exit(); + }); + + assert(proxyProcess.stderr); + assert(proxyProcess.stdout); + + proxyProcess.stderr.on("data", (data: Buffer) => { + if (data.includes("http: TLS handshake error")) { + return; + } + + broadcastConnectionUpdate({ + level: "error", + message: data.toString(), + }); + }); + + proxyProcess.stdout.on("data", (data: Buffer) => { + if (typeof port === "number") { + broadcastConnectionUpdate({ + level: "info", + message: data.toString(), + }); + } + }); + + port = await getPortFromStream(proxyProcess.stdout, { + lineRegex: startingServeRegex, + onFind: () => broadcastConnectionUpdate({ + level: "info", + message: "Authentication proxy started", + }), + }); + + logger.info(`[KUBE-AUTH-PROXY]: found port=${port}`); + + try { + await waitUntilPortIsUsed(port, 500, 10000); + ready.set(true); + } catch (error) { + logger.warn("[KUBE-AUTH-PROXY]: waitUntilUsed failed", error); + broadcastConnectionUpdate({ + level: "error", + message: "Proxy port failed to be used within time limit, restarting...", + }); + exit(); + + return run(); + } + }; + + return { + apiPrefix, + exit, + run, + get port() { + assert(port, "port has not yet been initialized"); + + return port; + }, + }; }; }, + lifecycle: lifecycleEnum.keyedSingleton({ + getInstanceKey: (di, cluster: Cluster) => cluster.id, + }), }); export default createKubeAuthProxyInjectable; diff --git a/packages/core/src/main/kube-auth-proxy/kube-auth-proxy.ts b/packages/core/src/main/kube-auth-proxy/kube-auth-proxy.ts deleted file mode 100644 index 160566c3a5..0000000000 --- a/packages/core/src/main/kube-auth-proxy/kube-auth-proxy.ts +++ /dev/null @@ -1,168 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { ChildProcess } from "child_process"; -import { randomBytes } from "crypto"; -import type { Cluster } from "../../common/cluster/cluster"; -import type { GetPortFromStream } from "../utils/get-port-from-stream.injectable"; -import { observable, when } from "mobx"; -import type { SelfSignedCert } from "selfsigned"; -import assert from "assert"; -import { TypedRegEx } from "typed-regex"; -import type { Spawn } from "../child-process/spawn.injectable"; -import type { Logger } from "../../common/logger"; -import type { WaitUntilPortIsUsed } from "./wait-until-port-is-used/wait-until-port-is-used.injectable"; -import type { GetDirnameOfPath } from "../../common/path/get-dirname.injectable"; -import type { BroadcastConnectionUpdate } from "../cluster/broadcast-connection-update.injectable"; -import type { KubeAuthProxy } from "./create-kube-auth-proxy.injectable"; - -const startingServeMatcher = "starting to serve on (?
.+)"; -const startingServeRegex = Object.assign(TypedRegEx(startingServeMatcher, "i"), { - rawMatcher: startingServeMatcher, -}); - -export interface KubeAuthProxyDependencies { - readonly proxyBinPath: string; - readonly proxyCert: SelfSignedCert; - readonly logger: Logger; - spawn: Spawn; - waitUntilPortIsUsed: WaitUntilPortIsUsed; - getPortFromStream: GetPortFromStream; - dirname: GetDirnameOfPath; - broadcastConnectionUpdate: BroadcastConnectionUpdate; -} - -export class KubeAuthProxyImpl implements KubeAuthProxy { - public readonly apiPrefix = `/${randomBytes(8).toString("hex")}`; - - public get port(): number { - const port = this._port; - - assert(port, "port has not yet been initialized"); - - return port; - } - - protected _port?: number; - protected proxyProcess?: ChildProcess; - protected readonly ready = observable.box(false); - - constructor( - private readonly dependencies: KubeAuthProxyDependencies, - protected readonly cluster: Cluster, - protected readonly env: NodeJS.ProcessEnv, - ) {} - - public async run(): Promise { - if (this.proxyProcess) { - return when(() => this.ready.get()); - } - - const proxyBin = this.dependencies.proxyBinPath; - const cert = this.dependencies.proxyCert; - - this.proxyProcess = this.dependencies.spawn(proxyBin, [], { - env: { - ...this.env, - KUBECONFIG: this.cluster.kubeConfigPath.get(), - KUBECONFIG_CONTEXT: this.cluster.contextName.get(), - API_PREFIX: this.apiPrefix, - PROXY_KEY: cert.private, - PROXY_CERT: cert.cert, - }, - cwd: this.dependencies.dirname(this.cluster.kubeConfigPath.get()), - }); - this.proxyProcess.on("error", (error) => { - this.dependencies.broadcastConnectionUpdate({ - level: "error", - message: error.message, - }); - this.exit(); - }); - - this.proxyProcess.on("exit", (code) => { - if (code) { - this.dependencies.broadcastConnectionUpdate({ - level: "error", - message: `proxy exited with code: ${code}`, - }); - } else { - this.dependencies.broadcastConnectionUpdate({ - level: "info", - message: "proxy exited successfully", - }); - } - this.exit(); - }); - - this.proxyProcess.on("disconnect", () => { - this.dependencies.broadcastConnectionUpdate({ - level: "error", - message: "Proxy disconnected communications", - }); - this.exit(); - }); - - assert(this.proxyProcess.stderr); - assert(this.proxyProcess.stdout); - - this.proxyProcess.stderr.on("data", (data: Buffer) => { - if (data.includes("http: TLS handshake error")) { - return; - } - - this.dependencies.broadcastConnectionUpdate({ - level: "error", - message: data.toString(), - }); - }); - - this.proxyProcess.stdout.on("data", (data: Buffer) => { - if (typeof this._port === "number") { - this.dependencies.broadcastConnectionUpdate({ - level: "info", - message: data.toString(), - }); - } - }); - - this._port = await this.dependencies.getPortFromStream(this.proxyProcess.stdout, { - lineRegex: startingServeRegex, - onFind: () => this.dependencies.broadcastConnectionUpdate({ - level: "info", - message: "Authentication proxy started", - }), - }); - - this.dependencies.logger.info(`[KUBE-AUTH-PROXY]: found port=${this._port}`); - - try { - await this.dependencies.waitUntilPortIsUsed(this.port, 500, 10000); - this.ready.set(true); - } catch (error) { - this.dependencies.logger.warn("[KUBE-AUTH-PROXY]: waitUntilUsed failed", error); - this.dependencies.broadcastConnectionUpdate({ - level: "error", - message: "Proxy port failed to be used within time limit, restarting...", - }); - this.exit(); - - return this.run(); - } - } - - public exit() { - this.ready.set(false); - - if (this.proxyProcess) { - this.dependencies.logger.debug("[KUBE-AUTH]: stopping local proxy", this.cluster.getMeta()); - this.proxyProcess.removeAllListeners(); - this.proxyProcess.stderr?.removeAllListeners(); - this.proxyProcess.stdout?.removeAllListeners(); - this.proxyProcess.kill(); - this.proxyProcess = undefined; - } - } -} diff --git a/packages/core/src/main/lens-proxy/proxy-functions/kube-api-upgrade-request.injectable.ts b/packages/core/src/main/lens-proxy/proxy-functions/kube-api-upgrade-request.injectable.ts index d6ddfca49a..a8f7b03b32 100644 --- a/packages/core/src/main/lens-proxy/proxy-functions/kube-api-upgrade-request.injectable.ts +++ b/packages/core/src/main/lens-proxy/proxy-functions/kube-api-upgrade-request.injectable.ts @@ -6,24 +6,24 @@ import { chunk } from "lodash"; import type { ConnectionOptions } from "tls"; import { connect } from "tls"; -import url, { URL } from "url"; +import url from "url"; import { apiKubePrefix } from "../../../common/vars"; import { getInjectable } from "@ogre-tools/injectable"; import type { LensProxyApiRequest } from "../lens-proxy"; import kubeAuthProxyServerInjectable from "../../cluster/kube-auth-proxy-server.injectable"; import kubeAuthProxyCertificateInjectable from "../../kube-auth-proxy/kube-auth-proxy-certificate.injectable"; +import clusterApiUrlInjectable from "../../../features/cluster/connections/main/api-url.injectable"; const skipRawHeaders = new Set(["Host", "Authorization"]); const kubeApiUpgradeRequestInjectable = getInjectable({ id: "kube-api-upgrade-request", instantiate: (di): LensProxyApiRequest => async ({ req, socket, head, cluster }) => { - const clusterUrl = new URL(cluster.apiUrl.get()); + const clusterApiUrl = await di.inject(clusterApiUrlInjectable, cluster)(); const kubeAuthProxyServer = di.inject(kubeAuthProxyServerInjectable, cluster); - const kubeAuthProxyCertificate = di.inject(kubeAuthProxyCertificateInjectable, clusterUrl.hostname); + const kubeAuthProxyCertificate = di.inject(kubeAuthProxyCertificateInjectable, clusterApiUrl.hostname); const proxyUrl = await kubeAuthProxyServer.ensureAuthProxyUrl() + req.url.replace(apiKubePrefix, ""); - const apiUrl = url.parse(cluster.apiUrl.get()); const pUrl = url.parse(proxyUrl); const connectOpts: ConnectionOptions = { port: pUrl.port ? parseInt(pUrl.port) : undefined, @@ -33,7 +33,7 @@ const kubeApiUpgradeRequestInjectable = getInjectable({ const proxySocket = connect(connectOpts, () => { proxySocket.write(`${req.method} ${pUrl.path} HTTP/1.1\r\n`); - proxySocket.write(`Host: ${apiUrl.host}\r\n`); + proxySocket.write(`Host: ${clusterApiUrl.host}\r\n`); for (const [key, value] of chunk(req.rawHeaders, 2)) { if (skipRawHeaders.has(key)) { diff --git a/packages/core/src/main/routes/kubeconfig-route/get-service-account-route.injectable.ts b/packages/core/src/main/routes/kubeconfig-route/get-service-account-route.injectable.ts index 08aef8da1d..267a3eafe7 100644 --- a/packages/core/src/main/routes/kubeconfig-route/get-service-account-route.injectable.ts +++ b/packages/core/src/main/routes/kubeconfig-route/get-service-account-route.injectable.ts @@ -5,12 +5,11 @@ import { apiPrefix } from "../../../common/vars"; import { getRouteInjectable } from "../../router/router.injectable"; -import type { Cluster } from "../../../common/cluster/cluster"; -import type { V1Secret } from "@kubernetes/client-node"; import { CoreV1Api } from "@kubernetes/client-node"; import { clusterRoute } from "../../router/route"; -import { dump } from "js-yaml"; +import * as yaml from "js-yaml"; import loadProxyKubeconfigInjectable from "../../cluster/load-proxy-kubeconfig.injectable"; +import clusterApiUrlInjectable from "../../../features/cluster/connections/main/api-url.injectable"; const getServiceAccountRouteInjectable = getRouteInjectable({ id: "get-service-account-route", @@ -25,73 +24,57 @@ const getServiceAccountRouteInjectable = getRouteInjectable({ const secretList = await client.listNamespacedSecret(params.namespace); const secret = secretList.body.items.find(secret => { - const { annotations } = secret.metadata ?? {}; + const { annotations = {}} = secret.metadata ?? {}; - return annotations?.["kubernetes.io/service-account.name"] === params.account; + return annotations["kubernetes.io/service-account.name"] === params.account; }); - if (!secret) { + if (!secret || !secret.data || !secret.metadata) { return { error: "No secret found", statusCode: 404, }; } - const kubeconfig = generateKubeConfig(params.account, secret, cluster); - - if (!kubeconfig) { - return { - error: "No secret found", - statusCode: 404, - }; - } + const { token, "ca.crt": caCrt } = secret.data; + const apiUrl = (await di.inject(clusterApiUrlInjectable, cluster)()).toString(); + const contextName = cluster.contextName.get(); return { - response: kubeconfig, + response: yaml.dump({ + apiVersion: "v1", + kind: "Config", + clusters: [ + { + name: contextName, + cluster: { + server: apiUrl, + "certificate-authority-data": caCrt, + }, + }, + ], + users: [ + { + name: params.account, + user: { + token: Buffer.from(token, "base64").toString("utf8"), + }, + }, + ], + contexts: [ + { + name: `${contextName}-${params.account}`, + context: { + user: params.account, + cluster: contextName, + namespace: secret.metadata.namespace, + }, + }, + ], + "current-context": contextName, + }), }; }), }); export default getServiceAccountRouteInjectable; - -function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster): string | undefined { - if (!secret.data || !secret.metadata) { - return undefined; - } - - const { token, "ca.crt": caCrt } = secret.data; - const tokenData = Buffer.from(token, "base64"); - - return dump({ - "apiVersion": "v1", - "kind": "Config", - "clusters": [ - { - "name": cluster.contextName.get(), - "cluster": { - "server": cluster.apiUrl.get(), - "certificate-authority-data": caCrt, - }, - }, - ], - "users": [ - { - "name": username, - "user": { - "token": tokenData.toString("utf8"), - }, - }, - ], - "contexts": [ - { - "name": [cluster.contextName.get(), username].join("-"), - "context": { - "user": username, - "cluster": cluster.contextName.get(), - "namespace": secret.metadata.namespace, - }, - }, - ], - "current-context": cluster.contextName.get(), - }); -} diff --git a/packages/core/src/main/shell-session/local-shell-session/techincal.test.ts b/packages/core/src/main/shell-session/local-shell-session/techincal.test.ts index f37e690561..6d921ee5fe 100644 --- a/packages/core/src/main/shell-session/local-shell-session/techincal.test.ts +++ b/packages/core/src/main/shell-session/local-shell-session/techincal.test.ts @@ -103,8 +103,6 @@ describe("technical unit tests for local shell sessions", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-kube-config-path", - }, { - clusterServerUrl: "https://localhost:9999", }); await openLocalShellSession({ diff --git a/packages/core/src/renderer/components/+config-horizontal-pod-autoscalers/hpa-details.test.tsx b/packages/core/src/renderer/components/+config-horizontal-pod-autoscalers/hpa-details.test.tsx index aa2d2a3b32..3190be6edd 100644 --- a/packages/core/src/renderer/components/+config-horizontal-pod-autoscalers/hpa-details.test.tsx +++ b/packages/core/src/renderer/components/+config-horizontal-pod-autoscalers/hpa-details.test.tsx @@ -53,8 +53,6 @@ describe("", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); render = renderFor(di); diff --git a/packages/core/src/renderer/components/+config-secrets/__tests__/secret-details.test.tsx b/packages/core/src/renderer/components/+config-secrets/__tests__/secret-details.test.tsx index e110056ab0..795c204975 100644 --- a/packages/core/src/renderer/components/+config-secrets/__tests__/secret-details.test.tsx +++ b/packages/core/src/renderer/components/+config-secrets/__tests__/secret-details.test.tsx @@ -31,8 +31,6 @@ describe("SecretDetails tests", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); const secret = new Secret({ diff --git a/packages/core/src/renderer/components/+namespaces/namespace-select-filter.test.tsx b/packages/core/src/renderer/components/+namespaces/namespace-select-filter.test.tsx index b2369689e7..a067224811 100644 --- a/packages/core/src/renderer/components/+namespaces/namespace-select-filter.test.tsx +++ b/packages/core/src/renderer/components/+namespaces/namespace-select-filter.test.tsx @@ -62,8 +62,6 @@ describe("", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); namespaceStore = di.inject(namespaceStoreInjectable); diff --git a/packages/core/src/renderer/components/+namespaces/namespace-store.test.ts b/packages/core/src/renderer/components/+namespaces/namespace-store.test.ts index c4b26e9b8a..f274746b0f 100644 --- a/packages/core/src/renderer/components/+namespaces/namespace-store.test.ts +++ b/packages/core/src/renderer/components/+namespaces/namespace-store.test.ts @@ -115,8 +115,6 @@ describe("NamespaceStore", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); namespaceStore = di.inject(namespaceStoreInjectable); diff --git a/packages/core/src/renderer/components/+user-management/+cluster-role-bindings/__tests__/dialog.test.tsx b/packages/core/src/renderer/components/+user-management/+cluster-role-bindings/__tests__/dialog.test.tsx index 04cf657606..3af6b8c8ff 100644 --- a/packages/core/src/renderer/components/+user-management/+cluster-role-bindings/__tests__/dialog.test.tsx +++ b/packages/core/src/renderer/components/+user-management/+cluster-role-bindings/__tests__/dialog.test.tsx @@ -40,8 +40,6 @@ describe("ClusterRoleBindingDialog tests", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); render = renderFor(di); diff --git a/packages/core/src/renderer/components/+user-management/+role-bindings/__tests__/dialog.test.tsx b/packages/core/src/renderer/components/+user-management/+role-bindings/__tests__/dialog.test.tsx index 96f7bb5b68..16e2b8e5d1 100644 --- a/packages/core/src/renderer/components/+user-management/+role-bindings/__tests__/dialog.test.tsx +++ b/packages/core/src/renderer/components/+user-management/+role-bindings/__tests__/dialog.test.tsx @@ -36,8 +36,6 @@ describe("RoleBindingDialog tests", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); render = renderFor(di); diff --git a/packages/core/src/renderer/components/__tests__/cronjob.store.test.ts b/packages/core/src/renderer/components/__tests__/cronjob.store.test.ts index 4e27c286eb..83bc2767e6 100644 --- a/packages/core/src/renderer/components/__tests__/cronjob.store.test.ts +++ b/packages/core/src/renderer/components/__tests__/cronjob.store.test.ts @@ -131,8 +131,6 @@ describe("CronJob Store tests", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); cronJobStore = di.inject(cronJobStoreInjectable); diff --git a/packages/core/src/renderer/components/__tests__/daemonset.store.test.ts b/packages/core/src/renderer/components/__tests__/daemonset.store.test.ts index bfd4861f48..72ab9e20b1 100644 --- a/packages/core/src/renderer/components/__tests__/daemonset.store.test.ts +++ b/packages/core/src/renderer/components/__tests__/daemonset.store.test.ts @@ -148,8 +148,6 @@ describe("DaemonSet Store tests", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); const podStore = di.inject(podStoreInjectable); diff --git a/packages/core/src/renderer/components/__tests__/deployments.store.test.ts b/packages/core/src/renderer/components/__tests__/deployments.store.test.ts index 23987ccd37..f1a8de27a0 100644 --- a/packages/core/src/renderer/components/__tests__/deployments.store.test.ts +++ b/packages/core/src/renderer/components/__tests__/deployments.store.test.ts @@ -220,8 +220,6 @@ describe("Deployment Store tests", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); const podStore = di.inject(podStoreInjectable); diff --git a/packages/core/src/renderer/components/__tests__/job.store.test.ts b/packages/core/src/renderer/components/__tests__/job.store.test.ts index 73a5cade8f..6f08fc5e7a 100644 --- a/packages/core/src/renderer/components/__tests__/job.store.test.ts +++ b/packages/core/src/renderer/components/__tests__/job.store.test.ts @@ -185,8 +185,6 @@ describe("Job Store tests", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); jobStore = di.inject(jobStoreInjectable); diff --git a/packages/core/src/renderer/components/__tests__/pods.store.test.ts b/packages/core/src/renderer/components/__tests__/pods.store.test.ts index 03a057458d..79d4f0d4de 100644 --- a/packages/core/src/renderer/components/__tests__/pods.store.test.ts +++ b/packages/core/src/renderer/components/__tests__/pods.store.test.ts @@ -131,8 +131,6 @@ describe("Pod Store tests", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); podStore = di.inject(podStoreInjectable); diff --git a/packages/core/src/renderer/components/__tests__/replicaset.store.test.ts b/packages/core/src/renderer/components/__tests__/replicaset.store.test.ts index aea690a507..18a0cb813e 100644 --- a/packages/core/src/renderer/components/__tests__/replicaset.store.test.ts +++ b/packages/core/src/renderer/components/__tests__/replicaset.store.test.ts @@ -148,8 +148,6 @@ describe("ReplicaSet Store tests", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); const podStore = di.inject(podStoreInjectable); diff --git a/packages/core/src/renderer/components/__tests__/statefulset.store.test.ts b/packages/core/src/renderer/components/__tests__/statefulset.store.test.ts index 9e7ada1aa1..de6acf220a 100644 --- a/packages/core/src/renderer/components/__tests__/statefulset.store.test.ts +++ b/packages/core/src/renderer/components/__tests__/statefulset.store.test.ts @@ -148,8 +148,6 @@ describe("StatefulSet Store tests", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); statefulSetStore = di.inject(statefulSetStoreInjectable); diff --git a/packages/core/src/renderer/components/cluster-settings/__tests__/cluster-local-terminal-settings.test.tsx b/packages/core/src/renderer/components/cluster-settings/__tests__/cluster-local-terminal-settings.test.tsx index ae807bab0a..7abaf8ac15 100644 --- a/packages/core/src/renderer/components/cluster-settings/__tests__/cluster-local-terminal-settings.test.tsx +++ b/packages/core/src/renderer/components/cluster-settings/__tests__/cluster-local-terminal-settings.test.tsx @@ -55,8 +55,6 @@ describe("ClusterLocalTerminalSettings", () => { terminalCWD: "/foobar", defaultNamespace: "kube-system", }, - }, { - clusterServerUrl: "https://localhost:12345", }); const dom = render(); @@ -76,8 +74,6 @@ describe("ClusterLocalTerminalSettings", () => { preferences: { terminalCWD: "/foobar", }, - }, { - clusterServerUrl: "https://localhost:12345", }); const dom = render(); @@ -98,8 +94,6 @@ describe("ClusterLocalTerminalSettings", () => { preferences: { terminalCWD: "/foobar", }, - }, { - clusterServerUrl: "https://localhost:12345", }); const dom = render(); @@ -129,8 +123,6 @@ describe("ClusterLocalTerminalSettings", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some/path", - }, { - clusterServerUrl: "https://localhost:12345", }); const dom = render(); @@ -161,8 +153,6 @@ describe("ClusterLocalTerminalSettings", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some/path", - }, { - clusterServerUrl: "https://localhost:12345", }); const dom = render(); diff --git a/packages/core/src/renderer/components/cluster-settings/__tests__/icon-settings.test.tsx b/packages/core/src/renderer/components/cluster-settings/__tests__/icon-settings.test.tsx index 31bf671854..4c88f34503 100644 --- a/packages/core/src/renderer/components/cluster-settings/__tests__/icon-settings.test.tsx +++ b/packages/core/src/renderer/components/cluster-settings/__tests__/icon-settings.test.tsx @@ -17,32 +17,6 @@ import { clusterIconSettingsComponentInjectionToken, clusterIconSettingsMenuInje import { runInAction } from "mobx"; import { getInjectable, type DiContainer } from "@ogre-tools/injectable"; -const cluster = new Cluster({ - contextName: "some-context", - id: "some-id", - kubeConfigPath: "/some/path/to/kubeconfig", - preferences: { - clusterName: "some-cluster-name", - }, -}, { - clusterServerUrl: "https://localhost:9999", -}); - -const clusterEntity = new KubernetesCluster({ - metadata: { - labels: {}, - name: "some-kubernetes-cluster", - uid: "some-entity-id", - }, - spec: { - kubeconfigContext: "some-context", - kubeconfigPath: "/some/path/to/kubeconfig", - }, - status: { - phase: "connecting", - }, -}); - const newMenuItem = getInjectable({ id: "cluster-icon-settings-menu-test-item", @@ -67,7 +41,7 @@ function CustomSettingsComponent(props: ClusterIconSettingComponentProps) {
); -} +} const newSettingsReactComponent = getInjectable({ id: "cluster-icon-settings-react-component", @@ -86,8 +60,31 @@ describe("Icon settings", () => { beforeEach(() => { di = getDiForUnitTesting(); - + const render = renderFor(di); + const cluster = new Cluster({ + contextName: "some-context", + id: "some-id", + kubeConfigPath: "/some/path/to/kubeconfig", + preferences: { + clusterName: "some-cluster-name", + }, + }); + + const clusterEntity = new KubernetesCluster({ + metadata: { + labels: {}, + name: "some-kubernetes-cluster", + uid: "some-entity-id", + }, + spec: { + kubeconfigContext: "some-context", + kubeconfigPath: "/some/path/to/kubeconfig", + }, + status: { + phase: "connecting", + }, + }); rendered = render( , diff --git a/packages/core/src/renderer/components/kube-object-list-layout/kube-object-list-layout.test.tsx b/packages/core/src/renderer/components/kube-object-list-layout/kube-object-list-layout.test.tsx index 74f31ff3dd..691000c887 100644 --- a/packages/core/src/renderer/components/kube-object-list-layout/kube-object-list-layout.test.tsx +++ b/packages/core/src/renderer/components/kube-object-list-layout/kube-object-list-layout.test.tsx @@ -38,8 +38,6 @@ describe("kube-object-list-layout", () => { contextName: "some-context-name", id: "some-cluster-id", kubeConfigPath: "/some-path-to-a-kubeconfig", - }, { - clusterServerUrl: "https://localhost:8080", })); render = renderFor(di); diff --git a/packages/core/src/renderer/components/test-utils/get-application-builder.tsx b/packages/core/src/renderer/components/test-utils/get-application-builder.tsx index ce103d7a83..48dd102bf8 100644 --- a/packages/core/src/renderer/components/test-utils/get-application-builder.tsx +++ b/packages/core/src/renderer/components/test-utils/get-application-builder.tsx @@ -528,8 +528,6 @@ export const getApplicationBuilder = () => { id: "some-cluster-id", contextName: "some-context-name", kubeConfigPath: "/some-path-to-kube-config", - }, { - clusterServerUrl: "https://localhost:12345", }); windowDi.override(activeKubernetesClusterInjectable, () => diff --git a/packages/core/src/renderer/frames/cluster-frame/cluster-frame.test.tsx b/packages/core/src/renderer/frames/cluster-frame/cluster-frame.test.tsx index 4ad315ab98..e3ce80e13a 100644 --- a/packages/core/src/renderer/frames/cluster-frame/cluster-frame.test.tsx +++ b/packages/core/src/renderer/frames/cluster-frame/cluster-frame.test.tsx @@ -48,16 +48,11 @@ describe("", () => { testUsingFakeTime("2000-01-01 12:00:00am"); - cluster = new Cluster( - { - contextName: "my-cluster", - id: "123456", - kubeConfigPath: "/irrelavent", - }, - { - clusterServerUrl: "https://localhost", - }, - ); + cluster = new Cluster({ + contextName: "my-cluster", + id: "123456", + kubeConfigPath: "/irrelavent", + }); di.override(hostedClusterInjectable, () => cluster); di.override(hostedClusterIdInjectable, () => cluster.id); diff --git a/packages/utility-features/utilities/src/collection-functions.ts b/packages/utility-features/utilities/src/collection-functions.ts index 0c2d5cf119..9a50bb917f 100644 --- a/packages/utility-features/utilities/src/collection-functions.ts +++ b/packages/utility-features/utilities/src/collection-functions.ts @@ -85,6 +85,15 @@ export async function getOrInsertWithAsync(map: Map, key: K, asyncBu return map.get(key)!; } +/** + * Insert `val` into `map` under `key` and then get the value back + */ +export function setAndGet(map: Map, key: K, val: V): V { + map.set(key, val); + + return map.get(key)!; +} + /** * Set the value associated with `key` iff there was not a previous value * @param map The map to interact with From b5a085b55c455d48a67004309f00a69545f9d500 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 31 Mar 2023 15:30:21 -0400 Subject: [PATCH 28/35] Get dev mode fixed (#7447) * Get dev mode fixed Signed-off-by: Sebastian Malton * Add empty scripts for windows to satisfy run-script-os Signed-off-by: Sebastian Malton --------- Signed-off-by: Sebastian Malton --- .nxignore | 4 ++++ package-lock.json | 12 ++++++++---- package.json | 5 ++++- packages/bump-version-for-cron/package.json | 8 ++++++-- packages/core/package.json | 8 -------- packages/ensure-binaries/package.json | 6 +++++- packages/generate-tray-icons/package.json | 6 +++++- packages/legacy-extension-example/package.json | 1 - packages/open-lens/package.json | 12 +----------- packages/release-tool/package.json | 8 ++++++-- .../application/agnostic/package.json | 2 +- .../application/electron-main/package.json | 2 +- .../application/legacy-extensions/package.json | 2 +- .../technical-features/feature-core/package.json | 2 +- .../messaging/agnostic/package.json | 2 +- .../messaging/computed-channel/package.json | 2 +- .../messaging/electron/main/package.json | 2 +- .../messaging/electron/renderer/package.json | 2 +- .../messaging/message-bridge-fake/package.json | 2 +- .../react-application/package.json | 2 +- .../react-testing-library-discovery/package.json | 2 +- packages/utility-features/run-many/package.json | 2 +- .../startable-stoppable/package.json | 7 +------ packages/utility-features/test-utils/package.json | 4 ++-- packages/utility-features/utilities/package.json | 2 +- 25 files changed, 55 insertions(+), 52 deletions(-) create mode 100644 .nxignore diff --git a/.nxignore b/.nxignore new file mode 100644 index 0000000000..885f2fc229 --- /dev/null +++ b/.nxignore @@ -0,0 +1,4 @@ +packages/**/dist +packages/**/static/build +packages/**/build/webpack +packages/**/binaries diff --git a/package-lock.json b/package-lock.json index d398f4aef3..1232778a9e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37600,7 +37600,8 @@ "@swc/core": "^1.3.44", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", - "rimraf": "^4.4.1" + "rimraf": "^4.4.1", + "run-script-os": "^1.1.6" } }, "packages/bump-version-for-cron/node_modules/@swc/core": { @@ -39514,7 +39515,8 @@ "@types/node": "^16.18.11", "@types/semver": "^7.3.13", "@types/tar-stream": "^2.2.2", - "rimraf": "^4.4.1" + "rimraf": "^4.4.1", + "run-script-os": "^1.1.6" } }, "packages/ensure-binaries/node_modules/@swc/core": { @@ -40043,7 +40045,8 @@ "@types/jsdom": "^20.0.1", "@types/node": "^18.11.18", "@types/sharp": "^0.31.1", - "rimraf": "^4.4.1" + "rimraf": "^4.4.1", + "run-script-os": "^1.1.6" } }, "packages/generate-tray-icons/node_modules/@swc/core": { @@ -43704,7 +43707,8 @@ "@types/inquirer": "^9.0.3", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", - "rimraf": "^4.4.1" + "rimraf": "^4.4.1", + "run-script-os": "^1.1.6" } }, "packages/release-tool/node_modules/@swc/core": { diff --git a/package.json b/package.json index 00b7c62388..016cb3464c 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,10 @@ "build:docs": "lerna run --stream build:docs", "clean": "lerna run clean --stream", "clean:node_modules": "lerna clean -y && rimraf node_modules", - "dev": "lerna run dev --stream --skip-nx-cache", + "dev": "cross-env NODE_ENV=development lerna run build --stream --skip-nx-cache", + "postdev": "lerna watch -- lerna run build --stream --scope \\$LERNA_PACKAGE_NAME", + "prestart-dev": "cd packages/open-lens && rimraf static/build/ && npm run build:tray-icons && npm run download:binaries", + "start-dev": "lerna run start", "lint": "lerna run lint --stream", "lint:fix": "lerna run lint:fix --stream", "mkdocs:serve-local": "docker build -t mkdocs-serve-local:latest mkdocs/ && docker run --rm -it -p 8000:8000 -v ${PWD}:/docs mkdocs-serve-local:latest", diff --git a/packages/bump-version-for-cron/package.json b/packages/bump-version-for-cron/package.json index efb3a3f786..c5a0ad681c 100644 --- a/packages/bump-version-for-cron/package.json +++ b/packages/bump-version-for-cron/package.json @@ -5,7 +5,10 @@ "license": "MIT", "scripts": { "clean": "rimraf dist/", - "build": "swc ./src/index.ts -d ./dist" + "build": "swc ./src/index.ts -d ./dist", + "postbuild": "run-script-os", + "postbuild:windows": "", + "postbuild:nix": "chmod u+x ./dist/index.js" }, "type": "module", "bin": "./dist/index.js", @@ -26,6 +29,7 @@ "@swc/core": "^1.3.44", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", - "rimraf": "^4.4.1" + "rimraf": "^4.4.1", + "run-script-os": "^1.1.6" } } diff --git a/packages/core/package.json b/packages/core/package.json index be81f74f14..2d06f347d9 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -48,8 +48,6 @@ "scripts": { "build": "cross-env NODE_ENV=production webpack --config webpack/library-bundle.ts --progress", "clean": "rimraf dist static/build", - "prepare:dev": "cross-env NODE_ENV=development webpack --config webpack/library-bundle.ts --progress", - "dev": "cross-env NODE_ENV=development webpack --config webpack/library-bundle.ts --watch", "test:unit": "jest --testPathIgnorePatterns integration", "test:watch": "func() { jest ${1} --watch --testPathIgnorePatterns integration; }; func", "lint": "PROD=true eslint --ext js,ts,tsx --max-warnings=0 .", @@ -98,7 +96,6 @@ ], "runtime": "@side/jest-runtime" }, - "build": {}, "nx": { "targets": { "build": { @@ -108,11 +105,6 @@ "outputs": [ "{workspaceRoot}/static/build/" ] - }, - "dev": { - "outputs": [ - "{workspaceRoot}/static/build/" - ] } } }, diff --git a/packages/ensure-binaries/package.json b/packages/ensure-binaries/package.json index e12d4a0432..c7d7cb5256 100644 --- a/packages/ensure-binaries/package.json +++ b/packages/ensure-binaries/package.json @@ -7,6 +7,9 @@ "scripts": { "clean": "rimraf dist/", "build": "swc ./src/index.ts -d ./dist/", + "postbuild": "run-script-os", + "postbuild:windows": "", + "postbuild:nix": "chmod u+x ./dist/index.js", "prepare:dev": "npm run build", "prepare": "npm run build" }, @@ -38,6 +41,7 @@ "@types/node": "^16.18.11", "@types/semver": "^7.3.13", "@types/tar-stream": "^2.2.2", - "rimraf": "^4.4.1" + "rimraf": "^4.4.1", + "run-script-os": "^1.1.6" } } diff --git a/packages/generate-tray-icons/package.json b/packages/generate-tray-icons/package.json index ce85daf62f..04d58cc449 100644 --- a/packages/generate-tray-icons/package.json +++ b/packages/generate-tray-icons/package.json @@ -6,6 +6,9 @@ "scripts": { "clean": "rimraf dist/", "build": "swc ./src/index.ts -d ./dist/", + "postbuild": "run-script-os", + "postbuild:windows": "", + "postbuild:nix": "chmod u+x ./dist/index.js", "prepare:dev": "npm run build", "prepare": "npm run build" }, @@ -27,7 +30,8 @@ "@types/jsdom": "^20.0.1", "@types/node": "^18.11.18", "@types/sharp": "^0.31.1", - "rimraf": "^4.4.1" + "rimraf": "^4.4.1", + "run-script-os": "^1.1.6" }, "dependencies": { "arg": "^5.0.2", diff --git a/packages/legacy-extension-example/package.json b/packages/legacy-extension-example/package.json index e2fdde25e2..d37249fdfe 100644 --- a/packages/legacy-extension-example/package.json +++ b/packages/legacy-extension-example/package.json @@ -32,7 +32,6 @@ "scripts": { "clean": "rimraf dist/", "build": "webpack --config webpack.ts", - "dev": "webpack --mode=development --watch --config webpack.ts", "lint": "lens-lint", "lint:fix": "lens-lint --fix" }, diff --git a/packages/open-lens/package.json b/packages/open-lens/package.json index 950b0d2648..7fa19eeb23 100644 --- a/packages/open-lens/package.json +++ b/packages/open-lens/package.json @@ -28,8 +28,7 @@ "build:dir": "npm run compile && electron-builder --dir", "compile": "cross-env NODE_ENV=production webpack --config webpack/webpack.ts --progress", "postcompile": "npm run build:tray-icons && npm run download:binaries", - "predev": "rimraf static/build/ && npm run build:tray-icons && npm run download:binaries", - "dev": "concurrently -i -k \"npm run dev-run -C\" npm:dev:*", + "start": "concurrently -i -k \"npm run dev-run -C\" npm:dev:*", "dev-run": "nodemon --watch ./static/build/main.js --exec \"electron --remote-debugging-port=9223 --inspect .\"", "dev:main": "cross-env NODE_ENV=development webpack --config webpack/main.ts --progress --watch", "dev:renderer": "cross-env NODE_ENV=development ts-node ./webpack/dev-server.ts", @@ -70,15 +69,6 @@ "{workspaceRoot}/static/build/" ] }, - "dev": { - "dependsOn": [ - "^prepare:dev" - ], - "outputs": [ - "{workspaceRoot}/binaries/", - "{workspaceRoot}/static/build/" - ] - }, "build:app": { "dependsOn": [ "build" diff --git a/packages/release-tool/package.json b/packages/release-tool/package.json index b1c475aed2..22b3180c3d 100644 --- a/packages/release-tool/package.json +++ b/packages/release-tool/package.json @@ -7,7 +7,10 @@ "private": true, "scripts": { "clean": "rimraf dist/", - "build": "swc ./src/index.ts -d ./dist" + "build": "swc ./src/index.ts -d ./dist", + "postbuild": "run-script-os", + "postbuild:windows": "", + "postbuild:nix": "chmod u+x ./dist/index.js" }, "bin": { "create-release-pr": "./dist/index.js" @@ -19,7 +22,8 @@ "@types/inquirer": "^9.0.3", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", - "rimraf": "^4.4.1" + "rimraf": "^4.4.1", + "run-script-os": "^1.1.6" }, "dependencies": { "chalk": "^5.2.0", diff --git a/packages/technical-features/application/agnostic/package.json b/packages/technical-features/application/agnostic/package.json index ab869a87c0..9874443c4f 100644 --- a/packages/technical-features/application/agnostic/package.json +++ b/packages/technical-features/application/agnostic/package.json @@ -24,8 +24,8 @@ "license": "MIT", "homepage": "https://github.com/lensapp/lens", "scripts": { + "clean": "rimraf dist/", "build": "webpack", - "dev": "webpack --mode=development --watch", "test:unit": "jest --coverage --runInBand", "lint": "lens-lint", "lint:fix": "lens-lint --fix" diff --git a/packages/technical-features/application/electron-main/package.json b/packages/technical-features/application/electron-main/package.json index 96d649a362..92817dc407 100644 --- a/packages/technical-features/application/electron-main/package.json +++ b/packages/technical-features/application/electron-main/package.json @@ -24,8 +24,8 @@ "license": "MIT", "homepage": "https://github.com/lensapp/lens", "scripts": { + "clean": "rimraf dist/", "build": "webpack", - "dev": "webpack --mode=development --watch", "test:unit": "jest --coverage --runInBand", "lint": "lens-lint", "lint:fix": "lens-lint --fix" diff --git a/packages/technical-features/application/legacy-extensions/package.json b/packages/technical-features/application/legacy-extensions/package.json index 6e92ca7c02..ee170be546 100644 --- a/packages/technical-features/application/legacy-extensions/package.json +++ b/packages/technical-features/application/legacy-extensions/package.json @@ -24,8 +24,8 @@ "license": "MIT", "homepage": "https://github.com/lensapp/lens", "scripts": { + "clean": "rimraf dist/", "build": "webpack", - "dev": "webpack --mode=development --watch", "lint": "lens-lint", "lint:fix": "lens-lint --fix" }, diff --git a/packages/technical-features/feature-core/package.json b/packages/technical-features/feature-core/package.json index cabb6e17a0..8d989c720c 100644 --- a/packages/technical-features/feature-core/package.json +++ b/packages/technical-features/feature-core/package.json @@ -24,8 +24,8 @@ "license": "MIT", "homepage": "https://github.com/lensapp/lens", "scripts": { + "clean": "rimraf dist/", "build": "webpack", - "dev": "webpack --mode=development --watch", "test:unit": "jest --coverage --runInBand", "lint": "lens-lint", "lint:fix": "lens-lint --fix" diff --git a/packages/technical-features/messaging/agnostic/package.json b/packages/technical-features/messaging/agnostic/package.json index 085304d4e0..ac4383c37a 100644 --- a/packages/technical-features/messaging/agnostic/package.json +++ b/packages/technical-features/messaging/agnostic/package.json @@ -26,8 +26,8 @@ "license": "MIT", "homepage": "https://github.com/lensapp/lens", "scripts": { + "clean": "rimraf dist/", "build": "webpack", - "dev": "webpack --mode=development --watch", "test:unit": "jest --coverage --runInBand", "lint:fix": "lens-lint --fix", "lint": "lens-lint" diff --git a/packages/technical-features/messaging/computed-channel/package.json b/packages/technical-features/messaging/computed-channel/package.json index 81c4f80013..05763dba08 100644 --- a/packages/technical-features/messaging/computed-channel/package.json +++ b/packages/technical-features/messaging/computed-channel/package.json @@ -26,8 +26,8 @@ "license": "MIT", "homepage": "https://github.com/lensapp/lens", "scripts": { + "clean": "rimraf dist/", "build": "webpack", - "dev": "webpack --mode=development --watch", "test:unit": "jest --coverage --runInBand", "lint": "lens-lint", "lint:fix": "lens-lint --fix" diff --git a/packages/technical-features/messaging/electron/main/package.json b/packages/technical-features/messaging/electron/main/package.json index ff1a76a7d3..b1e17ef979 100644 --- a/packages/technical-features/messaging/electron/main/package.json +++ b/packages/technical-features/messaging/electron/main/package.json @@ -26,8 +26,8 @@ "license": "MIT", "homepage": "https://github.com/lensapp/lens", "scripts": { + "clean": "rimraf dist/", "build": "webpack", - "dev": "webpack --mode=development --watch", "test:unit": "jest --coverage --runInBand", "lint": "lens-lint", "lint:fix": "lens-lint --fix" diff --git a/packages/technical-features/messaging/electron/renderer/package.json b/packages/technical-features/messaging/electron/renderer/package.json index 75fcb8e38f..f3864f7e4d 100644 --- a/packages/technical-features/messaging/electron/renderer/package.json +++ b/packages/technical-features/messaging/electron/renderer/package.json @@ -26,8 +26,8 @@ "license": "MIT", "homepage": "https://github.com/lensapp/lens", "scripts": { + "clean": "rimraf dist/", "build": "webpack", - "dev": "webpack --mode=development --watch", "test:unit": "jest --coverage --runInBand", "lint": "lens-lint", "lint:fix": "lens-lint --fix" diff --git a/packages/technical-features/messaging/message-bridge-fake/package.json b/packages/technical-features/messaging/message-bridge-fake/package.json index 6837504a0e..a48b2b5a33 100644 --- a/packages/technical-features/messaging/message-bridge-fake/package.json +++ b/packages/technical-features/messaging/message-bridge-fake/package.json @@ -26,8 +26,8 @@ "license": "MIT", "homepage": "https://github.com/lensapp/lens", "scripts": { + "clean": "rimraf dist/", "build": "webpack", - "dev": "webpack --mode=development --watch", "test:unit": "jest --coverage --runInBand", "lint:fix": "lens-lint --fix", "lint": "lens-lint" diff --git a/packages/technical-features/react-application/package.json b/packages/technical-features/react-application/package.json index e3ca7956a8..45a2b3e1f5 100644 --- a/packages/technical-features/react-application/package.json +++ b/packages/technical-features/react-application/package.json @@ -24,8 +24,8 @@ "license": "MIT", "homepage": "https://github.com/lensapp/lens", "scripts": { + "clean": "rimraf dist/", "build": "webpack", - "dev": "webpack --mode=development --watch", "test:unit": "jest --coverage --runInBand", "lint": "lens-lint", "lint:fix": "lens-lint --fix" diff --git a/packages/utility-features/react-testing-library-discovery/package.json b/packages/utility-features/react-testing-library-discovery/package.json index 489549a187..3f49c82588 100644 --- a/packages/utility-features/react-testing-library-discovery/package.json +++ b/packages/utility-features/react-testing-library-discovery/package.json @@ -20,8 +20,8 @@ "license": "MIT", "homepage": "https://github.com/lensapp/lens", "scripts": { + "clean": "rimraf dist/", "build": "webpack", - "dev": "webpack --mode=development --watch", "lint": "lens-lint", "lint:fix": "lens-lint --fix" }, diff --git a/packages/utility-features/run-many/package.json b/packages/utility-features/run-many/package.json index 1fa8af2ba1..0b3484794d 100644 --- a/packages/utility-features/run-many/package.json +++ b/packages/utility-features/run-many/package.json @@ -20,8 +20,8 @@ "license": "MIT", "homepage": "https://github.com/lensapp/lens", "scripts": { + "clean": "rimraf dist/", "build": "webpack", - "dev": "webpack --mode=development --watch", "test:unit": "jest --coverage --runInBand" }, "peerDependencies": { diff --git a/packages/utility-features/startable-stoppable/package.json b/packages/utility-features/startable-stoppable/package.json index 940e1e91b2..92b434294c 100644 --- a/packages/utility-features/startable-stoppable/package.json +++ b/packages/utility-features/startable-stoppable/package.json @@ -4,15 +4,10 @@ "version": "1.0.0-alpha.1", "description": "TBD", "type": "commonjs", - "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" }, - - "files": [ - "build" - ], "repository": { "type": "git", "url": "git+https://github.com/lensapp/lens.git" @@ -26,8 +21,8 @@ "license": "MIT", "homepage": "https://github.com/lensapp/lens", "scripts": { + "clean": "rimraf dist/", "build": "webpack", - "dev": "webpack --mode=development --watch", "test:unit": "jest --coverage --runInBand", "lint": "lens-lint", "lint:fix": "lens-lint --fix" diff --git a/packages/utility-features/test-utils/package.json b/packages/utility-features/test-utils/package.json index 4336c0682b..746dbcfe99 100644 --- a/packages/utility-features/test-utils/package.json +++ b/packages/utility-features/test-utils/package.json @@ -20,8 +20,8 @@ "license": "MIT", "homepage": "https://github.com/lensapp/lens", "scripts": { - "build": "webpack", - "dev": "webpack --mode=development --watch" + "clean": "rimraf dist/", + "build": "webpack" }, "peerDependencies": { "@ogre-tools/injectable": "^15.1.2", diff --git a/packages/utility-features/utilities/package.json b/packages/utility-features/utilities/package.json index 777907d851..d7bafbe16e 100644 --- a/packages/utility-features/utilities/package.json +++ b/packages/utility-features/utilities/package.json @@ -20,8 +20,8 @@ "license": "MIT", "homepage": "https://github.com/lensapp/lens", "scripts": { + "clean": "rimraf dist/", "build": "webpack", - "dev": "webpack --mode=development --watch", "test:unit": "jest --coverage --runInBand" }, "peerDependencies": { From 3b8ef07a9e2184b559e43ade0c623ae78badd6e6 Mon Sep 17 00:00:00 2001 From: Panu Horsmalahti Date: Mon, 3 Apr 2023 13:44:57 +0300 Subject: [PATCH 29/35] conf v10.2.0 (#7462) Signed-off-by: Panu Horsmalahti --- package-lock.json | 83 +++++++++++++++++++++++++++----------- packages/core/package.json | 2 +- 2 files changed, 60 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1232778a9e..d66943ede4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13550,29 +13550,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/conf": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/conf/-/conf-7.1.2.tgz", - "integrity": "sha512-r8/HEoWPFn4CztjhMJaWNAe5n+gPUCSaJ0oufbqDLFKsA1V8JjAG7G+p0pgoDFAws9Bpk2VtVLLXqOBA7WxLeg==", - "dependencies": { - "ajv": "^6.12.2", - "atomically": "^1.3.1", - "debounce-fn": "^4.0.0", - "dot-prop": "^5.2.0", - "env-paths": "^2.2.0", - "json-schema-typed": "^7.0.3", - "make-dir": "^3.1.0", - "onetime": "^5.1.0", - "pkg-up": "^3.1.0", - "semver": "^7.3.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/config-chain": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", @@ -15010,6 +14987,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, "dependencies": { "is-obj": "^2.0.0" }, @@ -38076,7 +38054,7 @@ "await-lock": "^2.2.2", "byline": "^5.0.0", "chokidar": "^3.5.3", - "conf": "^7.1.2", + "conf": "^10.2.0", "crypto-js": "^4.1.1", "electron-devtools-installer": "^3.2.0", "electron-updater": "^4.6.5", @@ -38771,6 +38749,21 @@ "webpack": "^5" } }, + "packages/core/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "packages/core/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -38847,6 +38840,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "packages/core/node_modules/conf": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/conf/-/conf-10.2.0.tgz", + "integrity": "sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg==", + "dependencies": { + "ajv": "^8.6.3", + "ajv-formats": "^2.1.1", + "atomically": "^1.7.0", + "debounce-fn": "^4.0.0", + "dot-prop": "^6.0.1", + "env-paths": "^2.2.1", + "json-schema-typed": "^7.0.3", + "onetime": "^5.1.2", + "pkg-up": "^3.1.0", + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "packages/core/node_modules/diff-sequences": { "version": "29.4.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", @@ -38856,6 +38872,20 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "packages/core/node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "packages/core/node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", @@ -39361,6 +39391,11 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "packages/core/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, "packages/core/node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", diff --git a/packages/core/package.json b/packages/core/package.json index 2d06f347d9..9cb3d0b755 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -128,7 +128,7 @@ "await-lock": "^2.2.2", "byline": "^5.0.0", "chokidar": "^3.5.3", - "conf": "^7.1.2", + "conf": "^10.2.0", "crypto-js": "^4.1.1", "electron-devtools-installer": "^3.2.0", "electron-updater": "^4.6.5", From a73586d84413c29148a3161ff8ccb63d4ae81088 Mon Sep 17 00:00:00 2001 From: Juho Heikka Date: Mon, 3 Apr 2023 15:06:53 +0300 Subject: [PATCH 30/35] Fix metrics visibility logic (#7465) Signed-off-by: Juho Heikka --- .../entity/__tests__/metrics-enabled.test.ts | 52 +++++++++++++++++++ ...cs-details-component-enabled.injectable.ts | 2 +- .../entity/metrics-enabled.injectable.ts | 4 +- .../components/+cluster/cluster-overview.tsx | 3 +- .../+workloads-pods/pod-details-container.tsx | 4 +- 5 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 packages/core/src/renderer/api/catalog/entity/__tests__/metrics-enabled.test.ts diff --git a/packages/core/src/renderer/api/catalog/entity/__tests__/metrics-enabled.test.ts b/packages/core/src/renderer/api/catalog/entity/__tests__/metrics-enabled.test.ts new file mode 100644 index 0000000000..c248133541 --- /dev/null +++ b/packages/core/src/renderer/api/catalog/entity/__tests__/metrics-enabled.test.ts @@ -0,0 +1,52 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { Cluster } from "../../../../../common/cluster/cluster"; +import { getDiForUnitTesting } from "../../../../getDiForUnitTesting"; +import enabledMetricsInjectable from "../metrics-enabled.injectable"; +import activeEntityInternalClusterInjectable from "../get-active-cluster-entity.injectable"; +import { observable } from "mobx"; +import { ClusterMetricsResourceType } from "../../../../../common/cluster-types"; +import type { DiContainer } from "@ogre-tools/injectable"; + +describe("metrics-enabled", () => { + let cluster: Cluster; + let di: DiContainer; + + beforeEach(() => { + di = getDiForUnitTesting(); + + cluster = new Cluster({ contextName: "irrelevant", id: "irrelevant", kubeConfigPath: "irrelevant" }); + const observableCluster = observable.box(cluster); + + di.override(activeEntityInternalClusterInjectable, () => observableCluster); + }); + + it("given cluster has no hidden metrics preferences, should be true for all resources", () => { + const resourceTypes = Object.values(ClusterMetricsResourceType); + + delete cluster.preferences.hiddenMetrics; + resourceTypes.forEach((resourceType) => { + expect(di.inject(enabledMetricsInjectable, resourceType).get()).toBe(true); + }); + }); + + it("given cluster has metrics preferences, but nothing is hidden, should be true for all resources", () => { + const resourceTypes = Object.values(ClusterMetricsResourceType); + + cluster.preferences.hiddenMetrics = []; + + resourceTypes.forEach((resourceType) => { + expect(di.inject(enabledMetricsInjectable, resourceType).get()).toBe(true); + }); + }); + + it("given cluster has metrics preferences, and some resource is hidden, should be false", () => { + cluster.preferences.hiddenMetrics = [ClusterMetricsResourceType.Pod]; + + expect(di.inject(enabledMetricsInjectable, ClusterMetricsResourceType.Pod).get()).toBe(false); + }); +}); + diff --git a/packages/core/src/renderer/api/catalog/entity/metrics-details-component-enabled.injectable.ts b/packages/core/src/renderer/api/catalog/entity/metrics-details-component-enabled.injectable.ts index e480eadc78..7b837291c8 100644 --- a/packages/core/src/renderer/api/catalog/entity/metrics-details-component-enabled.injectable.ts +++ b/packages/core/src/renderer/api/catalog/entity/metrics-details-component-enabled.injectable.ts @@ -21,7 +21,7 @@ const metricsDetailsComponentEnabledInjectable = getInjectable({ return false; } - return current.object.kind == kind && metricsEnabled.get(); + return metricsEnabled.get() && current.object.kind == kind; }); }, lifecycle: lifecycleEnum.keyedSingleton({ diff --git a/packages/core/src/renderer/api/catalog/entity/metrics-enabled.injectable.ts b/packages/core/src/renderer/api/catalog/entity/metrics-enabled.injectable.ts index 0954259d98..2b9148bd81 100644 --- a/packages/core/src/renderer/api/catalog/entity/metrics-enabled.injectable.ts +++ b/packages/core/src/renderer/api/catalog/entity/metrics-enabled.injectable.ts @@ -16,10 +16,10 @@ const enabledMetricsInjectable = getInjectable({ const cluster = activeEntityInternalCluster.get(); if (!cluster?.preferences.hiddenMetrics) { - return false; + return true; } - return cluster.preferences.hiddenMetrics.includes(kind); + return !cluster.preferences.hiddenMetrics.includes(kind); }); }, lifecycle: lifecycleEnum.keyedSingleton({ diff --git a/packages/core/src/renderer/components/+cluster/cluster-overview.tsx b/packages/core/src/renderer/components/+cluster/cluster-overview.tsx index 516a2f9114..75b3e8cd1e 100644 --- a/packages/core/src/renderer/components/+cluster/cluster-overview.tsx +++ b/packages/core/src/renderer/components/+cluster/cluster-overview.tsx @@ -98,11 +98,12 @@ class NonInjectedClusterOverview extends React.Component { render() { const { eventStore, nodeStore, clusterMetricsAreVisible } = this.props; const isLoaded = nodeStore.isLoaded && eventStore.isLoaded; + const isMetricsHidden = !clusterMetricsAreVisible.get(); return (
- {this.renderClusterOverview(isLoaded, clusterMetricsAreVisible.get())} + {this.renderClusterOverview(isLoaded, isMetricsHidden)}
); diff --git a/packages/core/src/renderer/components/+workloads-pods/pod-details-container.tsx b/packages/core/src/renderer/components/+workloads-pods/pod-details-container.tsx index 00db1af71b..d066497780 100644 --- a/packages/core/src/renderer/components/+workloads-pods/pod-details-container.tsx +++ b/packages/core/src/renderer/components/+workloads-pods/pod-details-container.tsx @@ -97,7 +97,7 @@ class NonInjectedPodDetailsContainer extends React.Component c.name == name); - const isMetricHidden = containerMetricsVisible.get(); + const isMetricVisible = containerMetricsVisible.get(); return (
@@ -105,7 +105,7 @@ class NonInjectedPodDetailsContainer extends React.Component {name}
- {(!isMetricHidden && !isInitContainer && metrics) && ( + {(isMetricVisible && !isInitContainer && metrics) && ( Date: Mon, 3 Apr 2023 15:23:42 +0300 Subject: [PATCH 31/35] Introduce Feature for Keyboard Shortcuts (#7442) * Introduce feature for assigning keyboard shortcuts Signed-off-by: Janne Savolainen * Enable keyboard shortcuts automatically instead of requiring explicit listener to be used in the application Signed-off-by: Janne Savolainen * Start using keyboard shortcuts feature Signed-off-by: Janne Savolainen * Update package-lock after rebase Signed-off-by: Janne Savolainen * Tweak scripts for a package Signed-off-by: Janne Savolainen * Introduce modifier for ctrl or command based on platform in use Signed-off-by: Janne Savolainen --------- Signed-off-by: Janne Savolainen --- package-lock.json | 180 +++++---- .../keyboard-shortcuts/.eslintrc.json | 6 + .../keyboard-shortcuts/.prettierrc | 1 + .../keyboard-shortcuts/README.md | 21 ++ .../keyboard-shortcuts/index.ts | 7 + .../keyboard-shortcuts/jest.config.js | 1 + .../keyboard-shortcuts/package.json | 46 +++ .../keyboard-shortcuts.test.tsx.snap | 15 + .../keyboard-shortcuts/src/feature.ts | 17 + .../src/invoke-shortcut.injectable.ts | 94 +++++ .../src/keyboard-shortcut-injection-token.ts | 22 ++ ...tener-react-application-hoc.injectable.tsx | 10 + .../src/keyboard-shortcut-listener.tsx | 41 ++ .../src/keyboard-shortcut-scope.tsx | 12 + .../src/keyboard-shortcuts.test.tsx | 353 ++++++++++++++++++ .../src/platform.injectable.ts | 11 + .../keyboard-shortcuts/tsconfig.json | 4 + .../keyboard-shortcuts/webpack.config.js | 1 + packages/open-lens/package.json | 1 + packages/open-lens/src/renderer/index.ts | 2 + 20 files changed, 772 insertions(+), 73 deletions(-) create mode 100644 packages/business-features/keyboard-shortcuts/.eslintrc.json create mode 100644 packages/business-features/keyboard-shortcuts/.prettierrc create mode 100644 packages/business-features/keyboard-shortcuts/README.md create mode 100644 packages/business-features/keyboard-shortcuts/index.ts create mode 100644 packages/business-features/keyboard-shortcuts/jest.config.js create mode 100644 packages/business-features/keyboard-shortcuts/package.json create mode 100644 packages/business-features/keyboard-shortcuts/src/__snapshots__/keyboard-shortcuts.test.tsx.snap create mode 100644 packages/business-features/keyboard-shortcuts/src/feature.ts create mode 100644 packages/business-features/keyboard-shortcuts/src/invoke-shortcut.injectable.ts create mode 100644 packages/business-features/keyboard-shortcuts/src/keyboard-shortcut-injection-token.ts create mode 100644 packages/business-features/keyboard-shortcuts/src/keyboard-shortcut-listener-react-application-hoc.injectable.tsx create mode 100644 packages/business-features/keyboard-shortcuts/src/keyboard-shortcut-listener.tsx create mode 100644 packages/business-features/keyboard-shortcuts/src/keyboard-shortcut-scope.tsx create mode 100644 packages/business-features/keyboard-shortcuts/src/keyboard-shortcuts.test.tsx create mode 100644 packages/business-features/keyboard-shortcuts/src/platform.injectable.ts create mode 100644 packages/business-features/keyboard-shortcuts/tsconfig.json create mode 100644 packages/business-features/keyboard-shortcuts/webpack.config.js diff --git a/package-lock.json b/package-lock.json index d66943ede4..31bf465203 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4606,6 +4606,10 @@ "resolved": "packages/infrastructure/jest", "link": true }, + "node_modules/@k8slens/keyboard-shortcuts": { + "resolved": "packages/business-features/keyboard-shortcuts", + "link": true + }, "node_modules/@k8slens/legacy-extension-example": { "resolved": "packages/legacy-extension-example", "link": true @@ -5042,13 +5046,13 @@ } }, "node_modules/@lerna/legacy-package-management/node_modules/glob": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", - "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.4.tgz", + "integrity": "sha512-qaSc49hojMOv1EPM4EuyITjDSgSKI0rthoHnvE81tcOi1SCVndHko7auqxdQ14eiQG2NDBJBE86+2xIrbIvrbA==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", - "minimatch": "^7.4.1", + "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" }, @@ -5069,15 +5073,15 @@ } }, "node_modules/@lerna/legacy-package-management/node_modules/glob/node_modules/minimatch": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", - "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.2.tgz", + "integrity": "sha512-ikHGF67ODxj7vS5NKU2wvTsFLbExee+KXVCnBWh8Cg2hVJfBMQIrlo50qru/09E0EifjnU8dZhJ/iHhyXJM6Mw==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -6022,13 +6026,13 @@ } }, "node_modules/@npmcli/arborist/node_modules/cacache/node_modules/glob": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", - "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.4.tgz", + "integrity": "sha512-qaSc49hojMOv1EPM4EuyITjDSgSKI0rthoHnvE81tcOi1SCVndHko7auqxdQ14eiQG2NDBJBE86+2xIrbIvrbA==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", - "minimatch": "^7.4.1", + "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" }, @@ -6040,15 +6044,15 @@ } }, "node_modules/@npmcli/arborist/node_modules/cacache/node_modules/minimatch": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", - "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.2.tgz", + "integrity": "sha512-ikHGF67ODxj7vS5NKU2wvTsFLbExee+KXVCnBWh8Cg2hVJfBMQIrlo50qru/09E0EifjnU8dZhJ/iHhyXJM6Mw==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -6091,9 +6095,9 @@ } }, "node_modules/@npmcli/arborist/node_modules/ignore-walk/node_modules/minimatch": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", - "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.4.tgz", + "integrity": "sha512-T+8B3kNrLP7jDb5eaC4rUIp6DKoeTSb6f9SwF2phcY2gxJUA0GEf1i29/FHxBMEfx0ppWlr434/D0P+6jb8bOQ==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -6612,13 +6616,13 @@ } }, "node_modules/@npmcli/arborist/node_modules/read-package-json/node_modules/glob": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", - "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.4.tgz", + "integrity": "sha512-qaSc49hojMOv1EPM4EuyITjDSgSKI0rthoHnvE81tcOi1SCVndHko7auqxdQ14eiQG2NDBJBE86+2xIrbIvrbA==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", - "minimatch": "^7.4.1", + "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" }, @@ -6630,15 +6634,15 @@ } }, "node_modules/@npmcli/arborist/node_modules/read-package-json/node_modules/minimatch": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", - "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.2.tgz", + "integrity": "sha512-ikHGF67ODxj7vS5NKU2wvTsFLbExee+KXVCnBWh8Cg2hVJfBMQIrlo50qru/09E0EifjnU8dZhJ/iHhyXJM6Mw==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -6888,13 +6892,13 @@ } }, "node_modules/@npmcli/map-workspaces/node_modules/glob": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", - "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.4.tgz", + "integrity": "sha512-qaSc49hojMOv1EPM4EuyITjDSgSKI0rthoHnvE81tcOi1SCVndHko7auqxdQ14eiQG2NDBJBE86+2xIrbIvrbA==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", - "minimatch": "^7.4.1", + "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" }, @@ -6905,10 +6909,25 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@npmcli/map-workspaces/node_modules/glob/node_modules/minimatch": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.2.tgz", + "integrity": "sha512-ikHGF67ODxj7vS5NKU2wvTsFLbExee+KXVCnBWh8Cg2hVJfBMQIrlo50qru/09E0EifjnU8dZhJ/iHhyXJM6Mw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@npmcli/map-workspaces/node_modules/minimatch": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", - "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.4.tgz", + "integrity": "sha512-T+8B3kNrLP7jDb5eaC4rUIp6DKoeTSb6f9SwF2phcY2gxJUA0GEf1i29/FHxBMEfx0ppWlr434/D0P+6jb8bOQ==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -7040,13 +7059,13 @@ } }, "node_modules/@npmcli/metavuln-calculator/node_modules/glob": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", - "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.4.tgz", + "integrity": "sha512-qaSc49hojMOv1EPM4EuyITjDSgSKI0rthoHnvE81tcOi1SCVndHko7auqxdQ14eiQG2NDBJBE86+2xIrbIvrbA==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", - "minimatch": "^7.4.1", + "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" }, @@ -7081,6 +7100,21 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/@npmcli/metavuln-calculator/node_modules/ignore-walk/node_modules/minimatch": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.4.tgz", + "integrity": "sha512-T+8B3kNrLP7jDb5eaC4rUIp6DKoeTSb6f9SwF2phcY2gxJUA0GEf1i29/FHxBMEfx0ppWlr434/D0P+6jb8bOQ==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@npmcli/metavuln-calculator/node_modules/json-parse-even-better-errors": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", @@ -7260,15 +7294,15 @@ } }, "node_modules/@npmcli/metavuln-calculator/node_modules/minimatch": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", - "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.2.tgz", + "integrity": "sha512-ikHGF67ODxj7vS5NKU2wvTsFLbExee+KXVCnBWh8Cg2hVJfBMQIrlo50qru/09E0EifjnU8dZhJ/iHhyXJM6Mw==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -9386,9 +9420,9 @@ } }, "node_modules/@tufjs/models/node_modules/minimatch": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", - "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.4.tgz", + "integrity": "sha512-T+8B3kNrLP7jDb5eaC4rUIp6DKoeTSb6f9SwF2phcY2gxJUA0GEf1i29/FHxBMEfx0ppWlr434/D0P+6jb8bOQ==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -24023,13 +24057,13 @@ } }, "node_modules/lerna/node_modules/glob": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", - "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.4.tgz", + "integrity": "sha512-qaSc49hojMOv1EPM4EuyITjDSgSKI0rthoHnvE81tcOi1SCVndHko7auqxdQ14eiQG2NDBJBE86+2xIrbIvrbA==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", - "minimatch": "^7.4.1", + "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" }, @@ -24050,15 +24084,15 @@ } }, "node_modules/lerna/node_modules/glob/node_modules/minimatch": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", - "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.2.tgz", + "integrity": "sha512-ikHGF67ODxj7vS5NKU2wvTsFLbExee+KXVCnBWh8Cg2hVJfBMQIrlo50qru/09E0EifjnU8dZhJ/iHhyXJM6Mw==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -31480,9 +31514,9 @@ } }, "node_modules/promise-call-limit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-1.0.1.tgz", - "integrity": "sha512-3+hgaa19jzCGLuSCbieeRsu5C2joKfYn8pY6JAuXFRVfF4IO+L7UPpFWNTeWT9pM7uhskvbPPd/oEOktCn317Q==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-1.0.2.tgz", + "integrity": "sha512-1vTUnfI2hzui8AEIixbdAJlFY4LFDXqQswy/2eOlThAscXCY4It8FdVuI0fMJGAB2aWGbdQf/gv0skKYXmdrHA==", "dev": true, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -33701,13 +33735,13 @@ } }, "node_modules/sigstore/node_modules/glob": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", - "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.4.tgz", + "integrity": "sha512-qaSc49hojMOv1EPM4EuyITjDSgSKI0rthoHnvE81tcOi1SCVndHko7auqxdQ14eiQG2NDBJBE86+2xIrbIvrbA==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", - "minimatch": "^7.4.1", + "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" }, @@ -33754,15 +33788,15 @@ } }, "node_modules/sigstore/node_modules/minimatch": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", - "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.2.tgz", + "integrity": "sha512-ikHGF67ODxj7vS5NKU2wvTsFLbExee+KXVCnBWh8Cg2hVJfBMQIrlo50qru/09E0EifjnU8dZhJ/iHhyXJM6Mw==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -35858,13 +35892,13 @@ } }, "node_modules/tuf-js/node_modules/glob": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", - "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.4.tgz", + "integrity": "sha512-qaSc49hojMOv1EPM4EuyITjDSgSKI0rthoHnvE81tcOi1SCVndHko7auqxdQ14eiQG2NDBJBE86+2xIrbIvrbA==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", - "minimatch": "^7.4.1", + "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" }, @@ -35911,15 +35945,15 @@ } }, "node_modules/tuf-js/node_modules/minimatch": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", - "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.2.tgz", + "integrity": "sha512-ikHGF67ODxj7vS5NKU2wvTsFLbExee+KXVCnBWh8Cg2hVJfBMQIrlo50qru/09E0EifjnU8dZhJ/iHhyXJM6Mw==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -37809,7 +37843,6 @@ "packages/business-features/keyboard-shortcuts": { "name": "@k8slens/keyboard-shortcuts", "version": "1.0.0-alpha.0", - "extraneous": true, "license": "MIT", "devDependencies": { "@async-fn/jest": "^1.6.4", @@ -42366,6 +42399,7 @@ "@k8slens/core": "^6.5.0-alpha.3", "@k8slens/ensure-binaries": "^6.5.0-alpha.1", "@k8slens/feature-core": "^6.5.0-alpha.1", + "@k8slens/keyboard-shortcuts": "^1.0.0-alpha.0", "@k8slens/legacy-extension-example": "^1.0.0-alpha.1", "@k8slens/legacy-extensions": "^1.0.0-alpha.1", "@k8slens/messaging": "^1.0.0-alpha.1", diff --git a/packages/business-features/keyboard-shortcuts/.eslintrc.json b/packages/business-features/keyboard-shortcuts/.eslintrc.json new file mode 100644 index 0000000000..b15115cb69 --- /dev/null +++ b/packages/business-features/keyboard-shortcuts/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "@k8slens/eslint-config/eslint", + "parserOptions": { + "project": "./tsconfig.json" + } +} diff --git a/packages/business-features/keyboard-shortcuts/.prettierrc b/packages/business-features/keyboard-shortcuts/.prettierrc new file mode 100644 index 0000000000..edd47b479e --- /dev/null +++ b/packages/business-features/keyboard-shortcuts/.prettierrc @@ -0,0 +1 @@ +"@k8slens/eslint-config/prettier" diff --git a/packages/business-features/keyboard-shortcuts/README.md b/packages/business-features/keyboard-shortcuts/README.md new file mode 100644 index 0000000000..25cc2f8cdb --- /dev/null +++ b/packages/business-features/keyboard-shortcuts/README.md @@ -0,0 +1,21 @@ +# @k8slens/keyboard-shortcuts + +This Feature enables keyboard shortcuts in Lens + +# Usage + +```bash +$ npm install @k8slens/keyboard-shortcuts +``` + +```typescript +import { keyboardShortcutsFeature } from "@k8slens/keyboard-shortcuts"; +import { registerFeature } from "@k8slens/feature-core"; +import { createContainer } from "@ogre-tools/injectable"; + +const di = createContainer("some-container"); + +registerFeature(di, keyboardShortcutsFeature); +``` + +## Extendability diff --git a/packages/business-features/keyboard-shortcuts/index.ts b/packages/business-features/keyboard-shortcuts/index.ts new file mode 100644 index 0000000000..7f8ac51c47 --- /dev/null +++ b/packages/business-features/keyboard-shortcuts/index.ts @@ -0,0 +1,7 @@ +export { KeyboardShortcutScope } from "./src/keyboard-shortcut-scope"; +export type { KeyboardShortcutScopeProps } from "./src/keyboard-shortcut-scope"; + +export { keyboardShortcutInjectionToken } from "./src/keyboard-shortcut-injection-token"; +export type { Binding, KeyboardShortcut } from "./src/keyboard-shortcut-injection-token"; + +export { keyboardShortcutsFeature } from "./src/feature"; diff --git a/packages/business-features/keyboard-shortcuts/jest.config.js b/packages/business-features/keyboard-shortcuts/jest.config.js new file mode 100644 index 0000000000..38d54ab7b6 --- /dev/null +++ b/packages/business-features/keyboard-shortcuts/jest.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/jest").monorepoPackageConfig(__dirname).configForReact; diff --git a/packages/business-features/keyboard-shortcuts/package.json b/packages/business-features/keyboard-shortcuts/package.json new file mode 100644 index 0000000000..1b60e66133 --- /dev/null +++ b/packages/business-features/keyboard-shortcuts/package.json @@ -0,0 +1,46 @@ +{ + "name": "@k8slens/keyboard-shortcuts", + "private": false, + "version": "1.0.0-alpha.0", + "description": "Keyboard shortcuts for Lens", + "type": "commonjs", + "files": [ + "dist" + ], + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/lensapp/lens.git" + }, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "author": { + "name": "OpenLens Authors", + "email": "info@k8slens.dev" + }, + "license": "MIT", + "homepage": "https://github.com/lensapp/lens", + "scripts": { + "build": "webpack", + "clean": "rimraf dist/", + "test:unit": "jest --coverage --runInBand", + "lint": "lens-lint", + "lint:fix": "lens-lint --fix" + }, + "peerDependencies": { + "@k8slens/feature-core": "^6.5.0-alpha.0", + "@k8slens/react-application": "^1.0.0-alpha.0", + "@ogre-tools/injectable": "^15.1.2", + "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", + "@ogre-tools/fp": "^15.1.2", + "lodash": "^4.17.21" + }, + "devDependencies": { + "@async-fn/jest": "^1.6.4", + "@k8slens/eslint-config": "6.5.0-alpha.1", + "@k8slens/react-testing-library-discovery": "^1.0.0-alpha.0" + } +} diff --git a/packages/business-features/keyboard-shortcuts/src/__snapshots__/keyboard-shortcuts.test.tsx.snap b/packages/business-features/keyboard-shortcuts/src/__snapshots__/keyboard-shortcuts.test.tsx.snap new file mode 100644 index 0000000000..b2cba6a543 --- /dev/null +++ b/packages/business-features/keyboard-shortcuts/src/__snapshots__/keyboard-shortcuts.test.tsx.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`keyboard-shortcuts when application is started renders 1`] = ` + +
+
+
+
+
+ +`; diff --git a/packages/business-features/keyboard-shortcuts/src/feature.ts b/packages/business-features/keyboard-shortcuts/src/feature.ts new file mode 100644 index 0000000000..32d5f2bc62 --- /dev/null +++ b/packages/business-features/keyboard-shortcuts/src/feature.ts @@ -0,0 +1,17 @@ +import { getFeature } from "@k8slens/feature-core"; +import { autoRegister } from "@ogre-tools/injectable-extension-for-auto-registration"; +import { reactApplicationFeature } from "@k8slens/react-application"; + +export const keyboardShortcutsFeature = getFeature({ + id: "keyboard-shortcuts", + + register: (di) => { + autoRegister({ + di, + targetModule: module, + getRequireContexts: () => [require.context("./", true, /\.injectable\.(ts|tsx)$/)], + }); + }, + + dependencies: [reactApplicationFeature], +}); diff --git a/packages/business-features/keyboard-shortcuts/src/invoke-shortcut.injectable.ts b/packages/business-features/keyboard-shortcuts/src/invoke-shortcut.injectable.ts new file mode 100644 index 0000000000..5b0c324203 --- /dev/null +++ b/packages/business-features/keyboard-shortcuts/src/invoke-shortcut.injectable.ts @@ -0,0 +1,94 @@ +import { pipeline } from "@ogre-tools/fp"; +import { filter, isString } from "lodash/fp"; +import { getInjectable } from "@ogre-tools/injectable"; +import { + Binding, + KeyboardShortcut, + keyboardShortcutInjectionToken, +} from "./keyboard-shortcut-injection-token"; +import platformInjectable from "./platform.injectable"; + +export type InvokeShortcut = (event: KeyboardEvent) => void; + +const toShortcutsWithMatchingScope = (shortcut: KeyboardShortcut) => { + const activeScopeElement = document.activeElement?.closest("[data-keyboard-shortcut-scope]"); + + if (!activeScopeElement) { + const shortcutIsRootLevel = !shortcut.scope; + + return shortcutIsRootLevel; + } + + const castedActiveScopeElementHtml = activeScopeElement as HTMLDivElement; + + // eslint-disable-next-line xss/no-mixed-html + const activeScope = castedActiveScopeElementHtml.dataset.keyboardShortcutScope; + + return shortcut.scope === activeScope; +}; + +const toBindingWithDefaults = (binding: Binding) => + isString(binding) + ? { + code: binding, + shift: false, + ctrl: false, + altOrOption: false, + meta: false, + ctrlOrCommand: false, + } + : { + ctrl: false, + shift: false, + altOrOption: false, + meta: false, + ctrlOrCommand: false, + ...binding, + }; + +const toShortcutsWithMatchingBinding = + (event: KeyboardEvent, platform: string) => (shortcut: KeyboardShortcut) => { + const binding = toBindingWithDefaults(shortcut.binding); + + const shiftModifierMatches = binding.shift === event.shiftKey; + const altModifierMatches = binding.altOrOption === event.altKey; + + const isMac = platform === "darwin"; + + const ctrlModifierMatches = + binding.ctrl === event.ctrlKey || (!isMac && binding.ctrlOrCommand === event.ctrlKey); + + const metaModifierMatches = + binding.meta === event.metaKey || (isMac && binding.ctrlOrCommand === event.metaKey); + + return ( + event.code === binding.code && + shiftModifierMatches && + ctrlModifierMatches && + altModifierMatches && + metaModifierMatches + ); + }; + +const invokeShortcutInjectable = getInjectable({ + id: "invoke-shortcut", + + instantiate: (di): InvokeShortcut => { + const getShortcuts = () => di.injectMany(keyboardShortcutInjectionToken); + const platform = di.inject(platformInjectable); + + return (event) => { + const shortcutsToInvoke = pipeline( + getShortcuts(), + filter(toShortcutsWithMatchingBinding(event, platform)), + filter(toShortcutsWithMatchingScope), + ); + + if (shortcutsToInvoke.length) { + shortcutsToInvoke.forEach((shortcut) => shortcut.invoke()); + } + }; + }, +}); + +export default invokeShortcutInjectable; diff --git a/packages/business-features/keyboard-shortcuts/src/keyboard-shortcut-injection-token.ts b/packages/business-features/keyboard-shortcuts/src/keyboard-shortcut-injection-token.ts new file mode 100644 index 0000000000..637990b107 --- /dev/null +++ b/packages/business-features/keyboard-shortcuts/src/keyboard-shortcut-injection-token.ts @@ -0,0 +1,22 @@ +import { getInjectionToken } from "@ogre-tools/injectable"; + +export type Binding = + | string + | { + code: string; + shift?: boolean; + ctrl?: boolean; + altOrOption?: boolean; + meta?: boolean; + ctrlOrCommand?: boolean; + }; + +export type KeyboardShortcut = { + binding: Binding; + invoke: () => void; + scope?: string; +}; + +export const keyboardShortcutInjectionToken = getInjectionToken({ + id: "keyboard-shortcut-injection-token", +}); diff --git a/packages/business-features/keyboard-shortcuts/src/keyboard-shortcut-listener-react-application-hoc.injectable.tsx b/packages/business-features/keyboard-shortcuts/src/keyboard-shortcut-listener-react-application-hoc.injectable.tsx new file mode 100644 index 0000000000..ed22ef7fe8 --- /dev/null +++ b/packages/business-features/keyboard-shortcuts/src/keyboard-shortcut-listener-react-application-hoc.injectable.tsx @@ -0,0 +1,10 @@ +import { getInjectable } from "@ogre-tools/injectable"; +import { KeyboardShortcutListener } from "./keyboard-shortcut-listener"; +import { reactApplicationHigherOrderComponentInjectionToken } from "@k8slens/react-application"; + +export const keyboardShortcutListenerReactApplicationHocInjectable = getInjectable({ + id: "keyboard-shortcut-listener-react-application-hoc", + instantiate: () => KeyboardShortcutListener, + + injectionToken: reactApplicationHigherOrderComponentInjectionToken, +}); diff --git a/packages/business-features/keyboard-shortcuts/src/keyboard-shortcut-listener.tsx b/packages/business-features/keyboard-shortcuts/src/keyboard-shortcut-listener.tsx new file mode 100644 index 0000000000..5f2479d059 --- /dev/null +++ b/packages/business-features/keyboard-shortcuts/src/keyboard-shortcut-listener.tsx @@ -0,0 +1,41 @@ +import { withInjectables } from "@ogre-tools/injectable-react"; +import React, { useEffect } from "react"; + +import invokeShortcutInjectable, { InvokeShortcut } from "./invoke-shortcut.injectable"; + +export interface KeyboardShortcutListenerProps { + children: React.ReactNode; +} + +interface Dependencies { + invokeShortcut: InvokeShortcut; +} + +const NonInjectedKeyboardShortcutListener = ({ + children, + invokeShortcut, +}: KeyboardShortcutListenerProps & Dependencies) => { + useEffect(() => { + document.addEventListener("keydown", invokeShortcut); + + return () => { + document.removeEventListener("keydown", invokeShortcut); + }; + }); + + return <>{children}; +}; + +export const KeyboardShortcutListener = withInjectables< + Dependencies, + KeyboardShortcutListenerProps +>( + NonInjectedKeyboardShortcutListener, + + { + getProps: (di, props) => ({ + invokeShortcut: di.inject(invokeShortcutInjectable), + ...props, + }), + }, +); diff --git a/packages/business-features/keyboard-shortcuts/src/keyboard-shortcut-scope.tsx b/packages/business-features/keyboard-shortcuts/src/keyboard-shortcut-scope.tsx new file mode 100644 index 0000000000..0e725cc4d4 --- /dev/null +++ b/packages/business-features/keyboard-shortcuts/src/keyboard-shortcut-scope.tsx @@ -0,0 +1,12 @@ +import React from "react"; + +export interface KeyboardShortcutScopeProps { + id: string; + children: React.ReactNode; +} + +export const KeyboardShortcutScope = ({ id, children }: KeyboardShortcutScopeProps) => ( +
+ {children} +
+); diff --git a/packages/business-features/keyboard-shortcuts/src/keyboard-shortcuts.test.tsx b/packages/business-features/keyboard-shortcuts/src/keyboard-shortcuts.test.tsx new file mode 100644 index 0000000000..d2bbfb85a4 --- /dev/null +++ b/packages/business-features/keyboard-shortcuts/src/keyboard-shortcuts.test.tsx @@ -0,0 +1,353 @@ +import userEvent from "@testing-library/user-event"; +import type { RenderResult } from "@testing-library/react"; +import { render } from "@testing-library/react"; +import { createContainer, DiContainer, getInjectable } from "@ogre-tools/injectable"; +import { registerInjectableReact } from "@ogre-tools/injectable-react"; +import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx"; +import { keyboardShortcutInjectionToken } from "./keyboard-shortcut-injection-token"; +import { registerFeature } from "@k8slens/feature-core"; +import { keyboardShortcutsFeature } from "./feature"; +import React from "react"; +import { computed, runInAction } from "mobx"; +import { KeyboardShortcutScope } from "./keyboard-shortcut-scope"; +import { Discover, discoverFor } from "@k8slens/react-testing-library-discovery"; +import { startApplicationInjectionToken } from "@k8slens/application"; +import { renderInjectionToken } from "@k8slens/react-application"; +import { reactApplicationChildrenInjectionToken } from "@k8slens/react-application"; +import platformInjectable from "./platform.injectable"; + +describe("keyboard-shortcuts", () => { + let di: DiContainer; + let invokeMock: jest.Mock; + let rendered: RenderResult; + + beforeEach(() => { + di = createContainer("irrelevant"); + + registerInjectableReact(di); + registerMobX(di); + + runInAction(() => { + registerFeature(di, keyboardShortcutsFeature); + }); + + invokeMock = jest.fn(); + + const someKeyboardShortcutInjectable = getInjectable({ + id: "some-keyboard-shortcut", + + instantiate: () => ({ + binding: "Escape", + invoke: () => invokeMock("esc-in-root"), + }), + + injectionToken: keyboardShortcutInjectionToken, + }); + + const someScopedKeyboardShortcutInjectable = getInjectable({ + id: "some-scoped-keyboard-shortcut", + + instantiate: () => ({ + binding: "Escape", + invoke: () => invokeMock("esc-in-scope"), + scope: "some-scope", + }), + + injectionToken: keyboardShortcutInjectionToken, + }); + + const someOtherKeyboardShortcutInjectable = getInjectable({ + id: "some-other-keyboard-shortcut", + + instantiate: () => ({ + binding: "something-else-than-esc", + invoke: () => invokeMock("something-else-than-esc"), + }), + + injectionToken: keyboardShortcutInjectionToken, + }); + + const childComponentForScopeInjectable = getInjectable({ + id: "some-child-component-for-scope", + + instantiate: () => ({ + id: "some-child-component-for-scope", + + enabled: computed(() => true), + + Component: () => ( + +
+ + ), + }), + + injectionToken: reactApplicationChildrenInjectionToken, + }); + + runInAction(() => { + di.register( + someKeyboardShortcutInjectable, + someScopedKeyboardShortcutInjectable, + someOtherKeyboardShortcutInjectable, + childComponentForScopeInjectable, + ); + }); + + di.override(renderInjectionToken, () => (application) => { + rendered = render(application); + }); + }); + + describe("when application is started", () => { + let discover: Discover; + + beforeEach(async () => { + const startApplication = di.inject(startApplicationInjectionToken); + + await startApplication(); + + discover = discoverFor(() => rendered); + }); + + it("renders", () => { + expect(rendered.baseElement).toMatchSnapshot(); + }); + + it("given focus is in the body, when pressing the shortcut, calls shortcut in global scope", () => { + userEvent.keyboard("{Escape}"); + + expect(invokeMock.mock.calls).toEqual([["esc-in-root"]]); + }); + + it("given focus inside a nested scope, when pressing the shortcut, calls only the callback for the scope", () => { + const result = discover.getSingleElement("keyboard-shortcut-scope", "some-scope"); + + const discoveredHtml = result.discovered as HTMLDivElement; + + discoveredHtml.focus(); + + userEvent.keyboard("{Escape}"); + + expect(invokeMock.mock.calls).toEqual([["esc-in-scope"]]); + }); + + it("given conflicting shortcut, when pressing the shortcut, calls both callbacks", () => { + const conflictingShortcutInjectable = getInjectable({ + id: "some-conflicting-keyboard-shortcut", + + instantiate: () => ({ + binding: "Escape", + invoke: () => invokeMock("conflicting-esc-in-root"), + }), + + injectionToken: keyboardShortcutInjectionToken, + }); + + runInAction(() => { + di.register(conflictingShortcutInjectable); + }); + + userEvent.keyboard("{Escape}"); + + expect(invokeMock.mock.calls).toEqual([["esc-in-root"], ["conflicting-esc-in-root"]]); + }); + + [ + { + scenario: "given shortcut without modifiers, when shortcut is pressed, calls the callback", + binding: { code: "Escape" }, + keyboard: "{Escape}", + shouldCallCallback: true, + }, + { + scenario: + "given shortcut without modifiers, when shortcut is pressed but with modifier, does not call the callback", + binding: { code: "F1" }, + keyboard: "{Meta>}[F1]", + shouldCallCallback: false, + }, + { + scenario: "given shortcut with meta modifier, when shortcut is pressed, calls the callback", + + binding: { meta: true, code: "F1" }, + keyboard: "{Meta>}[F1]", + shouldCallCallback: true, + }, + { + scenario: + "given shortcut with shift modifier, when shortcut is pressed, calls the callback", + + binding: { shift: true, code: "F1" }, + keyboard: "{Shift>}[F1]", + shouldCallCallback: true, + }, + { + scenario: "given shortcut with alt modifier, when shortcut is pressed, calls the callback", + binding: { altOrOption: true, code: "F1" }, + keyboard: "{Alt>}[F1]", + shouldCallCallback: true, + }, + { + scenario: "given shortcut with ctrl modifier, when shortcut is pressed, calls the callback", + binding: { ctrl: true, code: "F1" }, + keyboard: "{Control>}[F1]", + shouldCallCallback: true, + }, + { + scenario: "given shortcut with all modifiers, when shortcut is pressed, calls the callback", + + binding: { ctrl: true, altOrOption: true, shift: true, meta: true, code: "F1" }, + keyboard: "{Meta>}{Shift>}{Alt>}{Control>}[F1]", + shouldCallCallback: true, + }, + ].forEach(({ binding, keyboard, scenario, shouldCallCallback }) => { + // eslint-disable-next-line jest/valid-title + it(scenario, () => { + const invokeMock = jest.fn(); + + const shortcutInjectable = getInjectable({ + id: "shortcut", + + instantiate: () => ({ + binding, + invoke: invokeMock, + }), + + injectionToken: keyboardShortcutInjectionToken, + }); + + runInAction(() => { + di.register(shortcutInjectable); + }); + + userEvent.keyboard(keyboard); + + if (shouldCallCallback) { + // eslint-disable-next-line jest/no-conditional-expect + expect(invokeMock).toHaveBeenCalled(); + } else { + // eslint-disable-next-line jest/no-conditional-expect + expect(invokeMock).not.toHaveBeenCalled(); + } + }); + }); + }); + + describe("given in mac and keyboard shortcut with modifier for ctrl or command", () => { + beforeEach(async () => { + di.override(platformInjectable, () => "darwin"); + + invokeMock = jest.fn(); + + const shortcutInjectable = getInjectable({ + id: "shortcut", + + instantiate: () => ({ + binding: { code: "KeyK", ctrlOrCommand: true }, + invoke: invokeMock, + }), + + injectionToken: keyboardShortcutInjectionToken, + }); + + runInAction(() => { + di.register(shortcutInjectable); + }); + + const startApplication = di.inject(startApplicationInjectionToken); + + await startApplication(); + }); + + it("when pressing the keyboard shortcut with command, calls the callback", () => { + userEvent.keyboard("{Meta>}[KeyK]"); + + expect(invokeMock).toHaveBeenCalled(); + }); + + it("when pressing the keyboard shortcut with ctrl, does not call the callback", () => { + userEvent.keyboard("{Control>}[KeyK]"); + + expect(invokeMock).not.toHaveBeenCalled(); + }); + }); + + describe("given in windows and keyboard shortcut with modifier for ctrl or command", () => { + beforeEach(async () => { + di.override(platformInjectable, () => "win32"); + + invokeMock = jest.fn(); + + const shortcutInjectable = getInjectable({ + id: "shortcut", + + instantiate: () => ({ + binding: { code: "KeyK", ctrlOrCommand: true }, + invoke: invokeMock, + }), + + injectionToken: keyboardShortcutInjectionToken, + }); + + runInAction(() => { + di.register(shortcutInjectable); + }); + + const startApplication = di.inject(startApplicationInjectionToken); + + await startApplication(); + }); + + it("when pressing the keyboard shortcut with windows, does not call the callback", () => { + userEvent.keyboard("{Meta>}[KeyK]"); + + expect(invokeMock).not.toHaveBeenCalled(); + }); + + it("when pressing the keyboard shortcut with ctrl, calls the callback", () => { + userEvent.keyboard("{Control>}[KeyK]"); + + expect(invokeMock).toHaveBeenCalled(); + }); + }); + + describe("given in any other platform and keyboard shortcut with modifier for ctrl or command", () => { + beforeEach(async () => { + di.override(platformInjectable, () => "some-other-platform"); + + invokeMock = jest.fn(); + + const shortcutInjectable = getInjectable({ + id: "shortcut", + + instantiate: () => ({ + binding: { code: "KeyK", ctrlOrCommand: true }, + invoke: invokeMock, + }), + + injectionToken: keyboardShortcutInjectionToken, + }); + + runInAction(() => { + di.register(shortcutInjectable); + }); + + const startApplication = di.inject(startApplicationInjectionToken); + + await startApplication(); + }); + + it("when pressing the keyboard shortcut with meta, does not call the callback", () => { + userEvent.keyboard("{Meta>}[KeyK]"); + + expect(invokeMock).not.toHaveBeenCalled(); + }); + + it("when pressing the keyboard shortcut with ctrl, calls the callback", () => { + userEvent.keyboard("{Control>}[KeyK]"); + + expect(invokeMock).toHaveBeenCalled(); + }); + }); +}); diff --git a/packages/business-features/keyboard-shortcuts/src/platform.injectable.ts b/packages/business-features/keyboard-shortcuts/src/platform.injectable.ts new file mode 100644 index 0000000000..407af8a43d --- /dev/null +++ b/packages/business-features/keyboard-shortcuts/src/platform.injectable.ts @@ -0,0 +1,11 @@ +import { getInjectable } from "@ogre-tools/injectable"; + +export const allPlatforms = ["win32", "darwin", "linux"] as const; + +const platformInjectable = getInjectable({ + id: "platform", + instantiate: () => process.platform as (typeof allPlatforms)[number], + causesSideEffects: true, +}); + +export default platformInjectable; diff --git a/packages/business-features/keyboard-shortcuts/tsconfig.json b/packages/business-features/keyboard-shortcuts/tsconfig.json new file mode 100644 index 0000000000..9e140d79da --- /dev/null +++ b/packages/business-features/keyboard-shortcuts/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "@k8slens/typescript/config/base.json", + "include": ["**/*.ts", "**/*.tsx"], +} diff --git a/packages/business-features/keyboard-shortcuts/webpack.config.js b/packages/business-features/keyboard-shortcuts/webpack.config.js new file mode 100644 index 0000000000..1cda407f5a --- /dev/null +++ b/packages/business-features/keyboard-shortcuts/webpack.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/webpack").configForReact; diff --git a/packages/open-lens/package.json b/packages/open-lens/package.json index 7fa19eeb23..c229a32d58 100644 --- a/packages/open-lens/package.json +++ b/packages/open-lens/package.json @@ -190,6 +190,7 @@ "@k8slens/core": "^6.5.0-alpha.3", "@k8slens/ensure-binaries": "^6.5.0-alpha.1", "@k8slens/feature-core": "^6.5.0-alpha.1", + "@k8slens/keyboard-shortcuts": "^1.0.0-alpha.0", "@k8slens/legacy-extension-example": "^1.0.0-alpha.1", "@k8slens/legacy-extensions": "^1.0.0-alpha.1", "@k8slens/messaging": "^1.0.0-alpha.1", diff --git a/packages/open-lens/src/renderer/index.ts b/packages/open-lens/src/renderer/index.ts index 2d5dda2f04..d14e817347 100644 --- a/packages/open-lens/src/renderer/index.ts +++ b/packages/open-lens/src/renderer/index.ts @@ -15,6 +15,7 @@ import { createContainer } from "@ogre-tools/injectable"; import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx"; import { registerInjectableReact } from "@ogre-tools/injectable-react"; import { messagingFeatureForRenderer } from "@k8slens/messaging-for-renderer"; +import { keyboardShortcutsFeature } from "@k8slens/keyboard-shortcuts"; import { reactApplicationFeature } from "@k8slens/react-application"; const environment = "renderer"; @@ -30,6 +31,7 @@ runInAction(() => { di, applicationFeature, messagingFeatureForRenderer, + keyboardShortcutsFeature, reactApplicationFeature ); From 9d1464c39afe73e17cfd813773663d63f13209bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 08:27:35 -0400 Subject: [PATCH 32/35] Bump webpack-dev-server from 4.11.1 to 4.13.2 (#7457) Bumps [webpack-dev-server](https://github.com/webpack/webpack-dev-server) from 4.11.1 to 4.13.2. - [Release notes](https://github.com/webpack/webpack-dev-server/releases) - [Changelog](https://github.com/webpack/webpack-dev-server/blob/master/CHANGELOG.md) - [Commits](https://github.com/webpack/webpack-dev-server/compare/v4.11.1...v4.13.2) --- updated-dependencies: - dependency-name: webpack-dev-server dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 246 +++++++++++++++++++++++++++++++- packages/core/package.json | 2 +- packages/open-lens/package.json | 2 +- 3 files changed, 246 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 31bf465203..995db7bdd7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23792,6 +23792,16 @@ "language-subtag-registry": "~0.3.2" } }, + "node_modules/launch-editor": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", + "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.7.3" + } + }, "node_modules/lazy-cache": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", @@ -38266,7 +38276,7 @@ "typescript-plugin-css-modules": "^3.4.0", "webpack": "^5.77.0", "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.11.1", + "webpack-dev-server": "^4.13.2", "webpack-node-externals": "^3.0.0", "xterm": "^4.19.0", "xterm-addon-fit": "^0.5.0" @@ -38797,6 +38807,18 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "packages/core/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, "packages/core/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -39551,6 +39573,99 @@ } } }, + "packages/core/node_modules/webpack-dev-server": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.13.2.tgz", + "integrity": "sha512-5i6TrGBRxG4vnfDpB6qSQGfnB6skGBXNL5/542w2uRGLimX6qeE5BQMLrzIC3JYV/xlGOv+s+hTleI9AZKUQNw==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "packages/core/node_modules/webpack-dev-server/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/core/node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "packages/core/node_modules/webpack-sources": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", @@ -42482,7 +42597,7 @@ "typescript-plugin-css-modules": "^4.1.1", "webpack": "^5.77.0", "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.11.1", + "webpack-dev-server": "^4.13.2", "webpack-node-externals": "^3.0.0", "xterm-addon-fit": "^0.5.0" }, @@ -42956,6 +43071,34 @@ "webpack": "^5" } }, + "packages/open-lens/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "packages/open-lens/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, "packages/open-lens/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -43555,6 +43698,12 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "packages/open-lens/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, "packages/open-lens/node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -43749,6 +43898,99 @@ } } }, + "packages/open-lens/node_modules/webpack-dev-server": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.13.2.tgz", + "integrity": "sha512-5i6TrGBRxG4vnfDpB6qSQGfnB6skGBXNL5/542w2uRGLimX6qeE5BQMLrzIC3JYV/xlGOv+s+hTleI9AZKUQNw==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "packages/open-lens/node_modules/webpack-dev-server/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/open-lens/node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "packages/open-lens/node_modules/webpack-sources": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", diff --git a/packages/core/package.json b/packages/core/package.json index 9cb3d0b755..2a29e69bac 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -307,7 +307,7 @@ "typescript-plugin-css-modules": "^3.4.0", "webpack": "^5.77.0", "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.11.1", + "webpack-dev-server": "^4.13.2", "webpack-node-externals": "^3.0.0", "xterm": "^4.19.0", "xterm-addon-fit": "^0.5.0" diff --git a/packages/open-lens/package.json b/packages/open-lens/package.json index c229a32d58..720503b3ca 100644 --- a/packages/open-lens/package.json +++ b/packages/open-lens/package.json @@ -273,7 +273,7 @@ "typescript-plugin-css-modules": "^4.1.1", "webpack": "^5.77.0", "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.11.1", + "webpack-dev-server": "^4.13.2", "webpack-node-externals": "^3.0.0", "xterm-addon-fit": "^0.5.0" } From 8872b2f94a8b7b56275c192b4e2a0987e748ad97 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 08:28:29 -0400 Subject: [PATCH 33/35] Bump playwright from 1.31.2 to 1.32.1 (#7460) Bumps [playwright](https://github.com/Microsoft/playwright) from 1.31.2 to 1.32.1. - [Release notes](https://github.com/Microsoft/playwright/releases) - [Commits](https://github.com/Microsoft/playwright/compare/v1.31.2...v1.32.1) --- updated-dependencies: - dependency-name: playwright dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 88 ++++++++++++++++++++++----------- packages/core/package.json | 2 +- packages/open-lens/package.json | 2 +- 3 files changed, 60 insertions(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index 995db7bdd7..a279332cb4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30813,34 +30813,6 @@ "node": ">=4" } }, - "node_modules/playwright": { - "version": "1.31.2", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.31.2.tgz", - "integrity": "sha512-jpC47n2PKQNtzB7clmBuWh6ftBRS/Bt5EGLigJ9k2QAKcNeYXZkEaDH5gmvb6+AbcE0DO6GnXdbl9ogG6Eh+og==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "playwright-core": "1.31.2" - }, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/playwright-core": { - "version": "1.31.2", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.31.2.tgz", - "integrity": "sha512-a1dFgCNQw4vCsG7bnojZjDnPewZcw7tZUNFN0ZkcLYKj+mPmXvg4MpaaKZ5SgqPsOmqIf2YsVRkgqiRDxD+fDQ==", - "dev": true, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/plist": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.6.tgz", @@ -38248,7 +38220,7 @@ "node-gyp": "^8.3.0", "node-loader": "^2.0.0", "nodemon": "^2.0.20", - "playwright": "^1.30.0", + "playwright": "^1.32.1", "postcss": "^8.4.21", "postcss-loader": "^6.2.1", "query-string": "^7.1.3", @@ -39463,6 +39435,34 @@ "node": ">=8" } }, + "packages/core/node_modules/playwright": { + "version": "1.32.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.32.1.tgz", + "integrity": "sha512-GnEizysWMvoqHC3I9l8+4/ZxeLwLNdJJG76xdKGxzOcIZDcw5RSk/FKrFb5CuA+zcLpjIM2p9eR9Z4CuUDkWXg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "playwright-core": "1.32.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "packages/core/node_modules/playwright-core": { + "version": "1.32.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.32.1.tgz", + "integrity": "sha512-KZYUQC10mXD2Am1rGlidaalNGYk3LU1vZqqNk0gT4XPty1jOqgup8KDP8l2CUlqoNKhXM5IfGjWgW37xvGllBA==", + "dev": true, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, "packages/core/node_modules/pretty-format": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", @@ -42581,7 +42581,7 @@ "monaco-editor-webpack-plugin": "^5.0.0", "node-loader": "^2.0.0", "nodemon": "^2.0.20", - "playwright": "^1.30.0", + "playwright": "^1.32.1", "react-refresh": "^0.14.0", "react-refresh-typescript": "^2.0.7", "react-select": "^5.7.0", @@ -43716,6 +43716,34 @@ "node": ">=8" } }, + "packages/open-lens/node_modules/playwright": { + "version": "1.32.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.32.1.tgz", + "integrity": "sha512-GnEizysWMvoqHC3I9l8+4/ZxeLwLNdJJG76xdKGxzOcIZDcw5RSk/FKrFb5CuA+zcLpjIM2p9eR9Z4CuUDkWXg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "playwright-core": "1.32.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "packages/open-lens/node_modules/playwright-core": { + "version": "1.32.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.32.1.tgz", + "integrity": "sha512-KZYUQC10mXD2Am1rGlidaalNGYk3LU1vZqqNk0gT4XPty1jOqgup8KDP8l2CUlqoNKhXM5IfGjWgW37xvGllBA==", + "dev": true, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, "packages/open-lens/node_modules/pretty-format": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", diff --git a/packages/core/package.json b/packages/core/package.json index 2a29e69bac..518603f2ff 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -279,7 +279,7 @@ "node-gyp": "^8.3.0", "node-loader": "^2.0.0", "nodemon": "^2.0.20", - "playwright": "^1.30.0", + "playwright": "^1.32.1", "postcss": "^8.4.21", "postcss-loader": "^6.2.1", "query-string": "^7.1.3", diff --git a/packages/open-lens/package.json b/packages/open-lens/package.json index 720503b3ca..4060884d92 100644 --- a/packages/open-lens/package.json +++ b/packages/open-lens/package.json @@ -257,7 +257,7 @@ "monaco-editor-webpack-plugin": "^5.0.0", "node-loader": "^2.0.0", "nodemon": "^2.0.20", - "playwright": "^1.30.0", + "playwright": "^1.32.1", "react-refresh": "^0.14.0", "react-refresh-typescript": "^2.0.7", "react-select": "^5.7.0", From 47796228d035b123e2281d79367bdb2892a968c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 08:28:49 -0400 Subject: [PATCH 34/35] Bump @types/react-beautiful-dnd from 13.1.3 to 13.1.4 (#7459) Bumps [@types/react-beautiful-dnd](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-beautiful-dnd) from 13.1.3 to 13.1.4. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-beautiful-dnd) --- updated-dependencies: - dependency-name: "@types/react-beautiful-dnd" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 20 ++++++++++---------- packages/core/package.json | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index a279332cb4..9d52332f11 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10064,15 +10064,6 @@ "csstype": "^3.0.2" } }, - "node_modules/@types/react-beautiful-dnd": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.1.3.tgz", - "integrity": "sha512-BNdmvONKtsrZq3AGrujECQrIn8cDT+fZsxBLXuX3YWY/nHfZinUFx4W88eS0rkcXzuLbXpKOsu/1WCMPMLEpPg==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/react-dom": { "version": "17.0.19", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.19.tgz", @@ -38159,7 +38150,7 @@ "@types/proper-lockfile": "^4.1.2", "@types/randomcolor": "^0.5.7", "@types/react": "^17.0.45", - "@types/react-beautiful-dnd": "^13.1.3", + "@types/react-beautiful-dnd": "^13.1.4", "@types/react-dom": "^17.0.16", "@types/react-router": "^5.1.19", "@types/react-router-dom": "^5.3.3", @@ -38753,6 +38744,15 @@ "integrity": "sha512-ZOzvDRWp8dCVBmgnkIqYCArgdFOO9YzocZp8Ra25N/RStKiWvMOXHMz+GjSeVNe5TstaTmTWPucGJkDw0XXJWA==", "dev": true }, + "packages/core/node_modules/@types/react-beautiful-dnd": { + "version": "13.1.4", + "resolved": "https://registry.npmjs.org/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.1.4.tgz", + "integrity": "sha512-4bIBdzOr0aavN+88q3C7Pgz+xkb7tz3whORYrmSj77wfVEMfiWiooIwVWFR7KM2e+uGTe5BVrXqSfb0aHeflJA==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "packages/core/node_modules/@types/webpack": { "version": "5.28.1", "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-5.28.1.tgz", diff --git a/packages/core/package.json b/packages/core/package.json index 518603f2ff..e42f9853fe 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -218,7 +218,7 @@ "@types/proper-lockfile": "^4.1.2", "@types/randomcolor": "^0.5.7", "@types/react": "^17.0.45", - "@types/react-beautiful-dnd": "^13.1.3", + "@types/react-beautiful-dnd": "^13.1.4", "@types/react-dom": "^17.0.16", "@types/react-router": "^5.1.19", "@types/react-router-dom": "^5.3.3", From fef94430649885d5368c2a41353012294c6f746b Mon Sep 17 00:00:00 2001 From: Juho Heikka Date: Mon, 3 Apr 2023 16:12:35 +0300 Subject: [PATCH 35/35] Fix node metrics line progress (#7466) Signed-off-by: Juho Heikka --- packages/core/src/renderer/components/+nodes/nodes.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/core/src/renderer/components/+nodes/nodes.scss b/packages/core/src/renderer/components/+nodes/nodes.scss index 74adf66e3d..99cab9e3a0 100644 --- a/packages/core/src/renderer/components/+nodes/nodes.scss +++ b/packages/core/src/renderer/components/+nodes/nodes.scss @@ -16,6 +16,10 @@ @include table-cell-warning; } + .LineProgress { + width: 100%; + } + &.cpu { flex: 1.0; align-self: center;