diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 307032e036..d5ddc00cac 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -16,8 +16,8 @@ jobs: vmImage: windows-2019 strategy: matrix: - node_14.x: - node_version: 14.x + node: + node_version: 16.x steps: - powershell: | $CI_BUILD_TAG = git describe --tags @@ -64,8 +64,8 @@ jobs: vmImage: macOS-11 strategy: matrix: - node_14.x: - node_version: 14.x + node: + node_version: 16.x steps: - script: CI_BUILD_TAG=`git describe --tags` && echo "##vso[task.setvariable variable=CI_BUILD_TAG]$CI_BUILD_TAG" condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))" @@ -128,8 +128,8 @@ jobs: vmImage: ubuntu-18.04 strategy: matrix: - node_14.x: - node_version: 14.x + node: + node_version: 16.x steps: - script: CI_BUILD_TAG=`git describe --tags` && echo "##vso[task.setvariable variable=CI_BUILD_TAG]$CI_BUILD_TAG" condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))" diff --git a/.github/workflows/check-docs.yml b/.github/workflows/check-docs.yml index f94a2fda5c..9c942690b0 100644 --- a/.github/workflows/check-docs.yml +++ b/.github/workflows/check-docs.yml @@ -9,7 +9,7 @@ jobs: if: ${{ contains(github.event.pull_request.labels.*.name, 'area/documentation') }} strategy: matrix: - node-version: [14.x] + node-version: [16.x] steps: - name: Checkout Release from lens uses: actions/checkout@v2 diff --git a/.github/workflows/electronegativity.yml b/.github/workflows/electronegativity.yml index 059894530b..6e634082c4 100644 --- a/.github/workflows/electronegativity.yml +++ b/.github/workflows/electronegativity.yml @@ -14,12 +14,12 @@ jobs: - uses: actions/setup-node@v2 with: - node-version: "14" + node-version: "16" - uses: doyensec/electronegativity-action@v1.1 with: input: src/ - electron-version: "14.2.4" + electron-version: "15.5.7" severity: medium - name: Upload sarif diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 18ec977859..ac7ac673ca 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [14.x] + node-version: [16.x] steps: - name: Checkout Release from lens uses: actions/checkout@v2 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 300843633f..2fa32efc65 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [14.x] + node-version: [16.x] steps: - name: Set up Python 3.7 uses: actions/setup-python@v2 @@ -46,7 +46,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [14.x] + node-version: [16.x] needs: verify-docs steps: - name: Set up Python 3.7 diff --git a/.github/workflows/mkdocs-manual.yml b/.github/workflows/mkdocs-manual.yml index a0695d0e7d..cda83b86c3 100644 --- a/.github/workflows/mkdocs-manual.yml +++ b/.github/workflows/mkdocs-manual.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [14.x] + node-version: [16.x] steps: - name: Set up Python 3.7 uses: actions/setup-python@v2 diff --git a/.github/workflows/publish-master-npm.yml b/.github/workflows/publish-master-npm.yml index caccbe9d25..31f86ae6f0 100644 --- a/.github/workflows/publish-master-npm.yml +++ b/.github/workflows/publish-master-npm.yml @@ -14,7 +14,7 @@ jobs: ${{ github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'area/extension') }} strategy: matrix: - node-version: [14.x] + node-version: [16.x] steps: - name: Checkout Release uses: actions/checkout@v2 diff --git a/.github/workflows/publish-release-npm.yml b/.github/workflows/publish-release-npm.yml index 0bfc06a106..79a06c000f 100644 --- a/.github/workflows/publish-release-npm.yml +++ b/.github/workflows/publish-release-npm.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [14.x] + node-version: [16.x] steps: - name: Checkout Release uses: actions/checkout@v2 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 44967d192c..a71fc42771 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: os: [ubuntu-18.04, macos-11, windows-2019] - node-version: [14.x] + node-version: [16.x] steps: - name: Checkout Release from lens uses: actions/checkout@v2 diff --git a/.yarnrc b/.yarnrc index c8e7a49bbe..22e66ac2fe 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,3 +1,3 @@ disturl "https://atom.io/download/electron" -target "14.2.4" +target "15.5.0" runtime "electron" diff --git a/Makefile b/Makefile index 48ce768766..9dfb2cf512 100644 --- a/Makefile +++ b/Makefile @@ -56,6 +56,7 @@ integration: build build: node_modules binaries/client yarn run npm:fix-build-version $(MAKE) build-extensions -B + yarn run build:tray-icons yarn run compile ifeq "$(DETECTED_OS)" "Windows" # https://github.com/ukoloff/win-ca#clear-pem-folder-on-publish diff --git a/build/generate-tray-icons.ts b/build/generate-tray-icons.ts index a7ab3bd48b..ed90d27832 100644 --- a/build/generate-tray-icons.ts +++ b/build/generate-tray-icons.ts @@ -3,8 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { readFileSync } from "fs"; -import { ensureDirSync } from "fs-extra"; +import { ensureDir, readFile } from "fs-extra"; import { JSDOM } from "jsdom"; import path from "path"; import sharp from "sharp"; @@ -12,39 +11,120 @@ import sharp from "sharp"; const size = Number(process.env.OUTPUT_SIZE || "16"); const outputFolder = process.env.OUTPUT_DIR || "./build/tray"; const inputFile = process.env.INPUT_SVG_PATH || "./src/renderer/components/icon/logo-lens.svg"; +const noticeFile = process.env.NOTICE_SVG_PATH || "./src/renderer/components/icon/notice.svg"; -const svgData = readFileSync(inputFile, { encoding: "utf-8" }); -const svgDom = new JSDOM(`${svgData}`); -const svgRoot = svgDom.window.document.body.getElementsByTagName("svg")[0]; +async function ensureOutputFoler() { + await ensureDir(outputFolder); +} -svgRoot.innerHTML += ``; -const lightTemplate = svgRoot.outerHTML; +function getSvgStyling(colouring: "dark" | "light"): string { + return ` + + `; +} -svgRoot.innerHTML += ``; +type TargetSystems = "macos" | "windows-or-linux"; -const darkTemplate = svgRoot.outerHTML; +async function getBaseIconImage(system: TargetSystems) { + const svgData = await readFile(inputFile, { encoding: "utf-8" }); + const dom = new JSDOM(`${svgData}`); + const root = dom.window.document.body.getElementsByTagName("svg")[0]; -console.log("Generating tray icon pngs"); + root.innerHTML += getSvgStyling(system === "macos" ? "light" : "dark"); -ensureDirSync(outputFolder); + return Buffer.from(root.outerHTML); +} -Promise.all([ - sharp(Buffer.from(lightTemplate)) +async function generateImage(image: Buffer, size: number, namePrefix: string) { + sharp(image) .resize({ width: size, height: size }) .png() - .toFile(path.join(outputFolder, "trayIconDarkTemplate.png")), - sharp(Buffer.from(lightTemplate)) - .resize({ width: size*2, height: size*2 }) - .png() - .toFile(path.join(outputFolder, "trayIconDarkTemplate@2x.png")), - sharp(Buffer.from(darkTemplate)) - .resize({ width: size, height: size }) - .png() - .toFile(path.join(outputFolder, "trayIconTemplate.png")), - sharp(Buffer.from(darkTemplate)) - .resize({ width: size*2, height: size*2 }) - .png() - .toFile(path.join(outputFolder, "trayIconTemplate@2x.png")), -]) - .then((resolutions) => console.log(`Generated ${resolutions.length} images`)) - .catch(console.error); + .toFile(path.join(outputFolder, `${namePrefix}.png`)); +} + +async function generateImages(image: Buffer, size: number, name: string) { + await Promise.all([ + generateImage(image, size, name), + generateImage(image, size*2, `${name}@2x`), + generateImage(image, size*3, `${name}@3x`), + generateImage(image, size*4, `${name}@4x`), + ]); +} + +async function generateUpdateAvailableImages(baseImage: Buffer, system: TargetSystems) { + const noticeIconImage = await getNoticeIconImage(system); + const circleBuffer = await sharp(Buffer.from(` + + + + `)) + .toBuffer(); + + return sharp(baseImage) + .resize({ width: 128, height: 128 }) + .composite([ + { + input: circleBuffer, + top: 64, + left: 64, + blend: "dest-out", + }, + { + input: ( + await sharp(noticeIconImage) + .resize({ + width: 60, + height: 60, + }) + .toBuffer() + ), + top: 66, + left: 66, + }, + ]) + .toBuffer(); +} + +async function getNoticeIconImage(system: TargetSystems) { + const svgData = await readFile(noticeFile, { encoding: "utf-8" }); + const root = new JSDOM(svgData).window.document.getElementsByTagName("svg")[0]; + + root.innerHTML += getSvgStyling(system === "macos" ? "light" : "dark"); + + return Buffer.from(root.outerHTML); +} + +async function generateTrayIcons() { + try { + console.log("Generating tray icon pngs"); + await ensureOutputFoler(); + + const baseIconTemplateImage = await getBaseIconImage("macos"); + const updateAvailableTemplateImage = await generateUpdateAvailableImages(baseIconTemplateImage, "macos"); + const baseIconImage = await getBaseIconImage("windows-or-linux"); + const updateAvailableImage = await generateUpdateAvailableImages(baseIconImage, "windows-or-linux"); + + await Promise.all([ + // Templates are for macOS only + generateImages(baseIconTemplateImage, size, "trayIconTemplate"), + generateImages(updateAvailableTemplateImage, size, "trayIconUpdateAvailableTemplate"), + + // Non-templates are for windows and linux + generateImages(baseIconImage, size, "trayIcon"), + generateImages(updateAvailableImage, size, "trayIconUpdateAvailable"), + ]); + + console.log("Generated all images"); + } catch (error) { + console.error(error); + } +} + +generateTrayIcons(); diff --git a/build/tray/trayIconDarkTemplate.png b/build/tray/trayIcon.png similarity index 100% rename from build/tray/trayIconDarkTemplate.png rename to build/tray/trayIcon.png diff --git a/build/tray/trayIconDarkTemplate@2x.png b/build/tray/trayIcon@2x.png similarity index 100% rename from build/tray/trayIconDarkTemplate@2x.png rename to build/tray/trayIcon@2x.png diff --git a/build/tray/trayIcon@3x.png b/build/tray/trayIcon@3x.png new file mode 100644 index 0000000000..c706ec9b3a Binary files /dev/null and b/build/tray/trayIcon@3x.png differ diff --git a/build/tray/trayIcon@4x.png b/build/tray/trayIcon@4x.png new file mode 100644 index 0000000000..22b1c50c28 Binary files /dev/null and b/build/tray/trayIcon@4x.png differ diff --git a/build/tray/trayIconTemplate@3x.png b/build/tray/trayIconTemplate@3x.png new file mode 100644 index 0000000000..2e06ee1a7d Binary files /dev/null and b/build/tray/trayIconTemplate@3x.png differ diff --git a/build/tray/trayIconTemplate@4x.png b/build/tray/trayIconTemplate@4x.png new file mode 100644 index 0000000000..58567e118a Binary files /dev/null and b/build/tray/trayIconTemplate@4x.png differ diff --git a/build/tray/trayIconUpdateAvailable.png b/build/tray/trayIconUpdateAvailable.png new file mode 100644 index 0000000000..88dd098ce7 Binary files /dev/null and b/build/tray/trayIconUpdateAvailable.png differ diff --git a/build/tray/trayIconUpdateAvailable@2x.png b/build/tray/trayIconUpdateAvailable@2x.png new file mode 100644 index 0000000000..b4c1167c04 Binary files /dev/null and b/build/tray/trayIconUpdateAvailable@2x.png differ diff --git a/build/tray/trayIconUpdateAvailable@3x.png b/build/tray/trayIconUpdateAvailable@3x.png new file mode 100644 index 0000000000..30af0bb440 Binary files /dev/null and b/build/tray/trayIconUpdateAvailable@3x.png differ diff --git a/build/tray/trayIconUpdateAvailable@4x.png b/build/tray/trayIconUpdateAvailable@4x.png new file mode 100644 index 0000000000..42d2effc9e Binary files /dev/null and b/build/tray/trayIconUpdateAvailable@4x.png differ diff --git a/build/tray/trayIconUpdateAvailableTemplate.png b/build/tray/trayIconUpdateAvailableTemplate.png new file mode 100644 index 0000000000..72fd9a8cf7 Binary files /dev/null and b/build/tray/trayIconUpdateAvailableTemplate.png differ diff --git a/build/tray/trayIconUpdateAvailableTemplate@2x.png b/build/tray/trayIconUpdateAvailableTemplate@2x.png new file mode 100644 index 0000000000..eed819c648 Binary files /dev/null and b/build/tray/trayIconUpdateAvailableTemplate@2x.png differ diff --git a/build/tray/trayIconUpdateAvailableTemplate@3x.png b/build/tray/trayIconUpdateAvailableTemplate@3x.png new file mode 100644 index 0000000000..4fed4a6d09 Binary files /dev/null and b/build/tray/trayIconUpdateAvailableTemplate@3x.png differ diff --git a/build/tray/trayIconUpdateAvailableTemplate@4x.png b/build/tray/trayIconUpdateAvailableTemplate@4x.png new file mode 100644 index 0000000000..4d1342ea24 Binary files /dev/null and b/build/tray/trayIconUpdateAvailableTemplate@4x.png differ diff --git a/package.json b/package.json index 89326824b7..2f652eb980 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "sentryDsn": "" }, "engines": { - "node": ">=14 <15" + "node": ">=16 <17" }, "jest": { "collectCoverage": false, @@ -250,7 +250,7 @@ "monaco-editor": "^0.29.1", "monaco-editor-webpack-plugin": "^5.0.0", "node-fetch": "lensapp/node-fetch#2.x", - "node-pty": "^0.10.1", + "node-pty": "^0.11.0-beta19", "npm": "^6.14.17", "p-limit": "^3.1.0", "path-to-regexp": "^6.2.0", @@ -313,7 +313,7 @@ "@types/md5-file": "^4.0.2", "@types/mini-css-extract-plugin": "^2.4.0", "@types/mock-fs": "^4.13.1", - "@types/node": "14.18.18", + "@types/node": "^16.11.39", "@types/node-fetch": "^2.6.1", "@types/npm": "^2.0.32", "@types/proper-lockfile": "^4.1.2", @@ -343,7 +343,7 @@ "@types/webpack-dev-server": "^4.7.2", "@types/webpack-env": "^1.17.0", "@types/webpack-node-externals": "^2.5.3", - "@typescript-eslint/eslint-plugin": "^5.27.0", + "@typescript-eslint/eslint-plugin": "^5.27.1", "@typescript-eslint/parser": "^5.27.0", "ansi_up": "^5.1.0", "chart.js": "^2.9.4", @@ -355,7 +355,7 @@ "css-loader": "^6.7.1", "deepdash": "^5.3.9", "dompurify": "^2.3.8", - "electron": "^14.2.9", + "electron": "^15.5.7", "electron-builder": "^23.0.3", "electron-notarize": "^0.3.0", "esbuild": "^0.14.38", diff --git a/src/behaviours/application-update/__snapshots__/installing-update-using-tray.test.ts.snap b/src/behaviours/application-update/__snapshots__/installing-update-using-tray.test.ts.snap index 32e6cb1cb1..5c5ebac6e4 100644 --- a/src/behaviours/application-update/__snapshots__/installing-update-using-tray.test.ts.snap +++ b/src/behaviours/application-update/__snapshots__/installing-update-using-tray.test.ts.snap @@ -44,7 +44,7 @@ exports[`installing update using tray when started when user checks for updates > { let applicationBuilder: ApplicationBuilder; let checkForPlatformUpdatesMock: AsyncFnMock; let downloadPlatformUpdateMock: AsyncFnMock; let showApplicationWindowMock: jest.Mock; + let trayIconPaths: TrayIconPaths; beforeEach(() => { applicationBuilder = getApplicationBuilder(); @@ -44,6 +47,7 @@ describe("installing update using tray", () => { mainDi.override(electronUpdaterIsActiveInjectable, () => true); mainDi.override(publishIsConfiguredInjectable, () => true); + trayIconPaths = mainDi.inject(trayIconPathsInjectable); }); }); @@ -58,22 +62,29 @@ describe("installing update using tray", () => { expect(rendered.baseElement).toMatchSnapshot(); }); + it("should use the normal tray icon", () => { + expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.normal); + }); + it("user cannot install update yet", () => { - expect(applicationBuilder.tray.get("install-update")).toBeUndefined(); + expect(applicationBuilder.tray.get("install-update")).toBeNull(); }); describe("when user checks for updates using tray", () => { let processCheckingForUpdatesPromise: Promise; beforeEach(async () => { - processCheckingForUpdatesPromise = - applicationBuilder.tray.click("check-for-updates"); + processCheckingForUpdatesPromise = applicationBuilder.tray.click("check-for-updates"); }); it("does not show application window yet", () => { expect(showApplicationWindowMock).not.toHaveBeenCalled(); }); + it("should still use the normal tray icon", () => { + expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.normal); + }); + it("user cannot check for updates again", () => { expect( applicationBuilder.tray.get("check-for-updates")?.enabled.get(), @@ -87,7 +98,7 @@ describe("installing update using tray", () => { }); it("user cannot install update yet", () => { - expect(applicationBuilder.tray.get("install-update")).toBeUndefined(); + expect(applicationBuilder.tray.get("install-update")).toBeNull(); }); it("renders", () => { @@ -107,8 +118,12 @@ describe("installing update using tray", () => { expect(showApplicationWindowMock).toHaveBeenCalled(); }); + it("should still use the normal tray icon", () => { + expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.normal); + }); + it("user cannot install update", () => { - expect(applicationBuilder.tray.get("install-update")).toBeUndefined(); + expect(applicationBuilder.tray.get("install-update")).toBeNull(); }); it("user can check for updates again", () => { @@ -142,6 +157,10 @@ describe("installing update using tray", () => { expect(showApplicationWindowMock).toHaveBeenCalled(); }); + it("should use the update available icon", () => { + expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.updateAvailable); + }); + it("user cannot check for updates again yet", () => { expect( applicationBuilder.tray.get("check-for-updates")?.enabled.get(), @@ -167,7 +186,7 @@ describe("installing update using tray", () => { }); it("user still cannot install update", () => { - expect(applicationBuilder.tray.get("install-update")).toBeUndefined(); + expect(applicationBuilder.tray.get("install-update")).toBeNull(); }); it("renders", () => { @@ -182,7 +201,11 @@ describe("installing update using tray", () => { it("user cannot install update", () => { expect( applicationBuilder.tray.get("install-update"), - ).toBeUndefined(); + ).toBeNull(); + }); + + it("should revert to use the normal tray icon", () => { + expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.normal); }); it("user can check for updates again", () => { @@ -213,6 +236,10 @@ describe("installing update using tray", () => { ).toBe("Install update some-version"); }); + it("should use the update available icon", () => { + expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.updateAvailable); + }); + it("user can check for updates again", () => { expect( applicationBuilder.tray.get("check-for-updates")?.enabled.get(), diff --git a/src/common/application-update/update-channels.ts b/src/common/application-update/update-channels.ts index c5f7b4b8c1..dff1e5879e 100644 --- a/src/common/application-update/update-channels.ts +++ b/src/common/application-update/update-channels.ts @@ -3,6 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ + export type UpdateChannelId = "alpha" | "beta" | "latest"; const latestChannel: UpdateChannel = { diff --git a/src/common/utils/sync-box/sync-box-injection-token.ts b/src/common/utils/sync-box/sync-box-injection-token.ts index d35c7d5367..76ba0679f3 100644 --- a/src/common/utils/sync-box/sync-box-injection-token.ts +++ b/src/common/utils/sync-box/sync-box-injection-token.ts @@ -4,12 +4,21 @@ */ import { getInjectionToken } from "@ogre-tools/injectable"; import type { IComputedValue } from "mobx"; -import type { JsonValue } from "type-fest"; -export interface SyncBox { +type AsJson = T extends string | number | boolean | null + ? T + : T extends Function + ? never + : T extends Array + ? AsJson[] + : T extends object + ? { [K in keyof T]: AsJson } + : never; + +export interface SyncBox { id: string; - value: IComputedValue; - set: (value: TValue) => void; + value: IComputedValue>; + set: (value: AsJson) => void; } export const syncBoxInjectionToken = getInjectionToken>({ diff --git a/src/main/context-handler/context-handler.ts b/src/main/context-handler/context-handler.ts index cf35a0a67c..3ab4fc3ca7 100644 --- a/src/main/context-handler/context-handler.ts +++ b/src/main/context-handler/context-handler.ts @@ -152,9 +152,6 @@ export class ContextHandler implements ClusterContextHandler { protected async newApiTarget(timeout: number): Promise { const kubeAuthProxy = await this.ensureServerHelper(); - const ca = this.resolveAuthProxyCa(); - const clusterPath = this.clusterUrl.path !== "/" ? this.clusterUrl.path : ""; - const apiPrefix = `${kubeAuthProxy.apiPrefix}${clusterPath}`; const headers: Record = {}; if (this.clusterUrl.hostname) { @@ -166,8 +163,8 @@ export class ContextHandler implements ClusterContextHandler { protocol: "https:", host: "127.0.0.1", port: kubeAuthProxy.port, - path: apiPrefix, - ca, + path: kubeAuthProxy.apiPrefix, + ca: this.resolveAuthProxyCa(), }, changeOrigin: true, timeout, diff --git a/src/main/helm/exec.ts b/src/main/helm/exec.ts index aa5db805ba..2847ce6102 100644 --- a/src/main/helm/exec.ts +++ b/src/main/helm/exec.ts @@ -4,7 +4,7 @@ */ import { promiseExecFile } from "../../common/utils/promise-exec"; -import type { BaseEncodingOptions } from "fs"; +import type { ObjectEncodingOptions } from "fs"; import type { ExecFileOptions, ExecFileOptionsWithStringEncoding } from "child_process"; import { helmBinaryPath } from "../../common/vars"; import { UserStore } from "../../common/user-store"; @@ -14,7 +14,7 @@ import { isChildProcessError } from "../../common/utils"; * ExecFile the bundled helm CLI * @returns STDOUT */ -export async function execHelm(args: string[], { encoding, ...rest }: BaseEncodingOptions & ExecFileOptions = {}): Promise { +export async function execHelm(args: string[], { encoding, ...rest }: ObjectEncodingOptions & ExecFileOptions = {}): Promise { const options: ExecFileOptionsWithStringEncoding = { encoding: encoding ?? "utf-8", ...rest, diff --git a/src/main/start-main-application/lens-window/application-window/create-electron-window-for.injectable.ts b/src/main/start-main-application/lens-window/application-window/create-electron-window-for.injectable.ts index b0325c538c..5279bff30f 100644 --- a/src/main/start-main-application/lens-window/application-window/create-electron-window-for.injectable.ts +++ b/src/main/start-main-application/lens-window/application-window/create-electron-window-for.injectable.ts @@ -159,6 +159,7 @@ const createElectronWindowFor = getInjectable({ // Always disable Node.js integration for all webviews webPreferences.nodeIntegration = false; + webPreferences.nativeWindowOpen = false; }) .setWindowOpenHandler((details) => { diff --git a/src/main/tray/electron-tray/electron-tray.injectable.ts b/src/main/tray/electron-tray/electron-tray.injectable.ts index 409e7abf3f..a96104f047 100644 --- a/src/main/tray/electron-tray/electron-tray.injectable.ts +++ b/src/main/tray/electron-tray/electron-tray.injectable.ts @@ -5,31 +5,37 @@ import { getInjectable } from "@ogre-tools/injectable"; import { Menu, Tray } from "electron"; import packageJsonInjectable from "../../../common/vars/package-json.injectable"; -import logger from "../../logger"; -import { TRAY_LOG_PREFIX } from "../tray"; import showApplicationWindowInjectable from "../../start-main-application/lens-window/show-application-window.injectable"; -import type { TrayMenuItem } from "../tray-menu-item/tray-menu-item-injection-token"; -import { pipeline } from "@ogre-tools/fp"; -import { isEmpty, map, filter } from "lodash/fp"; import isWindowsInjectable from "../../../common/vars/is-windows.injectable"; import loggerInjectable from "../../../common/logger.injectable"; -import trayIconPathInjectable from "../tray-icon-path.injectable"; +import trayIconPathsInjectable from "../tray-icon-path.injectable"; +import type { TrayMenuItem } from "../tray-menu-item/tray-menu-item-injection-token"; +import { convertToElectronMenuTemplate } from "../reactive-tray-menu-items/converters"; + +const TRAY_LOG_PREFIX = "[TRAY]"; + +export interface ElectronTray { + start(): void; + stop(): void; + setMenuItems(menuItems: TrayMenuItem[]): void; + setIconPath(iconPath: string): void; +} const electronTrayInjectable = getInjectable({ id: "electron-tray", - instantiate: (di) => { + instantiate: (di): ElectronTray => { const packageJson = di.inject(packageJsonInjectable); const showApplicationWindow = di.inject(showApplicationWindowInjectable); const isWindows = di.inject(isWindowsInjectable); const logger = di.inject(loggerInjectable); - const trayIconPath = di.inject(trayIconPathInjectable); + const trayIconPaths = di.inject(trayIconPathsInjectable); let tray: Tray; return { start: () => { - tray = new Tray(trayIconPath); + tray = new Tray(trayIconPaths.normal); tray.setToolTip(packageJson.description); tray.setIgnoreDoubleClickEvents(true); @@ -41,21 +47,17 @@ const electronTrayInjectable = getInjectable({ }); } }, - stop: () => { tray.destroy(); }, + setMenuItems: (menuItems) => { + const template = convertToElectronMenuTemplate(menuItems); + const menu = Menu.buildFromTemplate(template); - setMenuItems: (items: TrayMenuItem[]) => { - pipeline( - items, - convertToElectronMenuTemplate, - Menu.buildFromTemplate, - - (template) => { - tray.setContextMenu(template); - }, - ); + tray.setContextMenu(menu); + }, + setIconPath: (iconPath) => { + tray.setImage(iconPath); }, }; }, @@ -64,53 +66,3 @@ const electronTrayInjectable = getInjectable({ }); export default electronTrayInjectable; - -const convertToElectronMenuTemplate = (trayMenuItems: TrayMenuItem[]) => { - const _toTrayMenuOptions = (parentId: string | null) => - pipeline( - trayMenuItems, - - filter((item) => item.parentId === parentId), - - map( - (trayMenuItem: TrayMenuItem): Electron.MenuItemConstructorOptions => { - if (trayMenuItem.separator) { - return { id: trayMenuItem.id, type: "separator" }; - } - - const childItems = _toTrayMenuOptions(trayMenuItem.id); - - return { - id: trayMenuItem.id, - label: trayMenuItem.label?.get(), - enabled: trayMenuItem.enabled.get(), - toolTip: trayMenuItem.tooltip, - - ...(isEmpty(childItems) - ? { - type: "normal", - submenu: _toTrayMenuOptions(trayMenuItem.id), - - click: () => { - try { - trayMenuItem.click?.(); - } catch (error) { - logger.error( - `${TRAY_LOG_PREFIX}: clicking item "${trayMenuItem.id} failed."`, - { error }, - ); - } - }, - } - : { - type: "submenu", - submenu: _toTrayMenuOptions(trayMenuItem.id), - }), - - }; - }, - ), - ); - - return _toTrayMenuOptions(null); -}; diff --git a/src/main/tray/menu-icon/reactive.injectable.ts b/src/main/tray/menu-icon/reactive.injectable.ts new file mode 100644 index 0000000000..42622ff2a8 --- /dev/null +++ b/src/main/tray/menu-icon/reactive.injectable.ts @@ -0,0 +1,37 @@ +/** + * 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 { reaction } from "mobx"; +import discoveredUpdateVersionInjectable from "../../../common/application-update/discovered-update-version/discovered-update-version.injectable"; +import { getStartableStoppable } from "../../../common/utils/get-startable-stoppable"; +import electronTrayInjectable from "../electron-tray/electron-tray.injectable"; +import trayIconPathsInjectable from "../tray-icon-path.injectable"; + +const reactiveTrayMenuIconInjectable = getInjectable({ + id: "reactive-tray-menu-icon", + instantiate: (di) => { + const discoveredUpdateVersion = di.inject(discoveredUpdateVersionInjectable); + const electronTray = di.inject(electronTrayInjectable); + const trayIconPaths = di.inject(trayIconPathsInjectable); + + return getStartableStoppable("reactive-tray-menu-icon", () => ( + reaction( + () => discoveredUpdateVersion.value.get(), + updateVersion => { + if (updateVersion) { + electronTray.setIconPath(trayIconPaths.updateAvailable); + } else { + electronTray.setIconPath(trayIconPaths.normal); + } + }, + { + fireImmediately: true, + }, + ) + )); + }, +}); + +export default reactiveTrayMenuIconInjectable; diff --git a/src/main/tray/menu-icon/start-reactivity.injectable.ts b/src/main/tray/menu-icon/start-reactivity.injectable.ts new file mode 100644 index 0000000000..373c3cf8fb --- /dev/null +++ b/src/main/tray/menu-icon/start-reactivity.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 { onLoadOfApplicationInjectionToken } from "../../start-main-application/runnable-tokens/on-load-of-application-injection-token"; +import startTrayInjectable from "../electron-tray/start-tray.injectable"; +import reactiveTrayMenuIconInjectable from "./reactive.injectable"; + +const startReactiveTrayMenuIconInjectable = getInjectable({ + id: "start-reactive-tray-menu-icon", + + instantiate: (di) => { + const reactiveTrayMenuIcon = di.inject(reactiveTrayMenuIconInjectable); + + return { + run: async () => { + await reactiveTrayMenuIcon.start(); + }, + + runAfter: di.inject(startTrayInjectable), + }; + }, + + injectionToken: onLoadOfApplicationInjectionToken, +}); + +export default startReactiveTrayMenuIconInjectable; diff --git a/src/main/tray/menu-icon/stop-reactivity.injectable.ts b/src/main/tray/menu-icon/stop-reactivity.injectable.ts new file mode 100644 index 0000000000..4b60aaaa54 --- /dev/null +++ b/src/main/tray/menu-icon/stop-reactivity.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 { beforeQuitOfBackEndInjectionToken } from "../../start-main-application/runnable-tokens/before-quit-of-back-end-injection-token"; +import reactiveTrayMenuIconInjectable from "./reactive.injectable"; + +const stopReactiveTrayMenuIconInjectable = getInjectable({ + id: "stop-reactive-tray-menu-icon", + + instantiate: (di) => { + const reactiveTrayMenuIcon = di.inject(reactiveTrayMenuIconInjectable); + + return { + run: async () => { + await reactiveTrayMenuIcon.stop(); + }, + }; + }, + + injectionToken: beforeQuitOfBackEndInjectionToken, +}); + +export default stopReactiveTrayMenuIconInjectable; diff --git a/src/main/tray/reactive-tray-menu-items/converters.ts b/src/main/tray/reactive-tray-menu-items/converters.ts new file mode 100644 index 0000000000..42add7481e --- /dev/null +++ b/src/main/tray/reactive-tray-menu-items/converters.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 type { TrayMenuItem } from "../tray-menu-item/tray-menu-item-injection-token"; + +export function convertToElectronMenuTemplate(trayMenuItems: TrayMenuItem[]): Electron.MenuItemConstructorOptions[] { + const toTrayMenuOptions = (parentId: string | null) => ( + trayMenuItems + .filter((item) => item.parentId === parentId) + .map((trayMenuItem: TrayMenuItem): Electron.MenuItemConstructorOptions => { + if (trayMenuItem.separator) { + return { id: trayMenuItem.id, type: "separator" }; + } + + const childItems = toTrayMenuOptions(trayMenuItem.id); + + return { + id: trayMenuItem.id, + label: trayMenuItem.label?.get(), + enabled: trayMenuItem.enabled.get(), + toolTip: trayMenuItem.tooltip, + + ...(childItems.length === 0 + ? { + type: "normal", + submenu: toTrayMenuOptions(trayMenuItem.id), + click: trayMenuItem.click, + } + : { + type: "submenu", + submenu: toTrayMenuOptions(trayMenuItem.id), + }), + + }; + }) + ); + + return toTrayMenuOptions(null); +} diff --git a/src/main/tray/reactive-tray-menu-items/reactive-tray-menu-items.injectable.ts b/src/main/tray/reactive-tray-menu-items/reactive-tray-menu-items.injectable.ts index b11654393a..22c3d29399 100644 --- a/src/main/tray/reactive-tray-menu-items/reactive-tray-menu-items.injectable.ts +++ b/src/main/tray/reactive-tray-menu-items/reactive-tray-menu-items.injectable.ts @@ -4,9 +4,9 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { getStartableStoppable } from "../../../common/utils/get-startable-stoppable"; -import { autorun } from "mobx"; -import trayMenuItemsInjectable from "../tray-menu-item/tray-menu-items.injectable"; +import { reaction } from "mobx"; import electronTrayInjectable from "../electron-tray/electron-tray.injectable"; +import trayMenuItemsInjectable from "../tray-menu-item/tray-menu-items.injectable"; const reactiveTrayMenuItemsInjectable = getInjectable({ id: "reactive-tray-menu-items", @@ -15,9 +15,15 @@ const reactiveTrayMenuItemsInjectable = getInjectable({ const electronTray = di.inject(electronTrayInjectable); const trayMenuItems = di.inject(trayMenuItemsInjectable); - return getStartableStoppable("reactive-tray-menu-items", () => autorun(() => { - electronTray.setMenuItems(trayMenuItems.get()); - })); + return getStartableStoppable("reactive-tray-menu-items", () => ( + reaction( + () => trayMenuItems.get(), + electronTray.setMenuItems, + { + fireImmediately: true, + }, + ) + )); }, }); diff --git a/src/main/tray/tray-icon-path.injectable.ts b/src/main/tray/tray-icon-path.injectable.ts index 1eb4d13118..df83a2e31c 100644 --- a/src/main/tray/tray-icon-path.injectable.ts +++ b/src/main/tray/tray-icon-path.injectable.ts @@ -6,21 +6,32 @@ import { getInjectable } from "@ogre-tools/injectable"; import getAbsolutePathInjectable from "../../common/path/get-absolute-path.injectable"; import staticFilesDirectoryInjectable from "../../common/vars/static-files-directory.injectable"; import isDevelopmentInjectable from "../../common/vars/is-development.injectable"; +import isMacInjectable from "../../common/vars/is-mac.injectable"; -const trayIconPathInjectable = getInjectable({ - id: "tray-icon-path", +export interface TrayIconPaths { + normal: string; + updateAvailable: string; +} - instantiate: (di) => { +const trayIconPathsInjectable = getInjectable({ + id: "tray-icon-paths", + + instantiate: (di): TrayIconPaths => { const getAbsolutePath = di.inject(getAbsolutePathInjectable); const staticFilesDirectory = di.inject(staticFilesDirectoryInjectable); const isDevelopment = di.inject(isDevelopmentInjectable); - - return getAbsolutePath( + const isMac = di.inject(isMacInjectable); + const baseIconDirectory = getAbsolutePath( staticFilesDirectory, isDevelopment ? "../build/tray" : "icons", // copied within electron-builder extras - "trayIconTemplate.png", ); + const fileSuffix = isMac ? "Template.png" : ".png"; + + return { + normal: getAbsolutePath(baseIconDirectory, `trayIcon${fileSuffix}`), + updateAvailable: getAbsolutePath(baseIconDirectory, `trayIconUpdateAvailable${fileSuffix}`), + }; }, }); -export default trayIconPathInjectable; +export default trayIconPathsInjectable; diff --git a/src/main/tray/tray-menu-items.injectable.ts b/src/main/tray/tray-menu-items.injectable.ts index 8ee9d25e5e..c008c123e0 100644 --- a/src/main/tray/tray-menu-items.injectable.ts +++ b/src/main/tray/tray-menu-items.injectable.ts @@ -12,8 +12,7 @@ const trayItemsInjectable = getInjectable({ instantiate: (di) => { const extensions = di.inject(mainExtensionsInjectable); - return computed(() => - extensions.get().flatMap(extension => extension.trayMenus)); + return computed(() => extensions.get().flatMap(extension => extension.trayMenus)); }, }); diff --git a/src/main/tray/tray.ts b/src/main/tray/tray.ts deleted file mode 100644 index 4d7e39c344..0000000000 --- a/src/main/tray/tray.ts +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import packageInfo from "../../../package.json"; -import { Menu, Tray } from "electron"; -import type { IComputedValue } from "mobx"; -import { autorun } from "mobx"; -import logger from "../logger"; -import { isWindows } from "../../common/vars"; -import type { Disposer } from "../../common/utils"; -import { disposer } from "../../common/utils"; -import type { TrayMenuItem } from "./tray-menu-item/tray-menu-item-injection-token"; -import { pipeline } from "@ogre-tools/fp"; -import { filter, isEmpty, map } from "lodash/fp"; - -export const TRAY_LOG_PREFIX = "[TRAY]"; - -// note: instance of Tray should be saved somewhere, otherwise it disappears -export let tray: Tray | null = null; - -export function initTray( - trayMenuItems: IComputedValue, - showApplicationWindow: () => Promise, - trayIconPath: string, -): Disposer { - tray = new Tray(trayIconPath); - tray.setToolTip(packageInfo.description); - tray.setIgnoreDoubleClickEvents(true); - - if (isWindows) { - tray.on("click", () => { - showApplicationWindow() - .catch(error => logger.error(`${TRAY_LOG_PREFIX}: Failed to open lens`, { error })); - }); - } - - return disposer( - autorun(() => { - try { - const options = toTrayMenuOptions(trayMenuItems.get()); - - const menu = Menu.buildFromTemplate(options); - - tray?.setContextMenu(menu); - } catch (error) { - logger.error(`${TRAY_LOG_PREFIX}: building failed`, { error }); - } - }), - () => { - tray?.destroy(); - tray = null; - }, - ); -} - -const toTrayMenuOptions = (trayMenuItems: TrayMenuItem[]) => { - const _toTrayMenuOptions = (parentId: string | null) => - pipeline( - trayMenuItems, - - filter((item) => item.parentId === parentId), - - map( - (trayMenuItem: TrayMenuItem): Electron.MenuItemConstructorOptions => { - if (trayMenuItem.separator) { - return { id: trayMenuItem.id, type: "separator" }; - } - - const childItems = _toTrayMenuOptions(trayMenuItem.id); - - return { - id: trayMenuItem.id, - label: trayMenuItem.label?.get(), - enabled: trayMenuItem.enabled.get(), - toolTip: trayMenuItem.tooltip, - - ...(isEmpty(childItems) - ? { - type: "normal", - submenu: _toTrayMenuOptions(trayMenuItem.id), - - click: () => { - trayMenuItem.click?.(); - }, - } - : { - type: "submenu", - submenu: _toTrayMenuOptions(trayMenuItem.id), - }), - }; - }, - ), - ); - - return _toTrayMenuOptions(null); -}; - diff --git a/src/renderer/components/drawer/drawer-title.tsx b/src/renderer/components/drawer/drawer-title.tsx index 9b83560dd4..d920a9cef9 100644 --- a/src/renderer/components/drawer/drawer-title.tsx +++ b/src/renderer/components/drawer/drawer-title.tsx @@ -9,7 +9,12 @@ import { cssNames } from "../../utils"; export interface DrawerTitleProps { className?: string; - children: React.ReactNode; + children?: React.ReactNode; + + /** + * @deprecated Prefer passing the value as `children` + */ + title?: React.ReactNode; /** * Specifies how large this title is diff --git a/src/renderer/components/icon/icon.tsx b/src/renderer/components/icon/icon.tsx index 084b75d804..7655194886 100644 --- a/src/renderer/components/icon/icon.tsx +++ b/src/renderer/components/icon/icon.tsx @@ -29,6 +29,7 @@ import Spinner from "./spinner.svg"; import Ssh from "./ssh.svg"; import Storage from "./storage.svg"; import Terminal from "./terminal.svg"; +import Notice from "./notice.svg"; import User from "./user.svg"; import Users from "./users.svg"; import Wheel from "./wheel.svg"; @@ -58,6 +59,7 @@ const localSvgIcons = new Map([ ["ssh", Ssh], ["storage", Storage], ["terminal", Terminal], + ["notice", Notice], ["user", User], ["users", Users], ["wheel", Wheel], diff --git a/src/renderer/components/icon/notice.svg b/src/renderer/components/icon/notice.svg new file mode 100644 index 0000000000..2774b185f6 --- /dev/null +++ b/src/renderer/components/icon/notice.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/renderer/components/test-utils/get-application-builder.tsx b/src/renderer/components/test-utils/get-application-builder.tsx index 5c8162cd2d..a817d21b71 100644 --- a/src/renderer/components/test-utils/get-application-builder.tsx +++ b/src/renderer/components/test-utils/get-application-builder.tsx @@ -24,12 +24,12 @@ import type { ClusterStore } from "../../../common/cluster-store/cluster-store"; import mainExtensionsInjectable from "../../../extensions/main-extensions.injectable"; import currentRouteComponentInjectable from "../../routes/current-route-component.injectable"; import { pipeline } from "@ogre-tools/fp"; -import { flatMap, compact, join, get, filter, find, map, matches } from "lodash/fp"; +import { flatMap, compact, join, get, filter, map, matches, find } from "lodash/fp"; import preferenceNavigationItemsInjectable from "../+preferences/preferences-navigation/preference-navigation-items.injectable"; import navigateToPreferencesInjectable from "../../../common/front-end-routing/routes/preferences/navigate-to-preferences.injectable"; import type { MenuItemOpts } from "../../../main/menu/application-menu-items.injectable"; import applicationMenuItemsInjectable from "../../../main/menu/application-menu-items.injectable"; -import type { MenuItem, MenuItemConstructorOptions } from "electron"; +import type { MenuItemConstructorOptions, MenuItem } from "electron"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import navigateToHelmChartsInjectable from "../../../common/front-end-routing/routes/cluster/helm/charts/navigate-to-helm-charts.injectable"; import hostedClusterInjectable from "../../../common/cluster-store/hosted-cluster.injectable"; @@ -43,7 +43,6 @@ import { flushPromises } from "../../../common/test-utils/flush-promises"; import type { NamespaceStore } from "../+namespaces/store"; import namespaceStoreInjectable from "../+namespaces/store.injectable"; import historyInjectable from "../../navigation/history.injectable"; -import type { TrayMenuItem } from "../../../main/tray/tray-menu-item/tray-menu-item-injection-token"; import electronTrayInjectable from "../../../main/tray/electron-tray/electron-tray.injectable"; import applicationWindowInjectable from "../../../main/start-main-application/lens-window/application-window/application-window.injectable"; import { Notifications } from "../notifications/notifications"; @@ -51,6 +50,8 @@ import broadcastThatRootFrameIsRenderedInjectable from "../../frames/root-frame/ import { getDiForUnitTesting as getRendererDi } from "../../getDiForUnitTesting"; import { getDiForUnitTesting as getMainDi } from "../../../main/getDiForUnitTesting"; import { overrideChannels } from "../../../test-utils/channel-fakes/override-channels"; +import type { TrayMenuItem } from "../../../main/tray/tray-menu-item/tray-menu-item-injection-token"; +import trayIconPathsInjectable from "../../../main/tray/tray-icon-path.injectable"; type Callback = (dis: DiContainers) => void | Promise; @@ -65,7 +66,8 @@ export interface ApplicationBuilder { tray: { click: (id: string) => Promise; - get: (id: string) => TrayMenuItem | undefined; + get: (id: string) => TrayMenuItem | null; + getIconPath: () => string; }; applicationMenu: { @@ -166,15 +168,22 @@ export const getApplicationBuilder = () => { computed(() => []), ); + const iconPaths = mainDi.inject(trayIconPathsInjectable); + let trayMenuItemsStateFake: TrayMenuItem[]; + let trayMenuIconPath: string; mainDi.override(electronTrayInjectable, () => ({ - start: () => {}, + start: () => { + trayMenuIconPath = iconPaths.normal; + }, stop: () => {}, - setMenuItems: (items) => { trayMenuItemsStateFake = items; }, + setIconPath: (path) => { + trayMenuIconPath = path; + }, })); let allowedResourcesState: IObservableArray; @@ -209,6 +218,7 @@ export const getApplicationBuilder = () => { { menu: null as never, commandId: 0, + userAccelerator: null, ...menuItem, } as MenuItem, undefined, @@ -221,9 +231,9 @@ export const getApplicationBuilder = () => { tray: { get: (id: string) => { - return trayMenuItemsStateFake.find(matches({ id })); + return trayMenuItemsStateFake.find(matches({ id })) ?? null; }, - + getIconPath: () => trayMenuIconPath, click: async (id: string) => { const menuItem = pipeline( trayMenuItemsStateFake, diff --git a/yarn.lock b/yarn.lock index 3a347cb290..120613934c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -473,7 +473,7 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@electron/get@^1.0.1": +"@electron/get@^1.13.0": version "1.14.1" resolved "https://registry.yarnpkg.com/@electron/get/-/get-1.14.1.tgz#16ba75f02dffb74c23965e72d617adc721d27f40" integrity sha512-BrZYyL/6m0ZXz/lDxy/nlVhQz+WF+iPS6qXolEU8atw7h6v1aYkjwJZ63m+bJMBTxDE66X+r2tPS4a/8C82sZw== @@ -1847,16 +1847,21 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.31.tgz#a5bb84ecfa27eec5e1c802c6bbf8139bdb163a5d" integrity sha512-AR0x5HbXGqkEx9CadRH3EBYx/VkiUgZIhP4wvPn/+5KIsgpNoyFaRlVe0Zlx9gRtg8fA06a9tskE2MSN7TcG4Q== -"@types/node@14.18.18", "@types/node@^14.6.2": - version "14.18.18" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.18.tgz#5c9503030df484ccffcbb935ea9a9e1d6fad1a20" - integrity sha512-B9EoJFjhqcQ9OmQrNorItO+OwEOORNn3S31WuiHvZY/dm9ajkB7AKD/8toessEtHHNL+58jofbq7hMMY9v4yig== - "@types/node@^10.12.0": version "10.17.60" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== +"@types/node@^14.6.2": + version "14.18.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.18.tgz#5c9503030df484ccffcbb935ea9a9e1d6fad1a20" + integrity sha512-B9EoJFjhqcQ9OmQrNorItO+OwEOORNn3S31WuiHvZY/dm9ajkB7AKD/8toessEtHHNL+58jofbq7hMMY9v4yig== + +"@types/node@^16.11.39": + version "16.11.39" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.39.tgz#07223cd2bc332ad9d92135e3a522eebdee3b060e" + integrity sha512-K0MsdV42vPwm9L6UwhIxMAOmcvH/1OoVkZyCgEtVu4Wx7sElGloy/W7kMBNe/oJ7V/jW9BVt1F6RahH6e7tPXw== + "@types/normalize-package-data@^2.4.0": version "2.4.1" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" @@ -2288,14 +2293,14 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.27.0": - version "5.27.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.27.0.tgz#23d82a4f21aaafd8f69dbab7e716323bb6695cc8" - integrity sha512-DDrIA7GXtmHXr1VCcx9HivA39eprYBIFxbQEHI6NyraRDxCGpxAFiYQAT/1Y0vh1C+o2vfBiy4IuPoXxtTZCAQ== +"@typescript-eslint/eslint-plugin@^5.27.1": + version "5.27.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.27.1.tgz#fdf59c905354139046b41b3ed95d1609913d0758" + integrity sha512-6dM5NKT57ZduNnJfpY81Phe9nc9wolnMCnknb1im6brWi1RYv84nbMS3olJa27B6+irUVV1X/Wb+Am0FjJdGFw== dependencies: - "@typescript-eslint/scope-manager" "5.27.0" - "@typescript-eslint/type-utils" "5.27.0" - "@typescript-eslint/utils" "5.27.0" + "@typescript-eslint/scope-manager" "5.27.1" + "@typescript-eslint/type-utils" "5.27.1" + "@typescript-eslint/utils" "5.27.1" debug "^4.3.4" functional-red-black-tree "^1.0.1" ignore "^5.2.0" @@ -2321,12 +2326,20 @@ "@typescript-eslint/types" "5.27.0" "@typescript-eslint/visitor-keys" "5.27.0" -"@typescript-eslint/type-utils@5.27.0": - version "5.27.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.27.0.tgz#36fd95f6747412251d79c795b586ba766cf0974b" - integrity sha512-vpTvRRchaf628Hb/Xzfek+85o//zEUotr1SmexKvTfs7czXfYjXVT/a5yDbpzLBX1rhbqxjDdr1Gyo0x1Fc64g== +"@typescript-eslint/scope-manager@5.27.1": + version "5.27.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.27.1.tgz#4d1504392d01fe5f76f4a5825991ec78b7b7894d" + integrity sha512-fQEOSa/QroWE6fAEg+bJxtRZJTH8NTskggybogHt4H9Da8zd4cJji76gA5SBlR0MgtwF7rebxTbDKB49YUCpAg== dependencies: - "@typescript-eslint/utils" "5.27.0" + "@typescript-eslint/types" "5.27.1" + "@typescript-eslint/visitor-keys" "5.27.1" + +"@typescript-eslint/type-utils@5.27.1": + version "5.27.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.27.1.tgz#369f695199f74c1876e395ebea202582eb1d4166" + integrity sha512-+UC1vVUWaDHRnC2cQrCJ4QtVjpjjCgjNFpg8b03nERmkHv9JV9X5M19D7UFMd+/G7T/sgFwX2pGmWK38rqyvXw== + dependencies: + "@typescript-eslint/utils" "5.27.1" debug "^4.3.4" tsutils "^3.21.0" @@ -2335,6 +2348,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.27.0.tgz#c3f44b9dda6177a9554f94a74745ca495ba9c001" integrity sha512-lY6C7oGm9a/GWhmUDOs3xAVRz4ty/XKlQ2fOLr8GAIryGn0+UBOoJDWyHer3UgrHkenorwvBnphhP+zPmzmw0A== +"@typescript-eslint/types@5.27.1": + version "5.27.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.27.1.tgz#34e3e629501349d38be6ae97841298c03a6ffbf1" + integrity sha512-LgogNVkBhCTZU/m8XgEYIWICD6m4dmEDbKXESCbqOXfKZxRKeqpiJXQIErv66sdopRKZPo5l32ymNqibYEH/xg== + "@typescript-eslint/typescript-estree@5.27.0": version "5.27.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.27.0.tgz#7965f5b553c634c5354a47dcce0b40b94611e995" @@ -2348,15 +2366,28 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.27.0": - version "5.27.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.27.0.tgz#d0021cbf686467a6a9499bd0589e19665f9f7e71" - integrity sha512-nZvCrkIJppym7cIbP3pOwIkAefXOmfGPnCM0LQfzNaKxJHI6VjI8NC662uoiPlaf5f6ymkTy9C3NQXev2mdXmA== +"@typescript-eslint/typescript-estree@5.27.1": + version "5.27.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.27.1.tgz#7621ee78607331821c16fffc21fc7a452d7bc808" + integrity sha512-DnZvvq3TAJ5ke+hk0LklvxwYsnXpRdqUY5gaVS0D4raKtbznPz71UJGnPTHEFo0GDxqLOLdMkkmVZjSpET1hFw== + dependencies: + "@typescript-eslint/types" "5.27.1" + "@typescript-eslint/visitor-keys" "5.27.1" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.27.1": + version "5.27.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.27.1.tgz#b4678b68a94bc3b85bf08f243812a6868ac5128f" + integrity sha512-mZ9WEn1ZLDaVrhRaYgzbkXBkTPghPFsup8zDbbsYTxC5OmqrFE7skkKS/sraVsLP3TcT3Ki5CSyEFBRkLH/H/w== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.27.0" - "@typescript-eslint/types" "5.27.0" - "@typescript-eslint/typescript-estree" "5.27.0" + "@typescript-eslint/scope-manager" "5.27.1" + "@typescript-eslint/types" "5.27.1" + "@typescript-eslint/typescript-estree" "5.27.1" eslint-scope "^5.1.1" eslint-utils "^3.0.0" @@ -2368,6 +2399,14 @@ "@typescript-eslint/types" "5.27.0" eslint-visitor-keys "^3.3.0" +"@typescript-eslint/visitor-keys@5.27.1": + version "5.27.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.27.1.tgz#05a62666f2a89769dac2e6baa48f74e8472983af" + integrity sha512-xYs6ffo01nhdJgPieyk7HAOpjhTsx7r/oB9LWEhwAXgwn33tkr+W8DI2ChboqhZlC4q3TC6geDYPoiX8ROqyOQ== + dependencies: + "@typescript-eslint/types" "5.27.1" + eslint-visitor-keys "^3.3.0" + "@webassemblyjs/ast@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" @@ -4989,12 +5028,12 @@ electron-window-state@^5.0.3: jsonfile "^4.0.0" mkdirp "^0.5.1" -electron@^14.2.9: - version "14.2.9" - resolved "https://registry.yarnpkg.com/electron/-/electron-14.2.9.tgz#9e1e95643ec3847592a186e8115d1ddb2e4921ee" - integrity sha512-7LdJFmqVzO9NLKO0hwOwPA6Kv4GSybGMcej8f2q7fVT4O8mIfL9oo/v4axVjVWm0+58ROQtHv8hYnnAs3ygG0Q== +electron@^15.5.7: + version "15.5.7" + resolved "https://registry.yarnpkg.com/electron/-/electron-15.5.7.tgz#aadb0081c504f2c2d8f81ea5fd23e38881afe86a" + integrity sha512-n4mVlxoMc4eYx07wWFWGficL+iOMz5xZEf5dBtE/wwLm0fQpYVyW4AlknMFG9F8Css0MM0JSwNMOyRg5e1vDtg== dependencies: - "@electron/get" "^1.0.1" + "@electron/get" "^1.13.0" "@types/node" "^14.6.2" extract-zip "^1.0.3" @@ -9477,10 +9516,10 @@ node-notifier@^8.0.0: uuid "^8.3.0" which "^2.0.2" -node-pty@^0.10.1: - version "0.10.1" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.10.1.tgz#cd05d03a2710315ec40221232ec04186f6ac2c6d" - integrity sha512-JTdtUS0Im/yRsWJSx7yiW9rtpfmxqxolrtnyKwPLI+6XqTAPW/O2MjS8FYL4I5TsMbH2lVgDb2VMjp+9LoQGNg== +node-pty@^0.11.0-beta19: + version "0.11.0-beta9" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.11.0-beta9.tgz#38a899d62b1c5c395ca466dfac5203eff989d350" + integrity sha512-bU/2zYV6xBMVMHaMe+yr4WEw36PCA0hyZ7A0IBQFWy5l1vjsD52sZ9sGJk+dH7bw3xpuBLHMh9Eq4Di8rJz4IQ== dependencies: nan "^2.14.0"