From b03eb443c9cc406863cf222f8ef17334ada25eae Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 7 Jul 2021 02:20:17 -0400 Subject: [PATCH 01/80] Await kubeconfigPathP for fish shell args (#3286) Signed-off-by: Sebastian Malton --- src/main/shell-session/local-shell-session.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/shell-session/local-shell-session.ts b/src/main/shell-session/local-shell-session.ts index 384e9317a8..35a1369339 100644 --- a/src/main/shell-session/local-shell-session.ts +++ b/src/main/shell-session/local-shell-session.ts @@ -51,7 +51,7 @@ export class LocalShellSession extends ShellSession { case "bash": return ["--init-file", path.join(await this.kubectlBinDirP, ".bash_set_path")]; case "fish": - return ["--login", "--init-command", `export PATH="${helmpath}:${kubectlPathDir}:$PATH"; export KUBECONFIG="${this.kubeconfigPathP}"`]; + return ["--login", "--init-command", `export PATH="${helmpath}:${kubectlPathDir}:$PATH"; export KUBECONFIG="${await this.kubeconfigPathP}"`]; case "zsh": return ["--login"]; default: From a301283adc862155791409a58c1a4cb86d3c61e9 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 7 Jul 2021 02:30:07 -0400 Subject: [PATCH 02/80] Fix unhandled exception in visibility handler (#3291) - If an KubernetesCluster entity is being deleted then the catalogEntityRegistry.getById() will return undefined. This leads to an unhandled exception in the handler because we tried to read apiVersion. This commit changes it so that we get the apiVersion and kind from KubernetesCluster class itself Signed-off-by: Sebastian Malton --- src/common/catalog-entities/kubernetes-cluster.ts | 7 +++++-- src/main/catalog/catalog-entity-registry.ts | 6 +++++- src/main/initializers/ipc.ts | 6 +++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/common/catalog-entities/kubernetes-cluster.ts b/src/common/catalog-entities/kubernetes-cluster.ts index 3b79c3ab56..db948df25a 100644 --- a/src/common/catalog-entities/kubernetes-cluster.ts +++ b/src/common/catalog-entities/kubernetes-cluster.ts @@ -62,8 +62,11 @@ export interface KubernetesClusterStatus extends CatalogEntityStatus { } export class KubernetesCluster extends CatalogEntity { - public readonly apiVersion = "entity.k8slens.dev/v1alpha1"; - public readonly kind = "KubernetesCluster"; + public static readonly apiVersion = "entity.k8slens.dev/v1alpha1"; + public static readonly kind = "KubernetesCluster"; + + public readonly apiVersion = KubernetesCluster.apiVersion; + public readonly kind = KubernetesCluster.kind; async connect(): Promise { if (app) { diff --git a/src/main/catalog/catalog-entity-registry.ts b/src/main/catalog/catalog-entity-registry.ts index 4cecf4f49b..f2188132eb 100644 --- a/src/main/catalog/catalog-entity-registry.ts +++ b/src/main/catalog/catalog-entity-registry.ts @@ -20,7 +20,7 @@ */ import { action, computed, IComputedValue, IObservableArray, makeObservable, observable } from "mobx"; -import { CatalogCategoryRegistry, catalogCategoryRegistry, CatalogEntity } from "../../common/catalog"; +import { CatalogCategoryRegistry, catalogCategoryRegistry, CatalogEntity, CatalogEntityKindData } from "../../common/catalog"; import { iter } from "../../common/utils"; export class CatalogEntityRegistry { @@ -62,6 +62,10 @@ export class CatalogEntityRegistry { return items as T[]; } + + getItemsByEntityClass({ apiVersion, kind }: CatalogEntityKindData): T[] { + return this.getItemsForApiKind(apiVersion, kind); + } } export const catalogEntityRegistry = new CatalogEntityRegistry(catalogCategoryRegistry); diff --git a/src/main/initializers/ipc.ts b/src/main/initializers/ipc.ts index 95c4571a41..3614c602d7 100644 --- a/src/main/initializers/ipc.ts +++ b/src/main/initializers/ipc.ts @@ -20,7 +20,7 @@ */ import type { IpcMainInvokeEvent } from "electron"; -import type { KubernetesCluster } from "../../common/catalog-entities"; +import { KubernetesCluster } from "../../common/catalog-entities"; import { clusterFrameMap } from "../../common/cluster-frames"; import { clusterActivateHandler, clusterSetFrameIdHandler, clusterVisibilityHandler, clusterRefreshHandler, clusterDisconnectHandler, clusterKubectlApplyAllHandler, clusterKubectlDeleteAllHandler, clusterDeleteHandler } from "../../common/cluster-ipc"; import { ClusterId, ClusterStore } from "../../common/cluster-store"; @@ -50,9 +50,9 @@ export function initIpcMainHandlers() { }); ipcMainHandle(clusterVisibilityHandler, (event: IpcMainInvokeEvent, clusterId: ClusterId, visible: boolean) => { - const entity = catalogEntityRegistry.getById(clusterId); + const entity = catalogEntityRegistry.getById(clusterId); - for (const kubeEntity of catalogEntityRegistry.getItemsForApiKind(entity.apiVersion, entity.kind)) { + for (const kubeEntity of catalogEntityRegistry.getItemsByEntityClass(KubernetesCluster)) { kubeEntity.status.active = false; } From f7ad554108cbce5c82bb01dc03251d730700b21e Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Wed, 7 Jul 2021 09:35:40 +0300 Subject: [PATCH 03/80] Fixing initial scroll-to-bottom in pod logs (#3281) * Fixing scroll to bottom in pod logs Signed-off-by: Alex Andreev * Fixing invalidDate error if no timestamp provided Signed-off-by: Alex Andreev --- .../dock/__test__/to-bottom.test.tsx | 53 ++++++++++++ src/renderer/components/dock/log-list.scss | 13 --- src/renderer/components/dock/log-list.tsx | 80 +++++++------------ src/renderer/components/dock/log.store.ts | 2 +- src/renderer/components/dock/to-bottom.tsx | 38 +++++++++ 5 files changed, 122 insertions(+), 64 deletions(-) create mode 100644 src/renderer/components/dock/__test__/to-bottom.test.tsx create mode 100644 src/renderer/components/dock/to-bottom.tsx diff --git a/src/renderer/components/dock/__test__/to-bottom.test.tsx b/src/renderer/components/dock/__test__/to-bottom.test.tsx new file mode 100644 index 0000000000..c19a7b19e3 --- /dev/null +++ b/src/renderer/components/dock/__test__/to-bottom.test.tsx @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +import React from "react"; +import "@testing-library/jest-dom/extend-expect"; +import { fireEvent, render } from "@testing-library/react"; +import { ToBottom } from "../to-bottom"; +import { noop } from "../../../utils"; + +describe("", () => { + it("renders w/o errors", () => { + const { container } = render(); + + expect(container).toBeInstanceOf(HTMLElement); + }); + + it("has 'To bottom' label", () => { + const { getByText } = render(); + + expect(getByText("To bottom")).toBeInTheDocument(); + }); + + it("has a arrow down icon", () => { + const { getByText } = render(); + + expect(getByText("expand_more")).toBeInTheDocument(); + }); + + it("fires an onclick event", () => { + const callback = jest.fn(); + const { getByText } = render(); + + fireEvent.click(getByText("To bottom")); + expect(callback).toBeCalled(); + }); +}); diff --git a/src/renderer/components/dock/log-list.scss b/src/renderer/components/dock/log-list.scss index edae55ad61..3bf5bfd833 100644 --- a/src/renderer/components/dock/log-list.scss +++ b/src/renderer/components/dock/log-list.scss @@ -84,17 +84,4 @@ overflow-x: hidden!important; // fixing scroll to bottom issues in PodLogs } } - - .JumpToBottom { - position: absolute; - right: 30px; - padding: 4px 9px; - border-radius: 20px; - z-index: 2; - top: 20px; - - .Icon { - --size: calc(var(--unit) * 2); - } - } } diff --git a/src/renderer/components/dock/log-list.tsx b/src/renderer/components/dock/log-list.tsx index 9437a854e2..211e66f936 100644 --- a/src/renderer/components/dock/log-list.tsx +++ b/src/renderer/components/dock/log-list.tsx @@ -25,20 +25,19 @@ import React from "react"; import AnsiUp from "ansi_up"; import DOMPurify from "dompurify"; import debounce from "lodash/debounce"; -import { action, computed, observable, makeObservable } from "mobx"; -import { observer } from "mobx-react"; +import { action, computed, observable, makeObservable, reaction } from "mobx"; +import { disposeOnUnmount, observer } from "mobx-react"; import moment from "moment-timezone"; import type { Align, ListOnScrollProps } from "react-window"; import { SearchStore, searchStore } from "../../../common/search-store"; import { UserStore } from "../../../common/user-store"; -import { cssNames } from "../../utils"; -import { Button } from "../button"; -import { Icon } from "../icon"; +import { boundMethod, cssNames } from "../../utils"; import { Spinner } from "../spinner"; import { VirtualList } from "../virtual-list"; import { logStore } from "./log.store"; import { logTabStore } from "./log-tab.store"; +import { ToBottom } from "./to-bottom"; interface Props { logs: string[] @@ -64,41 +63,44 @@ export class LogList extends React.Component { } componentDidMount() { - this.scrollToBottom(); + disposeOnUnmount(this, [ + reaction(() => this.props.logs, this.onLogsInitialLoad), + reaction(() => this.props.logs, this.onLogsUpdate), + reaction(() => this.props.logs, this.onUserScrolledUp) + ]); } - componentDidUpdate(prevProps: Props) { - const { logs, id } = this.props; - - if (id != prevProps.id) { + @boundMethod + onLogsInitialLoad(logs: string[], prevLogs: string[]) { + if (!prevLogs.length && logs.length) { this.isLastLineVisible = true; - - return; } + } - if (logs == prevProps.logs || !this.virtualListDiv.current) return; + @boundMethod + onLogsUpdate() { + if (this.isLastLineVisible) { + setTimeout(() => { + this.scrollToBottom(); + }, 500); // Giving some time to VirtualList to prepare its outerRef (this.virtualListDiv) element + } + } - const newLogsLoaded = prevProps.logs.length < logs.length; + @boundMethod + onUserScrolledUp(logs: string[], prevLogs: string[]) { + if (!this.virtualListDiv.current) return; + + const newLogsAdded = prevLogs.length < logs.length; const scrolledToBeginning = this.virtualListDiv.current.scrollTop === 0; - if (this.isLastLineVisible || prevProps.logs.length == 0) { - this.scrollToBottom(); // Scroll down to keep user watching/reading experience - - return; - } - - if (scrolledToBeginning && newLogsLoaded) { - const firstLineContents = prevProps.logs[0]; + if (newLogsAdded && scrolledToBeginning) { + const firstLineContents = prevLogs[0]; const lineToScroll = this.props.logs.findIndex((value) => value == firstLineContents); if (lineToScroll !== -1) { this.scrollToItem(lineToScroll, "start"); } } - - if (!logs.length) { - this.isLastLineVisible = false; - } } /** @@ -114,7 +116,7 @@ export class LogList extends React.Component { return this.props.logs .map(log => logStore.splitOutTimestamp(log)) - .map(([logTimestamp, log]) => (`${moment.tz(logTimestamp, UserStore.getInstance().localeTimezone).format()}${log}`)); + .map(([logTimestamp, log]) => (`${logTimestamp && moment.tz(logTimestamp, UserStore.getInstance().localeTimezone).format()}${log}`)); } /** @@ -158,7 +160,6 @@ export class LogList extends React.Component { } }; - @action scrollToBottom = () => { if (!this.virtualListDiv.current) return; this.virtualListDiv.current.scrollTop = this.virtualListDiv.current.scrollHeight; @@ -169,7 +170,6 @@ export class LogList extends React.Component { }; onScroll = (props: ListOnScrollProps) => { - if (!this.virtualListDiv.current) return; this.isLastLineVisible = false; this.onScrollDebounced(props); }; @@ -264,29 +264,9 @@ export class LogList extends React.Component { className="box grow" /> {this.isJumpButtonVisible && ( - + )} ); } } - -interface JumpToBottomProps { - onClick: () => void -} - -const JumpToBottom = ({ onClick }: JumpToBottomProps) => { - return ( - - ); -}; diff --git a/src/renderer/components/dock/log.store.ts b/src/renderer/components/dock/log.store.ts index 91682e8c0c..710ed3a690 100644 --- a/src/renderer/components/dock/log.store.ts +++ b/src/renderer/components/dock/log.store.ts @@ -183,7 +183,7 @@ export class LogStore { const extraction = /^(\d+\S+)(.*)/m.exec(logs); if (!extraction || extraction.length < 3) { - return ["", ""]; + return ["", logs]; } return [extraction[1], extraction[2]]; diff --git a/src/renderer/components/dock/to-bottom.tsx b/src/renderer/components/dock/to-bottom.tsx new file mode 100644 index 0000000000..f95ff6bebc --- /dev/null +++ b/src/renderer/components/dock/to-bottom.tsx @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +import React from "react"; +import { Icon } from "../icon"; + +export function ToBottom({ onClick }: { onClick: () => void }) { + return ( + + ); +} From 17a80446474ae57a292afba822e0c14ebfaeb6ba Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 7 Jul 2021 09:42:16 -0400 Subject: [PATCH 04/80] Add logging on proxy error (#3303) Signed-off-by: Sebastian Malton --- src/main/proxy/lens-proxy.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/proxy/lens-proxy.ts b/src/main/proxy/lens-proxy.ts index 00ef5fbb48..66a00284aa 100644 --- a/src/main/proxy/lens-proxy.ts +++ b/src/main/proxy/lens-proxy.ts @@ -177,6 +177,8 @@ export class LensProxy extends Singleton { return; } + logger.error(`[LENS-PROXY]: http proxy errored for cluster: ${error}`, { url: req.url }); + if (target) { logger.debug(`Failed proxy to target: ${JSON.stringify(target, null, 2)}`); @@ -196,7 +198,7 @@ export class LensProxy extends Singleton { } try { - res.writeHead(500).end("Oops, something went wrong."); + res.writeHead(500).end(`Oops, something went wrong.\n${error}`); } catch (e) { logger.error(`[LENS-PROXY]: Failed to write headers: `, e); } From fe443f462b096b3d682aa044e957062ca3ec01d6 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 7 Jul 2021 15:48:00 -0400 Subject: [PATCH 05/80] Fix table columns being hidden after changing any user preference (#3302) Signed-off-by: Sebastian Malton --- src/common/user-store/user-store.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/user-store/user-store.ts b/src/common/user-store/user-store.ts index e4f9a8a007..9801405b27 100644 --- a/src/common/user-store/user-store.ts +++ b/src/common/user-store/user-store.ts @@ -118,13 +118,13 @@ export class UserStore extends BaseStore /* implements UserStore */ isTableColumnHidden(tableId: string, ...columnIds: string[]): boolean { if (columnIds.length === 0) { - return true; + return false; } const config = this.hiddenTableColumns.get(tableId); if (!config) { - return true; + return false; } return columnIds.some(columnId => config.has(columnId)); From 497e47b277b374e1e8c18131a4d6aea29a530ba5 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 7 Jul 2021 16:29:58 -0400 Subject: [PATCH 06/80] Automatically sync all kubeConfigPaths (#3227) --- .../package/package.json | 25 ------- package.json | 2 +- src/common/user-store/index.ts | 2 +- src/common/user-store/user-store.ts | 5 +- src/main/index.ts | 2 +- src/migrations/hotbar-store/5.0.0-beta.10.ts | 4 +- src/migrations/user-store/5.0.3-beta.1.ts | 75 +++++++++++++++++++ src/migrations/user-store/index.ts | 2 + .../+extensions/__tests__/extensions.test.tsx | 12 ++- 9 files changed, 90 insertions(+), 39 deletions(-) delete mode 100644 extensions/kube-object-event-status/package/package.json create mode 100644 src/migrations/user-store/5.0.3-beta.1.ts diff --git a/extensions/kube-object-event-status/package/package.json b/extensions/kube-object-event-status/package/package.json deleted file mode 100644 index e6ab1bb688..0000000000 --- a/extensions/kube-object-event-status/package/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "kube-object-event-status", - "version": "0.1.0", - "description": "Adds kube object status from events", - "renderer": "dist/renderer.js", - "lens": { - "metadata": {}, - "styles": [] - }, - "scripts": { - "build": "webpack && npm pack", - "dev": "webpack --watch", - "test": "echo NO TESTS" - }, - "files": [ - "dist/**/*" - ], - "dependencies": {}, - "devDependencies": { - "@k8slens/extensions": "file:../../src/extensions/npm/extensions", - "ts-loader": "^8.0.4", - "typescript": "^4.0.3", - "webpack": "^4.44.2" - } -} diff --git a/package.json b/package.json index 4844f6f10a..8f7af30980 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "OpenLens", "description": "OpenLens - Open Source IDE for Kubernetes", "homepage": "https://github.com/lensapp/lens", - "version": "5.0.2", + "version": "5.0.3-beta.1", "main": "static/build/main.js", "copyright": "Š 2021 OpenLens Authors", "license": "MIT", diff --git a/src/common/user-store/index.ts b/src/common/user-store/index.ts index dc00ab6737..a8dc6eb028 100644 --- a/src/common/user-store/index.ts +++ b/src/common/user-store/index.ts @@ -20,4 +20,4 @@ */ export * from "./user-store"; -export type { KubeconfigSyncEntry, KubeconfigSyncValue } from "./preferences-helpers"; +export type { KubeconfigSyncEntry, KubeconfigSyncValue, UserPreferencesModel } from "./preferences-helpers"; diff --git a/src/common/user-store/user-store.ts b/src/common/user-store/user-store.ts index 9801405b27..9aa814890f 100644 --- a/src/common/user-store/user-store.ts +++ b/src/common/user-store/user-store.ts @@ -31,6 +31,7 @@ import path from "path"; import { fileNameMigration } from "../../migrations/user-store"; import { ObservableToggleSet, toJS } from "../../renderer/utils"; import { DESCRIPTORS, KubeconfigSyncValue, UserPreferencesModel } from "./preferences-helpers"; +import logger from "../../main/logger"; export interface UserStoreModel { lastSeenAppVersion: string; @@ -155,8 +156,8 @@ export class UserStore extends BaseStore /* implements UserStore } @action - protected fromStore(data: Partial = {}) { - const { lastSeenAppVersion, preferences } = data; + protected fromStore({ lastSeenAppVersion, preferences }: Partial = {}) { + logger.debug("UserStore.fromStore()", { lastSeenAppVersion, preferences }); if (lastSeenAppVersion) { this.lastSeenAppVersion = lastSeenAppVersion; diff --git a/src/main/index.ts b/src/main/index.ts index 0599f820cb..c94c561daa 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -138,8 +138,8 @@ app.on("ready", async () => { logger.info("💾 Loading stores"); - UserStore.createInstance().startMainReactions(); ClusterStore.createInstance().provideInitialFromMain(); + UserStore.createInstance().startMainReactions(); HotbarStore.createInstance(); ExtensionsStore.createInstance(); FilesystemProvisionerStore.createInstance(); diff --git a/src/migrations/hotbar-store/5.0.0-beta.10.ts b/src/migrations/hotbar-store/5.0.0-beta.10.ts index af6af5370c..f0a8fb4872 100644 --- a/src/migrations/hotbar-store/5.0.0-beta.10.ts +++ b/src/migrations/hotbar-store/5.0.0-beta.10.ts @@ -148,8 +148,8 @@ export default { store.set("hotbars", hotbars); } catch (error) { - if (!(error.code === "ENOENT" && error.path.endsWith("lens-workspace-store.json"))) { - // ignore lens-workspace-store.json being missing + if (error.code !== "ENOENT") { + // ignore files being missing throw error; } } diff --git a/src/migrations/user-store/5.0.3-beta.1.ts b/src/migrations/user-store/5.0.3-beta.1.ts new file mode 100644 index 0000000000..57271e30a4 --- /dev/null +++ b/src/migrations/user-store/5.0.3-beta.1.ts @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import { app } from "electron"; +import { existsSync, readJsonSync } from "fs-extra"; +import path from "path"; +import os from "os"; +import { ClusterStore, ClusterStoreModel } from "../../common/cluster-store"; +import type { KubeconfigSyncEntry, UserPreferencesModel } from "../../common/user-store"; +import { MigrationDeclaration, migrationLog } from "../helpers"; + +export default { + version: "5.0.3-beta.1", + run(store) { + try { + const { syncKubeconfigEntries = [], ...preferences }: UserPreferencesModel = store.get("preferences") ?? {}; + const { clusters = [] }: ClusterStoreModel = readJsonSync(path.resolve(app.getPath("userData"), "lens-cluster-store.json")) ?? {}; + const syncPaths = new Set(syncKubeconfigEntries.map(s => s.filePath)); + + syncPaths.add(path.join(os.homedir(), ".kube")); + + for (const cluster of clusters) { + const dirOfKubeconfig = path.dirname(cluster.kubeConfigPath); + + if (dirOfKubeconfig === ClusterStore.storedKubeConfigFolder) { + migrationLog(`Skipping ${cluster.id} because kubeConfigPath is under ClusterStore.storedKubeConfigFolder`); + continue; + } + + if (syncPaths.has(cluster.kubeConfigPath) || syncPaths.has(dirOfKubeconfig)) { + migrationLog(`Skipping ${cluster.id} because kubeConfigPath is already being synced`); + continue; + } + + if (!existsSync(cluster.kubeConfigPath)) { + migrationLog(`Skipping ${cluster.id} because kubeConfigPath no longer exists`); + continue; + } + + migrationLog(`Adding ${cluster.kubeConfigPath} from ${cluster.id} to sync paths`); + syncPaths.add(cluster.kubeConfigPath); + } + + const updatedSyncEntries: KubeconfigSyncEntry[] = [...syncPaths].map(filePath => ({ filePath })); + + migrationLog("Final list of synced paths", updatedSyncEntries); + store.set("preferences", { ...preferences, syncKubeconfigEntries: updatedSyncEntries }); + } catch (error) { + console.log(error); + + if (error.code !== "ENOENT") { + // ignore files being missing + throw error; + } + } + }, +} as MigrationDeclaration; diff --git a/src/migrations/user-store/index.ts b/src/migrations/user-store/index.ts index c08ef2c5c5..87628daeef 100644 --- a/src/migrations/user-store/index.ts +++ b/src/migrations/user-store/index.ts @@ -25,6 +25,7 @@ import { joinMigrations } from "../helpers"; import version210Beta4 from "./2.1.0-beta.4"; import version500Alpha3 from "./5.0.0-alpha.3"; +import version503Beta1 from "./5.0.3-beta.1"; import { fileNameMigration } from "./file-name-migration"; export { @@ -34,4 +35,5 @@ export { export default joinMigrations( version210Beta4, version500Alpha3, + version503Beta1, ); diff --git a/src/renderer/components/+extensions/__tests__/extensions.test.tsx b/src/renderer/components/+extensions/__tests__/extensions.test.tsx index 3c2484b92e..f51ba24575 100644 --- a/src/renderer/components/+extensions/__tests__/extensions.test.tsx +++ b/src/renderer/components/+extensions/__tests__/extensions.test.tsx @@ -59,14 +59,7 @@ describe("Extensions", () => { }); ExtensionInstallationStateStore.reset(); - UserStore.resetInstance(); - UserStore.createInstance(); - - ExtensionDiscovery.resetInstance(); - ExtensionDiscovery.createInstance().uninstallExtension = jest.fn(() => Promise.resolve()); - - ExtensionLoader.resetInstance(); ExtensionLoader.createInstance().addExtension({ id: "extensionId", manifest: { @@ -79,10 +72,15 @@ describe("Extensions", () => { isEnabled: true, isCompatible: true }); + ExtensionDiscovery.createInstance().uninstallExtension = jest.fn(() => Promise.resolve()); + UserStore.createInstance(); }); afterEach(() => { mockFs.restore(); + UserStore.resetInstance(); + ExtensionDiscovery.resetInstance(); + ExtensionLoader.resetInstance(); }); it("disables uninstall and disable buttons while uninstalling", async () => { From db968b8a5b8efe76a152178b475115d5925ff869 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 8 Jul 2021 09:13:29 -0400 Subject: [PATCH 07/80] Fix user-store/5.0.3-beta.1.ts comment (#3311) Signed-off-by: Sebastian Malton --- src/migrations/hotbar-store/5.0.0-beta.10.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/migrations/hotbar-store/5.0.0-beta.10.ts b/src/migrations/hotbar-store/5.0.0-beta.10.ts index f0a8fb4872..0bf780b201 100644 --- a/src/migrations/hotbar-store/5.0.0-beta.10.ts +++ b/src/migrations/hotbar-store/5.0.0-beta.10.ts @@ -148,8 +148,8 @@ export default { store.set("hotbars", hotbars); } catch (error) { + // ignore files being missing if (error.code !== "ENOENT") { - // ignore files being missing throw error; } } From 3b31dadf19f22460952f14b5e14e1f38b6f05d95 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 8 Jul 2021 11:35:54 -0400 Subject: [PATCH 08/80] Fix listing charts failing due to bad versions (#3308) --- src/common/utils/index.ts | 1 + src/common/utils/sort-compare.ts | 55 ++++++++++++++++ src/main/helm/__mocks__/helm-chart-manager.ts | 30 +++++++++ src/main/helm/__tests__/helm-service.test.ts | 30 +++++++++ src/main/helm/helm-service.ts | 64 +++++++++++++------ .../+apps-helm-charts/helm-chart.store.ts | 12 ++-- 6 files changed, 167 insertions(+), 25 deletions(-) create mode 100644 src/common/utils/sort-compare.ts diff --git a/src/common/utils/index.ts b/src/common/utils/index.ts index d652933341..1644c07f36 100644 --- a/src/common/utils/index.ts +++ b/src/common/utils/index.ts @@ -45,6 +45,7 @@ export * from "./openExternal"; export * from "./paths"; export * from "./reject-promise"; export * from "./singleton"; +export * from "./sort-compare"; export * from "./splitArray"; export * from "./tar"; export * from "./toggle-set"; diff --git a/src/common/utils/sort-compare.ts b/src/common/utils/sort-compare.ts new file mode 100644 index 0000000000..cd4e1b128a --- /dev/null +++ b/src/common/utils/sort-compare.ts @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import semver, { SemVer } from "semver"; + +export function sortCompare(left: T, right: T): -1 | 0 | 1 { + if (left < right) { + return -1; + } + + if (left === right) { + return 0; + } + + return 1; +} + +interface ChartVersion { + version: string; + __version?: SemVer; +} + +export function sortCompareChartVersions(left: ChartVersion, right: ChartVersion): -1 | 0 | 1 { + if (left.__version && right.__version) { + return semver.compare(right.__version, left.__version); + } + + if (!left.__version && right.__version) { + return 1; + } + + if (left.__version && !right.__version) { + return -1; + } + + return sortCompare(left.version, right.version); +} diff --git a/src/main/helm/__mocks__/helm-chart-manager.ts b/src/main/helm/__mocks__/helm-chart-manager.ts index 7d4a5e2a65..6a511273da 100644 --- a/src/main/helm/__mocks__/helm-chart-manager.ts +++ b/src/main/helm/__mocks__/helm-chart-manager.ts @@ -34,6 +34,36 @@ export class HelmChartManager { switch (this.repo.name) { case "stable": return Promise.resolve({ + "invalid-semver": [ + { + apiVersion: "3.0.0", + name: "weird-versioning", + version: "I am not semver", + repo: "stable", + digest: "test" + }, + { + apiVersion: "3.0.0", + name: "weird-versioning", + version: "v4.3.0", + repo: "stable", + digest: "test" + }, + { + apiVersion: "3.0.0", + name: "weird-versioning", + version: "I am not semver but more", + repo: "stable", + digest: "test" + }, + { + apiVersion: "3.0.0", + name: "weird-versioning", + version: "v4.4.0", + repo: "stable", + digest: "test" + }, + ], "apm-server": [ { apiVersion: "3.0.0", diff --git a/src/main/helm/__tests__/helm-service.test.ts b/src/main/helm/__tests__/helm-service.test.ts index 6ac169d5d0..56127c1684 100644 --- a/src/main/helm/__tests__/helm-service.test.ts +++ b/src/main/helm/__tests__/helm-service.test.ts @@ -62,6 +62,36 @@ describe("Helm Service tests", () => { digest: "test" } ], + "invalid-semver": [ + { + apiVersion: "3.0.0", + name: "weird-versioning", + version: "v4.4.0", + repo: "stable", + digest: "test" + }, + { + apiVersion: "3.0.0", + name: "weird-versioning", + version: "v4.3.0", + repo: "stable", + digest: "test" + }, + { + apiVersion: "3.0.0", + name: "weird-versioning", + version: "I am not semver", + repo: "stable", + digest: "test" + }, + { + apiVersion: "3.0.0", + name: "weird-versioning", + version: "I am not semver but more", + repo: "stable", + digest: "test" + }, + ], "redis": [ { apiVersion: "3.0.0", diff --git a/src/main/helm/helm-service.ts b/src/main/helm/helm-service.ts index 01262b6ef8..3cf56ccb13 100644 --- a/src/main/helm/helm-service.ts +++ b/src/main/helm/helm-service.ts @@ -19,13 +19,14 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import semver from "semver"; +import semver, { SemVer } from "semver"; import type { Cluster } from "../cluster"; import logger from "../logger"; import { HelmRepoManager } from "./helm-repo-manager"; import { HelmChartManager } from "./helm-chart-manager"; -import type { HelmChartList, RepoHelmChartList } from "../../renderer/api/endpoints/helm-charts.api"; +import type { HelmChart, HelmChartList, RepoHelmChartList } from "../../renderer/api/endpoints/helm-charts.api"; import { deleteRelease, getHistory, getRelease, getValues, installChart, listReleases, rollback, upgradeRelease } from "./helm-release-manager"; +import { iter, sortCompareChartVersions } from "../../common/utils"; interface GetReleaseValuesArgs { cluster: Cluster; @@ -132,28 +133,55 @@ class HelmService { } private excludeDeprecatedChartGroups(chartGroups: RepoHelmChartList) { - const groups = new Map(Object.entries(chartGroups)); + return Object.fromEntries( + iter.filterMap( + Object.entries(chartGroups), + ([name, charts]) => { + for (const chart of charts) { + if (chart.deprecated) { + // ignore chart group if any chart is deprecated + return undefined; + } + } - for (const [chartName, charts] of groups) { - if (charts[0].deprecated) { - groups.delete(chartName); - } + return [name, charts]; + } + ) + ); + } + + private sortCharts(charts: HelmChart[]) { + interface ExtendedHelmChart extends HelmChart { + __version: SemVer; } - return Object.fromEntries(groups); + const chartsWithVersion = Array.from( + iter.map( + charts, + (chart => { + const __version = semver.coerce(chart.version, { includePrerelease: true, loose: true }); + + if (!__version) { + logger.error(`[HELM-SERVICE]: Version from helm chart is not loosely coercable to semver.`, { name: chart.name, version: chart.version, repo: chart.repo }); + } + + (chart as ExtendedHelmChart).__version = __version; + + return chart as ExtendedHelmChart; + }) + ), + ); + + return chartsWithVersion + .sort(sortCompareChartVersions) + .map(chart => (delete chart.__version, chart as HelmChart)); } private sortChartsByVersion(chartGroups: RepoHelmChartList) { - for (const key in chartGroups) { - chartGroups[key] = chartGroups[key].sort((first, second) => { - const firstVersion = semver.coerce(first.version || 0); - const secondVersion = semver.coerce(second.version || 0); - - return semver.compare(secondVersion, firstVersion); - }); - } - - return chartGroups; + return Object.fromEntries( + Object.entries(chartGroups) + .map(([name, charts]) => [name, this.sortCharts(charts)]) + ); } } diff --git a/src/renderer/components/+apps-helm-charts/helm-chart.store.ts b/src/renderer/components/+apps-helm-charts/helm-chart.store.ts index c07dfaa886..71a5072068 100644 --- a/src/renderer/components/+apps-helm-charts/helm-chart.store.ts +++ b/src/renderer/components/+apps-helm-charts/helm-chart.store.ts @@ -21,7 +21,7 @@ import semver from "semver"; import { observable, makeObservable } from "mobx"; -import { autoBind } from "../../utils"; +import { autoBind, sortCompareChartVersions } from "../../utils"; import { getChartDetails, HelmChart, listCharts } from "../../api/endpoints/helm-charts.api"; import { ItemStore } from "../../item.store"; import flatten from "lodash/flatten"; @@ -60,12 +60,10 @@ export class HelmChartStore extends ItemStore { } protected sortVersions = (versions: IChartVersion[]) => { - return versions.sort((first, second) => { - const firstVersion = semver.coerce(first.version || 0); - const secondVersion = semver.coerce(second.version || 0); - - return semver.compare(secondVersion, firstVersion); - }); + return versions + .map(chartVersion => ({ ...chartVersion, __version: semver.coerce(chartVersion.version, { includePrerelease: true, loose: true }), })) + .sort(sortCompareChartVersions) + .map(({ __version, ...chartVersion }) => chartVersion); }; async getVersions(chartName: string, force?: boolean): Promise { From 05b1a2fc5d4cd2e5e973bd6194a7f9707684e202 Mon Sep 17 00:00:00 2001 From: chh <1474479+chenhunghan@users.noreply.github.com> Date: Thu, 8 Jul 2021 19:22:12 +0300 Subject: [PATCH 09/80] Add Sentry to capture exceptions and console.error messages, add a checkbox in preference to enable/disable error reporting (#3252) --- package.json | 7 +- src/common/sentry.ts | 115 +++++++++ src/common/user-store/preferences-helpers.ts | 14 ++ src/common/user-store/user-store.ts | 3 + src/common/utils/index.ts | 2 + src/common/utils/isValidSentryDsn.ts | 39 +++ src/common/utils/isValidURL.ts | 39 +++ src/common/vars.ts | 6 + src/main/index.ts | 3 + .../components/+preferences/preferences.tsx | 25 ++ .../error-boundary/error-boundary.tsx | 104 ++++---- src/renderer/lens-app.tsx | 3 + webpack.renderer.ts | 1 - yarn.lock | 223 +++++++++++++++++- 14 files changed, 513 insertions(+), 71 deletions(-) create mode 100644 src/common/sentry.ts create mode 100644 src/common/utils/isValidSentryDsn.ts create mode 100644 src/common/utils/isValidURL.ts diff --git a/package.json b/package.json index 8f7af30980..d1daf823ac 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,8 @@ }, "config": { "bundledKubectlVersion": "1.18.15", - "bundledHelmVersion": "3.5.4" + "bundledHelmVersion": "3.5.4", + "sentryDsn": "" }, "engines": { "node": ">=12 <13" @@ -183,6 +184,8 @@ "@hapi/call": "^8.0.1", "@hapi/subtext": "^7.0.3", "@kubernetes/client-node": "^0.14.3", + "@sentry/electron": "^2.5.0", + "@sentry/integrations": "^6.8.0", "abort-controller": "^3.0.0", "array-move": "^3.0.1", "auto-bind": "^4.0.0", @@ -251,6 +254,8 @@ "@material-ui/icons": "^4.11.2", "@material-ui/lab": "^4.0.0-alpha.57", "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3", + "@sentry/react": "^6.8.0", + "@sentry/types": "^6.8.0", "@testing-library/jest-dom": "^5.13.0", "@testing-library/react": "^11.2.6", "@types/byline": "^4.2.32", diff --git a/src/common/sentry.ts b/src/common/sentry.ts new file mode 100644 index 0000000000..ffe6a2b659 --- /dev/null +++ b/src/common/sentry.ts @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import { CaptureConsole, Dedupe, Offline } from "@sentry/integrations"; +import type { Event as SentryEvent } from "@sentry/types"; +import { sentryDsn, sentryDsnIsValid, isProduction } from "./vars"; +import { UserStore } from "./user-store"; +import logger from "../main/logger"; + +// https://www.electronjs.org/docs/api/process#processtype-readonly +const electronProcessType = ["browser", "renderer", "worker"] as const; + +export const integrations = [ + new CaptureConsole({ levels: ["error"] }), + new Dedupe(), + new Offline() +]; + +const initialScope = (processType: typeof electronProcessType[number]) => { + return { + tags: { + // "translate" browser to 'main' as Lens developer more familiar with the term 'main' + "process": processType === "browser" ? "main" : "renderer" + } + }; +}; + +export const environment = isProduction ? "production" : "development"; + +const logInitError = (reason: string) => { + logger.warn(`âš ī¸ [SENTRY-INIT]: ${reason}, Sentry is not initialized.`); +}; + +export const beforeSend = (event: SentryEvent) => { + const allowErrorReporting = UserStore.getInstance().allowErrorReporting; + + if (allowErrorReporting) return event; + + logger.info(`🔒 [SENTRY-BEFORE-SEND-HOOK]: allowErrorReporting: ${allowErrorReporting}. Sentry event is caught but not sent to server.`); + logger.info("🔒 [SENTRY-BEFORE-SEND-HOOK]: === START OF SENTRY EVENT ==="); + logger.info(event); + logger.info("🔒 [SENTRY-BEFORE-SEND-HOOK]: === END OF SENTRY EVENT ==="); + + // if return null, the event won't be sent + // ref https://github.com/getsentry/sentry-javascript/issues/2039 + return null; +}; + +export const SentryInit = () => { + if (!sentryDsnIsValid) { + logInitError("Sentry DSN is not valid"); + + return; + } + + const processType = process.type as typeof electronProcessType[number]; + + let Sentry; + + try { + // if in main process + if (processType === "browser") { + Sentry = require("@sentry/electron/dist/main"); + } + + // if in renderer process + if (processType === "renderer") { + Sentry = require("@sentry/electron/dist/renderer"); + } + } catch (error) { + logInitError(`Error loading Sentry module ${error?.message}`); + + return; + } + + + if (!Sentry) { + logInitError(`Unsupported process type ${processType}`); + + return; + } + + try { + Sentry.init({ + beforeSend, + dsn: sentryDsn, + integrations, + initialScope: initialScope(processType), + environment + }); + logger.info(`âœ”ī¸ [SENTRY-INIT]: Sentry for ${processType} is initialized.`); + } catch (error) { + logInitError(`Sentry.init() error ${error?.message}`); + + return; + } +}; diff --git a/src/common/user-store/preferences-helpers.ts b/src/common/user-store/preferences-helpers.ts index b35f7ddc51..3d205cd380 100644 --- a/src/common/user-store/preferences-helpers.ts +++ b/src/common/user-store/preferences-helpers.ts @@ -106,6 +106,19 @@ const allowTelemetry: PreferenceDescription = { }, }; +const allowErrorReporting: PreferenceDescription = { + fromStore(val) { + return val ?? true; + }, + toStore(val) { + if (val === true) { + return undefined; + } + + return val; + }, +}; + const downloadMirror: PreferenceDescription = { fromStore(val) { return val ?? "default"; @@ -227,6 +240,7 @@ export const DESCRIPTORS = { localeTimezone, allowUntrustedCAs, allowTelemetry, + allowErrorReporting, downloadMirror, downloadKubectlBinaries, downloadBinariesPath, diff --git a/src/common/user-store/user-store.ts b/src/common/user-store/user-store.ts index 9aa814890f..beeb2078e1 100644 --- a/src/common/user-store/user-store.ts +++ b/src/common/user-store/user-store.ts @@ -59,6 +59,7 @@ export class UserStore extends BaseStore /* implements UserStore @observable seenContexts = observable.set(); @observable newContexts = observable.set(); @observable allowTelemetry: boolean; + @observable allowErrorReporting: boolean; @observable allowUntrustedCAs: boolean; @observable colorTheme: string; @observable localeTimezone: string; @@ -169,6 +170,7 @@ export class UserStore extends BaseStore /* implements UserStore this.localeTimezone = DESCRIPTORS.localeTimezone.fromStore(preferences?.localeTimezone); this.allowUntrustedCAs = DESCRIPTORS.allowUntrustedCAs.fromStore(preferences?.allowUntrustedCAs); this.allowTelemetry = DESCRIPTORS.allowTelemetry.fromStore(preferences?.allowTelemetry); + this.allowErrorReporting = DESCRIPTORS.allowErrorReporting.fromStore(preferences?.allowErrorReporting); this.downloadMirror = DESCRIPTORS.downloadMirror.fromStore(preferences?.downloadMirror); this.downloadKubectlBinaries = DESCRIPTORS.downloadKubectlBinaries.fromStore(preferences?.downloadKubectlBinaries); this.downloadBinariesPath = DESCRIPTORS.downloadBinariesPath.fromStore(preferences?.downloadBinariesPath); @@ -188,6 +190,7 @@ export class UserStore extends BaseStore /* implements UserStore localeTimezone: DESCRIPTORS.localeTimezone.toStore(this.localeTimezone), allowUntrustedCAs: DESCRIPTORS.allowUntrustedCAs.toStore(this.allowUntrustedCAs), allowTelemetry: DESCRIPTORS.allowTelemetry.toStore(this.allowTelemetry), + allowErrorReporting: DESCRIPTORS.allowErrorReporting.toStore(this.allowErrorReporting), downloadMirror: DESCRIPTORS.downloadMirror.toStore(this.downloadMirror), downloadKubectlBinaries: DESCRIPTORS.downloadKubectlBinaries.toStore(this.downloadKubectlBinaries), downloadBinariesPath: DESCRIPTORS.downloadBinariesPath.toStore(this.downloadBinariesPath), diff --git a/src/common/utils/index.ts b/src/common/utils/index.ts index 1644c07f36..5ce6d20f55 100644 --- a/src/common/utils/index.ts +++ b/src/common/utils/index.ts @@ -51,6 +51,8 @@ export * from "./tar"; export * from "./toggle-set"; export * from "./toJS"; export * from "./type-narrowing"; +export * from "./isValidURL"; +export * from "./isValidSentryDsn"; import * as iter from "./iter"; diff --git a/src/common/utils/isValidSentryDsn.ts b/src/common/utils/isValidSentryDsn.ts new file mode 100644 index 0000000000..9b91ae1cac --- /dev/null +++ b/src/common/utils/isValidSentryDsn.ts @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +// Regular expression used to parse a Sentry Dsn. +// from https://github.com/getsentry/sentry-javascript/blob/f624f442fd76bf655de6def9fa4d7631735ebba0/packages/utils/src/dsn.ts#L6 +const DSN_REGEX = /^(?:(\w+):)\/\/(?:(\w+)(?::(\w+))?@)([\w.-]+)(?::(\d+))?\/(.+)/; + +/** + * check if string is a valid Sentry dsn + * + * @param {(string | undefined | null)} string + * @return {boolean} + */ +export const isValidSentryDsn = (string: string | undefined | null) => { + + const valid = DSN_REGEX.exec(string); + + return valid; + +}; diff --git a/src/common/utils/isValidURL.ts b/src/common/utils/isValidURL.ts new file mode 100644 index 0000000000..cf106f34da --- /dev/null +++ b/src/common/utils/isValidURL.ts @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/** + * check if string is valid URL + * + * @param {(string | undefined | null)} url + * @return {boolean} + */ +export const isValidURL = (url: string | undefined | null) => { + try { + new URL(url); + + return true; + } catch { + // ignore TypeError and return false + } + + return false; +}; diff --git a/src/common/vars.ts b/src/common/vars.ts index a49c8da910..f049d8b656 100644 --- a/src/common/vars.ts +++ b/src/common/vars.ts @@ -24,6 +24,8 @@ import path from "path"; import { SemVer } from "semver"; import packageInfo from "../../package.json"; import { defineGlobal } from "./utils/defineGlobal"; +import { isValidURL } from "./utils/isValidURL"; +import { isValidSentryDsn } from "./utils/isValidSentryDsn"; export const isMac = process.platform === "darwin"; export const isWindows = process.platform === "win32"; @@ -70,3 +72,7 @@ export const supportUrl = "https://docs.k8slens.dev/latest/support/" as string; export const appSemVer = new SemVer(packageInfo.version); export const docsUrl = `https://docs.k8slens.dev/main/` as string; + +export const sentryDsn = packageInfo.config?.sentryDsn; +export const sentryDsnIsValid = isValidURL(sentryDsn) && isValidSentryDsn(sentryDsn); + diff --git a/src/main/index.ts b/src/main/index.ts index c94c561daa..29b3798d7a 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -59,6 +59,9 @@ import { UserStore } from "../common/user-store"; import { WeblinkStore } from "../common/weblink-store"; import { ExtensionsStore } from "../extensions/extensions-store"; import { FilesystemProvisionerStore } from "./extension-filesystem"; +import { SentryInit } from "../common/sentry"; + +SentryInit(); const workingDir = path.join(app.getPath("appData"), appName); const cleanup = disposer(); diff --git a/src/renderer/components/+preferences/preferences.tsx b/src/renderer/components/+preferences/preferences.tsx index 9bf82f9e4f..3ec4693fe8 100644 --- a/src/renderer/components/+preferences/preferences.tsx +++ b/src/renderer/components/+preferences/preferences.tsx @@ -40,6 +40,8 @@ import { Tab, Tabs } from "../tabs"; import { FormSwitch, Switcher } from "../switch"; import { KubeconfigSyncs } from "./kubeconfig-syncs"; import { SettingLayout } from "../layout/setting-layout"; +import { Checkbox } from "../checkbox"; +import { sentryDsnIsValid } from "../../../common/vars"; enum Pages { Application = "application", @@ -257,6 +259,29 @@ export class Preferences extends React.Component {

Telemetry

{telemetryExtensions.map(this.renderExtension)} + {sentryDsnIsValid ? ( + +
+ + { + UserStore.getInstance().allowErrorReporting = value; + }} + /> +
+ + Automatic error reports provide vital information about issues and application crashes. + It is highly recommended to keep this feature enabled to ensure fast turnaround for issues you might encounter. + +
+
+
+
) : + // we don't need to shows the checkbox at all if Sentry dsn is not a valid url + null + }
)} {this.activeTab == Pages.Extensions && ( diff --git a/src/renderer/components/error-boundary/error-boundary.tsx b/src/renderer/components/error-boundary/error-boundary.tsx index d2b0ef90c5..56be840ff7 100644 --- a/src/renderer/components/error-boundary/error-boundary.tsx +++ b/src/renderer/components/error-boundary/error-boundary.tsx @@ -21,74 +21,54 @@ import "./error-boundary.scss"; -import React, { ErrorInfo } from "react"; -import { reaction } from "mobx"; -import { disposeOnUnmount, observer } from "mobx-react"; +import React from "react"; import { Button } from "../button"; import { navigation } from "../../navigation"; import { issuesTrackerUrl, slackUrl } from "../../../common/vars"; - -interface Props { -} - -interface State { - error?: Error; - errorInfo?: ErrorInfo; -} +import * as Sentry from "@sentry/react"; +import { observer } from "mobx-react"; @observer -export class ErrorBoundary extends React.Component { - public state: State = {}; - - @disposeOnUnmount - resetOnNavigate = reaction( - () => navigation.toString(), - () => this.setState({ error: null, errorInfo: null }) - ); - - componentDidCatch(error: Error, errorInfo: ErrorInfo) { - this.setState({ error, errorInfo }); - } - - back = () => { - navigation.goBack(); - }; - +export class ErrorBoundary extends React.Component { render() { - const { error, errorInfo } = this.state; + return ( + { + const slackLink = Slack; + const githubLink = Github; + const pageUrl = location.pathname; - if (error) { - const slackLink = Slack; - const githubLink = Github; - const pageUrl = location.pathname; - - return ( -
-
- App crash at {pageUrl} -
-

- To help us improve the product please report bugs to {slackLink} community or {githubLink} issues tracker. -

-
- -

Component stack:

- {errorInfo.componentStack} -
- -

Error stack:


- {error.stack} -
-
-
- ); - } - - return this.props.children; + return ( +
+
+ App crash at {pageUrl} +
+

+ To help us improve the product please report bugs to {slackLink} community or {githubLink} issues tracker. +

+
+ +

Component stack:

+ {componentStack} +
+ +

Error stack:


+ {error.stack} +
+
+
+ ); + }}> + {this.props.children} +
+ ); } } diff --git a/src/renderer/lens-app.tsx b/src/renderer/lens-app.tsx index 35151dcee2..cbe0d27f6d 100644 --- a/src/renderer/lens-app.tsx +++ b/src/renderer/lens-app.tsx @@ -36,6 +36,9 @@ import { registerIpcHandlers } from "./ipc"; import { ipcRenderer } from "electron"; import { IpcRendererNavigationEvents } from "./navigation/events"; import { catalogEntityRegistry } from "./api/catalog-entity-registry"; +import { SentryInit } from "../common/sentry"; + +SentryInit(); @observer export class LensApp extends React.Component { diff --git a/webpack.renderer.ts b/webpack.renderer.ts index 027d18ac08..c0353ef1f8 100755 --- a/webpack.renderer.ts +++ b/webpack.renderer.ts @@ -174,7 +174,6 @@ export function webpackLensRenderer({ showVars = true } = {}): webpack.Configura isDevelopment && new webpack.HotModuleReplacementPlugin(), isDevelopment && new ReactRefreshWebpackPlugin(), - ].filter(Boolean), }; } diff --git a/yarn.lock b/yarn.lock index 602f3cc2f2..1602d70c9c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -944,6 +944,171 @@ schema-utils "^2.6.5" source-map "^0.7.3" +"@sentry/browser@6.7.1": + version "6.7.1" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.7.1.tgz#e01144a08984a486ecc91d7922cc457e9c9bd6b7" + integrity sha512-R5PYx4TTvifcU790XkK6JVGwavKaXwycDU0MaAwfc4Vf7BLm5KCNJCsDySu1RPAap/017MVYf54p6dWvKiRviA== + dependencies: + "@sentry/core" "6.7.1" + "@sentry/types" "6.7.1" + "@sentry/utils" "6.7.1" + tslib "^1.9.3" + +"@sentry/browser@6.8.0": + version "6.8.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.8.0.tgz#023707cd2302f6818014e9a7e124856b2d064178" + integrity sha512-nxa71csHlG5sMHUxI4e4xxuCWtbCv/QbBfMsYw7ncJSfCKG3yNlCVh8NJ7NS0rZW/MJUT6S6+r93zw0HetNDOA== + dependencies: + "@sentry/core" "6.8.0" + "@sentry/types" "6.8.0" + "@sentry/utils" "6.8.0" + tslib "^1.9.3" + +"@sentry/core@6.7.1": + version "6.7.1" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.7.1.tgz#c3aaa6415d06bec65ac446b13b84f073805633e3" + integrity sha512-VAv8OR/7INn2JfiLcuop4hfDcyC7mfL9fdPndQEhlacjmw8gRrgXjR7qyhnCTgzFLkHI7V5bcdIzA83TRPYQpA== + dependencies: + "@sentry/hub" "6.7.1" + "@sentry/minimal" "6.7.1" + "@sentry/types" "6.7.1" + "@sentry/utils" "6.7.1" + tslib "^1.9.3" + +"@sentry/core@6.8.0": + version "6.8.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.8.0.tgz#bfac76844deee9126460c18dc6166015992efdc3" + integrity sha512-vJzWt/znEB+JqVwtwfjkRrAYRN+ep+l070Ti8GhJnvwU4IDtVlV3T/jVNrj6rl6UChcczaJQMxVxtG5x0crlAA== + dependencies: + "@sentry/hub" "6.8.0" + "@sentry/minimal" "6.8.0" + "@sentry/types" "6.8.0" + "@sentry/utils" "6.8.0" + tslib "^1.9.3" + +"@sentry/electron@^2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@sentry/electron/-/electron-2.5.0.tgz#4168ff04ee01cb5a99ce042f3435660a510c634d" + integrity sha512-OiJWi9BKtlj4UeoaCArVXIvfW808fgW1GLmeiC7wD7B64ALHSYSwu8tkqZK+IMVhPmQN04AUyoYXrZohfJ7sOg== + dependencies: + "@sentry/browser" "6.7.1" + "@sentry/core" "6.7.1" + "@sentry/minimal" "6.7.1" + "@sentry/node" "6.7.1" + "@sentry/types" "6.7.1" + "@sentry/utils" "6.7.1" + tslib "^2.2.0" + +"@sentry/hub@6.7.1": + version "6.7.1" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.7.1.tgz#d46d24deec67f0731a808ca16796e6765b371bc1" + integrity sha512-eVCTWvvcp6xa0A5GGNHMQEWslmKPlisE5rGmsV/kjvSUv3zSrI0eIDfb51ikdnCiBjHpK2NBWP8Vy8cZOEJegg== + dependencies: + "@sentry/types" "6.7.1" + "@sentry/utils" "6.7.1" + tslib "^1.9.3" + +"@sentry/hub@6.8.0": + version "6.8.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.8.0.tgz#cb0f8509093919ed3c1ef98ef8cf63dc102a6524" + integrity sha512-hFrI2Ss1fTov7CH64FJpigqRxH7YvSnGeqxT9Jc1BL7nzW/vgCK+Oh2mOZbosTcrzoDv+lE8ViOnSN3w/fo+rg== + dependencies: + "@sentry/types" "6.8.0" + "@sentry/utils" "6.8.0" + tslib "^1.9.3" + +"@sentry/integrations@^6.8.0": + version "6.8.0" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-6.8.0.tgz#990d042d683ed4b45fcbe0cbf3e8077587a45f85" + integrity sha512-K8xmWGQFKxkKj5rMwGENm0SbbUs/SVhHE+V8+KkhXFmHAwfNAYTFaNg0Ryu9DADAJ4QYzZvYeRxl8voFecOqzA== + dependencies: + "@sentry/types" "6.8.0" + "@sentry/utils" "6.8.0" + localforage "^1.8.1" + tslib "^1.9.3" + +"@sentry/minimal@6.7.1": + version "6.7.1" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.7.1.tgz#babf85ee2f167e9dcf150d750d7a0b250c98449c" + integrity sha512-HDDPEnQRD6hC0qaHdqqKDStcdE1KhkFh0RCtJNMCDn0zpav8Dj9AteF70x6kLSlliAJ/JFwi6AmQrLz+FxPexw== + dependencies: + "@sentry/hub" "6.7.1" + "@sentry/types" "6.7.1" + tslib "^1.9.3" + +"@sentry/minimal@6.8.0": + version "6.8.0" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.8.0.tgz#d6c3e4c96f231367aeb2b8a87a83b53d28e7c6db" + integrity sha512-MRxUKXiiYwKjp8mOQMpTpEuIby1Jh3zRTU0cmGZtfsZ38BC1JOle8xlwC4FdtOH+VvjSYnPBMya5lgNHNPUJDQ== + dependencies: + "@sentry/hub" "6.8.0" + "@sentry/types" "6.8.0" + tslib "^1.9.3" + +"@sentry/node@6.7.1": + version "6.7.1" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.7.1.tgz#b09e2eca8e187168feba7bd865a23935bf0f5cc0" + integrity sha512-rtZo1O8ROv4lZwuljQz3iFZW89oXSlgXCG2VqkxQyRspPWu89abROpxLjYzsWwQ8djnur1XjFv51kOLDUTS6Qw== + dependencies: + "@sentry/core" "6.7.1" + "@sentry/hub" "6.7.1" + "@sentry/tracing" "6.7.1" + "@sentry/types" "6.7.1" + "@sentry/utils" "6.7.1" + cookie "^0.4.1" + https-proxy-agent "^5.0.0" + lru_map "^0.3.3" + tslib "^1.9.3" + +"@sentry/react@^6.8.0": + version "6.8.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-6.8.0.tgz#3cf4a2e1ef042ee227836e268e702e9cb3b67e41" + integrity sha512-yXNnDaVw8kIacbwQjA27w8DA74WxmDVw4RlUTJGtq35SDmWsaGN1mwvU+mE1u3zEg927QTCBYig2Zqk8Tdt/fQ== + dependencies: + "@sentry/browser" "6.8.0" + "@sentry/minimal" "6.8.0" + "@sentry/types" "6.8.0" + "@sentry/utils" "6.8.0" + hoist-non-react-statics "^3.3.2" + tslib "^1.9.3" + +"@sentry/tracing@6.7.1": + version "6.7.1" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.7.1.tgz#b11f0c17a6c5dc14ef44733e5436afb686683268" + integrity sha512-wyS3nWNl5mzaC1qZ2AIp1hjXnfO9EERjMIJjCihs2LWBz1r3efxrHxJHs8wXlNWvrT3KLhq/7vvF5CdU82uPeQ== + dependencies: + "@sentry/hub" "6.7.1" + "@sentry/minimal" "6.7.1" + "@sentry/types" "6.7.1" + "@sentry/utils" "6.7.1" + tslib "^1.9.3" + +"@sentry/types@6.7.1": + version "6.7.1" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.7.1.tgz#c8263e1886df5e815570c4668eb40a1cfaa1c88b" + integrity sha512-9AO7HKoip2MBMNQJEd6+AKtjj2+q9Ze4ooWUdEvdOVSt5drg7BGpK221/p9JEOyJAZwEPEXdcMd3VAIMiOb4MA== + +"@sentry/types@6.8.0", "@sentry/types@^6.8.0": + version "6.8.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.8.0.tgz#97fd531a0ed1e75e65b4a24b26509fb7c15eb7b8" + integrity sha512-PbSxqlh6Fd5thNU5f8EVYBVvX+G7XdPA+ThNb2QvSK8yv3rIf0McHTyF6sIebgJ38OYN7ZFK7vvhC/RgSAfYTA== + +"@sentry/utils@6.7.1": + version "6.7.1" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.7.1.tgz#909184ad580f0f6375e1e4d4a6ffd33dfe64a4d1" + integrity sha512-Tq2otdbWlHAkctD+EWTYKkEx6BL1Qn3Z/imkO06/PvzpWvVhJWQ5qHAzz5XnwwqNHyV03KVzYB6znq1Bea9HuA== + dependencies: + "@sentry/types" "6.7.1" + tslib "^1.9.3" + +"@sentry/utils@6.8.0": + version "6.8.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.8.0.tgz#0ffafa5b69fe0cdeabad5c4a6cc68a426eaa6b37" + integrity sha512-OYlI2JNrcWKMdvYbWNdQwR4QBVv2V0y5wK0U6f53nArv6RsyO5TzwRu5rMVSIZofUUqjoE5hl27jqnR+vpUrsA== + dependencies: + "@sentry/types" "6.8.0" + tslib "^1.9.3" + "@sideway/address@^4.1.0": version "4.1.0" resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.0.tgz#0b301ada10ac4e0e3fa525c90615e0b61a72b78d" @@ -2305,6 +2470,13 @@ agent-base@4, agent-base@^4.3.0: dependencies: es6-promisify "^5.0.0" +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + agent-base@~4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" @@ -4174,6 +4346,11 @@ cookie@0.4.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== +cookie@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" + integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== + copy-anything@^2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-2.0.3.tgz#842407ba02466b0df844819bbe3baebbe5d45d87" @@ -4554,6 +4731,13 @@ debug@3.1.0, debug@~3.1.0: dependencies: ms "2.0.0" +debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + dependencies: + ms "2.1.2" + debug@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87" @@ -4575,13 +4759,6 @@ debug@^3.1.0: dependencies: ms "^2.1.1" -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== - dependencies: - ms "2.1.2" - debug@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" @@ -7233,6 +7410,14 @@ https-proxy-agent@^2.2.3: agent-base "^4.3.0" debug "^3.1.0" +https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + dependencies: + agent-base "6" + debug "4" + human-signals@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" @@ -9208,6 +9393,13 @@ libnpx@^10.2.4: y18n "^4.0.0" yargs "^14.2.3" +lie@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4= + dependencies: + immediate "~3.0.5" + lie@~3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" @@ -9283,6 +9475,13 @@ loader-utils@^2.0.0: emojis-list "^3.0.0" json5 "^2.1.2" +localforage@^1.8.1: + version "1.9.0" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.9.0.tgz#f3e4d32a8300b362b4634cc4e066d9d00d2f09d1" + integrity sha512-rR1oyNrKulpe+VM9cYmcFn6tsHuokyVHFaCM3+osEmxaHTbEk8oQu6eGDfS6DQLWi/N67XRmB8ECG37OES368g== + dependencies: + lie "3.1.1" + locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" @@ -9470,6 +9669,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru_map@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" + integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0= + lunr@^2.3.9: version "2.3.9" resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" @@ -14362,6 +14566,11 @@ tslib@^2.1.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== +tslib@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" + integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== + tsutils@^3.17.1: version "3.17.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" From 77f8ea67bd78da6721114d40e285dc3296087ada Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 8 Jul 2021 16:57:29 -0400 Subject: [PATCH 10/80] Cleanup sentry integration (#3315) --- src/common/sentry.ts | 141 ++++++++---------- src/common/utils/index.ts | 2 - src/common/utils/isValidSentryDsn.ts | 39 ----- src/common/utils/isValidURL.ts | 39 ----- src/common/vars.ts | 6 +- src/main/index.ts | 11 +- src/renderer/bootstrap.tsx | 8 + .../components/+preferences/preferences.tsx | 4 +- src/renderer/lens-app.tsx | 3 - 9 files changed, 78 insertions(+), 175 deletions(-) delete mode 100644 src/common/utils/isValidSentryDsn.ts delete mode 100644 src/common/utils/isValidURL.ts diff --git a/src/common/sentry.ts b/src/common/sentry.ts index ffe6a2b659..36435b86c9 100644 --- a/src/common/sentry.ts +++ b/src/common/sentry.ts @@ -20,96 +20,73 @@ */ import { CaptureConsole, Dedupe, Offline } from "@sentry/integrations"; -import type { Event as SentryEvent } from "@sentry/types"; -import { sentryDsn, sentryDsnIsValid, isProduction } from "./vars"; +import { sentryDsn, isProduction } from "./vars"; import { UserStore } from "./user-store"; import logger from "../main/logger"; -// https://www.electronjs.org/docs/api/process#processtype-readonly -const electronProcessType = ["browser", "renderer", "worker"] as const; +export let sentryIsInitialized = false; -export const integrations = [ - new CaptureConsole({ levels: ["error"] }), - new Dedupe(), - new Offline() -]; - -const initialScope = (processType: typeof electronProcessType[number]) => { - return { - tags: { - // "translate" browser to 'main' as Lens developer more familiar with the term 'main' - "process": processType === "browser" ? "main" : "renderer" - } - }; -}; - -export const environment = isProduction ? "production" : "development"; - -const logInitError = (reason: string) => { - logger.warn(`âš ī¸ [SENTRY-INIT]: ${reason}, Sentry is not initialized.`); -}; - -export const beforeSend = (event: SentryEvent) => { - const allowErrorReporting = UserStore.getInstance().allowErrorReporting; - - if (allowErrorReporting) return event; - - logger.info(`🔒 [SENTRY-BEFORE-SEND-HOOK]: allowErrorReporting: ${allowErrorReporting}. Sentry event is caught but not sent to server.`); - logger.info("🔒 [SENTRY-BEFORE-SEND-HOOK]: === START OF SENTRY EVENT ==="); - logger.info(event); - logger.info("🔒 [SENTRY-BEFORE-SEND-HOOK]: === END OF SENTRY EVENT ==="); - - // if return null, the event won't be sent - // ref https://github.com/getsentry/sentry-javascript/issues/2039 - return null; -}; - -export const SentryInit = () => { - if (!sentryDsnIsValid) { - logInitError("Sentry DSN is not valid"); - - return; +/** + * This function bypasses webpack issues. + * + * See: https://docs.sentry.io/platforms/javascript/guides/electron/#webpack-configuration + */ +async function requireSentry() { + switch (process.type) { + case "browser": + return import("@sentry/electron/dist/main"); + case "renderer": + return import("@sentry/electron/dist/renderer"); + default: + throw new Error(`Unsupported process type ${process.type}`); } +} - const processType = process.type as typeof electronProcessType[number]; - - let Sentry; - +/** + * Initialize Sentry for the current process so to send errors for debugging. + */ +export async function SentryInit(): Promise { try { - // if in main process - if (processType === "browser") { - Sentry = require("@sentry/electron/dist/main"); - } + const Sentry = await requireSentry(); - // if in renderer process - if (processType === "renderer") { - Sentry = require("@sentry/electron/dist/renderer"); + try { + Sentry.init({ + beforeSend: event => { + if (UserStore.getInstance().allowErrorReporting) { + return event; + } + + logger.info(`🔒 [SENTRY-BEFORE-SEND-HOOK]: allowErrorReporting: false. Sentry event is caught but not sent to server.`); + logger.info("🔒 [SENTRY-BEFORE-SEND-HOOK]: === START OF SENTRY EVENT ==="); + logger.info(event); + logger.info("🔒 [SENTRY-BEFORE-SEND-HOOK]: === END OF SENTRY EVENT ==="); + + // if return null, the event won't be sent + // ref https://github.com/getsentry/sentry-javascript/issues/2039 + return null; + }, + dsn: sentryDsn, + integrations: [ + new CaptureConsole({ levels: ["error"] }), + new Dedupe(), + new Offline() + ], + initialScope: { + tags: { + // "translate" browser to 'main' as Lens developer more familiar with the term 'main' + "process": process.type === "browser" ? "main" : "renderer" + } + }, + environment: isProduction ? "production" : "development", + }); + + sentryIsInitialized = true; + + logger.info(`âœ”ī¸ [SENTRY-INIT]: Sentry for ${process.type} is initialized.`); + } catch (error) { + logger.warn(`âš ī¸ [SENTRY-INIT]: Sentry.init() error: ${error?.message ?? error}.`); } } catch (error) { - logInitError(`Error loading Sentry module ${error?.message}`); - - return; + logger.warn(`âš ī¸ [SENTRY-INIT]: Error loading Sentry module ${error?.message ?? error}.`); } - - - if (!Sentry) { - logInitError(`Unsupported process type ${processType}`); - - return; - } - - try { - Sentry.init({ - beforeSend, - dsn: sentryDsn, - integrations, - initialScope: initialScope(processType), - environment - }); - logger.info(`âœ”ī¸ [SENTRY-INIT]: Sentry for ${processType} is initialized.`); - } catch (error) { - logInitError(`Sentry.init() error ${error?.message}`); - - return; - } -}; +} diff --git a/src/common/utils/index.ts b/src/common/utils/index.ts index 5ce6d20f55..1644c07f36 100644 --- a/src/common/utils/index.ts +++ b/src/common/utils/index.ts @@ -51,8 +51,6 @@ export * from "./tar"; export * from "./toggle-set"; export * from "./toJS"; export * from "./type-narrowing"; -export * from "./isValidURL"; -export * from "./isValidSentryDsn"; import * as iter from "./iter"; diff --git a/src/common/utils/isValidSentryDsn.ts b/src/common/utils/isValidSentryDsn.ts deleted file mode 100644 index 9b91ae1cac..0000000000 --- a/src/common/utils/isValidSentryDsn.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2021 OpenLens Authors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -// Regular expression used to parse a Sentry Dsn. -// from https://github.com/getsentry/sentry-javascript/blob/f624f442fd76bf655de6def9fa4d7631735ebba0/packages/utils/src/dsn.ts#L6 -const DSN_REGEX = /^(?:(\w+):)\/\/(?:(\w+)(?::(\w+))?@)([\w.-]+)(?::(\d+))?\/(.+)/; - -/** - * check if string is a valid Sentry dsn - * - * @param {(string | undefined | null)} string - * @return {boolean} - */ -export const isValidSentryDsn = (string: string | undefined | null) => { - - const valid = DSN_REGEX.exec(string); - - return valid; - -}; diff --git a/src/common/utils/isValidURL.ts b/src/common/utils/isValidURL.ts deleted file mode 100644 index cf106f34da..0000000000 --- a/src/common/utils/isValidURL.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2021 OpenLens Authors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - - -/** - * check if string is valid URL - * - * @param {(string | undefined | null)} url - * @return {boolean} - */ -export const isValidURL = (url: string | undefined | null) => { - try { - new URL(url); - - return true; - } catch { - // ignore TypeError and return false - } - - return false; -}; diff --git a/src/common/vars.ts b/src/common/vars.ts index f049d8b656..74dcb0abf3 100644 --- a/src/common/vars.ts +++ b/src/common/vars.ts @@ -24,8 +24,6 @@ import path from "path"; import { SemVer } from "semver"; import packageInfo from "../../package.json"; import { defineGlobal } from "./utils/defineGlobal"; -import { isValidURL } from "./utils/isValidURL"; -import { isValidSentryDsn } from "./utils/isValidSentryDsn"; export const isMac = process.platform === "darwin"; export const isWindows = process.platform === "win32"; @@ -71,8 +69,6 @@ export const slackUrl = "https://join.slack.com/t/k8slens/shared_invite/enQtOTc5 export const supportUrl = "https://docs.k8slens.dev/latest/support/" as string; export const appSemVer = new SemVer(packageInfo.version); -export const docsUrl = `https://docs.k8slens.dev/main/` as string; +export const docsUrl = "https://docs.k8slens.dev/main/" as string; export const sentryDsn = packageInfo.config?.sentryDsn; -export const sentryDsnIsValid = isValidURL(sentryDsn) && isValidSentryDsn(sentryDsn); - diff --git a/src/main/index.ts b/src/main/index.ts index 29b3798d7a..20e1c8d19c 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -61,8 +61,6 @@ import { ExtensionsStore } from "../extensions/extensions-store"; import { FilesystemProvisionerStore } from "./extension-filesystem"; import { SentryInit } from "../common/sentry"; -SentryInit(); - const workingDir = path.join(app.getPath("appData"), appName); const cleanup = disposer(); @@ -141,8 +139,15 @@ app.on("ready", async () => { logger.info("💾 Loading stores"); - ClusterStore.createInstance().provideInitialFromMain(); UserStore.createInstance().startMainReactions(); + + /** + * There is no point setting up sentry before UserStore is initialized as + * `allowErrorReporting` will always be falsy. + */ + await SentryInit(); + + ClusterStore.createInstance().provideInitialFromMain(); HotbarStore.createInstance(); ExtensionsStore.createInstance(); FilesystemProvisionerStore.createInstance(); diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx index 7768a9e0eb..21dbca9c1a 100644 --- a/src/renderer/bootstrap.tsx +++ b/src/renderer/bootstrap.tsx @@ -47,6 +47,7 @@ import { WeblinkStore } from "../common/weblink-store"; import { ExtensionsStore } from "../extensions/extensions-store"; import { FilesystemProvisionerStore } from "../main/extension-filesystem"; import { ThemeStore } from "./theme.store"; +import { SentryInit } from "../common/sentry"; configurePackages(); @@ -85,6 +86,13 @@ export async function bootstrap(App: AppComponent) { ExtensionDiscovery.createInstance().init(); UserStore.createInstance(); + + /** + * There is no point setting up sentry before UserStore is initialized as + * `allowErrorReporting` will always be falsy. + */ + await SentryInit(); + await ClusterStore.createInstance().loadInitialOnRenderer(); HotbarStore.createInstance(); ExtensionsStore.createInstance(); diff --git a/src/renderer/components/+preferences/preferences.tsx b/src/renderer/components/+preferences/preferences.tsx index 3ec4693fe8..285c9b2c75 100644 --- a/src/renderer/components/+preferences/preferences.tsx +++ b/src/renderer/components/+preferences/preferences.tsx @@ -41,7 +41,7 @@ import { FormSwitch, Switcher } from "../switch"; import { KubeconfigSyncs } from "./kubeconfig-syncs"; import { SettingLayout } from "../layout/setting-layout"; import { Checkbox } from "../checkbox"; -import { sentryDsnIsValid } from "../../../common/vars"; +import { sentryIsInitialized } from "../../../common/sentry"; enum Pages { Application = "application", @@ -259,7 +259,7 @@ export class Preferences extends React.Component {

Telemetry

{telemetryExtensions.map(this.renderExtension)} - {sentryDsnIsValid ? ( + {sentryIsInitialized ? (
diff --git a/src/renderer/lens-app.tsx b/src/renderer/lens-app.tsx index cbe0d27f6d..35151dcee2 100644 --- a/src/renderer/lens-app.tsx +++ b/src/renderer/lens-app.tsx @@ -36,9 +36,6 @@ import { registerIpcHandlers } from "./ipc"; import { ipcRenderer } from "electron"; import { IpcRendererNavigationEvents } from "./navigation/events"; import { catalogEntityRegistry } from "./api/catalog-entity-registry"; -import { SentryInit } from "../common/sentry"; - -SentryInit(); @observer export class LensApp extends React.Component { From ad8dc8a7c924e54638ba406502c03ba43de162e6 Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Fri, 9 Jul 2021 19:19:37 +0300 Subject: [PATCH 11/80] New spinner for cluster connect status page (#3324) Signed-off-by: Jari Kolehmainen --- src/renderer/components/cluster-manager/cluster-status.scss | 5 +++++ src/renderer/components/cluster-manager/cluster-status.tsx | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/renderer/components/cluster-manager/cluster-status.scss b/src/renderer/components/cluster-manager/cluster-status.scss index 1d048e7459..86527eb75f 100644 --- a/src/renderer/components/cluster-manager/cluster-status.scss +++ b/src/renderer/components/cluster-manager/cluster-status.scss @@ -35,6 +35,11 @@ white-space: pre-line; } + .Spinner { + --spinner-size: 48px; + --spinner-border: calc(var(--spinner-size) / 10); + } + .Icon { --size: 70px; margin: auto; diff --git a/src/renderer/components/cluster-manager/cluster-status.tsx b/src/renderer/components/cluster-manager/cluster-status.tsx index 456f606570..30065e2dd0 100644 --- a/src/renderer/components/cluster-manager/cluster-status.tsx +++ b/src/renderer/components/cluster-manager/cluster-status.tsx @@ -32,7 +32,7 @@ import type { Cluster } from "../../../main/cluster"; import { cssNames, IClassName } from "../../utils"; import { Button } from "../button"; import { Icon } from "../icon"; -import { CubeSpinner } from "../spinner"; +import { Spinner } from "../spinner"; import type { KubeAuthProxyLog } from "../../../main/kube-auth-proxy"; import { navigate } from "../../navigation"; import { entitySettingsURL } from "../../../common/routes"; @@ -100,7 +100,7 @@ export class ClusterStatus extends React.Component { if (!hasErrors || this.isReconnecting) { return ( <> - +
             

{this.isReconnecting ? "Reconnecting..." : "Connecting..."}

{authOutput.map(({ data, error }, index) => { From b1f3046736ca9d4d1c4999517df6071393dd882b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Jul 2021 17:39:43 -0400 Subject: [PATCH 12/80] Bump xterm-addon-fit from 0.4.0 to 0.5.0 (#3112) Bumps [xterm-addon-fit](https://github.com/xtermjs/xterm.js) from 0.4.0 to 0.5.0. - [Release notes](https://github.com/xtermjs/xterm.js/releases) - [Commits](https://github.com/xtermjs/xterm.js/compare/0.4...0.5) --- updated-dependencies: - dependency-name: xterm-addon-fit 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.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d1daf823ac..8141e43e62 100644 --- a/package.json +++ b/package.json @@ -385,6 +385,6 @@ "webpack-node-externals": "^1.7.2", "what-input": "^5.2.10", "xterm": "^4.12.0", - "xterm-addon-fit": "^0.4.0" + "xterm-addon-fit": "^0.5.0" } } diff --git a/yarn.lock b/yarn.lock index 1602d70c9c..902a56119c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15651,10 +15651,10 @@ xtend@^4.0.0, xtend@^4.0.2, xtend@~4.0.1: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -xterm-addon-fit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/xterm-addon-fit/-/xterm-addon-fit-0.4.0.tgz#06e0c5d0a6aaacfb009ef565efa1c81e93d90193" - integrity sha512-p4BESuV/g2L6pZzFHpeNLLnep9mp/DkF3qrPglMiucSFtD8iJxtMufEoEJbN8LZwB4i+8PFpFvVuFrGOSpW05w== +xterm-addon-fit@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/xterm-addon-fit/-/xterm-addon-fit-0.5.0.tgz#2d51b983b786a97dcd6cde805e700c7f913bc596" + integrity sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ== xterm@^4.12.0: version "4.12.0" From d7db8770794efef2c719b8ba862e7886cdc61d79 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Jul 2021 17:40:08 -0400 Subject: [PATCH 13/80] Bump html-webpack-plugin from 4.3.0 to 4.5.2 (#3116) Bumps [html-webpack-plugin](https://github.com/jantimon/html-webpack-plugin) from 4.3.0 to 4.5.2. - [Release notes](https://github.com/jantimon/html-webpack-plugin/releases) - [Changelog](https://github.com/jantimon/html-webpack-plugin/blob/v4.5.2/CHANGELOG.md) - [Commits](https://github.com/jantimon/html-webpack-plugin/compare/v4.3.0...v4.5.2) --- updated-dependencies: - dependency-name: html-webpack-plugin 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.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 8141e43e62..c570176d77 100644 --- a/package.json +++ b/package.json @@ -336,7 +336,7 @@ "flex.box": "^3.4.4", "fork-ts-checker-webpack-plugin": "^5.0.0", "hoist-non-react-statics": "^3.3.2", - "html-webpack-plugin": "^4.3.0", + "html-webpack-plugin": "^4.5.2", "identity-obj-proxy": "^3.0.0", "include-media": "^1.4.9", "jest": "^26.0.1", diff --git a/yarn.lock b/yarn.lock index 902a56119c..5c09fb1f65 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7274,17 +7274,17 @@ html-tags@^3.1.0: resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg== -html-webpack-plugin@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.3.0.tgz#53bf8f6d696c4637d5b656d3d9863d89ce8174fd" - integrity sha512-C0fzKN8yQoVLTelcJxZfJCE+aAvQiY2VUf3UuKrR4a9k5UMWYOtpDLsaXwATbcVCnI05hUS7L9ULQHWLZhyi3w== +html-webpack-plugin@^4.5.2: + version "4.5.2" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.5.2.tgz#76fc83fa1a0f12dd5f7da0404a54e2699666bc12" + integrity sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A== dependencies: "@types/html-minifier-terser" "^5.0.0" "@types/tapable" "^1.0.5" "@types/webpack" "^4.41.8" html-minifier-terser "^5.0.1" loader-utils "^1.2.3" - lodash "^4.17.15" + lodash "^4.17.20" pretty-error "^2.1.1" tapable "^1.1.3" util.promisify "1.0.0" From b367aed7d239596be8b595529f664bbe912f0318 Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Sat, 10 Jul 2021 00:40:25 +0300 Subject: [PATCH 14/80] Fork-ts-checker-webpack-plugin 5.2.1 (#3046) --- package.json | 2 +- yarn.lock | 135 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 81 insertions(+), 56 deletions(-) diff --git a/package.json b/package.json index c570176d77..9eadc47b53 100644 --- a/package.json +++ b/package.json @@ -334,7 +334,7 @@ "eslint-plugin-unused-imports": "^1.0.1", "file-loader": "^6.2.0", "flex.box": "^3.4.4", - "fork-ts-checker-webpack-plugin": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^5.2.1", "hoist-non-react-statics": "^3.3.2", "html-webpack-plugin": "^4.5.2", "identity-obj-proxy": "^3.0.0", diff --git a/yarn.lock b/yarn.lock index 5c09fb1f65..2b56b94d6c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,7 +7,14 @@ resolved "https://registry.yarnpkg.com/7zip-bin/-/7zip-bin-5.0.3.tgz#bc5b5532ecafd923a61f2fb097e3b108c0106a3f" integrity sha512-GLyWIFBbGvpKPGo55JyRZAo4lVbnBiD52cKlw/0Vt+wnmKvWJkpZvsjVoaIolyBXDeAQKSicRtqFNPem9w0WYA== -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.1", "@babel/code-frame@^7.8.3": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb" + integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== + dependencies: + "@babel/highlight" "^7.14.5" + +"@babel/code-frame@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.1.tgz#d5481c5095daa1c57e16e54c6f9198443afb49ff" integrity sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw== @@ -133,10 +140,10 @@ dependencies: "@babel/types" "^7.10.1" -"@babel/helper-validator-identifier@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz#5770b0c1a826c4f53f5ede5e153163e0318e94b5" - integrity sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw== +"@babel/helper-validator-identifier@^7.10.1", "@babel/helper-validator-identifier@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz#d0f0e277c512e0c938277faa85a3968c9a44c0e8" + integrity sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg== "@babel/helper-validator-identifier@^7.10.4": version "7.10.4" @@ -152,12 +159,12 @@ "@babel/traverse" "^7.10.1" "@babel/types" "^7.10.1" -"@babel/highlight@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.1.tgz#841d098ba613ba1a427a2b383d79e35552c38ae0" - integrity sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg== +"@babel/highlight@^7.10.1", "@babel/highlight@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" + integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== dependencies: - "@babel/helper-validator-identifier" "^7.10.1" + "@babel/helper-validator-identifier" "^7.14.5" chalk "^2.0.0" js-tokens "^4.0.0" @@ -1585,7 +1592,7 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ== -"@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6": +"@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6": version "7.0.7" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== @@ -2512,30 +2519,30 @@ ajv-errors@^1.0.0: resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== -ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" - integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== - -ajv-keywords@^3.5.2: +ajv-keywords@^3.1.0, ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.12.2, ajv@^6.5.5: - version "6.12.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" - integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ== +ajv-keywords@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" + integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== + +ajv@^6.1.0, ajv@^6.12.4, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^6.12.4, ajv@^6.12.5: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== +ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.12.2, ajv@^6.5.5: + version "6.12.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" + integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ== dependencies: fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" @@ -3065,9 +3072,9 @@ babel-runtime@^6.26.0: regenerator-runtime "^0.11.0" balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base64-js@^1.0.2: version "1.3.1" @@ -6470,20 +6477,21 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= -fork-ts-checker-webpack-plugin@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.0.0.tgz#43a8efda935aba382ca88ae169ab11b70041c06a" - integrity sha512-XdMGiyz12rl8HFEj1D9NsC0yxevLZqWncMbuhelV1a1h7ciX7ftauTHIBzO0gKGjqoqZG0NqnrnN7xavIHvzDQ== +fork-ts-checker-webpack-plugin@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz#79326d869797906fa8b24e2abcf9421fc805450d" + integrity sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw== dependencies: "@babel/code-frame" "^7.8.3" - chalk "^2.4.1" + "@types/json-schema" "^7.0.5" + chalk "^4.1.0" cosmiconfig "^6.0.0" deepmerge "^4.2.2" fs-extra "^9.0.0" memfs "^3.1.2" minimatch "^3.0.4" - schema-utils "1.0.0" - semver "^5.6.0" + schema-utils "2.7.0" + semver "^7.3.2" tapable "^1.0.0" form-data@^2.5.0: @@ -6593,10 +6601,10 @@ fs-minipass@^2.0.0: dependencies: minipass "^3.0.0" -fs-monkey@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.1.tgz#4a82f36944365e619f4454d9fff106553067b781" - integrity sha512-fcSa+wyTqZa46iWweI7/ZiUfegOZl0SG8+dltIwFXo7+zYU9J9kpS3NB6pZcSlJdhvIwp81Adx2XhZorncxiaA== +fs-monkey@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" + integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== fs-vacuum@^1.2.10, fs-vacuum@~1.2.10: version "1.2.10" @@ -7550,7 +7558,7 @@ import-fresh@^2.0.0: caller-path "^2.0.0" resolve-from "^3.0.0" -import-fresh@^3.0.0, import-fresh@^3.1.0: +import-fresh@^3.0.0: version "3.2.1" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== @@ -7558,6 +7566,14 @@ import-fresh@^3.0.0, import-fresh@^3.1.0: parent-module "^1.0.0" resolve-from "^4.0.0" +import-fresh@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-fresh@^3.2.1: version "3.2.2" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.2.tgz#fc129c160c5d68235507f4331a6baad186bdbc3e" @@ -9829,11 +9845,11 @@ mem@^4.0.0: p-is-promise "^2.0.0" memfs@^3.1.2: - version "3.2.0" - resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.2.0.tgz#f9438e622b5acd1daa8a4ae160c496fdd1325b26" - integrity sha512-f/xxz2TpdKv6uDn6GtHee8ivFyxwxmPuXatBb1FBwxYNuVpbM3k/Y1Z+vC0mH/dIXXrukYfe3qe5J32Dfjg93A== + version "3.2.2" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.2.2.tgz#5de461389d596e3f23d48bb7c2afb6161f4df40e" + integrity sha512-RE0CwmIM3CEvpcdK3rZ19BC4E6hv9kADkMN5rPduRak58cNArWLi/9jFLsa4rhsjfVxMP3v0jO7FHXq7SvFY5Q== dependencies: - fs-monkey "1.0.1" + fs-monkey "1.0.3" "memoize-one@>=3.1.1 <6", memoize-one@^5.0.0, memoize-one@^5.1.1: version "5.1.1" @@ -11373,13 +11389,13 @@ parse-json@^4.0.0: json-parse-better-errors "^1.0.1" parse-json@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.0.0.tgz#73e5114c986d143efa3712d4ea24db9a4266f60f" - integrity sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw== + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== dependencies: "@babel/code-frame" "^7.0.0" error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" + json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" parse-passwd@^1.0.0: @@ -13038,7 +13054,16 @@ scheduler@^0.20.1: loose-envify "^1.1.0" object-assign "^4.1.1" -schema-utils@1.0.0, schema-utils@^1.0.0: +schema-utils@2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" + integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A== + dependencies: + "@types/json-schema" "^7.0.4" + ajv "^6.12.2" + ajv-keywords "^3.4.1" + +schema-utils@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== @@ -14937,9 +14962,9 @@ update-notifier@^5.1.0: xdg-basedir "^4.0.0" uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" @@ -15697,9 +15722,9 @@ yallist@^4.0.0: integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== yaml@^1.7.2: - version "1.10.0" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e" - integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg== + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== yargs-parser@18.x, yargs-parser@^18.1.1: version "18.1.3" From 3e18b619be1ed1f569bd0653ff7b6f9bac96b21d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Jul 2021 18:51:01 -0400 Subject: [PATCH 15/80] Bump jest-mock-extended from 1.0.10 to 1.0.16 (#3341) Bumps [jest-mock-extended](https://github.com/marchaos/jest-mock-extended) from 1.0.10 to 1.0.16. - [Release notes](https://github.com/marchaos/jest-mock-extended/releases) - [Commits](https://github.com/marchaos/jest-mock-extended/commits) --- updated-dependencies: - dependency-name: jest-mock-extended 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.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 9eadc47b53..03577c3534 100644 --- a/package.json +++ b/package.json @@ -342,7 +342,7 @@ "jest": "^26.0.1", "jest-canvas-mock": "^2.3.0", "jest-fetch-mock": "^3.0.3", - "jest-mock-extended": "^1.0.10", + "jest-mock-extended": "^1.0.16", "make-plural": "^6.2.2", "mini-css-extract-plugin": "^1.6.0", "node-loader": "^1.0.3", diff --git a/yarn.lock b/yarn.lock index 2b56b94d6c..d34cce3a5f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8580,10 +8580,10 @@ jest-message-util@^26.0.1: slash "^3.0.0" stack-utils "^2.0.2" -jest-mock-extended@^1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/jest-mock-extended/-/jest-mock-extended-1.0.10.tgz#a4b1f5b0bb1121acf7c58cd5423d04c473532702" - integrity sha512-R2wKiOgEUPoHZ2kLsAQeQP2IfVEgo3oQqWLSXKdMXK06t3UHkQirA2Xnsdqg/pX6KPWTsdnrzE2ig6nqNjdgVw== +jest-mock-extended@^1.0.16: + version "1.0.16" + resolved "https://registry.yarnpkg.com/jest-mock-extended/-/jest-mock-extended-1.0.16.tgz#f6a96c795acc2f5ae9ee74d7b048c3b4399c6fc8" + integrity sha512-W1lI7cO0ZYmTQUBZH11nSDKyU36SxAyzBjZNxBWcpFnCKHGNWIPdFA8RJMhmobLQ8WLI4y9AMIbYzMN9q/GiRQ== dependencies: ts-essentials "^4.0.0" From 52ab6994263c24d4a4542715ee2f7967791fc09d Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 12 Jul 2021 01:45:15 -0400 Subject: [PATCH 16/80] Remove and as both are unused (#3336) Signed-off-by: Sebastian Malton --- .../components/app-init/app-init.scss | 29 ----- src/renderer/components/app-init/app-init.tsx | 73 ----------- .../components/spinner/cube-spinner.scss | 114 ------------------ .../components/spinner/cube-spinner.tsx | 51 -------- src/renderer/components/spinner/index.ts | 1 - 5 files changed, 268 deletions(-) delete mode 100644 src/renderer/components/app-init/app-init.scss delete mode 100644 src/renderer/components/app-init/app-init.tsx delete mode 100644 src/renderer/components/spinner/cube-spinner.scss delete mode 100644 src/renderer/components/spinner/cube-spinner.tsx diff --git a/src/renderer/components/app-init/app-init.scss b/src/renderer/components/app-init/app-init.scss deleted file mode 100644 index 7583111eba..0000000000 --- a/src/renderer/components/app-init/app-init.scss +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) 2021 OpenLens Authors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -.AppInit { - height: 100%; - - .waiting-services { - font-size: small; - opacity: .75; - } -} \ No newline at end of file diff --git a/src/renderer/components/app-init/app-init.tsx b/src/renderer/components/app-init/app-init.tsx deleted file mode 100644 index 7d1460bb1e..0000000000 --- a/src/renderer/components/app-init/app-init.tsx +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Copyright (c) 2021 OpenLens Authors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -import "./app-init.scss"; - -import React from "react"; -import { render } from "react-dom"; -import { CubeSpinner } from "../spinner"; -import { apiBase } from "../../api"; - -interface Props { - serviceWaitingList?: string[]; -} - -export class AppInit extends React.Component { - static async start(rootElem: HTMLElement) { - render(, rootElem); // show loading indicator asap - await AppInit.readyStateCheck(rootElem); // wait while all good to run - } - - protected static async readyStateCheck(rootElem: HTMLElement) { - const waitingList = await apiBase.get("/ready"); - - if (waitingList.length > 0) { - // update waiting state - render(, rootElem); - - // check again in 1-5 seconds - return new Promise(resolve => { - const timeoutDelay = 1000 + Math.random() * 4000; - - setTimeout(() => resolve(AppInit.readyStateCheck(rootElem)), timeoutDelay); - }); - } - } - - render() { - const { serviceWaitingList = [] } = this.props; - const serviceNames = serviceWaitingList.join(", "); - - return ( -
-
-
Lens - Loading..
- {serviceWaitingList.length > 0 && ( -

- Waiting services to be running: {serviceNames} -

- )} - -
-
- ); - } -} diff --git a/src/renderer/components/spinner/cube-spinner.scss b/src/renderer/components/spinner/cube-spinner.scss deleted file mode 100644 index 18dab776d7..0000000000 --- a/src/renderer/components/spinner/cube-spinner.scss +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Copyright (c) 2021 OpenLens Authors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -// http://tobiasahlin.com/spinkit/ - -.CubeSpinner { - --size: 70px; - - &.center { - position: absolute; - left: 50%; - top: 50%; - transform: translate(-50%, -50%); - } - - .sk-cube-grid { - $size: 70px; - width: $size; - height: $size; - transform: rotate(45deg); - margin: $margin * 4 auto; - border-bottom-left-radius: $radius; - border-top-right-radius: $radius; - overflow: hidden; - } - - .sk-cube-grid .sk-cube { - width: 33%; - height: 33%; - float: left; - -webkit-animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out; - animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out; - } - - .sk-cube-grid .sk-cube1 { - -webkit-animation-delay: 0.2s; - animation-delay: 0.2s; - } - - .sk-cube-grid .sk-cube2 { - -webkit-animation-delay: 0.3s; - animation-delay: 0.3s; - } - - .sk-cube-grid .sk-cube3 { - -webkit-animation-delay: 0.4s; - animation-delay: 0.4s; - } - - .sk-cube-grid .sk-cube4 { - -webkit-animation-delay: 0.1s; - animation-delay: 0.1s; - } - - .sk-cube-grid .sk-cube5 { - -webkit-animation-delay: 0.2s; - animation-delay: 0.2s; - } - - .sk-cube-grid .sk-cube6 { - -webkit-animation-delay: 0.3s; - animation-delay: 0.3s; - } - - .sk-cube-grid .sk-cube7 { - -webkit-animation-delay: 0s; - animation-delay: 0s; - } - - .sk-cube-grid .sk-cube8 { - -webkit-animation-delay: 0.1s; - animation-delay: 0.1s; - } - - .sk-cube-grid .sk-cube9 { - -webkit-animation-delay: 0.2s; - animation-delay: 0.2s; - } - - @keyframes sk-cubeGridScaleDelay { - 0%, 35% { - background-color: #36393e; - } - 0%, 70%, 100% { - -webkit-transform: scale3D(1, 1, 1); - transform: scale3D(1, 1, 1); - } - 35% { - -webkit-transform: scale3D(0, 0, 1); - transform: scale3D(0, 0, 1); - } - 100% { - background-color: #3389ca; - } - } -} \ No newline at end of file diff --git a/src/renderer/components/spinner/cube-spinner.tsx b/src/renderer/components/spinner/cube-spinner.tsx deleted file mode 100644 index 80b9fea57f..0000000000 --- a/src/renderer/components/spinner/cube-spinner.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) 2021 OpenLens Authors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -import "./cube-spinner.scss"; -import React from "react"; -import { cssNames } from "../../utils"; - -export interface CubeSpinnerProps { - className?: string; - center?: boolean; -} - -export class CubeSpinner extends React.Component { - render() { - const { className, center } = this.props; - - return ( -
-
-
-
-
-
-
-
-
-
-
-
-
- ); - } -} diff --git a/src/renderer/components/spinner/index.ts b/src/renderer/components/spinner/index.ts index d060b78aa0..53ed99304a 100644 --- a/src/renderer/components/spinner/index.ts +++ b/src/renderer/components/spinner/index.ts @@ -20,4 +20,3 @@ */ export * from "./spinner"; -export * from "./cube-spinner"; From 538c6c2013f32c0a8a939e1dfd8f5960dd682d42 Mon Sep 17 00:00:00 2001 From: Violetta Shakirova <38247153+vshakirova@users.noreply.github.com> Date: Mon, 12 Jul 2021 12:36:26 +0400 Subject: [PATCH 17/80] Selecting one namespace at a time (#2919) Signed-off-by: vshakirova --- .../+namespaces/namespace-select-filter.tsx | 62 ++++++++++++++----- .../components/+namespaces/namespace.store.ts | 6 ++ 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/renderer/components/+namespaces/namespace-select-filter.tsx b/src/renderer/components/+namespaces/namespace-select-filter.tsx index 8ae2e97958..514749ed44 100644 --- a/src/renderer/components/+namespaces/namespace-select-filter.tsx +++ b/src/renderer/components/+namespaces/namespace-select-filter.tsx @@ -30,6 +30,8 @@ import { NamespaceSelect } from "./namespace-select"; import { namespaceStore } from "./namespace.store"; import type { SelectOption, SelectProps } from "../select"; +import { isLinux, isMac, isWindows } from "../../../common/vars"; +import { observable } from "mobx"; const Placeholder = observer((props: PlaceholderProps) => { const getPlaceholder = (): React.ReactNode => { @@ -55,13 +57,16 @@ const Placeholder = observer((props: PlaceholderProps) => { @observer export class NamespaceSelectFilter extends React.Component { + static isMultiSelection = observable.box(false); + static isMenuOpen = observable.box(false); + formatOptionLabel({ value: namespace, label }: SelectOption) { if (namespace) { const isSelected = namespaceStore.hasContext(namespace); return (
- + {namespace} {isSelected && }
@@ -72,26 +77,55 @@ export class NamespaceSelectFilter extends React.Component { } onChange([{ value: namespace }]: SelectOption[]) { - if (namespace) { + if (NamespaceSelectFilter.isMultiSelection.get() && namespace) { namespaceStore.toggleContext(namespace); + } else if (!NamespaceSelectFilter.isMultiSelection.get() && namespace) { + namespaceStore.toggleSingle(namespace); } else { - namespaceStore.toggleAll(false); // "All namespaces" clicked + namespaceStore.toggleAll(true); // "All namespaces" clicked } } + onKeyDown = (e: React.KeyboardEvent) => { + if (isMac && e.metaKey || (isWindows || isLinux) && e.ctrlKey) { + NamespaceSelectFilter.isMultiSelection.set(true); + } + }; + + onKeyUp = (e: React.KeyboardEvent) => { + if (isMac && e.key === "Meta" || (isWindows || isLinux) && e.key === "Control") { + NamespaceSelectFilter.isMultiSelection.set(false); + } + }; + + onClick = () => { + if (!NamespaceSelectFilter.isMultiSelection.get()) { + NamespaceSelectFilter.isMenuOpen.set(!NamespaceSelectFilter.isMenuOpen.get()); + } + }; + + reset = () => { + NamespaceSelectFilter.isMultiSelection.set(false); + NamespaceSelectFilter.isMenuOpen.set(false); + }; + render() { return ( - +
+ +
); } } diff --git a/src/renderer/components/+namespaces/namespace.store.ts b/src/renderer/components/+namespaces/namespace.store.ts index c292f0f9fa..e8db0948ca 100644 --- a/src/renderer/components/+namespaces/namespace.store.ts +++ b/src/renderer/components/+namespaces/namespace.store.ts @@ -161,6 +161,12 @@ export class NamespaceStore extends KubeObjectStore { } } + @action + toggleSingle(namespace: string){ + this.clearSelected(); + this.selectNamespaces(namespace); + } + @action toggleAll(showAll?: boolean) { if (typeof showAll === "boolean") { From ff704b5d3dcf8c7b41a35e9bedc86daa27b3bea5 Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Mon, 12 Jul 2021 16:18:08 +0300 Subject: [PATCH 18/80] sync activeEntity to cluster renderer (#3323) Signed-off-by: Jari Kolehmainen --- src/renderer/components/app.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index 1e1c14fd4c..52c9d5d0c3 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ import React from "react"; -import { observable, makeObservable } from "mobx"; +import { observable, makeObservable, reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { Redirect, Route, Router, Switch } from "react-router"; import { history } from "../navigation"; @@ -69,6 +69,7 @@ import { Nodes } from "./+nodes"; import { Workloads } from "./+workloads"; import { Config } from "./+config"; import { Storage } from "./+storage"; +import { catalogEntityRegistry } from "../api/catalog-entity-registry"; @observer export class App extends React.Component { @@ -78,6 +79,7 @@ export class App extends React.Component { } static async init() { + catalogEntityRegistry.init(); const frameId = webFrame.routingId; const clusterId = getHostedClusterId(); @@ -86,6 +88,15 @@ export class App extends React.Component { await requestMain(clusterSetFrameIdHandler, clusterId); await getHostedCluster().whenReady; // cluster.activate() is done at this point + + const activeEntityDisposer = reaction(() => catalogEntityRegistry.getById(clusterId), (entity) => { + if (!entity) { + return; + } + catalogEntityRegistry.activeEntity = entity; + activeEntityDisposer(); + }, {fireImmediately: true}); + ExtensionLoader.getInstance().loadOnClusterRenderer(); setTimeout(() => { appEventBus.emit({ From f86360d641d86a7ebd347b46932f64f6c1fc3978 Mon Sep 17 00:00:00 2001 From: chh <1474479+chenhunghan@users.noreply.github.com> Date: Mon, 12 Jul 2021 16:42:51 +0300 Subject: [PATCH 19/80] Fix Sentry integration bugs (#3325) --- src/common/sentry.ts | 89 ++++++++----------- src/common/vars.ts | 2 +- src/main/index.ts | 10 +-- src/renderer/bootstrap.tsx | 6 +- .../components/+preferences/preferences.tsx | 4 +- 5 files changed, 45 insertions(+), 66 deletions(-) diff --git a/src/common/sentry.ts b/src/common/sentry.ts index 36435b86c9..da0e749994 100644 --- a/src/common/sentry.ts +++ b/src/common/sentry.ts @@ -20,73 +20,58 @@ */ import { CaptureConsole, Dedupe, Offline } from "@sentry/integrations"; +import * as Sentry from "@sentry/electron"; import { sentryDsn, isProduction } from "./vars"; import { UserStore } from "./user-store"; import logger from "../main/logger"; -export let sentryIsInitialized = false; - /** - * This function bypasses webpack issues. - * - * See: https://docs.sentry.io/platforms/javascript/guides/electron/#webpack-configuration + * "Translate" 'browser' to 'main' as Lens developer more familiar with the term 'main' */ -async function requireSentry() { - switch (process.type) { - case "browser": - return import("@sentry/electron/dist/main"); - case "renderer": - return import("@sentry/electron/dist/renderer"); - default: - throw new Error(`Unsupported process type ${process.type}`); +function mapProcessName(processType: string) { + if (processType === "browser") { + return "main"; } + + return processType; } /** * Initialize Sentry for the current process so to send errors for debugging. */ -export async function SentryInit(): Promise { - try { - const Sentry = await requireSentry(); +export function SentryInit() { + const processName = mapProcessName(process.type); - try { - Sentry.init({ - beforeSend: event => { - if (UserStore.getInstance().allowErrorReporting) { - return event; - } + Sentry.init({ + beforeSend: (event) => { + // default to false, in case instance of UserStore is not created (yet) + const allowErrorReporting = UserStore.getInstance(false)?.allowErrorReporting ?? false; - logger.info(`🔒 [SENTRY-BEFORE-SEND-HOOK]: allowErrorReporting: false. Sentry event is caught but not sent to server.`); - logger.info("🔒 [SENTRY-BEFORE-SEND-HOOK]: === START OF SENTRY EVENT ==="); - logger.info(event); - logger.info("🔒 [SENTRY-BEFORE-SEND-HOOK]: === END OF SENTRY EVENT ==="); + if (allowErrorReporting) { + return event; + } - // if return null, the event won't be sent - // ref https://github.com/getsentry/sentry-javascript/issues/2039 - return null; - }, - dsn: sentryDsn, - integrations: [ - new CaptureConsole({ levels: ["error"] }), - new Dedupe(), - new Offline() - ], - initialScope: { - tags: { - // "translate" browser to 'main' as Lens developer more familiar with the term 'main' - "process": process.type === "browser" ? "main" : "renderer" - } - }, - environment: isProduction ? "production" : "development", - }); + logger.info(`🔒 [SENTRY-BEFORE-SEND-HOOK]: allowErrorReporting: ${allowErrorReporting}. Sentry event is caught but not sent to server.`); + logger.info("🔒 [SENTRY-BEFORE-SEND-HOOK]: === START OF SENTRY EVENT ==="); + logger.info(event); + logger.info("🔒 [SENTRY-BEFORE-SEND-HOOK]: === END OF SENTRY EVENT ==="); - sentryIsInitialized = true; + // if return null, the event won't be sent + // ref https://github.com/getsentry/sentry-javascript/issues/2039 + return null; + }, + dsn: sentryDsn, + integrations: [ + new CaptureConsole({ levels: ["error"] }), + new Dedupe(), + new Offline() + ], + initialScope: { + tags: { - logger.info(`âœ”ī¸ [SENTRY-INIT]: Sentry for ${process.type} is initialized.`); - } catch (error) { - logger.warn(`âš ī¸ [SENTRY-INIT]: Sentry.init() error: ${error?.message ?? error}.`); - } - } catch (error) { - logger.warn(`âš ī¸ [SENTRY-INIT]: Error loading Sentry module ${error?.message ?? error}.`); - } + "process": processName + } + }, + environment: isProduction ? "production" : "development", + }); } diff --git a/src/common/vars.ts b/src/common/vars.ts index 74dcb0abf3..0dea82cab6 100644 --- a/src/common/vars.ts +++ b/src/common/vars.ts @@ -71,4 +71,4 @@ export const supportUrl = "https://docs.k8slens.dev/latest/support/" as string; export const appSemVer = new SemVer(packageInfo.version); export const docsUrl = "https://docs.k8slens.dev/main/" as string; -export const sentryDsn = packageInfo.config?.sentryDsn; +export const sentryDsn = packageInfo.config?.sentryDsn ?? ""; diff --git a/src/main/index.ts b/src/main/index.ts index 20e1c8d19c..91a9b7c68a 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -61,6 +61,10 @@ import { ExtensionsStore } from "../extensions/extensions-store"; import { FilesystemProvisionerStore } from "./extension-filesystem"; import { SentryInit } from "../common/sentry"; +// This has to be called before start using winton-based logger +// For example, before any logger.log +SentryInit(); + const workingDir = path.join(app.getPath("appData"), appName); const cleanup = disposer(); @@ -141,12 +145,6 @@ app.on("ready", async () => { UserStore.createInstance().startMainReactions(); - /** - * There is no point setting up sentry before UserStore is initialized as - * `allowErrorReporting` will always be falsy. - */ - await SentryInit(); - ClusterStore.createInstance().provideInitialFromMain(); HotbarStore.createInstance(); ExtensionsStore.createInstance(); diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx index 21dbca9c1a..cde700e2b5 100644 --- a/src/renderer/bootstrap.tsx +++ b/src/renderer/bootstrap.tsx @@ -87,11 +87,7 @@ export async function bootstrap(App: AppComponent) { UserStore.createInstance(); - /** - * There is no point setting up sentry before UserStore is initialized as - * `allowErrorReporting` will always be falsy. - */ - await SentryInit(); + SentryInit(); await ClusterStore.createInstance().loadInitialOnRenderer(); HotbarStore.createInstance(); diff --git a/src/renderer/components/+preferences/preferences.tsx b/src/renderer/components/+preferences/preferences.tsx index 285c9b2c75..6e9ae5f210 100644 --- a/src/renderer/components/+preferences/preferences.tsx +++ b/src/renderer/components/+preferences/preferences.tsx @@ -41,7 +41,7 @@ import { FormSwitch, Switcher } from "../switch"; import { KubeconfigSyncs } from "./kubeconfig-syncs"; import { SettingLayout } from "../layout/setting-layout"; import { Checkbox } from "../checkbox"; -import { sentryIsInitialized } from "../../../common/sentry"; +import { sentryDsn } from "../../../common/vars"; enum Pages { Application = "application", @@ -259,7 +259,7 @@ export class Preferences extends React.Component {

Telemetry

{telemetryExtensions.map(this.renderExtension)} - {sentryIsInitialized ? ( + {sentryDsn ? (
From 50ec37f15819a66bb3677079ffd7d3f720cb5f10 Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Mon, 12 Jul 2021 17:07:54 +0300 Subject: [PATCH 20/80] Set res.statusCode before flushing headers (#3353) Signed-off-by: Jari Kolehmainen --- src/main/proxy/lens-proxy.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/proxy/lens-proxy.ts b/src/main/proxy/lens-proxy.ts index 66a00284aa..480a4b047a 100644 --- a/src/main/proxy/lens-proxy.ts +++ b/src/main/proxy/lens-proxy.ts @@ -168,7 +168,10 @@ export class LensProxy extends Singleton { if (!res.headersSent && req.url) { const url = new URL(req.url, "http://localhost"); - if (url.searchParams.has("watch")) res.flushHeaders(); + if (url.searchParams.has("watch")) { + res.statusCode = proxyRes.statusCode; + res.flushHeaders(); + } } }); From 26fb2e796e24fa9d67daeb361eee4bed12d63473 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 12 Jul 2021 10:13:11 -0400 Subject: [PATCH 21/80] Fix not being able to configure non-Lens prometheus settings (#3355) Signed-off-by: Sebastian Malton --- src/main/prometheus/helm.ts | 2 +- src/main/prometheus/lens.ts | 2 +- src/main/prometheus/operator.ts | 2 +- src/main/prometheus/stacklight.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/prometheus/helm.ts b/src/main/prometheus/helm.ts index f583578ddb..4f98107946 100644 --- a/src/main/prometheus/helm.ts +++ b/src/main/prometheus/helm.ts @@ -27,7 +27,7 @@ export class PrometheusHelm extends PrometheusLens { readonly id: string = "helm"; readonly name: string = "Helm"; readonly rateAccuracy: string = "5m"; - readonly isConfigurable: boolean = false; + readonly isConfigurable: boolean = true; public async getPrometheusService(client: CoreV1Api): Promise { return this.getFirstNamespacedServer(client, "app=prometheus,component=server,heritage=Helm"); diff --git a/src/main/prometheus/lens.ts b/src/main/prometheus/lens.ts index 63341fe30e..c00bc31069 100644 --- a/src/main/prometheus/lens.ts +++ b/src/main/prometheus/lens.ts @@ -28,7 +28,7 @@ export class PrometheusLens extends PrometheusProvider { readonly id: string = "lens"; readonly name: string = "Lens"; readonly rateAccuracy: string = "1m"; - readonly isConfigurable: boolean = true; + readonly isConfigurable: boolean = false; public async getPrometheusService(client: CoreV1Api): Promise { try { diff --git a/src/main/prometheus/operator.ts b/src/main/prometheus/operator.ts index 58d41210b5..f037ef8a53 100644 --- a/src/main/prometheus/operator.ts +++ b/src/main/prometheus/operator.ts @@ -27,7 +27,7 @@ export class PrometheusOperator extends PrometheusProvider { readonly rateAccuracy: string = "1m"; readonly id: string = "operator"; readonly name: string = "Prometheus Operator"; - readonly isConfigurable: boolean = false; + readonly isConfigurable: boolean = true; public async getPrometheusService(client: CoreV1Api): Promise { return this.getFirstNamespacedServer(client, "operated-prometheus=true", "self-monitor=true"); diff --git a/src/main/prometheus/stacklight.ts b/src/main/prometheus/stacklight.ts index 7960e666a8..8148f3bff7 100644 --- a/src/main/prometheus/stacklight.ts +++ b/src/main/prometheus/stacklight.ts @@ -28,7 +28,7 @@ export class PrometheusStacklight extends PrometheusProvider { readonly id: string = "stacklight"; readonly name: string = "Stacklight"; readonly rateAccuracy: string = "1m"; - readonly isConfigurable: boolean = false; + readonly isConfigurable: boolean = true; public async getPrometheusService(client: CoreV1Api): Promise { try { From 621f5ba0b348bdbb2ab478eccfd39a8195498196 Mon Sep 17 00:00:00 2001 From: Violetta Shakirova <38247153+vshakirova@users.noreply.github.com> Date: Mon, 12 Jul 2021 19:21:46 +0400 Subject: [PATCH 22/80] Make node shell image configurable (#3249) Signed-off-by: vshakirova --- src/common/cluster-store.ts | 4 + src/main/cluster.ts | 9 ++ src/main/shell-session/node-shell-session.ts | 5 +- .../cluster-settings/cluster-settings.tsx | 14 +++ .../components/cluster-node-shell-setting.tsx | 112 ++++++++++++++++++ .../cluster-settings/components/index.ts | 1 + .../initializers/entity-settings-registry.ts | 9 ++ 7 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 src/renderer/components/cluster-settings/components/cluster-node-shell-setting.tsx diff --git a/src/common/cluster-store.ts b/src/common/cluster-store.ts index fa5219ceb6..b6e198a213 100644 --- a/src/common/cluster-store.ts +++ b/src/common/cluster-store.ts @@ -101,6 +101,8 @@ export interface ClusterPreferences extends ClusterPrometheusPreferences { icon?: string; httpsProxy?: string; hiddenMetrics?: string[]; + nodeShellImage?: string; + imagePullSecret?: string; } export interface ClusterPrometheusPreferences { @@ -117,6 +119,8 @@ export interface ClusterPrometheusPreferences { const initialStates = "cluster:states"; +export const initialNodeShellImage = "docker.io/alpine:3.13"; + export class ClusterStore extends BaseStore { private static StateChannel = "cluster:state"; diff --git a/src/main/cluster.ts b/src/main/cluster.ts index 1266a9c00a..bf893f8484 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -34,6 +34,7 @@ import { VersionDetector } from "./cluster-detectors/version-detector"; import { detectorRegistry } from "./cluster-detectors/detector-registry"; import plimit from "p-limit"; import { toJS } from "../common/utils"; +import { initialNodeShellImage } from "../common/cluster-store"; export enum ClusterStatus { AccessGranted = 2, @@ -745,4 +746,12 @@ export class Cluster implements ClusterModel, ClusterState { isMetricHidden(resource: ClusterMetricsResourceType): boolean { return Boolean(this.preferences.hiddenMetrics?.includes(resource)); } + + get nodeShellImage(): string { + return this.preferences.nodeShellImage || initialNodeShellImage; + } + + get imagePullSecret(): string { + return this.preferences.imagePullSecret || ""; + } } diff --git a/src/main/shell-session/node-shell-session.ts b/src/main/shell-session/node-shell-session.ts index a3cc918371..7542baecd6 100644 --- a/src/main/shell-session/node-shell-session.ts +++ b/src/main/shell-session/node-shell-session.ts @@ -77,13 +77,16 @@ export class NodeShellSession extends ShellSession { }], containers: [{ name: "shell", - image: "docker.io/alpine:3.13", + image: this.cluster.nodeShellImage, securityContext: { privileged: true, }, command: ["nsenter"], args: ["-t", "1", "-m", "-u", "-i", "-n", "sleep", "14000"] }], + imagePullSecrets: [{ + name: this.cluster.imagePullSecret, + }] } }); } diff --git a/src/renderer/components/cluster-settings/cluster-settings.tsx b/src/renderer/components/cluster-settings/cluster-settings.tsx index 2f11883fa0..21081bc5ce 100644 --- a/src/renderer/components/cluster-settings/cluster-settings.tsx +++ b/src/renderer/components/cluster-settings/cluster-settings.tsx @@ -118,3 +118,17 @@ export function MetricsSettings({ entity }: EntitySettingViewProps) {
); } + +export function NodeShellSettings({entity}: EntitySettingViewProps) { + const cluster = getClusterForEntity(entity); + + if(!cluster) { + return null; + } + + return ( +
+ +
+ ); +} diff --git a/src/renderer/components/cluster-settings/components/cluster-node-shell-setting.tsx b/src/renderer/components/cluster-settings/components/cluster-node-shell-setting.tsx new file mode 100644 index 0000000000..a5b4300fe3 --- /dev/null +++ b/src/renderer/components/cluster-settings/components/cluster-node-shell-setting.tsx @@ -0,0 +1,112 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import type { Cluster } from "../../../../main/cluster"; +import { autorun, makeObservable, observable } from "mobx"; +import { SubTitle } from "../../layout/sub-title"; +import React from "react"; +import { Input } from "../../input/input"; +import { disposeOnUnmount, observer } from "mobx-react"; +import { Icon } from "../../icon/icon"; +import { initialNodeShellImage } from "../../../../common/cluster-store"; + +interface Props { + cluster: Cluster; +} + +@observer +export class ClusterNodeShellSetting extends React.Component { + @observable nodeShellImage = ""; + @observable imagePullSecret = ""; + + constructor(props: Props) { + super(props); + makeObservable(this); + } + + componentDidMount() { + disposeOnUnmount(this, + autorun(() => { + this.nodeShellImage = this.props.cluster.nodeShellImage; + this.imagePullSecret = this.props.cluster.imagePullSecret; + }) + ); + } + + onImageChange = (value: string) => { + this.nodeShellImage = value; + }; + + onSecretChange = (value: string) => { + this.imagePullSecret = value; + }; + + saveImage = () => { + this.props.cluster.preferences.nodeShellImage = this.nodeShellImage; + }; + + saveSecret = () => { + this.props.cluster.preferences.imagePullSecret = this.imagePullSecret; + }; + + resetImage = () => { + this.nodeShellImage = initialNodeShellImage; //revert to default + }; + + clearSecret = () => { + this.imagePullSecret = ""; + }; + + render() { + + return ( + <> +
+ + } + /> + + Node shell image. Used for creating node shell pod. + +
+
+ + } + /> + + Name of a pre-existing secret (optional). Used for pulling image from a private registry. + +
+ + ); + } +} diff --git a/src/renderer/components/cluster-settings/components/index.ts b/src/renderer/components/cluster-settings/components/index.ts index e82425c9c7..beb80269b7 100644 --- a/src/renderer/components/cluster-settings/components/index.ts +++ b/src/renderer/components/cluster-settings/components/index.ts @@ -28,3 +28,4 @@ export * from "./cluster-prometheus-setting"; export * from "./cluster-proxy-setting"; export * from "./cluster-show-metrics"; export * from "./cluster-icon-settings"; +export * from "./cluster-node-shell-setting"; diff --git a/src/renderer/initializers/entity-settings-registry.ts b/src/renderer/initializers/entity-settings-registry.ts index 10723c8ebf..31c8c81c21 100644 --- a/src/renderer/initializers/entity-settings-registry.ts +++ b/src/renderer/initializers/entity-settings-registry.ts @@ -70,6 +70,15 @@ export function initEntitySettingsRegistry() { components: { View: clusterSettings.MetricsSettings, } + }, + { + apiVersions: ["entity.k8slens.dev/v1alpha1"], + kind: "KubernetesCluster", + title: "Node Shell", + group: "Settings", + components: { + View: clusterSettings.NodeShellSettings, + } } ]); } From 9b2031159dd529595002ad78953a077f633fc632 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 12 Jul 2021 12:05:05 -0400 Subject: [PATCH 23/80] Ignore extensions' clusters when adding to kubeConfigSync (#3313) --- src/common/__tests__/user-store.test.ts | 39 +++++-- src/common/utils/__tests__/paths.test.ts | 130 ++++++++++++++++++++++ src/common/utils/paths.ts | 32 ++++++ src/migrations/user-store/5.0.3-beta.1.ts | 13 ++- 4 files changed, 201 insertions(+), 13 deletions(-) create mode 100644 src/common/utils/__tests__/paths.test.ts diff --git a/src/common/__tests__/user-store.test.ts b/src/common/__tests__/user-store.test.ts index 6e5a6433ef..c5a15aec28 100644 --- a/src/common/__tests__/user-store.test.ts +++ b/src/common/__tests__/user-store.test.ts @@ -19,10 +19,6 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { Console } from "console"; - -console = new Console(process.stdout, process.stderr); - import mockFs from "mock-fs"; jest.mock("electron", () => { @@ -37,27 +33,27 @@ jest.mock("electron", () => { }); import { UserStore } from "../user-store"; +import { Console } from "console"; import { SemVer } from "semver"; import electron from "electron"; import { stdout, stderr } from "process"; import { beforeEachWrapped } from "../../../integration/helpers/utils"; import { ThemeStore } from "../../renderer/theme.store"; +import type { ClusterStoreModel } from "../cluster-store"; console = new Console(stdout, stderr); describe("user store tests", () => { describe("for an empty config", () => { beforeEachWrapped(() => { - UserStore.resetInstance(); mockFs({ tmp: { "config.json": "{}", "kube_config": "{}" } }); (UserStore.createInstance() as any).refreshNewContexts = jest.fn(() => Promise.resolve()); - - UserStore.getInstance(); }); afterEach(() => { mockFs.restore(); + UserStore.resetInstance(); }); it("allows setting and retrieving lastSeenAppVersion", () => { @@ -99,14 +95,31 @@ describe("user store tests", () => { describe("migrations", () => { beforeEachWrapped(() => { - UserStore.resetInstance(); mockFs({ "tmp": { "config.json": JSON.stringify({ user: { username: "foobar" }, preferences: { colorTheme: "light" }, lastSeenAppVersion: "1.2.3" - }) + }), + "lens-cluster-store.json": JSON.stringify({ + clusters: [ + { + id: "foobar", + kubeConfigPath: "tmp/extension_data/foo/bar", + }, + { + id: "barfoo", + kubeConfigPath: "some/other/path", + }, + ] + } as ClusterStoreModel), + "extension_data": {}, + }, + "some": { + "other": { + "path": "is file", + } } }); @@ -114,6 +127,7 @@ describe("user store tests", () => { }); afterEach(() => { + UserStore.resetInstance(); mockFs.restore(); }); @@ -122,5 +136,12 @@ describe("user store tests", () => { expect(us.lastSeenAppVersion).toBe("0.0.0"); }); + + it.only("skips clusters for adding to kube-sync with files under extension_data/", () => { + const us = UserStore.getInstance(); + + expect(us.syncKubeconfigEntries.has("tmp/extension_data/foo/bar")).toBe(false); + expect(us.syncKubeconfigEntries.has("some/other/path")).toBe(true); + }); }); }); diff --git a/src/common/utils/__tests__/paths.test.ts b/src/common/utils/__tests__/paths.test.ts new file mode 100644 index 0000000000..0eec289fb9 --- /dev/null +++ b/src/common/utils/__tests__/paths.test.ts @@ -0,0 +1,130 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import { describeIf } from "../../../../integration/helpers/utils"; +import { isWindows } from "../../vars"; +import { isLogicalChildPath } from "../paths"; + +describe("isLogicalChildPath", () => { + describeIf(isWindows)("windows tests", () => { + it.each([ + { + parentPath: "C:\\Foo", + testPath: "C:\\Foo\\Bar", + expected: true, + }, + { + parentPath: "C:\\Foo", + testPath: "C:\\Bar", + expected: false, + }, + { + parentPath: "C:\\Foo", + testPath: "C:/Bar", + expected: false, + }, + { + parentPath: "C:\\Foo", + testPath: "C:/Foo/Bar", + expected: true, + }, + { + parentPath: "C:\\Foo", + testPath: "D:\\Foo\\Bar", + expected: false, + }, + ])("test %#", (testData) => { + expect(isLogicalChildPath(testData.parentPath, testData.testPath)).toBe(testData.expected); + }); + }); + + describeIf(!isWindows)("posix tests", () => { + it.each([ + { + parentPath: "/foo", + testPath: "/foo", + expected: false, + }, + { + parentPath: "/foo", + testPath: "/bar", + expected: false, + }, + { + parentPath: "/foo", + testPath: "/foobar", + expected: false, + }, + { + parentPath: "/foo", + testPath: "/foo/bar", + expected: true, + }, + { + parentPath: "/foo", + testPath: "/foo/../bar", + expected: false, + }, + { + parentPath: "/foo", + testPath: "/foo/./bar", + expected: true, + }, + { + parentPath: "/foo", + testPath: "/foo/.bar", + expected: true, + }, + { + parentPath: "/foo", + testPath: "/foo/..bar", + expected: true, + }, + { + parentPath: "/foo", + testPath: "/foo/...bar", + expected: true, + }, + { + parentPath: "/foo", + testPath: "/foo/..\\.bar", + expected: true, + }, + { + parentPath: "/bar/../foo", + testPath: "/foo/bar", + expected: true, + }, + { + parentPath: "/foo", + testPath: "/foo/\\bar", + expected: true, + }, + { + parentPath: "/foo", + testPath: "./bar", + expected: false, + }, + ])("test %#", (testData) => { + expect(isLogicalChildPath(testData.parentPath, testData.testPath)).toBe(testData.expected); + }); + }); +}); diff --git a/src/common/utils/paths.ts b/src/common/utils/paths.ts index 391e1392f2..68d8f61ffa 100644 --- a/src/common/utils/paths.ts +++ b/src/common/utils/paths.ts @@ -33,3 +33,35 @@ function resolveTilde(filePath: string) { export function resolvePath(filePath: string): string { return path.resolve(resolveTilde(filePath)); } + +/** + * Checks if `testPath` represents a potential filesystem entry that would be + * logically "within" the `parentPath` directory. + * + * This function will return `true` in the above case, and `false` otherwise. + * It will return `false` if the two paths are the same (after resolving them). + * + * The function makes no FS calls and is platform dependant. Meaning that the + * results are only guaranteed to be correct for the platform you are running + * on. + * @param parentPath The known path of a directory + * @param testPath The path that is to be tested + */ +export function isLogicalChildPath(parentPath: string, testPath: string): boolean { + parentPath = path.resolve(parentPath); + testPath = path.resolve(testPath); + + if (parentPath === testPath) { + return false; + } + + while (testPath.length >= parentPath.length) { + if (testPath === parentPath) { + return true; + } + + testPath = path.dirname(testPath); + } + + return false; +} diff --git a/src/migrations/user-store/5.0.3-beta.1.ts b/src/migrations/user-store/5.0.3-beta.1.ts index 57271e30a4..ef3448116d 100644 --- a/src/migrations/user-store/5.0.3-beta.1.ts +++ b/src/migrations/user-store/5.0.3-beta.1.ts @@ -20,19 +20,21 @@ */ import { app } from "electron"; -import { existsSync, readJsonSync } from "fs-extra"; +import { existsSync, readFileSync } from "fs"; import path from "path"; import os from "os"; import { ClusterStore, ClusterStoreModel } from "../../common/cluster-store"; import type { KubeconfigSyncEntry, UserPreferencesModel } from "../../common/user-store"; import { MigrationDeclaration, migrationLog } from "../helpers"; +import { isLogicalChildPath } from "../../common/utils"; export default { version: "5.0.3-beta.1", run(store) { try { const { syncKubeconfigEntries = [], ...preferences }: UserPreferencesModel = store.get("preferences") ?? {}; - const { clusters = [] }: ClusterStoreModel = readJsonSync(path.resolve(app.getPath("userData"), "lens-cluster-store.json")) ?? {}; + const { clusters = [] }: ClusterStoreModel = JSON.parse(readFileSync(path.resolve(app.getPath("userData"), "lens-cluster-store.json"), "utf-8")) ?? {}; + const extensionDataDir = path.resolve(app.getPath("userData"), "extension_data"); const syncPaths = new Set(syncKubeconfigEntries.map(s => s.filePath)); syncPaths.add(path.join(os.homedir(), ".kube")); @@ -50,6 +52,11 @@ export default { continue; } + if (isLogicalChildPath(extensionDataDir, cluster.kubeConfigPath)) { + migrationLog(`Skipping ${cluster.id} because kubeConfigPath is placed under an extension_data folder`); + continue; + } + if (!existsSync(cluster.kubeConfigPath)) { migrationLog(`Skipping ${cluster.id} because kubeConfigPath no longer exists`); continue; @@ -64,8 +71,6 @@ export default { migrationLog("Final list of synced paths", updatedSyncEntries); store.set("preferences", { ...preferences, syncKubeconfigEntries: updatedSyncEntries }); } catch (error) { - console.log(error); - if (error.code !== "ENOENT") { // ignore files being missing throw error; From d0d6233869ace7732450264a99c8a8d7a6f9f90f Mon Sep 17 00:00:00 2001 From: Jim Ehrismann <40840436+jim-docker@users.noreply.github.com> Date: Mon, 12 Jul 2021 12:34:34 -0400 Subject: [PATCH 24/80] ignore Lens's prerelease tag when checking extension compatibility (#3317) --- .../__tests__/extension-compatibility.test.ts | 138 ++++++++++++++++++ src/extensions/extension-compatibility.ts | 33 +++++ src/extensions/extension-discovery.ts | 15 +- 3 files changed, 173 insertions(+), 13 deletions(-) create mode 100644 src/extensions/__tests__/extension-compatibility.test.ts create mode 100644 src/extensions/extension-compatibility.ts diff --git a/src/extensions/__tests__/extension-compatibility.test.ts b/src/extensions/__tests__/extension-compatibility.test.ts new file mode 100644 index 0000000000..d8e789a9d9 --- /dev/null +++ b/src/extensions/__tests__/extension-compatibility.test.ts @@ -0,0 +1,138 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import { isCompatibleExtension } from "../extension-compatibility"; +import { Console } from "console"; +import { stdout, stderr } from "process"; +import type { LensExtensionManifest } from "../lens-extension"; +import { appSemVer } from "../../common/vars"; + +console = new Console(stdout, stderr); + +describe("extension compatibility", () => { + describe("appSemVer with no prerelease tag", () => { + beforeAll(() => { + appSemVer.major = 5; + appSemVer.minor = 0; + appSemVer.patch = 3; + appSemVer.prerelease = []; + }); + + it("has no extension comparator", () => { + const manifest = { name: "extensionName", version: "0.0.1"}; + + expect(isCompatibleExtension(manifest,)).toBe(false); + }); + + it.each([ + { + comparator: "", + expected: false, + }, + { + comparator: "bad comparator", + expected: false, + }, + { + comparator: "^4.0.0", + expected: false, + }, + { + comparator: "^5.0.0", + expected: true, + }, + { + comparator: "^6.0.0", + expected: false, + }, + { + comparator: "^4.0.0-alpha.1", + expected: false, + }, + { + comparator: "^5.0.0-alpha.1", + expected: true, + }, + { + comparator: "^6.0.0-alpha.1", + expected: false, + }, + ])("extension comparator test: %p", ({ comparator, expected }) => { + const manifest: LensExtensionManifest = { name: "extensionName", version: "0.0.1", engines: { lens: comparator}}; + + expect(isCompatibleExtension(manifest,)).toBe(expected); + }); + }); + + describe("appSemVer with prerelease tag", () => { + beforeAll(() => { + appSemVer.major = 5; + appSemVer.minor = 0; + appSemVer.patch = 3; + appSemVer.prerelease = ["beta", 3]; + }); + + it("has no extension comparator", () => { + const manifest = { name: "extensionName", version: "0.0.1"}; + + expect(isCompatibleExtension(manifest,)).toBe(false); + }); + + it.each([ + { + comparator: "", + expected: false, + }, + { + comparator: "bad comparator", + expected: false, + }, + { + comparator: "^4.0.0", + expected: false, + }, + { + comparator: "^5.0.0", + expected: true, + }, + { + comparator: "^6.0.0", + expected: false, + }, + { + comparator: "^4.0.0-alpha.1", + expected: false, + }, + { + comparator: "^5.0.0-alpha.1", + expected: true, + }, + { + comparator: "^6.0.0-alpha.1", + expected: false, + }, + ])("extension comparator test: %p", ({ comparator, expected }) => { + const manifest: LensExtensionManifest = { name: "extensionName", version: "0.0.1", engines: { lens: comparator}}; + + expect(isCompatibleExtension(manifest,)).toBe(expected); + }); + }); +}); diff --git a/src/extensions/extension-compatibility.ts b/src/extensions/extension-compatibility.ts new file mode 100644 index 0000000000..9ca48a3f2d --- /dev/null +++ b/src/extensions/extension-compatibility.ts @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import semver from "semver"; +import { appSemVer } from "../common/vars"; +import type { LensExtensionManifest } from "./lens-extension"; + +export function isCompatibleExtension(manifest: LensExtensionManifest): boolean { + if (manifest.engines?.lens) { + /* include Lens's prerelease tag in the matching so the extension's compatibility is not limited by it */ + return semver.satisfies(appSemVer, manifest.engines.lens, { includePrerelease: true }); + } + + return false; +} diff --git a/src/extensions/extension-discovery.ts b/src/extensions/extension-discovery.ts index 85231cc88e..70f32de110 100644 --- a/src/extensions/extension-discovery.ts +++ b/src/extensions/extension-discovery.ts @@ -34,9 +34,8 @@ import { extensionInstaller } from "./extension-installer"; import { ExtensionsStore } from "./extensions-store"; import { ExtensionLoader } from "./extension-loader"; import type { LensExtensionId, LensExtensionManifest } from "./lens-extension"; -import semver from "semver"; -import { appSemVer } from "../common/vars"; import { isProduction } from "../common/vars"; +import { isCompatibleExtension } from "./extension-compatibility"; export interface InstalledExtension { id: LensExtensionId; @@ -362,17 +361,7 @@ export class ExtensionDiscovery extends Singleton { const extensionDir = path.dirname(manifestPath); const npmPackage = path.join(extensionDir, `${manifest.name}-${manifest.version}.tgz`); const absolutePath = (isProduction && await fse.pathExists(npmPackage)) ? npmPackage : extensionDir; - let isCompatible = isBundled; - - if (manifest.engines?.lens) { - const appSemVerLatestImplied = appSemVer; - - if (appSemVerLatestImplied.prerelease?.[0] === "latest") { - /* remove the "latest" prerelease tag so as not to require the extension to specify it */ - appSemVerLatestImplied.prerelease = []; - } - isCompatible = semver.satisfies(appSemVerLatestImplied, manifest.engines.lens); - } + const isCompatible = isBundled || isCompatibleExtension(manifest); return { id, From c6618bde88fe2d5d4cbeabc02d7928c563a5f3bb Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 12 Jul 2021 15:58:25 -0400 Subject: [PATCH 25/80] release v5.1.0-beta.1 (#3360) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 03577c3534..80491a71ac 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "OpenLens", "description": "OpenLens - Open Source IDE for Kubernetes", "homepage": "https://github.com/lensapp/lens", - "version": "5.0.3-beta.1", + "version": "5.1.0-beta.1", "main": "static/build/main.js", "copyright": "Š 2021 OpenLens Authors", "license": "MIT", From 485783167d6e621e3721a9d99ff2c2c3e871e33c Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 12 Jul 2021 16:13:24 -0400 Subject: [PATCH 26/80] Add SystemName validation to AccessibleNamespaces (#2754) - Don't validate after a submit Signed-off-by: Sebastian Malton --- .../cluster-accessible-namespaces.tsx | 2 + .../editable-list/editable-list.scss | 62 +++++++++++++---- .../editable-list/editable-list.tsx | 10 ++- src/renderer/components/input/input.tsx | 68 +++++++++---------- 4 files changed, 92 insertions(+), 50 deletions(-) diff --git a/src/renderer/components/cluster-settings/components/cluster-accessible-namespaces.tsx b/src/renderer/components/cluster-settings/components/cluster-accessible-namespaces.tsx index 6794646bea..0c087083fe 100644 --- a/src/renderer/components/cluster-settings/components/cluster-accessible-namespaces.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-accessible-namespaces.tsx @@ -25,6 +25,7 @@ import type { Cluster } from "../../../../main/cluster"; import { SubTitle } from "../../layout/sub-title"; import { EditableList } from "../../editable-list"; import { observable, makeObservable } from "mobx"; +import { systemName } from "../../input/input_validators"; interface Props { cluster: Cluster; @@ -49,6 +50,7 @@ export class ClusterAccessibleNamespaces extends React.Component { this.namespaces.add(newNamespace); this.props.cluster.accessibleNamespaces = Array.from(this.namespaces); }} + validators={systemName} items={Array.from(this.namespaces)} remove={({ oldItem: oldNamesapce }) => { this.namespaces.delete(oldNamesapce); diff --git a/src/renderer/components/editable-list/editable-list.scss b/src/renderer/components/editable-list/editable-list.scss index 0f88d009d9..6c62c0c59e 100644 --- a/src/renderer/components/editable-list/editable-list.scss +++ b/src/renderer/components/editable-list/editable-list.scss @@ -20,8 +20,13 @@ */ .EditableList { + --gradientColor: var(--colorVague); + .el-contents { display: flex; + background-color: var(--colorVague); + color: $textColorSecondary; + border-radius: $radius; flex-direction: column; &:not(:empty) { @@ -35,20 +40,53 @@ } .el-item { - display: grid; - grid-template-columns: 1fr auto; - padding: $padding $padding * 2; - margin-bottom: $padding / 4; - backdrop-filter: brightness(0.75); - border-radius: var(--border-radius); - - :last-child { - margin-bottom: unset; - } - - :first-child { + display: flex; + flex-direction: row; + padding: $padding 0; + margin-bottom: 1px; + + .el-value-container { + position: relative; + max-width: calc(100% - 29px); align-self: center; + + &::before, &::after { + content: ' '; + position: absolute; + z-index: 20; + display: block; + width: 8px; + height: var(--font-size); + } + + &::before { + left: 0px; + top: 0px; + background: linear-gradient(to right, var(--gradientColor) 0px, transparent); + } + + &::after { + right: 0px; + top: 0px; + background: linear-gradient(to left, var(--gradientColor) 0px, transparent); + } } + + .el-value { + white-space: nowrap; + overflow: scroll!important; + text-overflow: unset!important; + padding-left: 8px; + padding-right: 8px; + + &::-webkit-scrollbar { + display: none; + } + } + } + + :last-child { + margin-bottom: unset; } } } diff --git a/src/renderer/components/editable-list/editable-list.tsx b/src/renderer/components/editable-list/editable-list.tsx index 0b427b6f2a..61bf70bb70 100644 --- a/src/renderer/components/editable-list/editable-list.tsx +++ b/src/renderer/components/editable-list/editable-list.tsx @@ -25,7 +25,7 @@ import { observer } from "mobx-react"; import React from "react"; import { Icon } from "../icon"; -import { Input, InputProps } from "../input"; +import { Input, InputProps, InputValidator } from "../input"; import { boundMethod } from "../../utils"; export interface Props { @@ -33,6 +33,7 @@ export interface Props { add: (newItem: string) => void, remove: (info: { oldItem: T, index: number }) => void, placeholder?: string, + validators?: InputValidator | InputValidator[]; // An optional prop used to convert T to a displayable string // defaults to `String` @@ -61,7 +62,7 @@ export class EditableList extends React.Component> { } render() { - const { items, remove, renderItem, placeholder, inputTheme } = this.props; + const { items, remove, renderItem, placeholder, validators, inputTheme } = this.props; return (
@@ -69,6 +70,7 @@ export class EditableList extends React.Component> {
@@ -76,7 +78,9 @@ export class EditableList extends React.Component> { { items.map((item, index) => (
-
{renderItem(item, index)}
+
+
{renderItem(item, index)}
+
remove(({ index, oldItem: item }))} />
diff --git a/src/renderer/components/input/input.tsx b/src/renderer/components/input/input.tsx index fa1692e988..d182a8c202 100644 --- a/src/renderer/components/input/input.tsx +++ b/src/renderer/components/input/input.tsx @@ -31,6 +31,7 @@ import isString from "lodash/isString"; import isFunction from "lodash/isFunction"; import isBoolean from "lodash/isBoolean"; import uniqueId from "lodash/uniqueId"; +import { debounce } from "lodash"; const { conditionalValidators, ...InputValidators } = Validators; @@ -59,12 +60,12 @@ export type InputProps = Omit = { @@ -81,15 +82,14 @@ export class Input extends React.Component { public validators: InputValidator[] = []; public state: State = { - dirty: !!this.props.dirty, + focused: false, valid: true, + validating: false, + dirty: !!this.props.dirty, errors: [], + submitted: false, }; - isValid() { - return this.state.valid; - } - setValue(value = "") { if (value !== this.getValue()) { const nativeInputValueSetter = Object.getOwnPropertyDescriptor(this.input.constructor.prototype, "value").set; @@ -213,7 +213,6 @@ export class Input extends React.Component { } setDirty(dirty = true) { - if (this.state.dirty === dirty) return; this.setState({ dirty }); } @@ -221,30 +220,25 @@ export class Input extends React.Component { onFocus(evt: React.FocusEvent) { const { onFocus, autoSelectOnFocus } = this.props; - if (onFocus) onFocus(evt); + onFocus?.(evt); if (autoSelectOnFocus) this.select(); this.setState({ focused: true }); } @boundMethod onBlur(evt: React.FocusEvent) { - const { onBlur } = this.props; - - if (onBlur) onBlur(evt); - if (this.state.dirtyOnBlur) this.setState({ dirty: true, dirtyOnBlur: false }); + this.props.onBlur?.(evt); this.setState({ focused: false }); } + setDirtyOnChange = debounce(() => this.setDirty(), 500); + @boundMethod - onChange(evt: React.ChangeEvent) { + onChange(evt: React.ChangeEvent) { this.props.onChange?.(evt.currentTarget.value, evt); this.validate(); this.autoFitHeight(); - - // mark input as dirty for the first time only onBlur() to avoid immediate error-state show when start typing - if (!this.state.dirty) { - this.setState({ dirtyOnBlur: true }); - } + this.setDirtyOnChange(); // re-render component when used as uncontrolled input // when used @defaultValue instead of @value changing real input.value doesn't call render() @@ -255,20 +249,20 @@ export class Input extends React.Component { @boundMethod onKeyDown(evt: React.KeyboardEvent) { - const modified = evt.shiftKey || evt.metaKey || evt.altKey || evt.ctrlKey; - this.props.onKeyDown?.(evt); - switch (evt.key) { - case "Enter": - if (this.props.onSubmit && !modified && !evt.repeat && this.isValid()) { - this.props.onSubmit(this.getValue(), evt); + if (evt.shiftKey || evt.metaKey || evt.altKey || evt.ctrlKey || evt.repeat) { + return; + } - if (this.isUncontrolled) { - this.setValue(); - } - } - break; + if (evt.key === "Enter") { + if (this.state.valid) { + this.props.onSubmit?.(this.getValue(), evt); + this.setDirtyOnChange.cancel(); + this.setState({ submitted: true }); + } else { + this.setDirty(); + } } } @@ -291,7 +285,11 @@ export class Input extends React.Component { const { defaultValue, value, dirty, validators } = this.props; if (prevProps.value !== value || defaultValue !== prevProps.defaultValue) { - this.validate(); + if (!this.state.submitted) { + this.validate(); + } else { + this.setState({ submitted: false }); + } this.autoFitHeight(); } From 5bccc27204c1a548cff51e98c778a33a751f952b Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 13 Jul 2021 01:51:49 -0400 Subject: [PATCH 27/80] Check for unset pod spec (#3361) Signed-off-by: Sebastian Malton --- src/renderer/api/__tests__/pods.api.test.ts | 38 +++++++++++++++++++++ src/renderer/api/endpoints/pods.api.ts | 6 ++-- 2 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 src/renderer/api/__tests__/pods.api.test.ts diff --git a/src/renderer/api/__tests__/pods.api.test.ts b/src/renderer/api/__tests__/pods.api.test.ts new file mode 100644 index 0000000000..e7a90f8e38 --- /dev/null +++ b/src/renderer/api/__tests__/pods.api.test.ts @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import { Pod } from "../endpoints"; + +describe("Pod tests", () => { + it("getAllContainers() should never throw", () => { + const pod = new Pod({ + apiVersion: "foo", + kind: "Pod", + metadata: { + name: "foobar", + resourceVersion: "foobar", + uid: "foobar", + }, + }); + + expect(pod.getAllContainers()).toStrictEqual([]); + }); +}); diff --git a/src/renderer/api/endpoints/pods.api.ts b/src/renderer/api/endpoints/pods.api.ts index 8ac8024227..5b85a3d42b 100644 --- a/src/renderer/api/endpoints/pods.api.ts +++ b/src/renderer/api/endpoints/pods.api.ts @@ -213,7 +213,7 @@ export class Pod extends WorkloadKubeObject { autoBind(this); } - declare spec: { + declare spec?: { volumes?: { name: string; persistentVolumeClaim: { @@ -291,11 +291,11 @@ export class Pod extends WorkloadKubeObject { }; getInitContainers() { - return this.spec.initContainers || []; + return this.spec?.initContainers || []; } getContainers() { - return this.spec.containers || []; + return this.spec?.containers || []; } getAllContainers() { From c0c1139e3eaf49b88baa90ff86f4229244847677 Mon Sep 17 00:00:00 2001 From: Violetta Shakirova <38247153+vshakirova@users.noreply.github.com> Date: Tue, 13 Jul 2021 16:35:06 +0400 Subject: [PATCH 28/80] Fix incorrect CRD casing (#3365) Signed-off-by: vshakirova --- src/renderer/components/+custom-resources/crd-list.tsx | 2 +- src/renderer/components/layout/sidebar.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/components/+custom-resources/crd-list.tsx b/src/renderer/components/+custom-resources/crd-list.tsx index 822eff575f..e8bfee160d 100644 --- a/src/renderer/components/+custom-resources/crd-list.tsx +++ b/src/renderer/components/+custom-resources/crd-list.tsx @@ -139,7 +139,7 @@ export class CrdList extends React.Component { ]} renderTableContents={(crd: CustomResourceDefinition) => [ - {crd.getResourceTitle()} + {crd.getResourceKind()} , crd.getGroup(), crd.getVersion(), diff --git a/src/renderer/components/layout/sidebar.tsx b/src/renderer/components/layout/sidebar.tsx index 2aa3f37488..9842d9e45e 100644 --- a/src/renderer/components/layout/sidebar.tsx +++ b/src/renderer/components/layout/sidebar.tsx @@ -73,7 +73,7 @@ export class Sidebar extends React.Component { key={crd.getResourceApiBase()} id={`crd-resource:${crd.getResourceApiBase()}`} url={crd.getResourceUrl()} - text={crd.getResourceTitle()} + text={crd.getResourceKind()} /> ))} From dfd98438090ee82103be4266f8e9161f1f81a8b4 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 13 Jul 2021 08:44:27 -0400 Subject: [PATCH 29/80] Provide better typing for dock tabs (#3340) --- .../dock/__test__/dock-tabs.test.tsx | 20 ++--- .../components/dock/create-resource.store.ts | 8 +- .../components/dock/create-resource.tsx | 4 +- src/renderer/components/dock/dock-tab.tsx | 4 +- src/renderer/components/dock/dock-tabs.tsx | 10 +-- src/renderer/components/dock/dock.store.ts | 81 ++++++++++++++++--- src/renderer/components/dock/dock.tsx | 6 +- .../components/dock/edit-resource.store.ts | 8 +- .../components/dock/edit-resource.tsx | 4 +- .../components/dock/install-chart.store.ts | 8 +- .../components/dock/install-chart.tsx | 4 +- src/renderer/components/dock/log-tab.store.ts | 6 +- src/renderer/components/dock/logs.tsx | 4 +- .../components/dock/terminal-window.tsx | 4 +- .../components/dock/terminal.store.ts | 10 +-- .../components/dock/upgrade-chart.store.ts | 10 +-- .../components/dock/upgrade-chart.tsx | 4 +- 17 files changed, 125 insertions(+), 70 deletions(-) diff --git a/src/renderer/components/dock/__test__/dock-tabs.test.tsx b/src/renderer/components/dock/__test__/dock-tabs.test.tsx index ad27853900..e2061c6543 100644 --- a/src/renderer/components/dock/__test__/dock-tabs.test.tsx +++ b/src/renderer/components/dock/__test__/dock-tabs.test.tsx @@ -24,7 +24,7 @@ import { fireEvent, render } from "@testing-library/react"; import "@testing-library/jest-dom/extend-expect"; import { DockTabs } from "../dock-tabs"; -import { dockStore, IDockTab, TabKind } from "../dock.store"; +import { dockStore, DockTab, TabKind } from "../dock.store"; import { noop } from "../../../utils"; jest.mock("electron", () => ({ @@ -33,12 +33,12 @@ jest.mock("electron", () => ({ }, })); -const initialTabs: IDockTab[] = [ - { id: "terminal", kind: TabKind.TERMINAL, title: "Terminal" }, - { id: "create", kind: TabKind.CREATE_RESOURCE, title: "Create resource" }, - { id: "edit", kind: TabKind.EDIT_RESOURCE, title: "Edit resource" }, - { id: "install", kind: TabKind.INSTALL_CHART, title: "Install chart" }, - { id: "logs", kind: TabKind.POD_LOGS, title: "Logs" }, +const initialTabs: DockTab[] = [ + { id: "terminal", kind: TabKind.TERMINAL, title: "Terminal", pinned: false, }, + { id: "create", kind: TabKind.CREATE_RESOURCE, title: "Create resource", pinned: false, }, + { id: "edit", kind: TabKind.EDIT_RESOURCE, title: "Edit resource", pinned: false, }, + { id: "install", kind: TabKind.INSTALL_CHART, title: "Install chart", pinned: false, }, + { id: "logs", kind: TabKind.POD_LOGS, title: "Logs", pinned: false, }, ]; const getComponent = () => ( @@ -142,7 +142,7 @@ describe("", () => { it("disables 'Close All' & 'Close Other' items if only 1 tab available", () => { dockStore.tabs = [{ - id: "terminal", kind: TabKind.TERMINAL, title: "Terminal" + id: "terminal", kind: TabKind.TERMINAL, title: "Terminal", pinned: false, }]; const { container, getByText } = renderTabs(); const tab = container.querySelector(".Tab"); @@ -157,8 +157,8 @@ describe("", () => { it("disables 'Close To The Right' item if last tab clicked", () => { dockStore.tabs = [ - { id: "terminal", kind: TabKind.TERMINAL, title: "Terminal" }, - { id: "logs", kind: TabKind.POD_LOGS, title: "Pod Logs" }, + { id: "terminal", kind: TabKind.TERMINAL, title: "Terminal", pinned: false, }, + { id: "logs", kind: TabKind.POD_LOGS, title: "Pod Logs", pinned: false, }, ]; const { container, getByText } = renderTabs(); const tab = container.querySelectorAll(".Tab")[1]; diff --git a/src/renderer/components/dock/create-resource.store.ts b/src/renderer/components/dock/create-resource.store.ts index 2e049deacf..f0b6b41154 100644 --- a/src/renderer/components/dock/create-resource.store.ts +++ b/src/renderer/components/dock/create-resource.store.ts @@ -27,7 +27,7 @@ import filehound from "filehound"; import { watch } from "chokidar"; import { autoBind } from "../../utils"; import { DockTabStore } from "./dock-tab.store"; -import { dockStore, IDockTab, TabKind } from "./dock.store"; +import { dockStore, DockTabCreateSpecific, TabKind } from "./dock.store"; export class CreateResourceStore extends DockTabStore { constructor() { @@ -81,10 +81,10 @@ export class CreateResourceStore extends DockTabStore { export const createResourceStore = new CreateResourceStore(); -export function createResourceTab(tabParams: Partial = {}) { +export function createResourceTab(tabParams: DockTabCreateSpecific = {}) { return dockStore.createTab({ - kind: TabKind.CREATE_RESOURCE, title: "Create resource", - ...tabParams + ...tabParams, + kind: TabKind.CREATE_RESOURCE, }); } diff --git a/src/renderer/components/dock/create-resource.tsx b/src/renderer/components/dock/create-resource.tsx index 413cbebc6d..f3423a7771 100644 --- a/src/renderer/components/dock/create-resource.tsx +++ b/src/renderer/components/dock/create-resource.tsx @@ -30,7 +30,7 @@ import { observable, makeObservable } from "mobx"; import { observer } from "mobx-react"; import { cssNames } from "../../utils"; import { createResourceStore } from "./create-resource.store"; -import type { IDockTab } from "./dock.store"; +import type { DockTab } from "./dock.store"; import { EditorPanel } from "./editor-panel"; import { InfoPanel } from "./info-panel"; import { resourceApplierApi } from "../../api/endpoints/resource-applier.api"; @@ -39,7 +39,7 @@ import { Notifications } from "../notifications"; interface Props { className?: string; - tab: IDockTab; + tab: DockTab; } @observer diff --git a/src/renderer/components/dock/dock-tab.tsx b/src/renderer/components/dock/dock-tab.tsx index dd4ff63824..a42a2dd64b 100644 --- a/src/renderer/components/dock/dock-tab.tsx +++ b/src/renderer/components/dock/dock-tab.tsx @@ -24,13 +24,13 @@ import "./dock-tab.scss"; import React from "react"; import { observer } from "mobx-react"; import { boundMethod, cssNames, prevDefault, isMiddleClick } from "../../utils"; -import { dockStore, IDockTab } from "./dock.store"; +import { dockStore, DockTab as DockTabModel } from "./dock.store"; import { Tab, TabProps } from "../tabs"; import { Icon } from "../icon"; import { Menu, MenuItem } from "../menu"; import { observable, makeObservable } from "mobx"; -export interface DockTabProps extends TabProps { +export interface DockTabProps extends TabProps { moreActions?: React.ReactNode; } diff --git a/src/renderer/components/dock/dock-tabs.tsx b/src/renderer/components/dock/dock-tabs.tsx index 6064259cbc..372ef100d9 100644 --- a/src/renderer/components/dock/dock-tabs.tsx +++ b/src/renderer/components/dock/dock-tabs.tsx @@ -24,19 +24,19 @@ import React, { Fragment } from "react"; import { Icon } from "../icon"; import { Tabs } from "../tabs/tabs"; import { DockTab } from "./dock-tab"; -import type { IDockTab } from "./dock.store"; +import type { DockTab as DockTabModel } from "./dock.store"; import { TabKind } from "./dock.store"; import { TerminalTab } from "./terminal-tab"; interface Props { - tabs: IDockTab[] + tabs: DockTabModel[] autoFocus: boolean - selectedTab: IDockTab - onChangeTab: (tab: IDockTab) => void + selectedTab: DockTabModel + onChangeTab: (tab: DockTabModel) => void } export const DockTabs = ({ tabs, autoFocus, selectedTab, onChangeTab }: Props) => { - const renderTab = (tab?: IDockTab) => { + const renderTab = (tab?: DockTabModel) => { if (!tab) { return null; } diff --git a/src/renderer/components/dock/dock.store.ts b/src/renderer/components/dock/dock.store.ts index 2c9789ce41..516aba403b 100644 --- a/src/renderer/components/dock/dock.store.ts +++ b/src/renderer/components/dock/dock.store.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import MD5 from "crypto-js/md5"; +import * as uuid from "uuid"; import { action, computed, IReactionOptions, makeObservable, observable, reaction } from "mobx"; import { autoBind, createStorage } from "../../utils"; import throttle from "lodash/throttle"; @@ -35,16 +35,55 @@ export enum TabKind { POD_LOGS = "pod-logs", } -export interface IDockTab { +/** + * This is the storage model for dock tabs. + * + * All fields are required. + */ +export type DockTab = Required; + +/** + * These are the arguments for creating a new Tab on the dock + */ +export interface DockTabCreate { + /** + * The ID of the tab for reference purposes. + */ id?: TabId; + + /** + * What kind of dock tab it is + */ kind: TabKind; + + /** + * The tab's title, defaults to `kind` + */ title?: string; - pinned?: boolean; // not closable + + /** + * If true then the dock entry will take up the whole view and will not be + * closable. + */ + pinned?: boolean; + + /** + * Extra fields are supported. + */ + [key: string]: any; } +/** + * This type is for function which specifically create a single type of dock tab. + * + * That way users should get a type error if they try and specify a `kind` + * themselves. + */ +export type DockTabCreateSpecific = Omit; + export interface DockStorageState { height: number; - tabs: IDockTab[]; + tabs: DockTab[]; selectedTabId?: TabId; isOpen?: boolean; } @@ -62,7 +101,7 @@ export class DockStore implements DockStorageState { private storage = createStorage("dock", { height: 300, tabs: [ - { id: "terminal", kind: TabKind.TERMINAL, title: "Terminal" }, + { id: "terminal", kind: TabKind.TERMINAL, title: "Terminal", pinned: false }, ], }); @@ -88,11 +127,11 @@ export class DockStore implements DockStorageState { }); } - get tabs(): IDockTab[] { + get tabs(): DockTab[] { return this.storage.get().tabs; } - set tabs(tabs: IDockTab[]) { + set tabs(tabs: DockTab[]) { this.storage.merge({ tabs }); } @@ -191,15 +230,31 @@ export class DockStore implements DockStorageState { } @action - createTab(anonTab: IDockTab, addNumber = true): IDockTab { - const tabId = MD5(Math.random().toString() + Date.now()).toString(); - const tab: IDockTab = { id: tabId, ...anonTab }; + createTab(rawTabDesc: DockTabCreate, addNumber = true): DockTab { + const { + id = uuid.v4(), + kind, + pinned = false, + ...restOfTabFields + } = rawTabDesc; + let { title = kind } = rawTabDesc; if (addNumber) { - const tabNumber = this.getNewTabNumber(tab.kind); + const tabNumber = this.getNewTabNumber(kind); - if (tabNumber > 1) tab.title += ` (${tabNumber})`; + if (tabNumber > 1) { + title += ` (${tabNumber})`; + } } + + const tab: DockTab = { + ...restOfTabFields, + id, + kind, + pinned, + title + }; + this.tabs.push(tab); this.selectTab(tab.id); this.open(); @@ -234,7 +289,7 @@ export class DockStore implements DockStorageState { } } - closeTabs(tabs: IDockTab[]) { + closeTabs(tabs: DockTab[]) { tabs.forEach(tab => this.closeTab(tab.id)); } diff --git a/src/renderer/components/dock/dock.tsx b/src/renderer/components/dock/dock.tsx index c3c4ca520b..a8cea06d7b 100644 --- a/src/renderer/components/dock/dock.tsx +++ b/src/renderer/components/dock/dock.tsx @@ -32,7 +32,7 @@ import { ResizeDirection, ResizingAnchor } from "../resizing-anchor"; import { CreateResource } from "./create-resource"; import { createResourceTab } from "./create-resource.store"; import { DockTabs } from "./dock-tabs"; -import { dockStore, IDockTab, TabKind } from "./dock.store"; +import { dockStore, DockTab, TabKind } from "./dock.store"; import { EditResource } from "./edit-resource"; import { InstallChart } from "./install-chart"; import { Logs } from "./logs"; @@ -62,14 +62,14 @@ export class Dock extends React.Component { } }; - onChangeTab = (tab: IDockTab) => { + onChangeTab = (tab: DockTab) => { const { open, selectTab } = dockStore; open(); selectTab(tab.id); }; - renderTab(tab: IDockTab) { + renderTab(tab: DockTab) { switch (tab.kind) { case TabKind.CREATE_RESOURCE: return ; diff --git a/src/renderer/components/dock/edit-resource.store.ts b/src/renderer/components/dock/edit-resource.store.ts index 9b10491901..7931d86451 100644 --- a/src/renderer/components/dock/edit-resource.store.ts +++ b/src/renderer/components/dock/edit-resource.store.ts @@ -22,7 +22,7 @@ import { autoBind, noop } from "../../utils"; import { DockTabStore } from "./dock-tab.store"; import { autorun, IReactionDisposer } from "mobx"; -import { dockStore, IDockTab, TabId, TabKind } from "./dock.store"; +import { dockStore, DockTab, DockTabCreateSpecific, TabId, TabKind } from "./dock.store"; import type { KubeObject } from "../../api/kube-object"; import { apiManager } from "../../api/api-manager"; import type { KubeObjectStore } from "../../kube-object.store"; @@ -96,7 +96,7 @@ export class EditResourceStore extends DockTabStore { return this.getData(tabId)?.resource; } - getTabByResource(object: KubeObject): IDockTab { + getTabByResource(object: KubeObject): DockTab { const [tabId] = Array.from(this.data).find(([, { resource }]) => { return object.selfLink === resource; }) || []; @@ -115,7 +115,7 @@ export class EditResourceStore extends DockTabStore { export const editResourceStore = new EditResourceStore(); -export function editResourceTab(object: KubeObject, tabParams: Partial = {}) { +export function editResourceTab(object: KubeObject, tabParams: DockTabCreateSpecific = {}) { // use existing tab if already opened let tab = editResourceStore.getTabByResource(object); @@ -128,8 +128,8 @@ export function editResourceTab(object: KubeObject, tabParams: Partial if (!tab) { tab = dockStore.createTab({ title: `${object.kind}: ${object.getName()}`, + ...tabParams, kind: TabKind.EDIT_RESOURCE, - ...tabParams }, false); editResourceStore.setData(tab.id, { resource: object.selfLink, diff --git a/src/renderer/components/dock/edit-resource.tsx b/src/renderer/components/dock/edit-resource.tsx index 455bbda61a..0496ef3104 100644 --- a/src/renderer/components/dock/edit-resource.tsx +++ b/src/renderer/components/dock/edit-resource.tsx @@ -25,7 +25,7 @@ import React from "react"; import { action, computed, makeObservable, observable } from "mobx"; import { observer } from "mobx-react"; import jsYaml from "js-yaml"; -import type { IDockTab } from "./dock.store"; +import type { DockTab } from "./dock.store"; import { cssNames } from "../../utils"; import { editResourceStore } from "./edit-resource.store"; import { InfoPanel } from "./info-panel"; @@ -36,7 +36,7 @@ import type { KubeObject } from "../../api/kube-object"; interface Props { className?: string; - tab: IDockTab; + tab: DockTab; } @observer diff --git a/src/renderer/components/dock/install-chart.store.ts b/src/renderer/components/dock/install-chart.store.ts index 20e0a7a0ac..f7ae6930e6 100644 --- a/src/renderer/components/dock/install-chart.store.ts +++ b/src/renderer/components/dock/install-chart.store.ts @@ -20,7 +20,7 @@ */ import { action, autorun, makeObservable } from "mobx"; -import { dockStore, IDockTab, TabId, TabKind } from "./dock.store"; +import { dockStore, DockTabCreateSpecific, TabId, TabKind } from "./dock.store"; import { DockTabStore } from "./dock-tab.store"; import { getChartDetails, getChartValues, HelmChart } from "../../api/endpoints/helm-charts.api"; import type { IReleaseUpdateDetails } from "../../api/endpoints/helm-releases.api"; @@ -98,12 +98,12 @@ export class InstallChartStore extends DockTabStore { export const installChartStore = new InstallChartStore(); -export function createInstallChartTab(chart: HelmChart, tabParams: Partial = {}) { +export function createInstallChartTab(chart: HelmChart, tabParams: DockTabCreateSpecific = {}) { const { name, repo, version } = chart; const tab = dockStore.createTab({ - kind: TabKind.INSTALL_CHART, title: `Helm Install: ${repo}/${name}`, - ...tabParams + ...tabParams, + kind: TabKind.INSTALL_CHART, }, false); installChartStore.setData(tab.id, { diff --git a/src/renderer/components/dock/install-chart.tsx b/src/renderer/components/dock/install-chart.tsx index 69e0313eec..b0113018ea 100644 --- a/src/renderer/components/dock/install-chart.tsx +++ b/src/renderer/components/dock/install-chart.tsx @@ -24,7 +24,7 @@ import "./install-chart.scss"; import React, { Component } from "react"; import { observable, makeObservable } from "mobx"; import { observer } from "mobx-react"; -import { dockStore, IDockTab } from "./dock.store"; +import { dockStore, DockTab } from "./dock.store"; import { InfoPanel } from "./info-panel"; import { Badge } from "../badge"; import { NamespaceSelect } from "../+namespaces/namespace-select"; @@ -42,7 +42,7 @@ import { navigate } from "../../navigation"; import { releaseURL } from "../../../common/routes"; interface Props { - tab: IDockTab; + tab: DockTab; } @observer diff --git a/src/renderer/components/dock/log-tab.store.ts b/src/renderer/components/dock/log-tab.store.ts index 560cea5cff..50be7a1e34 100644 --- a/src/renderer/components/dock/log-tab.store.ts +++ b/src/renderer/components/dock/log-tab.store.ts @@ -26,7 +26,7 @@ import { podsStore } from "../+workloads-pods/pods.store"; import { IPodContainer, Pod } from "../../api/endpoints"; import type { WorkloadKubeObject } from "../../api/workload-kube-object"; import { DockTabStore } from "./dock-tab.store"; -import { dockStore, IDockTab, TabKind } from "./dock.store"; +import { dockStore, DockTabCreateSpecific, TabKind } from "./dock.store"; export interface LogTabData { pods: Pod[]; @@ -90,10 +90,10 @@ export class LogTabStore extends DockTabStore { dockStore.renameTab(tabId, `Pod ${selectedPod.metadata.name}`); } - private createDockTab(tabParams: Partial) { + private createDockTab(tabParams: DockTabCreateSpecific) { dockStore.createTab({ + ...tabParams, kind: TabKind.POD_LOGS, - ...tabParams }, false); } diff --git a/src/renderer/components/dock/logs.tsx b/src/renderer/components/dock/logs.tsx index 4649d28eeb..6c5c8d115f 100644 --- a/src/renderer/components/dock/logs.tsx +++ b/src/renderer/components/dock/logs.tsx @@ -25,7 +25,7 @@ import { disposeOnUnmount, observer } from "mobx-react"; import { searchStore } from "../../../common/search-store"; import { boundMethod } from "../../utils"; -import type { IDockTab } from "./dock.store"; +import type { DockTab } from "./dock.store"; import { InfoPanel } from "./info-panel"; import { LogResourceSelector } from "./log-resource-selector"; import { LogList } from "./log-list"; @@ -36,7 +36,7 @@ import { LogTabData, logTabStore } from "./log-tab.store"; interface Props { className?: string - tab: IDockTab + tab: DockTab } @observer diff --git a/src/renderer/components/dock/terminal-window.tsx b/src/renderer/components/dock/terminal-window.tsx index d5b4d4a53b..652086d811 100644 --- a/src/renderer/components/dock/terminal-window.tsx +++ b/src/renderer/components/dock/terminal-window.tsx @@ -25,14 +25,14 @@ import React from "react"; import { reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { cssNames } from "../../utils"; -import type { IDockTab } from "./dock.store"; +import type { DockTab } from "./dock.store"; import type { Terminal } from "./terminal"; import { terminalStore } from "./terminal.store"; import { ThemeStore } from "../../theme.store"; interface Props { className?: string; - tab: IDockTab; + tab: DockTab; } @observer diff --git a/src/renderer/components/dock/terminal.store.ts b/src/renderer/components/dock/terminal.store.ts index 7f0396336e..47d100b3ab 100644 --- a/src/renderer/components/dock/terminal.store.ts +++ b/src/renderer/components/dock/terminal.store.ts @@ -23,18 +23,18 @@ import { autorun, observable } from "mobx"; import { autoBind } from "../../utils"; import { Terminal } from "./terminal"; import { TerminalApi } from "../../api/terminal-api"; -import { dockStore, IDockTab, TabId, TabKind } from "./dock.store"; +import { dockStore, DockTab, DockTabCreateSpecific, TabId, TabKind } from "./dock.store"; import { WebSocketApiState } from "../../api/websocket-api"; -export interface ITerminalTab extends IDockTab { +export interface ITerminalTab extends DockTab { node?: string; // activate node shell mode } -export function createTerminalTab(tabParams: Partial = {}) { +export function createTerminalTab(tabParams: DockTabCreateSpecific = {}) { return dockStore.createTab({ - kind: TabKind.TERMINAL, title: `Terminal`, - ...tabParams + ...tabParams, + kind: TabKind.TERMINAL, }); } diff --git a/src/renderer/components/dock/upgrade-chart.store.ts b/src/renderer/components/dock/upgrade-chart.store.ts index 5aafdfb0ea..4a43ae4ab1 100644 --- a/src/renderer/components/dock/upgrade-chart.store.ts +++ b/src/renderer/components/dock/upgrade-chart.store.ts @@ -20,7 +20,7 @@ */ import { action, autorun, computed, IReactionDisposer, reaction, makeObservable } from "mobx"; -import { dockStore, IDockTab, TabId, TabKind } from "./dock.store"; +import { dockStore, DockTab, DockTabCreateSpecific, TabId, TabKind } from "./dock.store"; import { DockTabStore } from "./dock-tab.store"; import { getReleaseValues, HelmRelease } from "../../api/endpoints/helm-releases.api"; import { releaseStore } from "../+apps-releases/release.store"; @@ -120,14 +120,14 @@ export class UpgradeChartStore extends DockTabStore { this.values.setData(tabId, values); } - getTabByRelease(releaseName: string): IDockTab { + getTabByRelease(releaseName: string): DockTab { return dockStore.getTabById(this.releaseNameReverseLookup.get(releaseName)); } } export const upgradeChartStore = new UpgradeChartStore(); -export function createUpgradeChartTab(release: HelmRelease, tabParams: Partial = {}) { +export function createUpgradeChartTab(release: HelmRelease, tabParams: DockTabCreateSpecific = {}) { let tab = upgradeChartStore.getTabByRelease(release.getName()); if (tab) { @@ -137,9 +137,9 @@ export function createUpgradeChartTab(release: HelmRelease, tabParams: Partial Date: Tue, 13 Jul 2021 15:58:55 +0300 Subject: [PATCH 30/80] Removing limits and requests from Pod metrics (#3369) Signed-off-by: Alex Andreev --- .../+workloads-pods/container-charts.tsx | 8 ++- .../components/+workloads-pods/pod-charts.tsx | 51 +++---------------- 2 files changed, 11 insertions(+), 48 deletions(-) diff --git a/src/renderer/components/+workloads-pods/container-charts.tsx b/src/renderer/components/+workloads-pods/container-charts.tsx index df55fc9b59..0c810b47de 100644 --- a/src/renderer/components/+workloads-pods/container-charts.tsx +++ b/src/renderer/components/+workloads-pods/container-charts.tsx @@ -27,6 +27,7 @@ import { isMetricsEmpty, normalizeMetrics } from "../../api/endpoints/metrics.ap import { NoMetrics } from "../resource-metrics/no-metrics"; import { IResourceMetricsValue, ResourceMetricsContext } from "../resource-metrics"; import { ThemeStore } from "../../theme.store"; +import { mapValues } from "lodash"; type IContext = IResourceMetricsValue; @@ -37,10 +38,7 @@ export const ContainerCharts = observer(() => { if (!metrics) return null; if (isMetricsEmpty(metrics)) return ; - const values = Object.values(metrics) - .map(normalizeMetrics) - .map(({ data }) => data.result[0].values); - const [ + const { cpuUsage, cpuRequests, cpuLimits, @@ -48,7 +46,7 @@ export const ContainerCharts = observer(() => { memoryRequests, memoryLimits, fsUsage - ] = values; + } = mapValues(metrics, metric => normalizeMetrics(metric).data.result[0].values); const datasets = [ // CPU diff --git a/src/renderer/components/+workloads-pods/pod-charts.tsx b/src/renderer/components/+workloads-pods/pod-charts.tsx index d3aafa0214..cc05aeec55 100644 --- a/src/renderer/components/+workloads-pods/pod-charts.tsx +++ b/src/renderer/components/+workloads-pods/pod-charts.tsx @@ -19,15 +19,16 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import React, { useContext } from "react"; +import { mapValues } from "lodash"; import { observer } from "mobx-react"; -import type { IPodMetrics } from "../../api/endpoints"; -import { BarChart, cpuOptions, memoryOptions } from "../chart"; +import React, { useContext } from "react"; import { isMetricsEmpty, normalizeMetrics } from "../../api/endpoints/metrics.api"; -import { NoMetrics } from "../resource-metrics/no-metrics"; +import { BarChart, cpuOptions, memoryOptions } from "../chart"; import { IResourceMetricsValue, ResourceMetricsContext } from "../resource-metrics"; +import { NoMetrics } from "../resource-metrics/no-metrics"; + import type { WorkloadKubeObject } from "../../api/workload-kube-object"; -import { ThemeStore } from "../../theme.store"; +import type { IPodMetrics } from "../../api/endpoints"; export const podMetricTabs = [ "CPU", @@ -40,27 +41,19 @@ type IContext = IResourceMetricsValue { const { params: { metrics }, tabId, object } = useContext(ResourceMetricsContext); - const { chartCapacityColor } = ThemeStore.getInstance().activeTheme.colors; const id = object.getId(); if (!metrics) return null; if (isMetricsEmpty(metrics)) return ; const options = tabId == 0 ? cpuOptions : memoryOptions; - const values = Object.values(metrics) - .map(normalizeMetrics) - .map(({ data }) => data.result[0].values); - const [ + const { cpuUsage, - cpuRequests, - cpuLimits, memoryUsage, - memoryRequests, - memoryLimits, fsUsage, networkReceive, networkTransmit - ] = values; + } = mapValues(metrics, metric => normalizeMetrics(metric).data.result[0].values); const datasets = [ // CPU @@ -71,20 +64,6 @@ export const PodCharts = observer(() => { tooltip: `Container CPU cores usage`, borderColor: "#3D90CE", data: cpuUsage.map(([x, y]) => ({ x, y })) - }, - { - id: `${id}-cpuRequests`, - label: `Requests`, - tooltip: `Container CPU requests`, - borderColor: "#30b24d", - data: cpuRequests.map(([x, y]) => ({ x, y })) - }, - { - id: `${id}-cpuLimits`, - label: `Limits`, - tooltip: `CPU limits`, - borderColor: chartCapacityColor, - data: cpuLimits.map(([x, y]) => ({ x, y })) } ], // Memory @@ -96,20 +75,6 @@ export const PodCharts = observer(() => { borderColor: "#c93dce", data: memoryUsage.map(([x, y]) => ({ x, y })) }, - { - id: `${id}-memoryRequests`, - label: `Requests`, - tooltip: `Container memory requests`, - borderColor: "#30b24d", - data: memoryRequests.map(([x, y]) => ({ x, y })) - }, - { - id: `${id}-memoryLimits`, - label: `Limits`, - tooltip: `Container memory limits`, - borderColor: chartCapacityColor, - data: memoryLimits.map(([x, y]) => ({ x, y })) - } ], // Network [ From ca1ad425ab5b47992e02a695cb83a0dbcf90f12e Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 13 Jul 2021 17:00:11 +0300 Subject: [PATCH 31/80] Badge: option to show short/full versions of contents (#1397) * add button to expand and view whole badge contents Signed-off-by: Sebastian Malton * revert font changes due to update elsewhere already existing Signed-off-by: Sebastian Malton * make expanding icon smaller and not focusable Signed-off-by: Sebastian Malton * extended badge content by click, selecting text from label doesn't trigger auto-closing Signed-off-by: Roman * fix: hover only intercative badges (with extra content) Signed-off-by: Roman * added common document/selectionchange watcher Signed-off-by: Roman * lint fixes Signed-off-by: Roman * Convert Badge to CSS Modules Signed-off-by: Alex Andreev * Align Badge styles across components Signed-off-by: Alex Andreev * Cleaning up Signed-off-by: Alex Andreev * Not closing badge if user started to select text Signed-off-by: Alex Andreev Co-authored-by: Sebastian Malton Co-authored-by: Alex Andreev --- .../+apps-releases/release-details.scss | 8 +-- .../+apps-releases/release-details.tsx | 2 +- .../+catalog/catalog-entity.store.tsx | 1 + .../+config-autoscalers/hpa-details.scss | 2 +- .../+config-autoscalers/hpa-details.tsx | 2 +- .../components/+config-autoscalers/hpa.scss | 5 +- .../components/+config-autoscalers/hpa.tsx | 1 + .../components/+config-secrets/secrets.tsx | 2 +- .../+custom-resources/crd-details.scss | 19 +---- .../+custom-resources/crd-details.tsx | 4 +- .../crd-resource-details.scss | 10 +-- .../crd-resource-details.tsx | 3 +- .../+custom-resources/crd.mixins.scss | 2 +- .../components/+nodes/node-details.scss | 5 +- .../components/+nodes/nodes-mixins.scss | 2 +- .../+workloads-cronjobs/cronjob-details.scss | 4 +- .../deployment-details.scss | 24 +++---- .../deployment-details.tsx | 4 +- .../+workloads-jobs/job-details.scss | 4 +- .../pod-details-container.scss | 4 -- .../+workloads-pods/pod-details.tsx | 2 +- .../components/+workloads-pods/pods.tsx | 4 +- .../+workloads/workloads-mixins.scss | 2 +- .../badge/{badge.scss => badge.module.css} | 50 ++++++++----- src/renderer/components/badge/badge.tsx | 71 ++++++++++++++++--- src/renderer/components/chart/chart.scss | 2 +- src/renderer/components/chart/chart.tsx | 3 +- src/renderer/components/chart/pie-chart.scss | 2 +- .../components/cluster-show-metrics.tsx | 3 +- src/renderer/components/dock/info-panel.scss | 4 -- .../components/drawer/drawer-item.scss | 2 +- .../components/hotbar/hotbar-selector.scss | 2 +- .../components/hotbar/hotbar-selector.tsx | 1 + src/renderer/components/icon/icon.scss | 2 +- .../item-object-list/page-filters-list.tsx | 2 +- .../components/table/table.mixins.scss | 4 -- 36 files changed, 146 insertions(+), 118 deletions(-) rename src/renderer/components/badge/{badge.scss => badge.module.css} (75%) diff --git a/src/renderer/components/+apps-releases/release-details.scss b/src/renderer/components/+apps-releases/release-details.scss index 3afe13961c..a4bd53610c 100644 --- a/src/renderer/components/+apps-releases/release-details.scss +++ b/src/renderer/components/+apps-releases/release-details.scss @@ -27,13 +27,7 @@ } .status { - .Badge { - @include release-status-bgs; - - &:first-child { - margin-left: 0; - } - } + @include release-status-bgs; } .chart { diff --git a/src/renderer/components/+apps-releases/release-details.tsx b/src/renderer/components/+apps-releases/release-details.tsx index e5bda1f873..fae2e3ba71 100644 --- a/src/renderer/components/+apps-releases/release-details.tsx +++ b/src/renderer/components/+apps-releases/release-details.tsx @@ -272,7 +272,7 @@ export class ReleaseDetails extends Component { {this.renderValues()} diff --git a/src/renderer/components/+catalog/catalog-entity.store.tsx b/src/renderer/components/+catalog/catalog-entity.store.tsx index fea9e5e6ba..b606d54c1a 100644 --- a/src/renderer/components/+catalog/catalog-entity.store.tsx +++ b/src/renderer/components/+catalog/catalog-entity.store.tsx @@ -88,6 +88,7 @@ export class CatalogEntityItem implements ItemObject { onClick?.(event); event.stopPropagation(); }} + expandable={false} /> )); } diff --git a/src/renderer/components/+config-autoscalers/hpa-details.scss b/src/renderer/components/+config-autoscalers/hpa-details.scss index ef9506976f..c1c6e930fc 100644 --- a/src/renderer/components/+config-autoscalers/hpa-details.scss +++ b/src/renderer/components/+config-autoscalers/hpa-details.scss @@ -22,7 +22,7 @@ @import "autoscaler.mixins"; .HpaDetails { - .Badge { + .status { @include hpa-status-bgc; } diff --git a/src/renderer/components/+config-autoscalers/hpa-details.tsx b/src/renderer/components/+config-autoscalers/hpa-details.tsx index 1a6db54e78..cf56b2c35c 100644 --- a/src/renderer/components/+config-autoscalers/hpa-details.tsx +++ b/src/renderer/components/+config-autoscalers/hpa-details.tsx @@ -125,7 +125,7 @@ export class HpaDetails extends React.Component { {hpa.getReplicas()} - + {hpa.getConditions().map(({ type, tooltip, isReady }) => { if (!isReady) return null; diff --git a/src/renderer/components/+config-autoscalers/hpa.scss b/src/renderer/components/+config-autoscalers/hpa.scss index 41fa3f6d08..dc79016fcf 100644 --- a/src/renderer/components/+config-autoscalers/hpa.scss +++ b/src/renderer/components/+config-autoscalers/hpa.scss @@ -38,10 +38,7 @@ &.status { flex: 1.5; @include table-cell-labels-offsets; - - .Badge { - @include hpa-status-bgc; - } + @include hpa-status-bgc; } &.age { diff --git a/src/renderer/components/+config-autoscalers/hpa.tsx b/src/renderer/components/+config-autoscalers/hpa.tsx index eca60e8c63..539bbb18d7 100644 --- a/src/renderer/components/+config-autoscalers/hpa.tsx +++ b/src/renderer/components/+config-autoscalers/hpa.tsx @@ -104,6 +104,7 @@ export class HorizontalPodAutoscalers extends React.Component { label={type} tooltip={tooltip} className={cssNames(type.toLowerCase())} + expandable={false} /> ); }) diff --git a/src/renderer/components/+config-secrets/secrets.tsx b/src/renderer/components/+config-secrets/secrets.tsx index d74305a499..3bfeada163 100644 --- a/src/renderer/components/+config-secrets/secrets.tsx +++ b/src/renderer/components/+config-secrets/secrets.tsx @@ -79,7 +79,7 @@ export class Secrets extends React.Component { secret.getName(), , secret.getNs(), - secret.getLabels().map(label => ), + secret.getLabels().map(label => ), secret.getKeys().join(", "), secret.type, secret.getAge(), diff --git a/src/renderer/components/+custom-resources/crd-details.scss b/src/renderer/components/+custom-resources/crd-details.scss index e5d016bb30..8e969a580b 100644 --- a/src/renderer/components/+custom-resources/crd-details.scss +++ b/src/renderer/components/+custom-resources/crd-details.scss @@ -23,11 +23,9 @@ .CRDDetails { .conditions { - .Badge { - @include crd-condition-bgc; - } + @include crd-condition-bgc; } - + .Table { margin-left: -$margin * 2; margin-right: -$margin * 2; @@ -41,21 +39,8 @@ flex: 0.5; } - .description { - flex: 1.5; - - .Badge { - background: transparent; - } - } - .json-path { flex: 3; - - .Badge { - white-space: pre-line; - text-overflow: initial; - } } } } diff --git a/src/renderer/components/+custom-resources/crd-details.tsx b/src/renderer/components/+custom-resources/crd-details.tsx index 146c299884..bef1dc6f67 100644 --- a/src/renderer/components/+custom-resources/crd-details.tsx +++ b/src/renderer/components/+custom-resources/crd-details.tsx @@ -25,7 +25,6 @@ import React from "react"; import { Link } from "react-router-dom"; import { observer } from "mobx-react"; import type { CustomResourceDefinition } from "../../api/endpoints/crd.api"; -import { cssNames } from "../../utils"; import { AceEditor } from "../ace-editor"; import { Badge } from "../badge"; import { DrawerItem, DrawerTitle } from "../drawer"; @@ -86,7 +85,8 @@ export class CRDDetails extends React.Component {

{message}

diff --git a/src/renderer/components/+custom-resources/crd-resource-details.scss b/src/renderer/components/+custom-resources/crd-resource-details.scss index af2c36ef2c..b7e57a0295 100644 --- a/src/renderer/components/+custom-resources/crd-resource-details.scss +++ b/src/renderer/components/+custom-resources/crd-resource-details.scss @@ -21,13 +21,9 @@ .CrdResourceDetails { .status { - .value { - .Badge { - &.ready { - color: white; - background-color: $colorOk; - } - } + .ready { + color: white; + background-color: $colorOk; } } } \ No newline at end of file diff --git a/src/renderer/components/+custom-resources/crd-resource-details.tsx b/src/renderer/components/+custom-resources/crd-resource-details.tsx index f7305788eb..dc6181c63c 100644 --- a/src/renderer/components/+custom-resources/crd-resource-details.tsx +++ b/src/renderer/components/+custom-resources/crd-resource-details.tsx @@ -90,7 +90,8 @@ export class CrdResourceDetails extends React.Component { .map(({ kind, message, status }, index) => ( )); diff --git a/src/renderer/components/+custom-resources/crd.mixins.scss b/src/renderer/components/+custom-resources/crd.mixins.scss index 62a160b1ff..89c7c86acc 100644 --- a/src/renderer/components/+custom-resources/crd.mixins.scss +++ b/src/renderer/components/+custom-resources/crd.mixins.scss @@ -30,7 +30,7 @@ $crd-condition-colors: ( @mixin crd-condition-bgc { @each $status, $color in $crd-condition-colors { - &.#{$status} { + .#{$status} { background: $color; color: white; } diff --git a/src/renderer/components/+nodes/node-details.scss b/src/renderer/components/+nodes/node-details.scss index 895fdadfee..8d7672fde5 100644 --- a/src/renderer/components/+nodes/node-details.scss +++ b/src/renderer/components/+nodes/node-details.scss @@ -24,9 +24,6 @@ --status-default-bg: #{$colorError}; .conditions { - .Badge { - cursor: default; - @include node-status-bgs; - } + @include node-status-bgs; } } \ No newline at end of file diff --git a/src/renderer/components/+nodes/nodes-mixins.scss b/src/renderer/components/+nodes/nodes-mixins.scss index 5ac0e4400a..74979c7a9f 100644 --- a/src/renderer/components/+nodes/nodes-mixins.scss +++ b/src/renderer/components/+nodes/nodes-mixins.scss @@ -33,7 +33,7 @@ $node-status-color-list: ( @mixin node-status-bgs { @each $status, $color in $node-status-color-list { - &.#{$status} { + .#{$status} { background: $color; color: white; } diff --git a/src/renderer/components/+workloads-cronjobs/cronjob-details.scss b/src/renderer/components/+workloads-cronjobs/cronjob-details.scss index 513afd4273..f5e3c76ec8 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob-details.scss +++ b/src/renderer/components/+workloads-cronjobs/cronjob-details.scss @@ -33,8 +33,6 @@ } .conditions { - .Badge { - @include job-condition-bgs; - } + @include job-condition-bgs; } } \ No newline at end of file diff --git a/src/renderer/components/+workloads-deployments/deployment-details.scss b/src/renderer/components/+workloads-deployments/deployment-details.scss index 75ff19bbd4..490edf169f 100644 --- a/src/renderer/components/+workloads-deployments/deployment-details.scss +++ b/src/renderer/components/+workloads-deployments/deployment-details.scss @@ -21,21 +21,19 @@ .DeploymentDetails { .conditions { - .Badge { - &.available { - color: white; - background-color: $deployment-available; - } + .available { + color: white; + background-color: $deployment-available; + } - &.progressing { - color: white; - background-color: $deployment-progressing; - } + .progressing { + color: white; + background-color: $deployment-progressing; + } - &.replica-failure { - color: white; - background-color: $deployment-replicafailure; - } + .replica-failure { + color: white; + background-color: $deployment-replicafailure; } } } \ No newline at end of file diff --git a/src/renderer/components/+workloads-deployments/deployment-details.tsx b/src/renderer/components/+workloads-deployments/deployment-details.tsx index acd514749f..87f4e08378 100644 --- a/src/renderer/components/+workloads-deployments/deployment-details.tsx +++ b/src/renderer/components/+workloads-deployments/deployment-details.tsx @@ -27,7 +27,6 @@ import { disposeOnUnmount, observer } from "mobx-react"; import { DrawerItem } from "../drawer"; import { Badge } from "../badge"; import type { Deployment } from "../../api/endpoints"; -import { cssNames } from "../../utils"; import { PodDetailsTolerations } from "../+workloads-pods/pod-details-tolerations"; import { PodDetailsAffinities } from "../+workloads-pods/pod-details-affinities"; import { podsStore } from "../+workloads-pods/pods.store"; @@ -118,7 +117,8 @@ export class DeploymentDetails extends React.Component {

{message}

diff --git a/src/renderer/components/+workloads-jobs/job-details.scss b/src/renderer/components/+workloads-jobs/job-details.scss index ffd78bc791..8ac3a66a93 100644 --- a/src/renderer/components/+workloads-jobs/job-details.scss +++ b/src/renderer/components/+workloads-jobs/job-details.scss @@ -22,8 +22,6 @@ .JobDetails { .conditions { - .Badge { - @include job-condition-bgs; - } + @include job-condition-bgs; } } \ No newline at end of file diff --git a/src/renderer/components/+workloads-pods/pod-details-container.scss b/src/renderer/components/+workloads-pods/pod-details-container.scss index dc670c4c09..fca42c9433 100644 --- a/src/renderer/components/+workloads-pods/pod-details-container.scss +++ b/src/renderer/components/+workloads-pods/pod-details-container.scss @@ -58,8 +58,4 @@ @include pod-status-colors; } - - .Badge { - white-space: normal; - } } \ No newline at end of file diff --git a/src/renderer/components/+workloads-pods/pod-details.tsx b/src/renderer/components/+workloads-pods/pod-details.tsx index 2a7516b816..2bb08deeff 100644 --- a/src/renderer/components/+workloads-pods/pod-details.tsx +++ b/src/renderer/components/+workloads-pods/pod-details.tsx @@ -142,7 +142,7 @@ export class PodDetails extends React.Component { ); diff --git a/src/renderer/components/+workloads-pods/pods.tsx b/src/renderer/components/+workloads-pods/pods.tsx index 807d531b20..d7ef7175e8 100644 --- a/src/renderer/components/+workloads-pods/pods.tsx +++ b/src/renderer/components/+workloads-pods/pods.tsx @@ -127,7 +127,7 @@ export class Pods extends React.Component { { title: "Status", className: "status", sortBy: columnId.status, id: columnId.status }, ]} renderTableContents={(pod: Pod) => [ - , + , , pod.getNs(), this.renderContainersStatus(pod), @@ -145,7 +145,7 @@ export class Pods extends React.Component { ); }), pod.getNodeName() ? - + {pod.getNodeName()} diff --git a/src/renderer/components/+workloads/workloads-mixins.scss b/src/renderer/components/+workloads/workloads-mixins.scss index 61a56f03f8..03c05c2d48 100644 --- a/src/renderer/components/+workloads/workloads-mixins.scss +++ b/src/renderer/components/+workloads/workloads-mixins.scss @@ -98,7 +98,7 @@ $cronjob-condition-color-list: ( @mixin job-condition-bgs { @each $condition, $color in $job-condition-color-list { - &.#{$condition} { + .#{$condition} { color: white; background: $color; } diff --git a/src/renderer/components/badge/badge.scss b/src/renderer/components/badge/badge.module.css similarity index 75% rename from src/renderer/components/badge/badge.scss rename to src/renderer/components/badge/badge.module.css index 23f8e99ff0..19dc8c7631 100644 --- a/src/renderer/components/badge/badge.scss +++ b/src/renderer/components/badge/badge.module.css @@ -19,25 +19,41 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -.Badge { +.badge { + position: relative; display: inline-block; - white-space: nowrap; max-width: 100%; +} + +.badge + .badge { + margin-left: 8px; +} + +.badge.interactive:hover { + background-color: var(--mainBackground); + cursor: pointer; +} + +.badge:not(.isExpanded) { + white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - - &:not(.flat) { - background: $colorVague; - color: $textColorSecondary; - border-radius: $radius; - padding: .2em .4em; - } - - &.small { - font-size: $font-size-small; - } - - &.clickable { - cursor: pointer; - } +} + +.badge:not(.flat) { + background: var(--colorVague); + border-radius: 3px; + padding: .2em .4em; +} + +.small { + font-size: var(--font-size-small); +} + +.clickable { + cursor: pointer; +} + +.disabled { + opacity: 0.5; } diff --git a/src/renderer/components/badge/badge.tsx b/src/renderer/components/badge/badge.tsx index 14959b04d1..a16b5482c0 100644 --- a/src/renderer/components/badge/badge.tsx +++ b/src/renderer/components/badge/badge.tsx @@ -19,29 +19,84 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import "./badge.scss"; +import styles from "./badge.module.css"; import React from "react"; +import { computed, makeObservable, observable } from "mobx"; +import { observer } from "mobx-react"; import { cssNames } from "../../utils/cssNames"; import { TooltipDecoratorProps, withTooltip } from "../tooltip"; +import { boundMethod } from "../../utils"; export interface BadgeProps extends React.HTMLAttributes, TooltipDecoratorProps { small?: boolean; flat?: boolean; label?: React.ReactNode; + expandable?: boolean; + disabled?: boolean; } +// Common handler for all Badge instances +document.addEventListener("selectionchange", () => { + Badge.badgeMeta.hasTextSelected ||= window.getSelection().toString().trim().length > 0; +}); + @withTooltip +@observer export class Badge extends React.Component { - render() { - const { className, label, small, flat, children, ...elemProps } = this.props; - const clickable = Boolean(this.props.onClick); + static defaultProps: Partial = { + expandable: true + }; - return <> - + static badgeMeta = observable({ + hasTextSelected: false + }); + + @observable.ref elem: HTMLElement; + @observable isExpanded = false; + + constructor(props: BadgeProps) { + super(props); + makeObservable(this); + } + + @computed get isExpandable() { + if (!this.props.expandable) return false; + + return this.elem?.clientWidth < this.elem?.scrollWidth; + } + + @boundMethod + onMouseUp() { + if (!this.isExpandable || Badge.badgeMeta.hasTextSelected) { + Badge.badgeMeta.hasTextSelected = false; + } else { + this.isExpanded = !this.isExpanded; + } + } + + @boundMethod + bindRef(elem: HTMLElement) { + this.elem = elem; + } + + render() { + const { className, label, disabled, small, children, flat, expandable, ...elemProps } = this.props; + const clickable = Boolean(this.props.onClick) || this.isExpandable; + const classNames = cssNames(styles.badge, className, { + [styles.small]: small, + [styles.flat]: flat, + [styles.clickable]: clickable, + [styles.interactive]: this.isExpandable, + [styles.isExpanded]: this.isExpanded, + [styles.disabled]: disabled + }); + + return ( +
{label} {children} - - ; +
+ ); } } diff --git a/src/renderer/components/chart/chart.scss b/src/renderer/components/chart/chart.scss index 3429b251f9..554d62b883 100644 --- a/src/renderer/components/chart/chart.scss +++ b/src/renderer/components/chart/chart.scss @@ -29,7 +29,7 @@ } .legend { - .Badge { + .LegendBadge { background: transparent; transition: background-color 250ms; white-space: normal; diff --git a/src/renderer/components/chart/chart.tsx b/src/renderer/components/chart/chart.tsx index b68ece5523..d456c397d1 100644 --- a/src/renderer/components/chart/chart.tsx +++ b/src/renderer/components/chart/chart.tsx @@ -169,7 +169,7 @@ export class Chart extends React.Component { const labelElem = (title: string, color: string, tooltip?: string) => ( @@ -177,6 +177,7 @@ export class Chart extends React.Component {
)} tooltip={tooltip} + expandable={false} /> ); diff --git a/src/renderer/components/chart/pie-chart.scss b/src/renderer/components/chart/pie-chart.scss index 7034ee28a1..76c098e39d 100644 --- a/src/renderer/components/chart/pie-chart.scss +++ b/src/renderer/components/chart/pie-chart.scss @@ -30,7 +30,7 @@ flex-direction: column; > * { - &.Badge:hover { + &.LegendBadge:hover { background-color: transparent; } diff --git a/src/renderer/components/cluster-settings/components/cluster-show-metrics.tsx b/src/renderer/components/cluster-settings/components/cluster-show-metrics.tsx index 6544f2325b..effdc16160 100644 --- a/src/renderer/components/cluster-settings/components/cluster-show-metrics.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-show-metrics.tsx @@ -69,13 +69,14 @@ export class ShowMetricsSetting extends React.Component { const tooltipId = `${name}`; return ( - + {name} this.removeMetric(name)} tooltip="Remove" + className="mx-3" /> ); diff --git a/src/renderer/components/dock/info-panel.scss b/src/renderer/components/dock/info-panel.scss index 24b727f5d8..0933b236c1 100644 --- a/src/renderer/components/dock/info-panel.scss +++ b/src/renderer/components/dock/info-panel.scss @@ -30,10 +30,6 @@ margin-right: var(--padding); } - .Badge { - background-color: var(--dockBadgeBackground); - } - > .controls { white-space: nowrap; flex: 1 1; diff --git a/src/renderer/components/drawer/drawer-item.scss b/src/renderer/components/drawer/drawer-item.scss index a884be9576..37ea87947b 100644 --- a/src/renderer/components/drawer/drawer-item.scss +++ b/src/renderer/components/drawer/drawer-item.scss @@ -67,7 +67,7 @@ margin: 0; } - .Badge { + > div { float: left; margin: $spacing; diff --git a/src/renderer/components/hotbar/hotbar-selector.scss b/src/renderer/components/hotbar/hotbar-selector.scss index 4db5ae9900..d0fe3fa57c 100644 --- a/src/renderer/components/hotbar/hotbar-selector.scss +++ b/src/renderer/components/hotbar/hotbar-selector.scss @@ -33,7 +33,7 @@ top: -20px; } - .Badge { + .SelectorIndex { cursor: pointer; background: var(--secondaryBackground); width: 100%; diff --git a/src/renderer/components/hotbar/hotbar-selector.tsx b/src/renderer/components/hotbar/hotbar-selector.tsx index f0ca39d834..3bac4475fe 100644 --- a/src/renderer/components/hotbar/hotbar-selector.tsx +++ b/src/renderer/components/hotbar/hotbar-selector.tsx @@ -49,6 +49,7 @@ export function HotbarSelector({ hotbar }: Props) { preferredPositions: [TooltipPosition.TOP, TooltipPosition.TOP_LEFT], children: hotbar.name }} + className="SelectorIndex" /> store.switchToNext()} /> diff --git a/src/renderer/components/icon/icon.scss b/src/renderer/components/icon/icon.scss index b10eb3708b..02501b3716 100644 --- a/src/renderer/components/icon/icon.scss +++ b/src/renderer/components/icon/icon.scss @@ -153,4 +153,4 @@ @extend .active; } } -} \ No newline at end of file +} diff --git a/src/renderer/components/item-object-list/page-filters-list.tsx b/src/renderer/components/item-object-list/page-filters-list.tsx index 1bee3be8ba..6620350b01 100644 --- a/src/renderer/components/item-object-list/page-filters-list.tsx +++ b/src/renderer/components/item-object-list/page-filters-list.tsx @@ -70,7 +70,7 @@ export class PageFiltersList extends React.Component { diff --git a/src/renderer/components/table/table.mixins.scss b/src/renderer/components/table/table.mixins.scss index 3f7a021aff..12e009631d 100644 --- a/src/renderer/components/table/table.mixins.scss +++ b/src/renderer/components/table/table.mixins.scss @@ -49,8 +49,4 @@ @mixin table-cell-labels-offsets { padding-top: $padding / 2; padding-bottom: 0; - - .Badge + .Badge { - margin-left: $padding / 2; - } } \ No newline at end of file From 9e363b8d5f9d971108bce3cd6412042ac670794f Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 13 Jul 2021 11:40:52 -0400 Subject: [PATCH 32/80] Remove win-ca/pem before publish & catch inject error (#3362) --- .azure-pipelines.yml | 38 +++++++++++++++++++------------------- Makefile | 2 ++ src/common/system-ca.ts | 6 +++++- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index afec611177..223f85518d 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -24,12 +24,12 @@ jobs: Write-Output ("##vso[task.setvariable variable=CI_BUILD_TAG;]$CI_BUILD_TAG") condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))" displayName: Set the tag name as an environment variable - + - task: NodeTool@0 inputs: versionSpec: $(node_version) displayName: Install Node.js - + - task: Cache@2 inputs: key: 'yarn | "$(Agent.OS)"" | yarn.lock' @@ -37,7 +37,7 @@ jobs: yarn | "$(Agent.OS)" path: $(YARN_CACHE_FOLDER) displayName: Cache Yarn packages - + - bash: | set -e git clone "https://${GH_TOKEN}@github.com/lensapp/lens-ide.git" .lens-ide-overlay @@ -47,13 +47,13 @@ jobs: env: GH_TOKEN: $(LENS_IDE_GH_TOKEN) displayName: Customize config - + - script: make node_modules displayName: Install dependencies - + - script: make build-npm displayName: Generate npm package - + - script: make build condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))" env: @@ -75,12 +75,12 @@ jobs: - 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/'))" displayName: Set the tag name as an environment variable - + - task: NodeTool@0 inputs: versionSpec: $(node_version) displayName: Install Node.js - + - task: Cache@2 inputs: key: 'yarn | "$(Agent.OS)" | yarn.lock' @@ -88,7 +88,7 @@ jobs: yarn | "$(Agent.OS)" path: $(YARN_CACHE_FOLDER) displayName: Cache Yarn packages - + - bash: | set -e git clone "https://${GH_TOKEN}@github.com/lensapp/lens-ide.git" .lens-ide-overlay @@ -98,13 +98,13 @@ jobs: env: GH_TOKEN: $(LENS_IDE_GH_TOKEN) displayName: Customize config - + - script: make node_modules displayName: Install dependencies - + - script: make build-npm displayName: Generate npm package - + - script: make build condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))" env: @@ -128,12 +128,12 @@ jobs: - 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/'))" displayName: Set the tag name as an environment variable - + - task: NodeTool@0 inputs: versionSpec: $(node_version) displayName: Install Node.js - + - task: Cache@2 inputs: key: 'yarn | "$(Agent.OS)" | yarn.lock' @@ -141,7 +141,7 @@ jobs: yarn | "$(Agent.OS)" path: $(YARN_CACHE_FOLDER) displayName: Cache Yarn packages - + - bash: | set -e git clone "https://${GH_TOKEN}@github.com/lensapp/lens-ide.git" .lens-ide-overlay @@ -151,13 +151,13 @@ jobs: env: GH_TOKEN: $(LENS_IDE_GH_TOKEN) displayName: Customize config - + - script: make node_modules displayName: Install dependencies - + - script: make build-npm displayName: Generate npm package - + - bash: | sudo chown root:root / sudo apt-get update && sudo apt-get install -y snapd @@ -168,7 +168,7 @@ jobs: env: SNAP_LOGIN: $(SNAP_LOGIN) displayName: Setup snapcraft - + - script: make build condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))" env: diff --git a/Makefile b/Makefile index 8b2558e7f7..1a8baf0d37 100644 --- a/Makefile +++ b/Makefile @@ -60,6 +60,8 @@ build: node_modules binaries/client $(MAKE) build-extensions -B yarn run compile ifeq "$(DETECTED_OS)" "Windows" +# https://github.com/ukoloff/win-ca#clear-pem-folder-on-publish + rm -rf node_modules/win-ca/pem yarn run electron-builder --publish onTag --x64 --ia32 else yarn run electron-builder --publish onTag diff --git a/src/common/system-ca.ts b/src/common/system-ca.ts index a12e55cd02..7ed0120569 100644 --- a/src/common/system-ca.ts +++ b/src/common/system-ca.ts @@ -33,5 +33,9 @@ if (isMac) { } if (isWindows) { - winca.inject("+"); // see: https://github.com/ukoloff/win-ca#caveats + try { + winca.inject("+"); // see: https://github.com/ukoloff/win-ca#caveats + } catch (error) { + logger.error(`[CA]: failed to force load: ${error}`); + } } From c335b0f054e641510438557da1924eb77d63abcc Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 13 Jul 2021 12:36:46 -0400 Subject: [PATCH 33/80] Only create TerminalStore after ThemeStore (#3359) - Use Proxy for backwards compatability - Fix a bunch of unit tests that needed all the Singleton's created - Add comments on the order required for the store migrations Signed-off-by: Sebastian Malton --- package.json | 9 +- .../__tests__/page-registry.test.ts | 166 ++-- src/extensions/renderer-api/components.ts | 2 +- src/main/index.ts | 6 +- src/renderer/bootstrap.tsx | 15 +- .../dock/__test__/dock-tabs.test.tsx | 16 +- .../dock/__test__/log-tab.store.test.ts | 16 +- src/renderer/components/dock/dock.store.ts | 11 +- src/renderer/components/dock/log-tab.store.ts | 16 +- .../components/dock/terminal.store.ts | 27 +- src/renderer/components/tabs/tabs.tsx | 37 +- yarn.lock | 879 +++++++++--------- 12 files changed, 634 insertions(+), 566 deletions(-) diff --git a/package.json b/package.json index 80491a71ac..6f7ea53dbf 100644 --- a/package.json +++ b/package.json @@ -63,8 +63,7 @@ }, "moduleNameMapper": { "\\.(css|scss)$": "/__mocks__/styleMock.ts", - "\\.(svg)$": "/__mocks__/imageMock.ts", - "^@lingui/macro$": "/__mocks__/@linguiMacro.ts" + "\\.(svg)$": "/__mocks__/imageMock.ts" }, "modulePathIgnorePatterns": [ "/dist", @@ -218,7 +217,7 @@ "mobx": "^6.3.0", "mobx-observable-history": "^2.0.1", "mobx-react": "^7.1.0", - "mock-fs": "^4.12.0", + "mock-fs": "4.14", "moment": "^2.29.1", "moment-timezone": "^0.5.33", "node-pty": "^0.9.0", @@ -279,7 +278,7 @@ "@types/marked": "^2.0.3", "@types/md5-file": "^4.0.2", "@types/mini-css-extract-plugin": "^0.9.1", - "@types/mock-fs": "^4.10.0", + "@types/mock-fs": "^4.13.1", "@types/module-alias": "^2.0.0", "@types/node": "12.20", "@types/npm": "^2.0.31", @@ -339,7 +338,7 @@ "html-webpack-plugin": "^4.5.2", "identity-obj-proxy": "^3.0.0", "include-media": "^1.4.9", - "jest": "^26.0.1", + "jest": "26.6.3", "jest-canvas-mock": "^2.3.0", "jest-fetch-mock": "^3.0.3", "jest-mock-extended": "^1.0.16", diff --git a/src/extensions/registries/__tests__/page-registry.test.ts b/src/extensions/registries/__tests__/page-registry.test.ts index ed9bf983cd..9a64d95b6b 100644 --- a/src/extensions/registries/__tests__/page-registry.test.ts +++ b/src/extensions/registries/__tests__/page-registry.test.ts @@ -22,14 +22,24 @@ import { ClusterPageRegistry, getExtensionPageUrl, GlobalPageRegistry, PageParams } from "../page-registry"; import { LensExtension } from "../../lens-extension"; import React from "react"; +import fse from "fs-extra"; import { Console } from "console"; import { stdout, stderr } from "process"; +import { ThemeStore } from "../../../renderer/theme.store"; +import { TerminalStore } from "../../renderer-api/components"; +import { UserStore } from "../../../common/user-store"; + +jest.mock("electron", () => ({ + app: { + getPath: () => "tmp", + }, +})); console = new Console(stdout, stderr); let ext: LensExtension = null; -describe("getPageUrl", () => { +describe("page registry tests", () => { beforeEach(async () => { ext = new LensExtension({ manifest: { @@ -43,6 +53,9 @@ describe("getPageUrl", () => { isEnabled: true, isCompatible: true }); + UserStore.createInstance(); + ThemeStore.createInstance(); + TerminalStore.createInstance(); ClusterPageRegistry.createInstance(); GlobalPageRegistry.createInstance().add({ id: "page-with-params", @@ -54,70 +67,6 @@ describe("getPageUrl", () => { test2: "" // no default value, just declaration }, }, ext); - }); - - afterEach(() => { - GlobalPageRegistry.resetInstance(); - ClusterPageRegistry.resetInstance(); - }); - - it("returns a page url for extension", () => { - expect(getExtensionPageUrl({ extensionId: ext.name })).toBe("/extension/foo-bar"); - }); - - it("allows to pass base url as parameter", () => { - expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "/test" })).toBe("/extension/foo-bar/test"); - }); - - it("removes @ and replace `/` to `--`", () => { - expect(getExtensionPageUrl({ extensionId: "@foo/bar" })).toBe("/extension/foo--bar"); - }); - - it("adds / prefix", () => { - expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "test" })).toBe("/extension/foo-bar/test"); - }); - - it("normalize possible multi-slashes in page.id", () => { - expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "//test/" })).toBe("/extension/foo-bar/test"); - }); - - it("gets page url with custom params", () => { - const params: PageParams = { test1: "one", test2: "2" }; - const searchParams = new URLSearchParams(params); - const pageUrl = getExtensionPageUrl({ - extensionId: ext.name, - pageId: "page-with-params", - params, - }); - - expect(pageUrl).toBe(`/extension/foo-bar/page-with-params?${searchParams}`); - }); - - it("gets page url with default custom params", () => { - const defaultPageUrl = getExtensionPageUrl({ - extensionId: ext.name, - pageId: "page-with-params", - }); - - expect(defaultPageUrl).toBe(`/extension/foo-bar/page-with-params?test1=test1-default`); - }); -}); - -describe("globalPageRegistry", () => { - beforeEach(async () => { - ext = new LensExtension({ - manifest: { - name: "@acme/foo-bar", - version: "0.1.1" - }, - id: "/this/is/fake/package.json", - absolutePath: "/absolute/fake/", - manifestPath: "/this/is/fake/package.json", - isBundled: false, - isEnabled: true, - isCompatible: true - }); - ClusterPageRegistry.createInstance(); GlobalPageRegistry.createInstance().add([ { id: "test-page", @@ -142,33 +91,82 @@ describe("globalPageRegistry", () => { afterEach(() => { GlobalPageRegistry.resetInstance(); ClusterPageRegistry.resetInstance(); + TerminalStore.resetInstance(); + ThemeStore.resetInstance(); + UserStore.resetInstance(); + fse.remove("tmp"); }); - describe("getByPageTarget", () => { - it("matching to first registered page without id", () => { - const page = GlobalPageRegistry.getInstance().getByPageTarget({ extensionId: ext.name }); - - expect(page.id).toEqual(undefined); - expect(page.extensionId).toEqual(ext.name); - expect(page.url).toEqual(getExtensionPageUrl({ extensionId: ext.name })); + describe("getPageUrl", () => { + it("returns a page url for extension", () => { + expect(getExtensionPageUrl({ extensionId: ext.name })).toBe("/extension/foo-bar"); }); - it("returns matching page", () => { - const page = GlobalPageRegistry.getInstance().getByPageTarget({ - pageId: "test-page", - extensionId: ext.name - }); - - expect(page.id).toEqual("test-page"); + it("allows to pass base url as parameter", () => { + expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "/test" })).toBe("/extension/foo-bar/test"); }); - it("returns null if target not found", () => { - const page = GlobalPageRegistry.getInstance().getByPageTarget({ - pageId: "wrong-page", - extensionId: ext.name + it("removes @ and replace `/` to `--`", () => { + expect(getExtensionPageUrl({ extensionId: "@foo/bar" })).toBe("/extension/foo--bar"); + }); + + it("adds / prefix", () => { + expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "test" })).toBe("/extension/foo-bar/test"); + }); + + it("normalize possible multi-slashes in page.id", () => { + expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "//test/" })).toBe("/extension/foo-bar/test"); + }); + + it("gets page url with custom params", () => { + const params: PageParams = { test1: "one", test2: "2" }; + const searchParams = new URLSearchParams(params); + const pageUrl = getExtensionPageUrl({ + extensionId: ext.name, + pageId: "page-with-params", + params, }); - expect(page).toBeNull(); + expect(pageUrl).toBe(`/extension/foo-bar/page-with-params?${searchParams}`); + }); + + it("gets page url with default custom params", () => { + const defaultPageUrl = getExtensionPageUrl({ + extensionId: ext.name, + pageId: "page-with-params", + }); + + expect(defaultPageUrl).toBe(`/extension/foo-bar/page-with-params?test1=test1-default`); + }); + }); + + describe("globalPageRegistry", () => { + describe("getByPageTarget", () => { + it("matching to first registered page without id", () => { + const page = GlobalPageRegistry.getInstance().getByPageTarget({ extensionId: ext.name }); + + expect(page.id).toEqual(undefined); + expect(page.extensionId).toEqual(ext.name); + expect(page.url).toEqual(getExtensionPageUrl({ extensionId: ext.name })); + }); + + it("returns matching page", () => { + const page = GlobalPageRegistry.getInstance().getByPageTarget({ + pageId: "test-page", + extensionId: ext.name + }); + + expect(page.id).toEqual("test-page"); + }); + + it("returns null if target not found", () => { + const page = GlobalPageRegistry.getInstance().getByPageTarget({ + pageId: "wrong-page", + extensionId: ext.name + }); + + expect(page).toBeNull(); + }); }); }); }); diff --git a/src/extensions/renderer-api/components.ts b/src/extensions/renderer-api/components.ts index f19ef18f7a..cb4cfd0377 100644 --- a/src/extensions/renderer-api/components.ts +++ b/src/extensions/renderer-api/components.ts @@ -67,5 +67,5 @@ export * from "../../renderer/components/+events/kube-event-details"; // specific exports export * from "../../renderer/components/status-brick"; -export { terminalStore, createTerminalTab } from "../../renderer/components/dock/terminal.store"; +export { terminalStore, createTerminalTab, TerminalStore } from "../../renderer/components/dock/terminal.store"; export { logTabStore } from "../../renderer/components/dock/log-tab.store"; diff --git a/src/main/index.ts b/src/main/index.ts index 91a9b7c68a..684a2e5fb2 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -62,7 +62,7 @@ import { FilesystemProvisionerStore } from "./extension-filesystem"; import { SentryInit } from "../common/sentry"; // This has to be called before start using winton-based logger -// For example, before any logger.log +// For example, before any logger.log SentryInit(); const workingDir = path.join(app.getPath("appData"), appName); @@ -145,8 +145,12 @@ app.on("ready", async () => { UserStore.createInstance().startMainReactions(); + // ClusterStore depends on: UserStore ClusterStore.createInstance().provideInitialFromMain(); + + // HotbarStore depends on: ClusterStore HotbarStore.createInstance(); + ExtensionsStore.createInstance(); FilesystemProvisionerStore.createInstance(); WeblinkStore.createInstance(); diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx index cde700e2b5..132abc9cd6 100644 --- a/src/renderer/bootstrap.tsx +++ b/src/renderer/bootstrap.tsx @@ -48,6 +48,7 @@ import { ExtensionsStore } from "../extensions/extensions-store"; import { FilesystemProvisionerStore } from "../main/extension-filesystem"; import { ThemeStore } from "./theme.store"; import { SentryInit } from "../common/sentry"; +import { TerminalStore } from "./components/dock/terminal.store"; configurePackages(); @@ -89,18 +90,28 @@ export async function bootstrap(App: AppComponent) { SentryInit(); - await ClusterStore.createInstance().loadInitialOnRenderer(); + // ClusterStore depends on: UserStore + const cs = ClusterStore.createInstance(); + + await cs.loadInitialOnRenderer(); + + // HotbarStore depends on: ClusterStore HotbarStore.createInstance(); ExtensionsStore.createInstance(); FilesystemProvisionerStore.createInstance(); + + // ThemeStore depends on: UserStore ThemeStore.createInstance(); + + // TerminalStore depends on: ThemeStore + TerminalStore.createInstance(); WeblinkStore.createInstance(); ExtensionInstallationStateStore.bindIpcListeners(); HelmRepoManager.createInstance(); // initialize the manager // Register additional store listeners - ClusterStore.getInstance().registerIpcListener(); + cs.registerIpcListener(); // init app's dependencies if any if (App.init) { diff --git a/src/renderer/components/dock/__test__/dock-tabs.test.tsx b/src/renderer/components/dock/__test__/dock-tabs.test.tsx index e2061c6543..cdc1994f65 100644 --- a/src/renderer/components/dock/__test__/dock-tabs.test.tsx +++ b/src/renderer/components/dock/__test__/dock-tabs.test.tsx @@ -22,14 +22,18 @@ import React from "react"; import { fireEvent, render } from "@testing-library/react"; import "@testing-library/jest-dom/extend-expect"; +import fse from "fs-extra"; import { DockTabs } from "../dock-tabs"; import { dockStore, DockTab, TabKind } from "../dock.store"; import { noop } from "../../../utils"; +import { ThemeStore } from "../../../theme.store"; +import { TerminalStore } from "../terminal.store"; +import { UserStore } from "../../../../common/user-store"; jest.mock("electron", () => ({ app: { - getPath: () => "/foo", + getPath: () => "tmp", }, })); @@ -55,10 +59,20 @@ const getTabKinds = () => dockStore.tabs.map(tab => tab.kind); describe("", () => { beforeEach(async () => { + UserStore.createInstance(); + ThemeStore.createInstance(); + TerminalStore.createInstance(); await dockStore.whenReady; dockStore.tabs = initialTabs; }); + afterEach(() => { + ThemeStore.resetInstance(); + TerminalStore.resetInstance(); + UserStore.resetInstance(); + fse.remove("tmp"); + }); + it("renders w/o errors", () => { const { container } = renderTabs(); diff --git a/src/renderer/components/dock/__test__/log-tab.store.test.ts b/src/renderer/components/dock/__test__/log-tab.store.test.ts index 3e1542ed6a..da7d0b1052 100644 --- a/src/renderer/components/dock/__test__/log-tab.store.test.ts +++ b/src/renderer/components/dock/__test__/log-tab.store.test.ts @@ -20,14 +20,18 @@ */ import { podsStore } from "../../+workloads-pods/pods.store"; +import { UserStore } from "../../../../common/user-store"; import { Pod } from "../../../api/endpoints"; +import { ThemeStore } from "../../../theme.store"; import { dockStore } from "../dock.store"; import { logTabStore } from "../log-tab.store"; +import { TerminalStore } from "../terminal.store"; import { deploymentPod1, deploymentPod2, deploymentPod3, dockerPod } from "./pod.mock"; +import fse from "fs-extra"; jest.mock("electron", () => ({ app: { - getPath: () => "/foo", + getPath: () => "tmp", }, })); @@ -36,9 +40,19 @@ podsStore.items.push(new Pod(deploymentPod1)); podsStore.items.push(new Pod(deploymentPod2)); describe("log tab store", () => { + beforeEach(() => { + UserStore.createInstance(); + ThemeStore.createInstance(); + TerminalStore.createInstance(); + }); + afterEach(() => { logTabStore.reset(); dockStore.reset(); + UserStore.resetInstance(); + ThemeStore.resetInstance(); + TerminalStore.resetInstance(); + fse.remove("tmp"); }); it("creates log tab without sibling pods", () => { diff --git a/src/renderer/components/dock/dock.store.ts b/src/renderer/components/dock/dock.store.ts index 516aba403b..eb5902d7db 100644 --- a/src/renderer/components/dock/dock.store.ts +++ b/src/renderer/components/dock/dock.store.ts @@ -136,7 +136,12 @@ export class DockStore implements DockStorageState { } get selectedTabId(): TabId | undefined { - return this.storage.get().selectedTabId || this.tabs[0]?.id; + return this.storage.get().selectedTabId + || ( + this.tabs.length > 0 + ? this.tabs[0]?.id + : undefined + ); } set selectedTabId(tabId: TabId) { @@ -277,9 +282,9 @@ export class DockStore implements DockStorageState { if (newTab?.kind === TabKind.TERMINAL) { // close the dock when selected sibling inactive terminal tab - const { terminalStore } = await import("./terminal.store"); + const { TerminalStore } = await import("./terminal.store"); - if (!terminalStore.isConnected(newTab.id)) this.close(); + if (!TerminalStore.getInstance(false)?.isConnected(newTab.id)) this.close(); } this.selectTab(newTab.id); } else { diff --git a/src/renderer/components/dock/log-tab.store.ts b/src/renderer/components/dock/log-tab.store.ts index 50be7a1e34..bd7d61539b 100644 --- a/src/renderer/components/dock/log-tab.store.ts +++ b/src/renderer/components/dock/log-tab.store.ts @@ -108,8 +108,10 @@ export class LogTabStore extends DockTabStore { }); } - private updateTabsData() { - this.data.forEach((tabData, tabId) => { + private async updateTabsData() { + const promises: Promise[] = []; + + for (const [tabId, tabData] of this.data) { const pod = new Pod(tabData.selectedPod); const pods = podsStore.getPodsByOwnerId(pod.getOwnerRefs()[0]?.uid); const isSelectedPodInList = pods.find(item => item.getId() == pod.getId()); @@ -126,14 +128,16 @@ export class LogTabStore extends DockTabStore { this.renameTab(tabId); } else { - this.closeTab(tabId); + promises.push(this.closeTab(tabId)); } - }); + } + + await Promise.all(promises); } - private closeTab(tabId: string) { + private async closeTab(tabId: string) { this.clearData(tabId); - dockStore.closeTab(tabId); + await dockStore.closeTab(tabId); } } diff --git a/src/renderer/components/dock/terminal.store.ts b/src/renderer/components/dock/terminal.store.ts index 47d100b3ab..fb3359368d 100644 --- a/src/renderer/components/dock/terminal.store.ts +++ b/src/renderer/components/dock/terminal.store.ts @@ -20,7 +20,7 @@ */ import { autorun, observable } from "mobx"; -import { autoBind } from "../../utils"; +import { autoBind, Singleton } from "../../utils"; import { Terminal } from "./terminal"; import { TerminalApi } from "../../api/terminal-api"; import { dockStore, DockTab, DockTabCreateSpecific, TabId, TabKind } from "./dock.store"; @@ -38,11 +38,12 @@ export function createTerminalTab(tabParams: DockTabCreateSpecific = {}) { }); } -export class TerminalStore { +export class TerminalStore extends Singleton { protected terminals = new Map(); protected connections = observable.map(); constructor() { + super(); autoBind(this); // connect active tab @@ -129,4 +130,24 @@ export class TerminalStore { } } -export const terminalStore = new TerminalStore(); +/** + * @deprecated use `TerminalStore.getInstance()` instead + */ +export const terminalStore = new Proxy({}, { + get(target, p) { + if (p === "$$typeof") { + return "TerminalStore"; + } + + const ts = TerminalStore.getInstance(); + const res = (ts as any)?.[p]; + + if (typeof res === "function") { + return function(...args: any[]) { + return res.apply(ts, args); + }; + } + + return res; + }, +}) as TerminalStore; diff --git a/src/renderer/components/tabs/tabs.tsx b/src/renderer/components/tabs/tabs.tsx index fb3fb5e58c..8a910211fa 100644 --- a/src/renderer/components/tabs/tabs.tsx +++ b/src/renderer/components/tabs/tabs.tsx @@ -84,7 +84,7 @@ export interface TabProps extends DOMAttributes { export class Tab extends React.PureComponent { static contextType = TabsContext; declare context: TabsContextValue; - public elem: HTMLElement; + public ref = React.createRef(); get isActive() { const { active, value } = this.props; @@ -93,11 +93,11 @@ export class Tab extends React.PureComponent { } focus() { - this.elem.focus(); + this.ref.current?.focus(); } scrollIntoView() { - this.elem.scrollIntoView({ + this.ref.current?.scrollIntoView?.({ behavior: "smooth", inline: "center", }); @@ -106,30 +106,28 @@ export class Tab extends React.PureComponent { @boundMethod onClick(evt: React.MouseEvent) { const { value, active, disabled, onClick } = this.props; - const { onChange } = this.context; - if (disabled || active) return; - if (onClick) onClick(evt); - if (onChange) onChange(value); + if (disabled || active) { + return; + } + + onClick?.(evt); + this.context.onChange?.(value); } @boundMethod onFocus(evt: React.FocusEvent) { - const { onFocus } = this.props; - - if (onFocus) onFocus(evt); + this.props.onFocus?.(evt); this.scrollIntoView(); } @boundMethod onKeyDown(evt: React.KeyboardEvent) { - const ENTER_KEY = evt.keyCode === 13; - const SPACE_KEY = evt.keyCode === 32; + if (evt.key === " " || evt.key === "Enter") { + this.ref.current?.click(); + } - if (SPACE_KEY || ENTER_KEY) this.elem.click(); - const { onKeyDown } = this.props; - - if (onKeyDown) onKeyDown(evt); + this.props?.onKeyDown(evt); } componentDidMount() { @@ -138,11 +136,6 @@ export class Tab extends React.PureComponent { } } - @boundMethod - protected bindRef(elem: HTMLElement) { - this.elem = elem; - } - render() { const { active, disabled, icon, label, value, ...elemProps } = this.props; let { className } = this.props; @@ -160,7 +153,7 @@ export class Tab extends React.PureComponent { onClick={this.onClick} onFocus={this.onFocus} onKeyDown={this.onKeyDown} - ref={this.bindRef} + ref={this.ref} > {typeof icon === "string" ? : icon}
diff --git a/yarn.lock b/yarn.lock index d34cce3a5f..cff6305987 100644 --- a/yarn.lock +++ b/yarn.lock @@ -115,6 +115,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.1.tgz#ec5a5cf0eec925b66c60580328b122c01230a127" integrity sha512-fvoGeXt0bJc7VMWZGCAEBEMo/HAjW2mP8apF5eXK0wSqwLAVHAISCWRoLMBMUs2kqeaG77jltVqu4Hn8Egl3nA== +"@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" + integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== + "@babel/helper-replace-supers@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.1.tgz#ec6859d20c5d8087f6a2dc4e014db7228975f13d" @@ -203,6 +208,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.1" +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" @@ -252,6 +264,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/runtime-corejs3@^7.10.2": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.12.1.tgz#51b9092befbeeed938335a109dbe0df51451e9dc" @@ -587,156 +606,160 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== -"@jest/console@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.0.1.tgz#62b3b2fa8990f3cbffbef695c42ae9ddbc8f4b39" - integrity sha512-9t1KUe/93coV1rBSxMmBAOIK3/HVpwxArCA1CxskKyRiv6o8J70V8C/V3OJminVCTa2M0hQI9AWRd5wxu2dAHw== +"@jest/console@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" + integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.6.2" + "@types/node" "*" chalk "^4.0.0" - jest-message-util "^26.0.1" - jest-util "^26.0.1" + jest-message-util "^26.6.2" + jest-util "^26.6.2" slash "^3.0.0" -"@jest/core@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.0.1.tgz#aa538d52497dfab56735efb00e506be83d841fae" - integrity sha512-Xq3eqYnxsG9SjDC+WLeIgf7/8KU6rddBxH+SCt18gEpOhAGYC/Mq+YbtlNcIdwjnnT+wDseXSbU0e5X84Y4jTQ== +"@jest/core@^26.6.3": + version "26.6.3" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" + integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== dependencies: - "@jest/console" "^26.0.1" - "@jest/reporters" "^26.0.1" - "@jest/test-result" "^26.0.1" - "@jest/transform" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/console" "^26.6.2" + "@jest/reporters" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.4" - jest-changed-files "^26.0.1" - jest-config "^26.0.1" - jest-haste-map "^26.0.1" - jest-message-util "^26.0.1" + jest-changed-files "^26.6.2" + jest-config "^26.6.3" + jest-haste-map "^26.6.2" + jest-message-util "^26.6.2" jest-regex-util "^26.0.0" - jest-resolve "^26.0.1" - jest-resolve-dependencies "^26.0.1" - jest-runner "^26.0.1" - jest-runtime "^26.0.1" - jest-snapshot "^26.0.1" - jest-util "^26.0.1" - jest-validate "^26.0.1" - jest-watcher "^26.0.1" + jest-resolve "^26.6.2" + jest-resolve-dependencies "^26.6.3" + jest-runner "^26.6.3" + jest-runtime "^26.6.3" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + jest-watcher "^26.6.2" micromatch "^4.0.2" p-each-series "^2.1.0" rimraf "^3.0.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.0.1.tgz#82f519bba71959be9b483675ee89de8c8f72a5c8" - integrity sha512-xBDxPe8/nx251u0VJ2dFAFz2H23Y98qdIaNwnMK6dFQr05jc+Ne/2np73lOAx+5mSBO/yuQldRrQOf6hP1h92g== +"@jest/environment@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" + integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== dependencies: - "@jest/fake-timers" "^26.0.1" - "@jest/types" "^26.0.1" - jest-mock "^26.0.1" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" -"@jest/fake-timers@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.0.1.tgz#f7aeff13b9f387e9d0cac9a8de3bba538d19d796" - integrity sha512-Oj/kCBnTKhm7CR+OJSjZty6N1bRDr9pgiYQr4wY221azLz5PHi08x/U+9+QpceAYOWheauLP8MhtSVFrqXQfhg== +"@jest/fake-timers@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" + integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.6.2" "@sinonjs/fake-timers" "^6.0.1" - jest-message-util "^26.0.1" - jest-mock "^26.0.1" - jest-util "^26.0.1" + "@types/node" "*" + jest-message-util "^26.6.2" + jest-mock "^26.6.2" + jest-util "^26.6.2" -"@jest/globals@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.0.1.tgz#3f67b508a7ce62b6e6efc536f3d18ec9deb19a9c" - integrity sha512-iuucxOYB7BRCvT+TYBzUqUNuxFX1hqaR6G6IcGgEqkJ5x4htNKo1r7jk1ji9Zj8ZMiMw0oB5NaA7k5Tx6MVssA== +"@jest/globals@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" + integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== dependencies: - "@jest/environment" "^26.0.1" - "@jest/types" "^26.0.1" - expect "^26.0.1" + "@jest/environment" "^26.6.2" + "@jest/types" "^26.6.2" + expect "^26.6.2" -"@jest/reporters@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.0.1.tgz#14ae00e7a93e498cec35b0c00ab21c375d9b078f" - integrity sha512-NWWy9KwRtE1iyG/m7huiFVF9YsYv/e+mbflKRV84WDoJfBqUrNRyDbL/vFxQcYLl8IRqI4P3MgPn386x76Gf2g== +"@jest/reporters@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" + integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^26.0.1" - "@jest/test-result" "^26.0.1" - "@jest/transform" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/console" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" chalk "^4.0.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" glob "^7.1.2" graceful-fs "^4.2.4" istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^4.0.0" + istanbul-lib-instrument "^4.0.3" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.0.2" - jest-haste-map "^26.0.1" - jest-resolve "^26.0.1" - jest-util "^26.0.1" - jest-worker "^26.0.0" + jest-haste-map "^26.6.2" + jest-resolve "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" slash "^3.0.0" source-map "^0.6.0" string-length "^4.0.1" terminal-link "^2.0.0" - v8-to-istanbul "^4.1.3" + v8-to-istanbul "^7.0.0" optionalDependencies: - node-notifier "^7.0.0" + node-notifier "^8.0.0" -"@jest/source-map@^26.0.0": - version "26.0.0" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.0.0.tgz#fd7706484a7d3faf7792ae29783933bbf48a4749" - integrity sha512-S2Z+Aj/7KOSU2TfW0dyzBze7xr95bkm5YXNUqqCek+HE0VbNNSNzrRwfIi5lf7wvzDTSS0/ib8XQ1krFNyYgbQ== +"@jest/source-map@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.6.2.tgz#29af5e1e2e324cafccc936f218309f54ab69d535" + integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== dependencies: callsites "^3.0.0" graceful-fs "^4.2.4" source-map "^0.6.0" -"@jest/test-result@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.0.1.tgz#1ffdc1ba4bc289919e54b9414b74c9c2f7b2b718" - integrity sha512-oKwHvOI73ICSYRPe8WwyYPTtiuOAkLSbY8/MfWF3qDEd/sa8EDyZzin3BaXTqufir/O/Gzea4E8Zl14XU4Mlyg== +"@jest/test-result@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" + integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== dependencies: - "@jest/console" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/console" "^26.6.2" + "@jest/types" "^26.6.2" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.0.1.tgz#b0563424728f3fe9e75d1442b9ae4c11da73f090" - integrity sha512-ssga8XlwfP8YjbDcmVhwNlrmblddMfgUeAkWIXts1V22equp2GMIHxm7cyeD5Q/B0ZgKPK/tngt45sH99yLLGg== +"@jest/test-sequencer@^26.6.3": + version "26.6.3" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz#98e8a45100863886d074205e8ffdc5a7eb582b17" + integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== dependencies: - "@jest/test-result" "^26.0.1" + "@jest/test-result" "^26.6.2" graceful-fs "^4.2.4" - jest-haste-map "^26.0.1" - jest-runner "^26.0.1" - jest-runtime "^26.0.1" + jest-haste-map "^26.6.2" + jest-runner "^26.6.3" + jest-runtime "^26.6.3" -"@jest/transform@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.0.1.tgz#0e3ecbb34a11cd4b2080ed0a9c4856cf0ceb0639" - integrity sha512-pPRkVkAQ91drKGbzCfDOoHN838+FSbYaEAvBXvKuWeeRRUD8FjwXkqfUNUZL6Ke48aA/1cqq/Ni7kVMCoqagWA== +"@jest/transform@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" + integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== dependencies: "@babel/core" "^7.1.0" - "@jest/types" "^26.0.1" + "@jest/types" "^26.6.2" babel-plugin-istanbul "^6.0.0" chalk "^4.0.0" convert-source-map "^1.4.0" fast-json-stable-stringify "^2.0.0" graceful-fs "^4.2.4" - jest-haste-map "^26.0.1" + jest-haste-map "^26.6.2" jest-regex-util "^26.0.0" - jest-util "^26.0.1" + jest-util "^26.6.2" micromatch "^4.0.2" pirates "^4.0.1" slash "^3.0.0" @@ -753,16 +776,6 @@ "@types/yargs" "^15.0.0" chalk "^3.0.0" -"@jest/types@^26.0.1": - version "26.0.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.0.1.tgz#b78333fbd113fa7aec8d39de24f88de8686dac67" - integrity sha512-IbtjvqI9+eS1qFnOIEL7ggWmT+iK/U+Vde9cGWtYb/b6XgKb3X44ZAe/z9YZzoAAZ/E92m0DqrilF934IGNnQA== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^15.0.0" - chalk "^4.0.0" - "@jest/types@^26.3.0": version "26.3.0" resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.3.0.tgz#97627bf4bdb72c55346eef98e3b3f7ddc4941f71" @@ -1217,6 +1230,17 @@ resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.0.tgz#14264692a9d6e2fa4db3df5e56e94b5e25647ac0" integrity sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A== +"@types/babel__core@^7.0.0": + version "7.1.15" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.15.tgz#2ccfb1ad55a02c83f8e0ad327cbc332f55eb1024" + integrity sha512-bxlMKPDbY8x5h6HBwVzEOk2C8fb6SLfYQ5Jw3uBYuYF1lfWk/kbLd81la82vrIkBb0l+JdmrZaDikPrNxpS/Ew== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + "@types/babel__core@^7.1.7": version "7.1.8" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.8.tgz#057f725aca3641f49fc11c7a87a9de5ec588a5d7" @@ -1250,6 +1274,13 @@ dependencies: "@babel/types" "^7.3.0" +"@types/babel__traverse@^7.0.4": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" + integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== + dependencies: + "@babel/types" "^7.3.0" + "@types/body-parser@*": version "1.19.0" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f" @@ -1665,10 +1696,10 @@ dependencies: "@types/node" "*" -"@types/mock-fs@^4.10.0": - version "4.10.0" - resolved "https://registry.yarnpkg.com/@types/mock-fs/-/mock-fs-4.10.0.tgz#460061b186993d76856f669d5317cda8a007c24b" - integrity sha512-FQ5alSzmHMmliqcL36JqIA4Yyn9jyJKvRSGV3mvPh108VFatX7naJDzSG4fnFQNZFq9dIx0Dzoe6ddflMB2Xkg== +"@types/mock-fs@^4.13.1": + version "4.13.1" + resolved "https://registry.yarnpkg.com/@types/mock-fs/-/mock-fs-4.13.1.tgz#9201554ceb23671badbfa8ac3f1fa9e0706305be" + integrity sha512-m6nFAJ3lBSnqbvDZioawRvpLXSaPyn52Srf7OfzjubYbYX8MTUdIgDxQl0wEapm4m/pNYSd9TXocpQ0TvZFlYA== dependencies: "@types/node" "*" @@ -1956,10 +1987,10 @@ dependencies: "@types/node" "*" -"@types/stack-utils@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" - integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== "@types/stream-buffers@^3.0.3": version "3.0.3" @@ -2975,16 +3006,16 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2" integrity sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA== -babel-jest@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.0.1.tgz#450139ce4b6c17174b136425bda91885c397bc46" - integrity sha512-Z4GGmSNQ8pX3WS1O+6v3fo41YItJJZsVxG5gIQ+HuB/iuAQBJxMTHTwz292vuYws1LnHfwSRgoqI+nxdy/pcvw== +babel-jest@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" + integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== dependencies: - "@jest/transform" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" "@types/babel__core" "^7.1.7" babel-plugin-istanbul "^6.0.0" - babel-preset-jest "^26.0.0" + babel-preset-jest "^26.6.2" chalk "^4.0.0" graceful-fs "^4.2.4" slash "^3.0.0" @@ -3016,13 +3047,14 @@ babel-plugin-istanbul@^6.0.0: istanbul-lib-instrument "^4.0.0" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.0.0.tgz#fd1d35f95cf8849fc65cb01b5e58aedd710b34a8" - integrity sha512-+AuoehOrjt9irZL7DOt2+4ZaTM6dlu1s5TTS46JBa0/qem4dy7VNW3tMb96qeEqcIh20LD73TVNtmVEeymTG7w== +babel-plugin-jest-hoist@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" + integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" babel-plugin-macros@^2.0.0: @@ -3039,14 +3071,15 @@ babel-plugin-syntax-jsx@^6.18.0: resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= -babel-preset-current-node-syntax@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.2.tgz#fb4a4c51fe38ca60fede1dc74ab35eb843cb41d6" - integrity sha512-u/8cS+dEiK1SFILbOC8/rUI3ml9lboKuuMvZ/4aQnQmhecQAgPw5ew066C1ObnEAUmlx7dv/s2z52psWEtLNiw== +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-bigint" "^7.8.3" "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" "@babel/plugin-syntax-json-strings" "^7.8.3" "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" @@ -3054,14 +3087,15 @@ babel-preset-current-node-syntax@^0.1.2: "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-jest@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.0.0.tgz#1eac82f513ad36c4db2e9263d7c485c825b1faa6" - integrity sha512-9ce+DatAa31DpR4Uir8g4Ahxs5K4W4L8refzt+qHWQANb6LhGcAEfIFgLUwk67oya2cCUd6t4eUMtO/z64ocNw== +babel-preset-jest@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" + integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== dependencies: - babel-plugin-jest-hoist "^26.0.0" - babel-preset-current-node-syntax "^0.1.2" + babel-plugin-jest-hoist "^26.6.2" + babel-preset-current-node-syntax "^1.0.0" babel-runtime@^6.26.0: version "6.26.0" @@ -3879,6 +3913,11 @@ circular-dependency-plugin@^5.2.2: resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-5.2.2.tgz#39e836079db1d3cf2f988dc48c5188a44058b600" integrity sha512-g38K9Cm5WRwlaH6g03B9OEz/0qRizI+2I7n+Gz+L5DxXJAPAiWQvwlYNm1V1jkdpUv95bOe/ASm2vfi/G560jQ== +cjs-module-lexer@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" + integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== + class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -5030,16 +5069,16 @@ diff-sequences@^25.2.6: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== -diff-sequences@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.0.0.tgz#0760059a5c287637b842bd7085311db7060e88a6" - integrity sha512-JC/eHYEC3aSS0vZGjuoc4vHA0yAQTzhQQldXMeMF+JlxLGJlCO38Gma82NV9gk1jGFz8mDzUMeaKXvjRRdJ2dg== - diff-sequences@^26.5.0: version "26.5.0" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.5.0.tgz#ef766cf09d43ed40406611f11c6d8d9dd8b2fefd" integrity sha512-ZXx86srb/iYy6jG71k++wBN9P9J05UNQ5hQHQd9MtMPvcqXPx/vKU69jfHV637D00Q2gSgPk2D+jSx3l1lDW/Q== +diff-sequences@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" + integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== + diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -5419,6 +5458,11 @@ elliptic@^6.0.0, elliptic@^6.5.2: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +emittery@^0.7.1: + version "0.7.2" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" + integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ== + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -6046,16 +6090,16 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2: dependencies: homedir-polyfill "^1.0.1" -expect@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/expect/-/expect-26.0.1.tgz#18697b9611a7e2725e20ba3ceadda49bc9865421" - integrity sha512-QcCy4nygHeqmbw564YxNbHTJlXh47dVID2BUP52cZFpLU9zHViMFK6h07cC1wf7GYCTIigTdAXhVua8Yl1FkKg== +expect@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" + integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.6.2" ansi-styles "^4.0.0" - jest-get-type "^26.0.0" - jest-matcher-utils "^26.0.1" - jest-message-util "^26.0.1" + jest-get-type "^26.3.0" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" jest-regex-util "^26.0.0" express@^4.17.1: @@ -8233,7 +8277,7 @@ is-wsl@^1.1.0: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= -is-wsl@^2.1.1: +is-wsl@^2.1.1, is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -8296,7 +8340,7 @@ istanbul-lib-coverage@^3.0.0: resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== -istanbul-lib-instrument@^4.0.0: +istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== @@ -8359,57 +8403,57 @@ jest-canvas-mock@^2.3.0: cssfontparser "^1.2.1" moo-color "^1.0.2" -jest-changed-files@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.0.1.tgz#1334630c6a1ad75784120f39c3aa9278e59f349f" - integrity sha512-q8LP9Sint17HaE2LjxQXL+oYWW/WeeXMPE2+Op9X3mY8IEGFVc14xRxFjUuXUbcPAlDLhtWdIEt59GdQbn76Hw== +jest-changed-files@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" + integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.6.2" execa "^4.0.0" throat "^5.0.0" -jest-cli@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.0.1.tgz#3a42399a4cbc96a519b99ad069a117d955570cac" - integrity sha512-pFLfSOBcbG9iOZWaMK4Een+tTxi/Wcm34geqZEqrst9cZDkTQ1LZ2CnBrTlHWuYAiTMFr0EQeK52ScyFU8wK+w== +jest-cli@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" + integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== dependencies: - "@jest/core" "^26.0.1" - "@jest/test-result" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/core" "^26.6.3" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.4" import-local "^3.0.2" is-ci "^2.0.0" - jest-config "^26.0.1" - jest-util "^26.0.1" - jest-validate "^26.0.1" + jest-config "^26.6.3" + jest-util "^26.6.2" + jest-validate "^26.6.2" prompts "^2.0.1" - yargs "^15.3.1" + yargs "^15.4.1" -jest-config@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.0.1.tgz#096a3d4150afadf719d1fab00e9a6fb2d6d67507" - integrity sha512-9mWKx2L1LFgOXlDsC4YSeavnblN6A4CPfXFiobq+YYLaBMymA/SczN7xYTSmLaEYHZOcB98UdoN4m5uNt6tztg== +jest-config@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" + integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== dependencies: "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^26.0.1" - "@jest/types" "^26.0.1" - babel-jest "^26.0.1" + "@jest/test-sequencer" "^26.6.3" + "@jest/types" "^26.6.2" + babel-jest "^26.6.3" chalk "^4.0.0" deepmerge "^4.2.2" glob "^7.1.1" graceful-fs "^4.2.4" - jest-environment-jsdom "^26.0.1" - jest-environment-node "^26.0.1" - jest-get-type "^26.0.0" - jest-jasmine2 "^26.0.1" + jest-environment-jsdom "^26.6.2" + jest-environment-node "^26.6.2" + jest-get-type "^26.3.0" + jest-jasmine2 "^26.6.3" jest-regex-util "^26.0.0" - jest-resolve "^26.0.1" - jest-util "^26.0.1" - jest-validate "^26.0.1" + jest-resolve "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" micromatch "^4.0.2" - pretty-format "^26.0.1" + pretty-format "^26.6.2" jest-diff@^25.2.1: version "25.5.0" @@ -8431,15 +8475,15 @@ jest-diff@^26.0.0: jest-get-type "^26.3.0" pretty-format "^26.6.1" -jest-diff@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.0.1.tgz#c44ab3cdd5977d466de69c46929e0e57f89aa1de" - integrity sha512-odTcHyl5X+U+QsczJmOjWw5tPvww+y9Yim5xzqxVl/R1j4z71+fHW4g8qu1ugMmKdFdxw+AtQgs5mupPnzcIBQ== +jest-diff@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" + integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== dependencies: chalk "^4.0.0" - diff-sequences "^26.0.0" - jest-get-type "^26.0.0" - pretty-format "^26.0.1" + diff-sequences "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" jest-docblock@^26.0.0: version "26.0.0" @@ -8448,39 +8492,41 @@ jest-docblock@^26.0.0: dependencies: detect-newline "^3.0.0" -jest-each@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.0.1.tgz#633083061619302fc90dd8f58350f9d77d67be04" - integrity sha512-OTgJlwXCAR8NIWaXFL5DBbeS4QIYPuNASkzSwMCJO+ywo9BEa6TqkaSWsfR7VdbMLdgYJqSfQcIyjJCNwl5n4Q== +jest-each@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.6.2.tgz#02526438a77a67401c8a6382dfe5999952c167cb" + integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.6.2" chalk "^4.0.0" - jest-get-type "^26.0.0" - jest-util "^26.0.1" - pretty-format "^26.0.1" + jest-get-type "^26.3.0" + jest-util "^26.6.2" + pretty-format "^26.6.2" -jest-environment-jsdom@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.0.1.tgz#217690852e5bdd7c846a4e3b50c8ffd441dfd249" - integrity sha512-u88NJa3aptz2Xix2pFhihRBAatwZHWwSiRLBDBQE1cdJvDjPvv7ZGA0NQBxWwDDn7D0g1uHqxM8aGgfA9Bx49g== +jest-environment-jsdom@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" + integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== dependencies: - "@jest/environment" "^26.0.1" - "@jest/fake-timers" "^26.0.1" - "@jest/types" "^26.0.1" - jest-mock "^26.0.1" - jest-util "^26.0.1" - jsdom "^16.2.2" + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + jest-util "^26.6.2" + jsdom "^16.4.0" -jest-environment-node@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.0.1.tgz#584a9ff623124ff6eeb49e0131b5f7612b310b13" - integrity sha512-4FRBWcSn5yVo0KtNav7+5NH5Z/tEgDLp7VRQVS5tCouWORxj+nI+1tOLutM07Zb2Qi7ja+HEDoOUkjBSWZg/IQ== +jest-environment-node@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.6.2.tgz#824e4c7fb4944646356f11ac75b229b0035f2b0c" + integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== dependencies: - "@jest/environment" "^26.0.1" - "@jest/fake-timers" "^26.0.1" - "@jest/types" "^26.0.1" - jest-mock "^26.0.1" - jest-util "^26.0.1" + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + jest-util "^26.6.2" jest-fetch-mock@^3.0.3: version "3.0.3" @@ -8495,88 +8541,86 @@ jest-get-type@^25.2.6: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== -jest-get-type@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.0.0.tgz#381e986a718998dbfafcd5ec05934be538db4039" - integrity sha512-zRc1OAPnnws1EVfykXOj19zo2EMw5Hi6HLbFCSjpuJiXtOWAYIjNsHVSbpQ8bDX7L5BGYGI8m+HmKdjHYFF0kg== - jest-get-type@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== -jest-haste-map@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.0.1.tgz#40dcc03c43ac94d25b8618075804d09cd5d49de7" - integrity sha512-J9kBl/EdjmDsvyv7CiyKY5+DsTvVOScenprz/fGqfLg/pm1gdjbwwQ98nW0t+OIt+f+5nAVaElvn/6wP5KO7KA== +jest-haste-map@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" + integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.6.2" "@types/graceful-fs" "^4.1.2" + "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" graceful-fs "^4.2.4" - jest-serializer "^26.0.0" - jest-util "^26.0.1" - jest-worker "^26.0.0" + jest-regex-util "^26.0.0" + jest-serializer "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" micromatch "^4.0.2" sane "^4.0.3" walker "^1.0.7" - which "^2.0.2" optionalDependencies: fsevents "^2.1.2" -jest-jasmine2@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.0.1.tgz#947c40ee816636ba23112af3206d6fa7b23c1c1c" - integrity sha512-ILaRyiWxiXOJ+RWTKupzQWwnPaeXPIoLS5uW41h18varJzd9/7I0QJGqg69fhTT1ev9JpSSo9QtalriUN0oqOg== +jest-jasmine2@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" + integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== dependencies: "@babel/traverse" "^7.1.0" - "@jest/environment" "^26.0.1" - "@jest/source-map" "^26.0.0" - "@jest/test-result" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/environment" "^26.6.2" + "@jest/source-map" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" chalk "^4.0.0" co "^4.6.0" - expect "^26.0.1" + expect "^26.6.2" is-generator-fn "^2.0.0" - jest-each "^26.0.1" - jest-matcher-utils "^26.0.1" - jest-message-util "^26.0.1" - jest-runtime "^26.0.1" - jest-snapshot "^26.0.1" - jest-util "^26.0.1" - pretty-format "^26.0.1" + jest-each "^26.6.2" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-runtime "^26.6.3" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + pretty-format "^26.6.2" throat "^5.0.0" -jest-leak-detector@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.0.1.tgz#79b19ab3f41170e0a78eb8fa754a116d3447fb8c" - integrity sha512-93FR8tJhaYIWrWsbmVN1pQ9ZNlbgRpfvrnw5LmgLRX0ckOJ8ut/I35CL7awi2ecq6Ca4lL59bEK9hr7nqoHWPA== +jest-leak-detector@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" + integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== dependencies: - jest-get-type "^26.0.0" - pretty-format "^26.0.1" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" -jest-matcher-utils@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.0.1.tgz#12e1fc386fe4f14678f4cc8dbd5ba75a58092911" - integrity sha512-PUMlsLth0Azen8Q2WFTwnSkGh2JZ8FYuwijC8NR47vXKpsrKmA1wWvgcj1CquuVfcYiDEdj985u5Wmg7COEARw== +jest-matcher-utils@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" + integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw== dependencies: chalk "^4.0.0" - jest-diff "^26.0.1" - jest-get-type "^26.0.0" - pretty-format "^26.0.1" + jest-diff "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" -jest-message-util@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.0.1.tgz#07af1b42fc450b4cc8e90e4c9cef11b33ce9b0ac" - integrity sha512-CbK8uQREZ8umUfo8+zgIfEt+W7HAHjQCoRaNs4WxKGhAYBGwEyvxuK81FXa7VeB9pwDEXeeKOB2qcsNVCAvB7Q== +jest-message-util@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" + integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA== dependencies: "@babel/code-frame" "^7.0.0" - "@jest/types" "^26.0.1" - "@types/stack-utils" "^1.0.1" + "@jest/types" "^26.6.2" + "@types/stack-utils" "^2.0.0" chalk "^4.0.0" graceful-fs "^4.2.4" micromatch "^4.0.2" + pretty-format "^26.6.2" slash "^3.0.0" stack-utils "^2.0.2" @@ -8587,129 +8631,134 @@ jest-mock-extended@^1.0.16: dependencies: ts-essentials "^4.0.0" -jest-mock@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.0.1.tgz#7fd1517ed4955397cf1620a771dc2d61fad8fd40" - integrity sha512-MpYTBqycuPYSY6xKJognV7Ja46/TeRbAZept987Zp+tuJvMN0YBWyyhG9mXyYQaU3SBI0TUlSaO5L3p49agw7Q== +jest-mock@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" + integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.6.2" + "@types/node" "*" -jest-pnp-resolver@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a" - integrity sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ== +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== jest-regex-util@^26.0.0: version "26.0.0" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== -jest-resolve-dependencies@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.0.1.tgz#607ba7ccc32151d185a477cff45bf33bce417f0b" - integrity sha512-9d5/RS/ft0vB/qy7jct/qAhzJsr6fRQJyGAFigK3XD4hf9kIbEH5gks4t4Z7kyMRhowU6HWm/o8ILqhaHdSqLw== +jest-resolve-dependencies@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz#6680859ee5d22ee5dcd961fe4871f59f4c784fb6" + integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.6.2" jest-regex-util "^26.0.0" - jest-snapshot "^26.0.1" + jest-snapshot "^26.6.2" -jest-resolve@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.0.1.tgz#21d1ee06f9ea270a343a8893051aeed940cde736" - integrity sha512-6jWxk0IKZkPIVTvq6s72RH735P8f9eCJW3IM5CX/SJFeKq1p2cZx0U49wf/SdMlhaB/anann5J2nCJj6HrbezQ== +jest-resolve@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" + integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.6.2" chalk "^4.0.0" graceful-fs "^4.2.4" - jest-pnp-resolver "^1.2.1" - jest-util "^26.0.1" + jest-pnp-resolver "^1.2.2" + jest-util "^26.6.2" read-pkg-up "^7.0.1" - resolve "^1.17.0" + resolve "^1.18.1" slash "^3.0.0" -jest-runner@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.0.1.tgz#ea03584b7ae4bacfb7e533d680a575a49ae35d50" - integrity sha512-CApm0g81b49Znm4cZekYQK67zY7kkB4umOlI2Dx5CwKAzdgw75EN+ozBHRvxBzwo1ZLYZ07TFxkaPm+1t4d8jA== +jest-runner@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.6.3.tgz#2d1fed3d46e10f233fd1dbd3bfaa3fe8924be159" + integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== dependencies: - "@jest/console" "^26.0.1" - "@jest/environment" "^26.0.1" - "@jest/test-result" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/console" "^26.6.2" + "@jest/environment" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" chalk "^4.0.0" + emittery "^0.7.1" exit "^0.1.2" graceful-fs "^4.2.4" - jest-config "^26.0.1" + jest-config "^26.6.3" jest-docblock "^26.0.0" - jest-haste-map "^26.0.1" - jest-jasmine2 "^26.0.1" - jest-leak-detector "^26.0.1" - jest-message-util "^26.0.1" - jest-resolve "^26.0.1" - jest-runtime "^26.0.1" - jest-util "^26.0.1" - jest-worker "^26.0.0" + jest-haste-map "^26.6.2" + jest-leak-detector "^26.6.2" + jest-message-util "^26.6.2" + jest-resolve "^26.6.2" + jest-runtime "^26.6.3" + jest-util "^26.6.2" + jest-worker "^26.6.2" source-map-support "^0.5.6" throat "^5.0.0" -jest-runtime@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.0.1.tgz#a121a6321235987d294168e282d52b364d7d3f89" - integrity sha512-Ci2QhYFmANg5qaXWf78T2Pfo6GtmIBn2rRaLnklRyEucmPccmCKvS9JPljcmtVamsdMmkyNkVFb9pBTD6si9Lw== +jest-runtime@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" + integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== dependencies: - "@jest/console" "^26.0.1" - "@jest/environment" "^26.0.1" - "@jest/fake-timers" "^26.0.1" - "@jest/globals" "^26.0.1" - "@jest/source-map" "^26.0.0" - "@jest/test-result" "^26.0.1" - "@jest/transform" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/console" "^26.6.2" + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/globals" "^26.6.2" + "@jest/source-map" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" "@types/yargs" "^15.0.0" chalk "^4.0.0" + cjs-module-lexer "^0.6.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" glob "^7.1.3" graceful-fs "^4.2.4" - jest-config "^26.0.1" - jest-haste-map "^26.0.1" - jest-message-util "^26.0.1" - jest-mock "^26.0.1" + jest-config "^26.6.3" + jest-haste-map "^26.6.2" + jest-message-util "^26.6.2" + jest-mock "^26.6.2" jest-regex-util "^26.0.0" - jest-resolve "^26.0.1" - jest-snapshot "^26.0.1" - jest-util "^26.0.1" - jest-validate "^26.0.1" + jest-resolve "^26.6.2" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" slash "^3.0.0" strip-bom "^4.0.0" - yargs "^15.3.1" + yargs "^15.4.1" -jest-serializer@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.0.0.tgz#f6c521ddb976943b93e662c0d4d79245abec72a3" - integrity sha512-sQGXLdEGWFAE4wIJ2ZaIDb+ikETlUirEOBsLXdoBbeLhTHkZUJwgk3+M8eyFizhM6le43PDCCKPA1hzkSDo4cQ== +jest-serializer@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" + integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== dependencies: + "@types/node" "*" graceful-fs "^4.2.4" -jest-snapshot@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.0.1.tgz#1baa942bd83d47b837a84af7fcf5fd4a236da399" - integrity sha512-jxd+cF7+LL+a80qh6TAnTLUZHyQoWwEHSUFJjkw35u3Gx+BZUNuXhYvDqHXr62UQPnWo2P6fvQlLjsU93UKyxA== +jest-snapshot@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" + integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== dependencies: "@babel/types" "^7.0.0" - "@jest/types" "^26.0.1" + "@jest/types" "^26.6.2" + "@types/babel__traverse" "^7.0.4" "@types/prettier" "^2.0.0" chalk "^4.0.0" - expect "^26.0.1" + expect "^26.6.2" graceful-fs "^4.2.4" - jest-diff "^26.0.1" - jest-get-type "^26.0.0" - jest-matcher-utils "^26.0.1" - jest-message-util "^26.0.1" - jest-resolve "^26.0.1" - make-dir "^3.0.0" + jest-diff "^26.6.2" + jest-get-type "^26.3.0" + jest-haste-map "^26.6.2" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-resolve "^26.6.2" natural-compare "^1.4.0" - pretty-format "^26.0.1" + pretty-format "^26.6.2" semver "^7.3.2" jest-util@26.x: @@ -8724,57 +8773,60 @@ jest-util@26.x: is-ci "^2.0.0" micromatch "^4.0.2" -jest-util@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.0.1.tgz#72c4c51177b695fdd795ca072a6f94e3d7cef00a" - integrity sha512-byQ3n7ad1BO/WyFkYvlWQHTsomB6GIewBh8tlGtusiylAlaxQ1UpS0XYH0ngOyhZuHVLN79Qvl6/pMiDMSSG1g== +jest-util@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" + integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.6.2" + "@types/node" "*" chalk "^4.0.0" graceful-fs "^4.2.4" is-ci "^2.0.0" - make-dir "^3.0.0" + micromatch "^4.0.2" -jest-validate@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.0.1.tgz#a62987e1da5b7f724130f904725e22f4e5b2e23c" - integrity sha512-u0xRc+rbmov/VqXnX3DlkxD74rHI/CfS5xaV2VpeaVySjbb1JioNVOyly5b56q2l9ZKe7bVG5qWmjfctkQb0bA== +jest-validate@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" + integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== dependencies: - "@jest/types" "^26.0.1" + "@jest/types" "^26.6.2" camelcase "^6.0.0" chalk "^4.0.0" - jest-get-type "^26.0.0" + jest-get-type "^26.3.0" leven "^3.1.0" - pretty-format "^26.0.1" + pretty-format "^26.6.2" -jest-watcher@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.0.1.tgz#5b5e3ebbdf10c240e22a98af66d645631afda770" - integrity sha512-pdZPydsS8475f89kGswaNsN3rhP6lnC3/QDCppP7bg1L9JQz7oU9Mb/5xPETk1RHDCWeqmVC47M4K5RR7ejxFw== +jest-watcher@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975" + integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== dependencies: - "@jest/test-result" "^26.0.1" - "@jest/types" "^26.0.1" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" - jest-util "^26.0.1" + jest-util "^26.6.2" string-length "^4.0.1" -jest-worker@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.0.0.tgz#4920c7714f0a96c6412464718d0c58a3df3fb066" - integrity sha512-pPaYa2+JnwmiZjK9x7p9BoZht+47ecFCDFA/CJxspHzeDvQcfVBLWzCiWyo+EGrSiQMWZtCFo9iSvMZnAAo8vw== +jest-worker@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== dependencies: + "@types/node" "*" merge-stream "^2.0.0" supports-color "^7.0.0" -jest@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/jest/-/jest-26.0.1.tgz#5c51a2e58dff7525b65f169721767173bf832694" - integrity sha512-29Q54kn5Bm7ZGKIuH2JRmnKl85YRigp0o0asTc6Sb6l2ch1DCXIeZTLLFy9ultJvhkTqbswF5DEx4+RlkmCxWg== +jest@26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef" + integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q== dependencies: - "@jest/core" "^26.0.1" + "@jest/core" "^26.6.3" import-local "^3.0.2" - jest-cli "^26.0.1" + jest-cli "^26.6.3" joi@^17.3.0: version "17.3.0" @@ -8852,38 +8904,6 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= -jsdom@^16.2.2: - version "16.2.2" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.2.2.tgz#76f2f7541646beb46a938f5dc476b88705bedf2b" - integrity sha512-pDFQbcYtKBHxRaP55zGXCJWgFHkDAYbKcsXEK/3Icu9nKYZkutUXfLBwbD+09XDutkYSHcgfQLZ0qvpAAm9mvg== - dependencies: - abab "^2.0.3" - acorn "^7.1.1" - acorn-globals "^6.0.0" - cssom "^0.4.4" - cssstyle "^2.2.0" - data-urls "^2.0.0" - decimal.js "^10.2.0" - domexception "^2.0.1" - escodegen "^1.14.1" - html-encoding-sniffer "^2.0.1" - is-potential-custom-element-name "^1.0.0" - nwsapi "^2.2.0" - parse5 "5.1.1" - request "^2.88.2" - request-promise-native "^1.0.8" - saxes "^5.0.0" - symbol-tree "^3.2.4" - tough-cookie "^3.0.1" - w3c-hr-time "^1.0.2" - w3c-xmlserializer "^2.0.0" - webidl-conversions "^6.0.0" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.0.0" - ws "^7.2.3" - xml-name-validator "^3.0.0" - jsdom@^16.4.0: version "16.4.0" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.4.0.tgz#36005bde2d136f73eee1a830c6d45e55408edddb" @@ -10151,10 +10171,10 @@ mobx@^6.3.0: resolved "https://registry.yarnpkg.com/mobx/-/mobx-6.3.0.tgz#a8fb693c3047bdfcb1eaff9aa48e36a7eb084f96" integrity sha512-Aa1+VXsg4WxqJMTQfWoYuJi5UD10VZhiobSmcs5kcmI3BIT0aVtn7DysvCeDADCzl7dnbX+0BTHUj/v7gLlZpQ== -mock-fs@^4.12.0: - version "4.12.0" - resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.12.0.tgz#a5d50b12d2d75e5bec9dac3b67ffe3c41d31ade4" - integrity sha512-/P/HtrlvBxY4o/PzXY9cCNBrdylDNxg7gnrv2sMNxj+UJ2m8jSpl0/A6fuJeNAWr99ZvGWH8XCbE0vmnM5KupQ== +mock-fs@4.14: + version "4.14.0" + resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" + integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== modern-normalize@^1.0.0: version "1.1.0" @@ -10437,16 +10457,16 @@ node-modules-regexp@^1.0.0: resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= -node-notifier@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-7.0.1.tgz#a355e33e6bebacef9bf8562689aed0f4230ca6f9" - integrity sha512-VkzhierE7DBmQEElhTGJIoiZa1oqRijOtgOlsXg32KrJRXsPy0NXFBqWGW/wTswnJlDCs5viRYaqWguqzsKcmg== +node-notifier@^8.0.0: + version "8.0.2" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.2.tgz#f3167a38ef0d2c8a866a83e318c1ba0efeb702c5" + integrity sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg== dependencies: growly "^1.3.0" - is-wsl "^2.1.1" - semver "^7.2.1" + is-wsl "^2.2.0" + semver "^7.3.2" shellwords "^0.1.1" - uuid "^7.0.3" + uuid "^8.3.0" which "^2.0.2" node-pty@^0.9.0: @@ -11869,16 +11889,6 @@ pretty-format@^26.0.0, pretty-format@^26.6.1: ansi-styles "^4.0.0" react-is "^17.0.1" -pretty-format@^26.0.1: - version "26.0.1" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.0.1.tgz#a4fe54fe428ad2fd3413ca6bbd1ec8c2e277e197" - integrity sha512-SWxz6MbupT3ZSlL0Po4WF/KujhQaVehijR2blyRDCzk9e45EaYMVhMBn49fnRuHxtkSpXTes1GxNpVmH86Bxfw== - dependencies: - "@jest/types" "^26.0.1" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^16.12.0" - pretty-format@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" @@ -12812,7 +12822,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.17.0, resolve@^1.20.0, resolve@^1.3.2: +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.18.1, resolve@^1.20.0, resolve@^1.3.2: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -15081,12 +15091,7 @@ uuid@^3.3.2, uuid@^3.3.3, uuid@^3.4.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" - integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== - -uuid@^8.3.2: +uuid@^8.3.0, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== @@ -15101,10 +15106,10 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745" integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ== -v8-to-istanbul@^4.1.3: - version "4.1.4" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-4.1.4.tgz#b97936f21c0e2d9996d4985e5c5156e9d4e49cd6" - integrity sha512-Rw6vJHj1mbdK8edjR7+zuJrpDtKIgNdAvTSAcpYfgMIw+u2dPDntD3dgN4XQFLU2/fvFQdzj+EeSGfd/jnY5fQ== +v8-to-istanbul@^7.0.0: + version "7.1.2" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz#30898d1a7fa0c84d225a2c1434fb958f290883c1" + integrity sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow== dependencies: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^1.6.0" @@ -15257,7 +15262,7 @@ webidl-conversions@^5.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== -webidl-conversions@^6.0.0, webidl-conversions@^6.1.0: +webidl-conversions@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== @@ -15726,7 +15731,7 @@ yaml@^1.7.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yargs-parser@18.x, yargs-parser@^18.1.1: +yargs-parser@18.x, yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== @@ -15812,10 +15817,10 @@ yargs@^14.2.3: y18n "^4.0.0" yargs-parser "^15.0.1" -yargs@^15.3.1: - version "15.3.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" - integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA== +yargs@^15.4.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== dependencies: cliui "^6.0.0" decamelize "^1.2.0" @@ -15827,7 +15832,7 @@ yargs@^15.3.1: string-width "^4.2.0" which-module "^2.0.0" y18n "^4.0.0" - yargs-parser "^18.1.1" + yargs-parser "^18.1.2" yargs@^16.2.0: version "16.2.0" From 2059034eabf3cad1b0e0b35c1421fa6d298fbcd5 Mon Sep 17 00:00:00 2001 From: Jim Ehrismann <40840436+jim-docker@users.noreply.github.com> Date: Wed, 14 Jul 2021 01:47:06 -0400 Subject: [PATCH 34/80] remove unused filenamify package (#3371) Signed-off-by: Jim Ehrismann --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 6f7ea53dbf..0ea6d57a40 100644 --- a/package.json +++ b/package.json @@ -200,7 +200,6 @@ "electron-updater": "^4.3.1", "electron-window-state": "^5.0.3", "filehound": "^1.17.4", - "filenamify": "^4.1.0", "fs-extra": "^9.0.1", "grapheme-splitter": "^1.0.4", "handlebars": "^4.7.7", From f2cd0aa8e85beb9ab5754eb800bb0728f378be8b Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 14 Jul 2021 01:48:32 -0400 Subject: [PATCH 35/80] Catch empty string error is parseKubeApi (#3358) * Catch empty string error is parseKubeApi - Add more debugging lines Signed-off-by: Sebastian Malton * Add some unit tests Signed-off-by: Sebastian Malton * Use resolved pathname Signed-off-by: Sebastian Malton --- .../api/__tests__/kube-api-parse.test.ts | 12 ++++++- src/renderer/api/api-manager.ts | 10 ++++-- src/renderer/api/kube-api-parse.ts | 31 ++++++++++++++++--- .../kube-object/kube-object-details.tsx | 12 ++++--- 4 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/renderer/api/__tests__/kube-api-parse.test.ts b/src/renderer/api/__tests__/kube-api-parse.test.ts index beb8df8221..18b805212d 100644 --- a/src/renderer/api/__tests__/kube-api-parse.test.ts +++ b/src/renderer/api/__tests__/kube-api-parse.test.ts @@ -129,8 +129,18 @@ const tests: KubeApiParseTestData[] = [ }], ]; +const throwtests = [ + undefined, + "", + "ajklsmh" +]; + describe("parseApi unit tests", () => { - it.each(tests)("testing %s", (url, expected) => { + it.each(tests)("testing %j", (url, expected) => { expect(parseKubeApi(url)).toStrictEqual(expected); }); + + it.each(throwtests)("testing %j should throw", (url) => { + expect(() => parseKubeApi(url)).toThrowError("invalid apiPath"); + }); }); diff --git a/src/renderer/api/api-manager.ts b/src/renderer/api/api-manager.ts index eafcf0d8ee..9477446386 100644 --- a/src/renderer/api/api-manager.ts +++ b/src/renderer/api/api-manager.ts @@ -58,8 +58,14 @@ export class ApiManager { } } - protected resolveApi(api: string | KubeApi): KubeApi { - if (typeof api === "string") return this.getApi(api); + protected resolveApi(api?: string | KubeApi): KubeApi | undefined { + if (!api) { + return undefined; + } + + if (typeof api === "string") { + return this.getApi(api); + } return api; } diff --git a/src/renderer/api/kube-api-parse.ts b/src/renderer/api/kube-api-parse.ts index b02067fb63..10e280d6c8 100644 --- a/src/renderer/api/kube-api-parse.ts +++ b/src/renderer/api/kube-api-parse.ts @@ -24,6 +24,9 @@ import type { KubeObject } from "./kube-object"; import { splitArray } from "../../common/utils"; import { apiManager } from "./api-manager"; +import { isDebugging } from "../../common/vars"; +import logger from "../../main/logger"; +import { inspect } from "util"; export interface IKubeObjectRef { kind: string; @@ -47,8 +50,26 @@ export interface IKubeApiParsed extends IKubeApiLinkRef { } export function parseKubeApi(path: string): IKubeApiParsed { - path = new URL(path, location.origin).pathname; - const [, prefix, ...parts] = path.split("/"); + if (!isDebugging) { + return _parseKubeApi(path); + } + + try { + const res = _parseKubeApi(path); + + logger.debug(`parseKubeApi(${inspect(path, false, null, false)}) -> ${inspect(res, false, null, false)}`); + + return res; + } catch (error) { + logger.debug(`parseKubeApi(${inspect(path, false, null, false)}) threw: ${error}`); + + throw error; + } +} + +function _parseKubeApi(path: string): IKubeApiParsed { + const apiPath = new URL(path, location.origin).pathname; + const [, prefix, ...parts] = apiPath.split("/"); const apiPrefix = `/${prefix}`; const [left, right, namespaced] = splitArray(parts, "namespaces"); let apiGroup, apiVersion, namespace, resource, name; @@ -70,12 +91,14 @@ export function parseKubeApi(path: string): IKubeApiParsed { apiGroup = left.join("/"); } else { switch (left.length) { + case 0: + throw new Error(`invalid apiPath: ${apiPath}`); case 4: [apiGroup, apiVersion, resource, name] = left; break; case 2: resource = left.pop(); - // fallthrough + // fallthrough case 1: apiVersion = left.pop(); apiGroup = ""; @@ -113,7 +136,7 @@ export function parseKubeApi(path: string): IKubeApiParsed { const apiBase = [apiPrefix, apiGroup, apiVersion, resource].filter(v => v).join("/"); if (!apiBase) { - throw new Error(`invalid apiPath: ${path}`); + throw new Error(`invalid apiPath: ${apiPath}`); } return { diff --git a/src/renderer/components/kube-object/kube-object-details.tsx b/src/renderer/components/kube-object/kube-object-details.tsx index 8098f77064..1f0c494b4e 100644 --- a/src/renderer/components/kube-object/kube-object-details.tsx +++ b/src/renderer/components/kube-object/kube-object-details.tsx @@ -34,6 +34,7 @@ import { CrdResourceDetails } from "../+custom-resources"; import { KubeObjectMenu } from "./kube-object-menu"; import type { CustomResourceDefinition } from "../../api/endpoints"; import { KubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; +import logger from "../../../main/logger"; /** * Used to store `object.selfLink` to show more info about resource in the details panel. @@ -67,6 +68,7 @@ export function hideDetails() { } export function getDetailsUrl(selfLink: string, resetSelected = false, mergeGlobals = true) { + logger.debug("getDetailsUrl", { selfLink, resetSelected, mergeGlobals }); const params = new URLSearchParams(mergeGlobals ? navigation.searchParams : ""); params.set(kubeDetailsUrlParam.name, selfLink); @@ -100,10 +102,12 @@ export class KubeObjectDetails extends React.Component { } @computed get object() { - const store = apiManager.getStore(this.path); - - if (store) { - return store.getByPath(this.path); + try { + return apiManager + .getStore(this.path) + ?.getByPath(this.path); + } catch (error) { + logger.error(`[KUBE-OBJECT-DETAILS]: failed to get store or object: ${error}`, { path: this.path }); } } From 9c2942c333b1899b24bf0d7c852e4127814eaf47 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 14 Jul 2021 05:31:58 -0400 Subject: [PATCH 36/80] Fix `.TableHead.sticky` in for details panels (#3331) * Fix .TableHead.sticky in for details panels Signed-off-by: Sebastian Malton * Fine-tune TableHead styling in PodDetailsList Signed-off-by: Alex Andreev Co-authored-by: Alex Andreev --- src/renderer/components/+nodes/node-details-resources.tsx | 2 +- .../components/+workloads-pods/pod-details-list.scss | 4 ++++ src/renderer/components/table/table-head.scss | 5 +++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/renderer/components/+nodes/node-details-resources.tsx b/src/renderer/components/+nodes/node-details-resources.tsx index df613cf436..636a3f55f0 100644 --- a/src/renderer/components/+nodes/node-details-resources.tsx +++ b/src/renderer/components/+nodes/node-details-resources.tsx @@ -54,7 +54,7 @@ export class NodeDetailsResources extends React.Component { selectable scrollable={false} > - + CPU Memory Ephemeral Storage diff --git a/src/renderer/components/+workloads-pods/pod-details-list.scss b/src/renderer/components/+workloads-pods/pod-details-list.scss index 05dd787a2c..04ccd2d05e 100644 --- a/src/renderer/components/+workloads-pods/pod-details-list.scss +++ b/src/renderer/components/+workloads-pods/pod-details-list.scss @@ -28,6 +28,10 @@ &.virtual { height: 500px; } + + .TableHead.sticky { + top: calc(var(--spacing) * -1); + } } .TableCell { diff --git a/src/renderer/components/table/table-head.scss b/src/renderer/components/table/table-head.scss index 4e194b2708..efa0bdb9b9 100644 --- a/src/renderer/components/table/table-head.scss +++ b/src/renderer/components/table/table-head.scss @@ -38,7 +38,7 @@ position: -webkit-sticky; // safari position: sticky; z-index: 1; - top: 0; // turn on sticky behaviour + top: 0; } &.nowrap { @@ -48,6 +48,7 @@ .TableCell { display: flex; align-items: center; + word-break: normal; &.checkbox { > .Checkbox { @@ -55,4 +56,4 @@ } } } -} \ No newline at end of file +} From 0a8cf96415e2edcca97db617d0e5df6202ae44d1 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 14 Jul 2021 08:30:57 -0400 Subject: [PATCH 37/80] Add kube-version and distro on detail panel (#3335) --- .../catalog-entities/kubernetes-cluster.ts | 7 ++- src/extensions/lens-renderer-extension.ts | 3 +- .../catalog-entity-detail-registry.ts | 15 ++++-- src/main/cluster-manager.ts | 22 ++++---- src/main/cluster.ts | 19 ++++--- src/renderer/bootstrap.tsx | 1 + .../catalog-entity-detail-registry.tsx | 50 +++++++++++++++++++ src/renderer/initializers/index.ts | 5 +- 8 files changed, 95 insertions(+), 27 deletions(-) create mode 100644 src/renderer/initializers/catalog-entity-detail-registry.tsx diff --git a/src/common/catalog-entities/kubernetes-cluster.ts b/src/common/catalog-entities/kubernetes-cluster.ts index db948df25a..83a94547bb 100644 --- a/src/common/catalog-entities/kubernetes-cluster.ts +++ b/src/common/catalog-entities/kubernetes-cluster.ts @@ -55,13 +55,18 @@ export interface KubernetesClusterSpec extends CatalogEntitySpec { }; } +export interface KubernetesClusterMetadata extends CatalogEntityMetadata { + distro?: string; + kubeVersion?: string; +} + export type KubernetesClusterStatusPhase = "connected" | "connecting" | "disconnected" | "deleting"; export interface KubernetesClusterStatus extends CatalogEntityStatus { phase: KubernetesClusterStatusPhase; } -export class KubernetesCluster extends CatalogEntity { +export class KubernetesCluster extends CatalogEntity { public static readonly apiVersion = "entity.k8slens.dev/v1alpha1"; public static readonly kind = "KubernetesCluster"; diff --git a/src/extensions/lens-renderer-extension.ts b/src/extensions/lens-renderer-extension.ts index a3026d99a5..dd5670fd67 100644 --- a/src/extensions/lens-renderer-extension.ts +++ b/src/extensions/lens-renderer-extension.ts @@ -23,6 +23,7 @@ import type * as registries from "./registries"; import type { Cluster } from "../main/cluster"; import { LensExtension } from "./lens-extension"; import { getExtensionPageUrl } from "./registries/page-registry"; +import type { CatalogEntity } from "../common/catalog"; export class LensRendererExtension extends LensExtension { globalPages: registries.PageRegistration[] = []; @@ -37,7 +38,7 @@ export class LensRendererExtension extends LensExtension { kubeWorkloadsOverviewItems: registries.WorkloadsOverviewDetailRegistration[] = []; commands: registries.CommandRegistration[] = []; welcomeMenus: registries.WelcomeMenuRegistration[] = []; - catalogEntityDetailItems: registries.CatalogEntityDetailRegistration[] = []; + catalogEntityDetailItems: registries.CatalogEntityDetailRegistration[] = []; topBarItems: registries.TopBarRegistration[] = []; async navigate

(pageId?: string, params?: P) { diff --git a/src/extensions/registries/catalog-entity-detail-registry.ts b/src/extensions/registries/catalog-entity-detail-registry.ts index b4b9fb0dd2..4ee9c4d667 100644 --- a/src/extensions/registries/catalog-entity-detail-registry.ts +++ b/src/extensions/registries/catalog-entity-detail-registry.ts @@ -20,20 +20,25 @@ */ import type React from "react"; +import type { CatalogEntity } from "../common-api/catalog"; import { BaseRegistry } from "./base-registry"; -export interface CatalogEntityDetailComponents { - Details: React.ComponentType; +export interface CatalogEntityDetailsProps { + entity: T; } -export interface CatalogEntityDetailRegistration { +export interface CatalogEntityDetailComponents { + Details: React.ComponentType>; +} + +export interface CatalogEntityDetailRegistration { kind: string; apiVersions: string[]; - components: CatalogEntityDetailComponents; + components: CatalogEntityDetailComponents; priority?: number; } -export class CatalogEntityDetailRegistry extends BaseRegistry { +export class CatalogEntityDetailRegistry extends BaseRegistry> { getItemsForKind(kind: string, apiVersion: string) { const items = this.getItems().filter((item) => { return item.kind === kind && item.apiVersions.includes(apiVersion); diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index 42d2dd1d19..73d2c50f46 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -23,7 +23,7 @@ import "../common/cluster-ipc"; import type http from "http"; import { action, autorun, makeObservable, observable, observe, reaction, toJS } from "mobx"; import { ClusterId, ClusterStore, getClusterIdFromHost } from "../common/cluster-store"; -import type { Cluster } from "./cluster"; +import { Cluster } from "./cluster"; import logger from "./logger"; import { apiKubePrefix } from "../common/vars"; import { Singleton } from "../common/utils"; @@ -103,13 +103,13 @@ export class ClusterManager extends Singleton { this.updateEntityStatus(entity, cluster); - entity.metadata.labels = Object.assign({}, cluster.labels, entity.metadata.labels); - entity.metadata.labels.distro = cluster.distribution; - - if (cluster.preferences?.clusterName) { - entity.metadata.name = cluster.preferences.clusterName; - } - + entity.metadata.labels = { + ...entity.metadata.labels, + ...cluster.labels, + }; + entity.metadata.distro = cluster.distribution; + entity.metadata.kubeVersion = cluster.version; + entity.metadata.name = cluster.name; entity.spec.metrics ||= { source: "local" }; if (entity.spec.metrics.source === "local") { @@ -236,8 +236,10 @@ export function catalogEntityFromCluster(cluster: Cluster) { name: cluster.name, source: "local", labels: { - distro: cluster.distribution, - } + ...cluster.labels, + }, + distro: cluster.distribution, + kubeVersion: cluster.version, }, spec: { kubeconfigPath: cluster.kubeConfigPath, diff --git a/src/main/cluster.ts b/src/main/cluster.ts index bf893f8484..58dbbf944f 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -235,8 +235,18 @@ export class Cluster implements ClusterModel, ClusterState { return this.preferences.clusterName || this.contextName; } + /** + * The detected kubernetes distribution + */ @computed get distribution(): string { - return this.metadata.distribution?.toString() || "unknown"; + return this.metadata[ClusterMetadataKey.DISTRIBUTION]?.toString() || "unknown"; + } + + /** + * The detected kubernetes version + */ + @computed get version(): string { + return this.metadata[ClusterMetadataKey.VERSION]?.toString() || "unknown"; } /** @@ -251,13 +261,6 @@ export class Cluster implements ClusterModel, ClusterState { return toJS({ prometheus, prometheusProvider }); } - /** - * Kubernetes version - */ - get version(): string { - return String(this.metadata?.version ?? ""); - } - constructor(model: ClusterModel) { makeObservable(this); this.id = model.id; diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx index 132abc9cd6..2a36c15089 100644 --- a/src/renderer/bootstrap.tsx +++ b/src/renderer/bootstrap.tsx @@ -80,6 +80,7 @@ export async function bootstrap(App: AppComponent) { initializers.intiKubeObjectDetailRegistry(); initializers.initWelcomeMenuRegistry(); initializers.initWorkloadsOverviewDetailRegistry(); + initializers.initCatalogEntityDetailRegistry(); initializers.initCatalog(); initializers.initIpcRendererListeners(); diff --git a/src/renderer/initializers/catalog-entity-detail-registry.tsx b/src/renderer/initializers/catalog-entity-detail-registry.tsx new file mode 100644 index 0000000000..8cae26afbf --- /dev/null +++ b/src/renderer/initializers/catalog-entity-detail-registry.tsx @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import React from "react"; +import { KubernetesCluster } from "../../common/catalog-entities"; +import { CatalogEntityDetailRegistry, CatalogEntityDetailsProps } from "../../extensions/registries"; +import { DrawerItem, DrawerTitle } from "../components/drawer"; + +export function initCatalogEntityDetailRegistry() { + CatalogEntityDetailRegistry.getInstance() + .add([ + { + apiVersions: [KubernetesCluster.apiVersion], + kind: KubernetesCluster.kind, + components: { + Details: ({ entity }: CatalogEntityDetailsProps) => ( + <> + +

+ + {entity.metadata.distro || "unknown"} + + + {entity.metadata.kubeVersion || "unknown"} + +
+ + ), + }, + } + ]); +} diff --git a/src/renderer/initializers/index.ts b/src/renderer/initializers/index.ts index 03f32f1a9d..943fef6a30 100644 --- a/src/renderer/initializers/index.ts +++ b/src/renderer/initializers/index.ts @@ -19,12 +19,13 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +export * from "./catalog-entity-detail-registry"; +export * from "./catalog"; export * from "./command-registry"; export * from "./entity-settings-registry"; +export * from "./ipc"; export * from "./kube-object-detail-registry"; export * from "./kube-object-menu-registry"; export * from "./registries"; export * from "./welcome-menu-registry"; export * from "./workloads-overview-detail-registry"; -export * from "./catalog"; -export * from "./ipc"; From c029039035b0800774141082ac7217eae151c190 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 14 Jul 2021 08:33:41 -0400 Subject: [PATCH 38/80] Remove conflicting classNames under quota-entries (#3334) - Both flex and inline modify the display rule and inline was winning Signed-off-by: Sebastian Malton --- .../components/+config-resource-quotas/add-quota-dialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx b/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx index 1227e97049..17dc3e5eae 100644 --- a/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx +++ b/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx @@ -218,7 +218,7 @@ export class AddQuotaDialog extends React.Component {
{this.quotaEntries.map(([quota, value]) => { return ( -
+
{quota}
{value}
this.quotas[quota] = ""} /> From 2d831af78c67d2a9f80653d9f8427ca068b0bd61 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 14 Jul 2021 09:11:17 -0400 Subject: [PATCH 39/80] Update yarn.lock (#3380) Signed-off-by: Sebastian Malton --- yarn.lock | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/yarn.lock b/yarn.lock index cff6305987..c3aa2d82ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6361,20 +6361,6 @@ filelist@^1.0.1: dependencies: minimatch "^3.0.4" -filename-reserved-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" - integrity sha1-q/c9+rc10EVECr/qLZHzieu/oik= - -filenamify@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-4.1.0.tgz#54d110810ae74eebfe115c1b995bd07e03cf2184" - integrity sha512-KQV/uJDI9VQgN7sHH1Zbk6+42cD6mnQ2HONzkXUfPJ+K2FC8GZ1dpewbbHw0Sz8Tf5k3EVdHVayM4DoAwWlmtg== - dependencies: - filename-reserved-regex "^2.0.0" - strip-outer "^1.0.1" - trim-repeated "^1.0.0" - fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" @@ -14030,13 +14016,6 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -strip-outer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" - integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg== - dependencies: - escape-string-regexp "^1.0.2" - style-loader@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-2.0.0.tgz#9669602fd4690740eaaec137799a03addbbc393c" @@ -14511,13 +14490,6 @@ trim-newlines@^1.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= -trim-repeated@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" - integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE= - dependencies: - escape-string-regexp "^1.0.2" - triple-beam@^1.2.0, triple-beam@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" From 89a3575f9dab5c8275140527e58bc282b1006113 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Jul 2021 10:27:58 -0400 Subject: [PATCH 40/80] Bump raw-loader from 4.0.1 to 4.0.2 (#3373) Bumps [raw-loader](https://github.com/webpack-contrib/raw-loader) from 4.0.1 to 4.0.2. - [Release notes](https://github.com/webpack-contrib/raw-loader/releases) - [Changelog](https://github.com/webpack-contrib/raw-loader/blob/master/CHANGELOG.md) - [Commits](https://github.com/webpack-contrib/raw-loader/compare/v4.0.1...v4.0.2) --- updated-dependencies: - dependency-name: raw-loader 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.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 0ea6d57a40..89054fd33d 100644 --- a/package.json +++ b/package.json @@ -353,7 +353,7 @@ "postinstall-postinstall": "^2.1.0", "progress-bar-webpack-plugin": "^2.1.0", "randomcolor": "^0.6.2", - "raw-loader": "^4.0.1", + "raw-loader": "^4.0.2", "react-beautiful-dnd": "^13.1.0", "react-refresh": "^0.9.0", "react-router-dom": "^5.2.0", diff --git a/yarn.lock b/yarn.lock index c3aa2d82ed..9d099b7397 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12185,13 +12185,13 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -raw-loader@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-4.0.1.tgz#14e1f726a359b68437e183d5a5b7d33a3eba6933" - integrity sha512-baolhQBSi3iNh1cglJjA0mYzga+wePk7vdEX//1dTFd+v4TsQlQE0jitJSNF1OIP82rdYulH7otaVmdlDaJ64A== +raw-loader@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-4.0.2.tgz#1aac6b7d1ad1501e66efdac1522c73e59a584eb6" + integrity sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA== dependencies: loader-utils "^2.0.0" - schema-utils "^2.6.5" + schema-utils "^3.0.0" rc@^1.0.1, rc@^1.1.6, rc@^1.2.7, rc@^1.2.8: version "1.2.8" From 074b1562dd3d8580737d1fdfc727048a003e845f Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 14 Jul 2021 10:48:59 -0400 Subject: [PATCH 41/80] release v5.1.0-beta.2 (#3381) Signed-off-by: Sebastian Malton --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 89054fd33d..306bac96f8 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "OpenLens", "description": "OpenLens - Open Source IDE for Kubernetes", "homepage": "https://github.com/lensapp/lens", - "version": "5.1.0-beta.1", + "version": "5.1.0-beta.2", "main": "static/build/main.js", "copyright": "Š 2021 OpenLens Authors", "license": "MIT", From 07fbf741005b4ad6679ef75c196cd0c55f56b8a3 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 15 Jul 2021 10:29:56 -0400 Subject: [PATCH 42/80] release v5.1.0 (#3390) Signed-off-by: Sebastian Malton --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 306bac96f8..01d2b33d74 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "OpenLens", "description": "OpenLens - Open Source IDE for Kubernetes", "homepage": "https://github.com/lensapp/lens", - "version": "5.1.0-beta.2", + "version": "5.1.0", "main": "static/build/main.js", "copyright": "Š 2021 OpenLens Authors", "license": "MIT", From f9635504f9ec28c06b55b4312f5c93e127ee888f Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 15 Jul 2021 12:59:03 -0400 Subject: [PATCH 43/80] Stringify errors that get sent to notifications (#3393) Signed-off-by: Sebastian Malton --- src/renderer/components/notifications/notifications.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/components/notifications/notifications.tsx b/src/renderer/components/notifications/notifications.tsx index c940ec469a..b4e9344aa0 100644 --- a/src/renderer/components/notifications/notifications.tsx +++ b/src/renderer/components/notifications/notifications.tsx @@ -88,7 +88,7 @@ export class Notifications extends React.Component { getMessage(notification: Notification) { let { message } = notification; - if (message instanceof JsonApiErrorParsed) { + if (message instanceof JsonApiErrorParsed || message instanceof Error) { message = message.toString(); } From 873a165a60a7d66b5d0ae6a68c3384e1e8518f83 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 15 Jul 2021 12:59:43 -0400 Subject: [PATCH 44/80] Fix clusters not being defined (#3392) Signed-off-by: Sebastian Malton --- src/migrations/cluster-store/5.0.0-beta.10.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/migrations/cluster-store/5.0.0-beta.10.ts b/src/migrations/cluster-store/5.0.0-beta.10.ts index 3a2b5bdfe3..4b7fa9f3bd 100644 --- a/src/migrations/cluster-store/5.0.0-beta.10.ts +++ b/src/migrations/cluster-store/5.0.0-beta.10.ts @@ -45,7 +45,7 @@ export default { workspaces.set(id, name); } - const clusters: ClusterModel[] = store.get("clusters"); + const clusters: ClusterModel[] = store.get("clusters") ?? []; for (const cluster of clusters) { if (cluster.workspace && workspaces.has(cluster.workspace)) { From c3823b9d2721cf80daab0cbb110e082fe2131459 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 15 Jul 2021 13:52:21 -0400 Subject: [PATCH 45/80] Failing to load KubeStateMetrics should only warn (#3394) Signed-off-by: Sebastian Malton --- src/renderer/components/+workloads-pods/pods.store.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/renderer/components/+workloads-pods/pods.store.ts b/src/renderer/components/+workloads-pods/pods.store.ts index f9d5d87464..62a6a720af 100644 --- a/src/renderer/components/+workloads-pods/pods.store.ts +++ b/src/renderer/components/+workloads-pods/pods.store.ts @@ -51,11 +51,9 @@ export class PodsStore extends KubeObjectStore { async loadKubeMetrics(namespace?: string) { try { - const metrics = await podMetricsApi.list({ namespace }); - - this.kubeMetrics.replace(metrics); + this.kubeMetrics.replace(await podMetricsApi.list({ namespace })); } catch (error) { - console.error("loadKubeMetrics failed", error); + console.warn("loadKubeMetrics failed", error); } } From ea4a5a4c578ea95d3c43a0797a3b891d7d357f8b Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 15 Jul 2021 14:19:33 -0400 Subject: [PATCH 46/80] getPortFrom should log the lines it retrived if it fails to get a port (#3395) --- src/main/utils/get-port.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/utils/get-port.ts b/src/main/utils/get-port.ts index cdce0ce740..c44e843712 100644 --- a/src/main/utils/get-port.ts +++ b/src/main/utils/get-port.ts @@ -21,6 +21,7 @@ import type { Readable } from "stream"; import URLParse from "url-parse"; +import logger from "../logger"; interface GetPortArgs { /** @@ -47,11 +48,15 @@ interface GetPortArgs { * @returns A Promise for port number */ export function getPortFrom(stream: Readable, args: GetPortArgs): Promise { + const logLines: string[] = []; + return new Promise((resolve, reject) => { const handler = (data: any) => { const logItem: string = data.toString(); const match = logItem.match(args.lineRegex); + logLines.push(logItem); + if (match) { // use unknown protocol so that there is no default port const addr = new URLParse(`s://${match.groups.address.trim()}`); @@ -64,6 +69,7 @@ export function getPortFrom(stream: Readable, args: GetPortArgs): Promise { stream.off("data", handler); + logger.warn(`[getPortFrom]: failed to retrieve port via ${args.lineRegex.toString()}: ${logLines}`); reject(new Error("failed to retrieve port from stream")); }, args.timeout ?? 5000); From 9903417fedaf4e17d2fdf344cd6ff1065b35d588 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 15 Jul 2021 17:16:54 -0400 Subject: [PATCH 47/80] Failing to load chart releases should only warn (#3399) Signed-off-by: Sebastian Malton --- src/renderer/components/+apps-releases/release.store.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/components/+apps-releases/release.store.ts b/src/renderer/components/+apps-releases/release.store.ts index ae69d38bc1..d3ffdadb43 100644 --- a/src/renderer/components/+apps-releases/release.store.ts +++ b/src/renderer/components/+apps-releases/release.store.ts @@ -91,7 +91,7 @@ export class ReleaseStore extends ItemStore { this.failedLoading = false; } catch (error) { this.failedLoading = true; - console.error("Loading Helm Chart releases has failed", error); + console.warn("Loading Helm Chart releases has failed", error); if (error.error) { Notifications.error(error.error); From e87b4836be29eca6f7aaa4da5b1656798b67dc4a Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Fri, 16 Jul 2021 08:53:01 -0400 Subject: [PATCH 48/80] Fix spelling (#3181) Co-authored-by: Josh Soref --- docs/extensions/get-started/anatomy.md | 2 +- docs/extensions/guides/generator.md | 2 +- docs/extensions/guides/kube-object-list-layout.md | 2 +- docs/extensions/guides/main-extension.md | 2 +- docs/extensions/guides/resource-stack.md | 2 +- docs/extensions/guides/stores.md | 4 ++-- docs/extensions/testing-and-publishing/publishing.md | 2 +- src/common/__tests__/catalog-category-registry.test.ts | 2 +- src/common/hotbar-store.ts | 4 ++-- src/common/user-store/preferences-helpers.ts | 6 +++--- src/common/utils/extended-map.ts | 2 +- src/extensions/__tests__/extension-loader.test.ts | 2 +- src/extensions/ipc/ipc-main.ts | 2 +- src/extensions/lens-extension.ts | 2 +- src/main/__test__/context-handler.test.ts | 2 +- src/main/helm/helm-repo-manager.ts | 2 +- src/main/index.ts | 2 +- src/main/tray.ts | 2 +- src/renderer/api/kube-api-parse.ts | 2 +- src/renderer/bootstrap.tsx | 2 +- src/renderer/components/+apps-releases/release.store.ts | 2 +- src/renderer/components/+apps-releases/releases.tsx | 2 +- .../components/+extensions/extension-install.store.ts | 2 +- src/renderer/components/+extensions/extensions.tsx | 4 ++-- .../components/+preferences/add-helm-repo-dialog.tsx | 4 ++-- src/renderer/components/+preferences/preferences.tsx | 2 +- src/renderer/components/cluster-manager/bottom-bar.test.tsx | 2 +- .../components/cluster-accessible-namespaces.tsx | 4 ++-- src/renderer/components/error-boundary/error-boundary.tsx | 2 +- src/renderer/components/file-picker/file-picker.tsx | 4 ++-- .../kube-object-status-icon/kube-object-status-icon.tsx | 2 +- .../components/markdown-viewer/markdown-viewer.scss | 4 ++-- .../components/notifications/notifications.store.tsx | 2 +- src/renderer/components/resizing-anchor/resizing-anchor.tsx | 2 +- src/renderer/themes/lens-dark.json | 6 +++--- src/renderer/themes/lens-light.json | 6 +++--- src/renderer/themes/theme-vars.scss | 6 +++--- src/renderer/utils/__tests__/jsonPath.test.tsx | 2 +- src/renderer/utils/jsonPath.ts | 2 +- 39 files changed, 54 insertions(+), 54 deletions(-) diff --git a/docs/extensions/get-started/anatomy.md b/docs/extensions/get-started/anatomy.md index 87b3042189..745bff5a89 100644 --- a/docs/extensions/get-started/anatomy.md +++ b/docs/extensions/get-started/anatomy.md @@ -6,7 +6,7 @@ In this section you will learn how this extension works under the hood. The Hello World sample extension does three things: - Implements `onActivate()` and outputs a message to the console. -- Implements `onDectivate()` and outputs a message to the console. +- Implements `onDeactivate()` and outputs a message to the console. - Registers `ClusterPage` so that the page is visible in the left-side menu of the cluster dashboard. Let's take a closer look at our Hello World sample's source code and see how these three things are achieved. diff --git a/docs/extensions/guides/generator.md b/docs/extensions/guides/generator.md index cbbdaa31bd..64838c1bc4 100644 --- a/docs/extensions/guides/generator.md +++ b/docs/extensions/guides/generator.md @@ -72,4 +72,4 @@ To dive deeper, consider looking at [Common Capabilities](../capabilities/common If you find problems with the Lens Extension Generator, or have feature requests, you are welcome to raise an [issue](https://github.com/lensapp/generator-lens-ext/issues). You can find the latest Lens contribution guidelines [here](https://docs.k8slens.dev/latest/contributing). -The Generator source code is hosted at [Github](https://github.com/lensapp/generator-lens-ext). +The Generator source code is hosted at [GitHub](https://github.com/lensapp/generator-lens-ext). diff --git a/docs/extensions/guides/kube-object-list-layout.md b/docs/extensions/guides/kube-object-list-layout.md index f5ee72e902..6d350c98cf 100644 --- a/docs/extensions/guides/kube-object-list-layout.md +++ b/docs/extensions/guides/kube-object-list-layout.md @@ -213,7 +213,7 @@ export class CertificatePage extends React.Component<{ extension: LensRendererEx return ( certificate.getName(), [sortBy.namespace]: (certificate: Certificate) => certificate.metadata.namespace, diff --git a/docs/extensions/guides/main-extension.md b/docs/extensions/guides/main-extension.md index 8a501ca533..fec937db17 100644 --- a/docs/extensions/guides/main-extension.md +++ b/docs/extensions/guides/main-extension.md @@ -94,7 +94,7 @@ export default class SamplePageMainExtension extends Main.LensExtension { ``` When the menu item is clicked the `navigate()` method looks for and displays a global page with id `"myGlobalPage"`. -This page would be defined in your extension's `Renderer.LensExtension` implmentation (See [`Renderer.LensExtension`](renderer-extension.md)). +This page would be defined in your extension's `Renderer.LensExtension` implementation (See [`Renderer.LensExtension`](renderer-extension.md)). ### `addCatalogSource()` and `removeCatalogSource()` Methods diff --git a/docs/extensions/guides/resource-stack.md b/docs/extensions/guides/resource-stack.md index 8d36bb6495..4d8c494339 100644 --- a/docs/extensions/guides/resource-stack.md +++ b/docs/extensions/guides/resource-stack.md @@ -90,7 +90,7 @@ This is the cluster that the resource stack will be applied to, and the construc Similarly, `ExampleClusterFeature` implements an `uninstall()` method which simply invokes the `kubectlDeleteFolder()` method of the `Renderer.K8sApi.ResourceStack` class. `kubectlDeleteFolder()` tries to delete from the cluster all kubernetes resources found in the folder passed to it, again in this case `../resources`. -`ExampleClusterFeature` also implements an `isInstalled()` method, which demonstrates how you can utiliize the kubernetes api to inspect the resource stack status. +`ExampleClusterFeature` also implements an `isInstalled()` method, which demonstrates how you can utilize the kubernetes api to inspect the resource stack status. `isInstalled()` simply tries to find a pod named `example-pod`, as a way to determine if the pod is already installed. This method can be useful in creating a context-sensitive UI for installing/uninstalling the feature, as demonstrated in the next sample code. diff --git a/docs/extensions/guides/stores.md b/docs/extensions/guides/stores.md index 3a990f58b7..8b31548a32 100644 --- a/docs/extensions/guides/stores.md +++ b/docs/extensions/guides/stores.md @@ -148,8 +148,8 @@ export class ExamplePreferenceInput extends React.Component { return ( { ExamplePreferencesStore.getInstace().enabled = v; }} + value={ExamplePreferencesStore.getInstance().enabled} + onChange={v => { ExamplePreferencesStore.getInstance().enabled = v; }} /> ); } diff --git a/docs/extensions/testing-and-publishing/publishing.md b/docs/extensions/testing-and-publishing/publishing.md index d8e7b8efad..9ea33c4e19 100644 --- a/docs/extensions/testing-and-publishing/publishing.md +++ b/docs/extensions/testing-and-publishing/publishing.md @@ -43,4 +43,4 @@ Say you have your project folder at `~/my-extension/` and you want to create an npm pack ``` -This will create a NPM tarball that can be hosted on Github Releases or any other publicly available file hosting service. +This will create a NPM tarball that can be hosted on GitHub Releases or any other publicly available file hosting service. diff --git a/src/common/__tests__/catalog-category-registry.test.ts b/src/common/__tests__/catalog-category-registry.test.ts index 11f7a88afd..90615d552c 100644 --- a/src/common/__tests__/catalog-category-registry.test.ts +++ b/src/common/__tests__/catalog-category-registry.test.ts @@ -56,7 +56,7 @@ class TestCatalogCategory2 extends CatalogCategory { } describe("CatalogCategoryRegistry", () => { - it("should remove only the category registered when running the disopser", () => { + it("should remove only the category registered when running the disposer", () => { const registry = new TestCatalogCategoryRegistry(); expect(registry.items.length).toBe(0); diff --git a/src/common/hotbar-store.ts b/src/common/hotbar-store.ts index 90694e9976..1634bab5cb 100644 --- a/src/common/hotbar-store.ts +++ b/src/common/hotbar-store.ts @@ -52,7 +52,7 @@ export interface HotbarStoreModel { activeHotbarId: string; } -export const defaultHotbarCells = 12; // Number is choosen to easy hit any item with keyboard +export const defaultHotbarCells = 12; // Number is chosen to easy hit any item with keyboard export class HotbarStore extends BaseStore { @observable hotbars: Hotbar[] = []; @@ -203,7 +203,7 @@ export class HotbarStore extends BaseStore { } /** - * Remvove all hotbar items that reference the `uid`. + * 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. */ diff --git a/src/common/user-store/preferences-helpers.ts b/src/common/user-store/preferences-helpers.ts index 3d205cd380..4363511120 100644 --- a/src/common/user-store/preferences-helpers.ts +++ b/src/common/user-store/preferences-helpers.ts @@ -193,9 +193,9 @@ const hiddenTableColumns: PreferenceDescription<[string, string[]][], Map extends Map { } /** - * Get the value behind `key`. If it was not pressent, first insert the value returned by `getVal` + * Get the value behind `key`. If it was not present, first insert the value returned by `getVal` * @param key The key to insert into the map with * @param getVal A function that returns a new instance of `V`. * @returns The value in the map diff --git a/src/extensions/__tests__/extension-loader.test.ts b/src/extensions/__tests__/extension-loader.test.ts index 5e0844d02d..e35afe5a1b 100644 --- a/src/extensions/__tests__/extension-loader.test.ts +++ b/src/extensions/__tests__/extension-loader.test.ts @@ -84,7 +84,7 @@ jest.mock( (channel: string, listener: (event: any, ...args: any[]) => void) => { if (channel === "extensions:main") { // First initialize with extensions 1 and 2 - // and then broadcast event to remove extensioin 2 and add extension number 3 + // and then broadcast event to remove extension 2 and add extension number 3 setTimeout(() => { listener({}, [ [ diff --git a/src/extensions/ipc/ipc-main.ts b/src/extensions/ipc/ipc-main.ts index eec89e9966..5884a3989e 100644 --- a/src/extensions/ipc/ipc-main.ts +++ b/src/extensions/ipc/ipc-main.ts @@ -36,7 +36,7 @@ export abstract class IpcMain extends IpcRegistrar { * Listen for broadcasts within your extension * @param channel The channel to listen for broadcasts on * @param listener The function that will be called with the arguments of the broadcast - * @returns An optional disopser, Lens will cleanup when the extension is disabled or uninstalled even if this is not called + * @returns An optional disposer, Lens will cleanup when the extension is disabled or uninstalled even if this is not called */ listen(channel: string, listener: (event: Electron.IpcRendererEvent, ...args: any[]) => any): Disposer { const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`; diff --git a/src/extensions/lens-extension.ts b/src/extensions/lens-extension.ts index ac77a3b229..5d562953ca 100644 --- a/src/extensions/lens-extension.ts +++ b/src/extensions/lens-extension.ts @@ -74,7 +74,7 @@ export class LensExtension { * getExtensionFileFolder returns the path to an already created folder. This * folder is for the sole use of this extension. * - * Note: there is no security done on this folder, only obfiscation of the + * Note: there is no security done on this folder, only obfuscation of the * folder name. */ async getExtensionFileFolder(): Promise { diff --git a/src/main/__test__/context-handler.test.ts b/src/main/__test__/context-handler.test.ts index 0ba3a2d028..0652ed5733 100644 --- a/src/main/__test__/context-handler.test.ts +++ b/src/main/__test__/context-handler.test.ts @@ -207,7 +207,7 @@ describe("ContextHandler", () => { expect(service.id === "id_0"); }); - it("shouldn't pick the second provider of 2 succcess(es) after 1 failure(s)", async () => { + it("shouldn't pick the second provider of 2 success(es) after 1 failure(s)", async () => { const reg = PrometheusProviderRegistry.getInstance(); let count = 0; diff --git a/src/main/helm/helm-repo-manager.ts b/src/main/helm/helm-repo-manager.ts index dc30d92edd..d1c904539d 100644 --- a/src/main/helm/helm-repo-manager.ts +++ b/src/main/helm/helm-repo-manager.ts @@ -146,7 +146,7 @@ export class HelmRepoManager extends Singleton { return stdout; } - public static async addХustomRepo(repoAttributes : HelmRepo) { + public static async addCustomRepo(repoAttributes : HelmRepo) { logger.info(`[HELM]: adding repo "${repoAttributes.name}" from ${repoAttributes.url}`); const helm = await helmCli.binaryPath(); diff --git a/src/main/index.ts b/src/main/index.ts index 684a2e5fb2..a5116cfdb0 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -137,7 +137,7 @@ app.on("ready", async () => { /** * The following sync MUST be done before HotbarStore creation, because that * store has migrations that will remove items that previous migrations add - * if this is not presant + * if this is not present */ syncGeneralEntities(); diff --git a/src/main/tray.ts b/src/main/tray.ts index 24b00d122a..3a772503f8 100644 --- a/src/main/tray.ts +++ b/src/main/tray.ts @@ -93,7 +93,7 @@ function createTrayMenu(windowManager: WindowManager): Menu { click() { windowManager .navigate(preferencesURL()) - .catch(error => logger.error(`${TRAY_LOG_PREFIX}: Failed to nativate to Preferences`, { error })); + .catch(error => logger.error(`${TRAY_LOG_PREFIX}: Failed to navigate to Preferences`, { error })); }, } ]; diff --git a/src/renderer/api/kube-api-parse.ts b/src/renderer/api/kube-api-parse.ts index 10e280d6c8..689a6b9858 100644 --- a/src/renderer/api/kube-api-parse.ts +++ b/src/renderer/api/kube-api-parse.ts @@ -114,7 +114,7 @@ function _parseKubeApi(path: string): IKubeApiParsed { * There is no well defined selection from an array of items that were * separated by '/' * - * Solution is to create a huristic. Namely: + * Solution is to create a heuristic. Namely: * 1. if '.' in left[0] then apiGroup <- left[0] * 2. if left[1] matches /^v[0-9]/ then apiGroup, apiVersion <- left[0], left[1] * 3. otherwise assume apiVersion <- left[0] diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx index 2a36c15089..87c30dba59 100644 --- a/src/renderer/bootstrap.tsx +++ b/src/renderer/bootstrap.tsx @@ -53,7 +53,7 @@ import { TerminalStore } from "./components/dock/terminal.store"; configurePackages(); /** - * If this is a development buid, wait a second to attach + * If this is a development build, wait a second to attach * Chrome Debugger to renderer process * https://stackoverflow.com/questions/52844870/debugging-electron-renderer-process-with-vscode */ diff --git a/src/renderer/components/+apps-releases/release.store.ts b/src/renderer/components/+apps-releases/release.store.ts index d3ffdadb43..9b450a7465 100644 --- a/src/renderer/components/+apps-releases/release.store.ts +++ b/src/renderer/components/+apps-releases/release.store.ts @@ -58,7 +58,7 @@ export class ReleaseStore extends ItemStore { }); } - watchSelecteNamespaces(): (() => void) { + watchSelectedNamespaces(): (() => void) { return reaction(() => namespaceStore.context.contextNamespaces, namespaces => { this.loadAll(namespaces); }); diff --git a/src/renderer/components/+apps-releases/releases.tsx b/src/renderer/components/+apps-releases/releases.tsx index 9a746b8909..453983e8d0 100644 --- a/src/renderer/components/+apps-releases/releases.tsx +++ b/src/renderer/components/+apps-releases/releases.tsx @@ -56,7 +56,7 @@ export class HelmReleases extends Component { componentDidMount() { disposeOnUnmount(this, [ releaseStore.watchAssociatedSecrets(), - releaseStore.watchSelecteNamespaces(), + releaseStore.watchSelectedNamespaces(), ]); } diff --git a/src/renderer/components/+extensions/extension-install.store.ts b/src/renderer/components/+extensions/extension-install.store.ts index c02bb482fd..4ca79ec337 100644 --- a/src/renderer/components/+extensions/extension-install.store.ts +++ b/src/renderer/components/+extensions/extension-install.store.ts @@ -225,7 +225,7 @@ export class ExtensionInstallationStateStore { } /** - * If there is at least one extension currently ininstalling + * If there is at least one extension currently uninstalling */ static get anyUninstalling(): boolean { return ExtensionInstallationStateStore.uninstalling > 0; diff --git a/src/renderer/components/+extensions/extensions.tsx b/src/renderer/components/+extensions/extensions.tsx index b135487343..0265a6ddf3 100644 --- a/src/renderer/components/+extensions/extensions.tsx +++ b/src/renderer/components/+extensions/extensions.tsx @@ -49,7 +49,7 @@ import { docsUrl } from "../../../common/vars"; function getMessageFromError(error: any): string { if (!error || typeof error !== "object") { - return "an error has occured"; + return "an error has occurred"; } if (error.message) { @@ -63,7 +63,7 @@ function getMessageFromError(error: any): string { const rawMessage = String(error); if (rawMessage === String({})) { - return "an error has occured"; + return "an error has occurred"; } return rawMessage; diff --git a/src/renderer/components/+preferences/add-helm-repo-dialog.tsx b/src/renderer/components/+preferences/add-helm-repo-dialog.tsx index 1bf978de68..44ef32b9af 100644 --- a/src/renderer/components/+preferences/add-helm-repo-dialog.tsx +++ b/src/renderer/components/+preferences/add-helm-repo-dialog.tsx @@ -107,7 +107,7 @@ export class AddHelmRepoDialog extends React.Component { async addCustomRepo() { try { - await HelmRepoManager.addХustomRepo(this.helmRepo); + await HelmRepoManager.addCustomRepo(this.helmRepo); Notifications.ok(<>Helm repository {this.helmRepo.name} has added); this.props.onAddRepo(); this.close(); @@ -145,7 +145,7 @@ export class AddHelmRepoDialog extends React.Component { /> {this.renderFileInput(`Key file`, FileType.KeyFile, AddHelmRepoDialog.keyExtensions)} {this.renderFileInput(`Ca file`, FileType.CaFile, AddHelmRepoDialog.certExtensions)} - {this.renderFileInput(`Cerificate file`, FileType.CertFile, AddHelmRepoDialog.certExtensions)} + {this.renderFileInput(`Certificate file`, FileType.CertFile, AddHelmRepoDialog.certExtensions)} ", () => { expect(container).toBeInstanceOf(HTMLElement); }); - it("renders w/o errors when .getItems() returns unexpected (not type complient) data", async () => { + it("renders w/o errors when .getItems() returns unexpected (not type compliant) data", async () => { StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => undefined); expect(() => render()).not.toThrow(); StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => "hello"); diff --git a/src/renderer/components/cluster-settings/components/cluster-accessible-namespaces.tsx b/src/renderer/components/cluster-settings/components/cluster-accessible-namespaces.tsx index 0c087083fe..62f426efe1 100644 --- a/src/renderer/components/cluster-settings/components/cluster-accessible-namespaces.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-accessible-namespaces.tsx @@ -52,8 +52,8 @@ export class ClusterAccessibleNamespaces extends React.Component { }} validators={systemName} items={Array.from(this.namespaces)} - remove={({ oldItem: oldNamesapce }) => { - this.namespaces.delete(oldNamesapce); + remove={({ oldItem: oldNamespace }) => { + this.namespaces.delete(oldNamespace); this.props.cluster.accessibleNamespaces = Array.from(this.namespaces); }} inputTheme="round-black" diff --git a/src/renderer/components/error-boundary/error-boundary.tsx b/src/renderer/components/error-boundary/error-boundary.tsx index 56be840ff7..dd345e9f48 100644 --- a/src/renderer/components/error-boundary/error-boundary.tsx +++ b/src/renderer/components/error-boundary/error-boundary.tsx @@ -35,7 +35,7 @@ export class ErrorBoundary extends React.Component { { const slackLink = Slack; - const githubLink = Github; + const githubLink = GitHub; const pageUrl = location.pathname; return ( diff --git a/src/renderer/components/file-picker/file-picker.tsx b/src/renderer/components/file-picker/file-picker.tsx index cc1e850cd2..3661bb2cb2 100644 --- a/src/renderer/components/file-picker/file-picker.tsx +++ b/src/renderer/components/file-picker/file-picker.tsx @@ -127,7 +127,7 @@ export class FilePicker extends React.Component { return files; } - handleIndiviualFileSizes(files: File[]): File[] { + handleIndividualFileSizes(files: File[]): File[] { const { onOverSizeLimit, maxSize } = this.props; switch (onOverSizeLimit) { @@ -178,7 +178,7 @@ export class FilePicker extends React.Component { try { const numberLimitedFiles = this.handleFileCount(files); - const sizeLimitedFiles = this.handleIndiviualFileSizes(numberLimitedFiles); + const sizeLimitedFiles = this.handleIndividualFileSizes(numberLimitedFiles); const totalSizeLimitedFiles = this.handleTotalFileSizes(sizeLimitedFiles); if ("uploadDir" in this.props) { diff --git a/src/renderer/components/kube-object-status-icon/kube-object-status-icon.tsx b/src/renderer/components/kube-object-status-icon/kube-object-status-icon.tsx index ebde73f894..9cd9d6b3af 100644 --- a/src/renderer/components/kube-object-status-icon/kube-object-status-icon.tsx +++ b/src/renderer/components/kube-object-status-icon/kube-object-status-icon.tsx @@ -63,7 +63,7 @@ interface SplitStatusesByLevel { } /** - * This fuction returns the class level for corresponding to the highest status level + * This function returns the class level for corresponding to the highest status level * and the statuses split by their levels. * @param src a list of status items */ diff --git a/src/renderer/components/markdown-viewer/markdown-viewer.scss b/src/renderer/components/markdown-viewer/markdown-viewer.scss index 9afa1f29cc..ccd2599e18 100644 --- a/src/renderer/components/markdown-viewer/markdown-viewer.scss +++ b/src/renderer/components/markdown-viewer/markdown-viewer.scss @@ -383,8 +383,8 @@ blockquote { padding: 8px 1em; - color: $helmDescriptionBlockqouteColor; - border-left: 0.25em solid $helmDescriptionBlockqouteBorder; + color: $helmDescriptionBlockquoteColor; + border-left: 0.25em solid $helmDescriptionBlockquoteBorder; background: $helmDescriptionBlockquoteBackground; } diff --git a/src/renderer/components/notifications/notifications.store.tsx b/src/renderer/components/notifications/notifications.store.tsx index 753a0978d3..63ab5d5e05 100644 --- a/src/renderer/components/notifications/notifications.store.tsx +++ b/src/renderer/components/notifications/notifications.store.tsx @@ -39,7 +39,7 @@ export interface Notification { message: NotificationMessage; status?: NotificationStatus; timeout?: number; // auto-hiding timeout in milliseconds, 0 = no hide - onClose?(): void; // additonal logic on when the notification times out or is closed by the "x" + onClose?(): void; // additional logic on when the notification times out or is closed by the "x" } export class NotificationsStore { diff --git a/src/renderer/components/resizing-anchor/resizing-anchor.tsx b/src/renderer/components/resizing-anchor/resizing-anchor.tsx index a71a604e51..ec564ca219 100644 --- a/src/renderer/components/resizing-anchor/resizing-anchor.tsx +++ b/src/renderer/components/resizing-anchor/resizing-anchor.tsx @@ -100,7 +100,7 @@ interface Props { minExtent?: number; /** - * The following events are triggerred with respect to the above values. + * The following events are triggered with respect to the above values. * - The "__Exceed" call will be made when the unbounded extent goes from * < the above to >= the above * - The "__Subceed" call is similar but is triggered when the unbounded diff --git a/src/renderer/themes/lens-dark.json b/src/renderer/themes/lens-dark.json index fff229699b..9bc65a204a 100644 --- a/src/renderer/themes/lens-dark.json +++ b/src/renderer/themes/lens-dark.json @@ -44,8 +44,8 @@ "helmStableRepo": "#3d90ce", "helmIncubatorRepo": "#ff7043", "helmDescriptionHr": "#41474a", - "helmDescriptionBlockqouteColor": "#bbb", - "helmDescriptionBlockqouteBorder": "#8a8f93", + "helmDescriptionBlockquoteColor": "#bbb", + "helmDescriptionBlockquoteBorder": "#8a8f93", "helmDescriptionBlockquoteBackground": "#3b4348", "helmDescriptionHeaders": "#3e4147", "helmDescriptionH6": "#6a737d", @@ -113,7 +113,7 @@ "iconActiveColor": "#ffffff", "iconActiveBackground": "#ffffff18", "filterAreaBackground": "#23272b", - "chartLiveBarBackgound": "#00000033", + "chartLiveBarBackground": "#00000033", "chartStripesColor": "#ffffff08", "chartCapacityColor": "#4c545f", "pieChartDefaultColor": "#30353a", diff --git a/src/renderer/themes/lens-light.json b/src/renderer/themes/lens-light.json index 8893fe27ac..eae521c1cd 100644 --- a/src/renderer/themes/lens-light.json +++ b/src/renderer/themes/lens-light.json @@ -45,8 +45,8 @@ "helmStableRepo": "#3d90ce", "helmIncubatorRepo": "#ff7043", "helmDescriptionHr": "#dddddd", - "helmDescriptionBlockqouteColor": "#555555", - "helmDescriptionBlockqouteBorder": "#8a8f93", + "helmDescriptionBlockquoteColor": "#555555", + "helmDescriptionBlockquoteBorder": "#8a8f93", "helmDescriptionBlockquoteBackground": "#eeeeee", "helmDescriptionHeaders": "#3e4147", "helmDescriptionH6": "#6a737d", @@ -114,7 +114,7 @@ "iconActiveColor": "#ffffff", "iconActiveBackground": "#a6a6a694", "filterAreaBackground": "#f7f7f7", - "chartLiveBarBackgound": "#00000033", + "chartLiveBarBackground": "#00000033", "chartStripesColor": "#00000009", "chartCapacityColor": "#cccccc", "pieChartDefaultColor": "#efefef", diff --git a/src/renderer/themes/theme-vars.scss b/src/renderer/themes/theme-vars.scss index ac6424a183..80792216b9 100644 --- a/src/renderer/themes/theme-vars.scss +++ b/src/renderer/themes/theme-vars.scss @@ -74,8 +74,8 @@ $helmImgBackground: var(--helmImgBackground); $helmStableRepo: var(--helmStableRepo); $helmIncubatorRepo: var(--helmIncubatorRepo); $helmDescriptionHr: var(--helmDescriptionHr); -$helmDescriptionBlockqouteColor: var(--helmDescriptionBlockqouteColor); -$helmDescriptionBlockqouteBorder: var(--helmDescriptionBlockqouteBorder); +$helmDescriptionBlockquoteColor: var(--helmDescriptionBlockquoteColor); +$helmDescriptionBlockquoteBorder: var(--helmDescriptionBlockquoteBorder); $helmDescriptionBlockquoteBackground: var(--helmDescriptionBlockquoteBackground); $helmDescriptionHeaders: var(--helmDescriptionHeaders); $helmDescriptionH6: var(--helmDescriptionH6); @@ -132,7 +132,7 @@ $drawerItemNameColor: var(--drawerItemNameColor); $drawerItemValueColor: var(--drawerItemValueColor); // Charts -$chartLiveBarBackgound: var(--chartLiveBarBackgound); +$chartLiveBarBackground: var(--chartLiveBarBackground); $chartStripesColor: var(--chartStripesColor); $chartCapacityColor: var(--chartCapacityColor); $pieChartDefaultColor: var(--pieChartDefaultColor); diff --git a/src/renderer/utils/__tests__/jsonPath.test.tsx b/src/renderer/utils/__tests__/jsonPath.test.tsx index 6e2049ab19..43468bb1dc 100644 --- a/src/renderer/utils/__tests__/jsonPath.test.tsx +++ b/src/renderer/utils/__tests__/jsonPath.test.tsx @@ -28,7 +28,7 @@ describe("parseJsonPath", () => { expect(res).toBe(".metadata.labels['kubesphere.io/alias-name']"); }); - test("should convert keys with escpaped charatecrs to use indexed notation", () => { + test("should convert keys with escaped characters to use indexed notation", () => { const res = parseJsonPath(".metadata.labels.kubesphere\\\"io/alias-name"); expect(res).toBe(".metadata.labels['kubesphere\"io/alias-name']"); diff --git a/src/renderer/utils/jsonPath.ts b/src/renderer/utils/jsonPath.ts index d055bf6ecb..92855d241a 100644 --- a/src/renderer/utils/jsonPath.ts +++ b/src/renderer/utils/jsonPath.ts @@ -48,7 +48,7 @@ function convertToIndexNotation(key: string, firstItem = false) { } return `['${key}']`; - } else { // no illegal chracters found, do not touch + } else { // no illegal characters found, do not touch const prefix = firstItem ? "" : "."; return `${prefix}${key}`; From eef5dd5f9cca46ed030cb9047a3a57e154a5224d Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 16 Jul 2021 08:57:26 -0400 Subject: [PATCH 49/80] Display toleration's value in pod-details (#3384) Signed-off-by: Sebastian Malton --- src/renderer/api/workload-kube-object.ts | 1 + src/renderer/components/+workloads-pods/pod-tolerations.tsx | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/renderer/api/workload-kube-object.ts b/src/renderer/api/workload-kube-object.ts index 34fa5d5109..8d1f2a6a36 100644 --- a/src/renderer/api/workload-kube-object.ts +++ b/src/renderer/api/workload-kube-object.ts @@ -26,6 +26,7 @@ export interface IToleration { key?: string; operator?: string; effect?: string; + value?: string; tolerationSeconds?: number; } diff --git a/src/renderer/components/+workloads-pods/pod-tolerations.tsx b/src/renderer/components/+workloads-pods/pod-tolerations.tsx index 5ca65cc2b3..9fdaef1c81 100644 --- a/src/renderer/components/+workloads-pods/pod-tolerations.tsx +++ b/src/renderer/components/+workloads-pods/pod-tolerations.tsx @@ -35,6 +35,7 @@ enum sortBy { Operator = "operator", Effect = "effect", Seconds = "seconds", + Value = "value", } const sortingCallbacks = { @@ -45,7 +46,7 @@ const sortingCallbacks = { }; const getTableRow = (toleration: IToleration) => { - const { key, operator, effect, tolerationSeconds } = toleration; + const { key, operator, effect, tolerationSeconds, value } = toleration; return ( { > {key} {operator} + {value} {effect} {tolerationSeconds} @@ -74,6 +76,7 @@ export function PodTolerations({ tolerations }: Props) { Key Operator + Value Effect Seconds From acbca1ac1d49bfed08ebd2afd948ce9cffd0b5b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Jul 2021 14:06:49 -0400 Subject: [PATCH 50/80] Bump mock-fs from 4.12.0 to 4.14.0 (#3117) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Alex Andreev --- package.json | 2 +- yarn.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 01d2b33d74..952113d365 100644 --- a/package.json +++ b/package.json @@ -216,7 +216,7 @@ "mobx": "^6.3.0", "mobx-observable-history": "^2.0.1", "mobx-react": "^7.1.0", - "mock-fs": "4.14", + "mock-fs": "^4.14.0", "moment": "^2.29.1", "moment-timezone": "^0.5.33", "node-pty": "^0.9.0", diff --git a/yarn.lock b/yarn.lock index 9d099b7397..8243b03f6a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10157,7 +10157,7 @@ mobx@^6.3.0: resolved "https://registry.yarnpkg.com/mobx/-/mobx-6.3.0.tgz#a8fb693c3047bdfcb1eaff9aa48e36a7eb084f96" integrity sha512-Aa1+VXsg4WxqJMTQfWoYuJi5UD10VZhiobSmcs5kcmI3BIT0aVtn7DysvCeDADCzl7dnbX+0BTHUj/v7gLlZpQ== -mock-fs@4.14: +mock-fs@^4.14.0: version "4.14.0" resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== From 8c5457cf892c7920d0c72566787cbf3db42caa42 Mon Sep 17 00:00:00 2001 From: Alexandre Barone <48306674+devodev@users.noreply.github.com> Date: Fri, 16 Jul 2021 14:07:06 -0400 Subject: [PATCH 51/80] Fix broken shell when workdir not exists (#3349) Signed-off-by: devodev --- src/main/shell-session/local-shell-session.ts | 5 ++++- src/main/shell-session/node-shell-session.ts | 4 ++++ src/main/shell-session/shell-session.ts | 13 ++++++++----- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/main/shell-session/local-shell-session.ts b/src/main/shell-session/local-shell-session.ts index 35a1369339..ed1208fcbd 100644 --- a/src/main/shell-session/local-shell-session.ts +++ b/src/main/shell-session/local-shell-session.ts @@ -31,8 +31,11 @@ export class LocalShellSession extends ShellSession { return [helmCli.getBinaryDir()]; } - public async open() { + protected get cwd(): string | undefined { + return this.cluster.preferences?.terminalCWD; + } + public async open() { const env = await this.getCachedShellEnv(); const shell = env.PTYSHELL; const args = await this.getShellArgs(shell); diff --git a/src/main/shell-session/node-shell-session.ts b/src/main/shell-session/node-shell-session.ts index 7542baecd6..aa8c14ba9b 100644 --- a/src/main/shell-session/node-shell-session.ts +++ b/src/main/shell-session/node-shell-session.ts @@ -32,6 +32,10 @@ export class NodeShellSession extends ShellSession { protected podId = `node-shell-${uuid()}`; protected kc: KubeConfig; + protected get cwd(): string | undefined { + return undefined; + } + constructor(socket: WebSocket, cluster: Cluster, protected nodeName: string) { super(socket, cluster); } diff --git a/src/main/shell-session/shell-session.ts b/src/main/shell-session/shell-session.ts index 039caa44ce..4771ec8b77 100644 --- a/src/main/shell-session/shell-session.ts +++ b/src/main/shell-session/shell-session.ts @@ -19,6 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +import fse from "fs-extra"; import type { Cluster } from "../cluster"; import { Kubectl } from "../kubectl"; import type * as WebSocket from "ws"; @@ -50,9 +51,7 @@ export abstract class ShellSession { protected kubectlBinDirP: Promise; protected kubeconfigPathP: Promise; - protected get cwd(): string | undefined { - return this.cluster.preferences?.terminalCWD; - } + protected abstract get cwd(): string | undefined; constructor(protected websocket: WebSocket, protected cluster: Cluster) { this.kubectl = new Kubectl(cluster.version); @@ -60,10 +59,14 @@ export abstract class ShellSession { this.kubectlBinDirP = this.kubectl.binDir(); } - open(shell: string, args: string[], env: Record): void { + protected async open(shell: string, args: string[], env: Record) { + const cwd = (this.cwd && await fse.pathExists(this.cwd)) + ? this.cwd + : env.HOME; + this.shellProcess = pty.spawn(shell, args, { cols: 80, - cwd: this.cwd || env.HOME, + cwd, env, name: "xterm-256color", rows: 30, From 7f332d24b25a43801e5e9396e1b005f4d8a54cff Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 16 Jul 2021 23:04:17 -0400 Subject: [PATCH 52/80] release v5.1.1 (#3414) Signed-off-by: Sebastian Malton --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 952113d365..624643e4e3 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "OpenLens", "description": "OpenLens - Open Source IDE for Kubernetes", "homepage": "https://github.com/lensapp/lens", - "version": "5.1.0", + "version": "5.1.1", "main": "static/build/main.js", "copyright": "Š 2021 OpenLens Authors", "license": "MIT", From b03a255f29a6684928549b6e1a76912ff90f7726 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Jul 2021 07:32:59 +0300 Subject: [PATCH 53/80] Bump webpack from 4.44.2 to 4.46.0 (#3413) Bumps [webpack](https://github.com/webpack/webpack) from 4.44.2 to 4.46.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v4.44.2...v4.46.0) --- updated-dependencies: - dependency-name: webpack 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.json | 2 +- yarn.lock | 68 ++++++++++------------------------------------------ 2 files changed, 14 insertions(+), 56 deletions(-) diff --git a/package.json b/package.json index 624643e4e3..e51b56986d 100644 --- a/package.json +++ b/package.json @@ -377,7 +377,7 @@ "typescript": "^4.3.2", "typescript-plugin-css-modules": "^3.2.0", "url-loader": "^4.1.0", - "webpack": "^4.44.2", + "webpack": "^4.46.0", "webpack-cli": "^3.3.11", "webpack-dev-server": "^3.11.0", "webpack-node-externals": "^1.7.2", diff --git a/yarn.lock b/yarn.lock index 8243b03f6a..41166efdd7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2486,21 +2486,11 @@ acorn@^6.4.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== -acorn@^7.0.0: +acorn@^7.0.0, acorn@^7.1.1, acorn@^7.4.0: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^7.1.1: - version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe" - integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ== - -acorn@^7.4.0: - version "7.4.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c" - integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w== - agent-base@4, agent-base@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" @@ -2550,17 +2540,12 @@ ajv-errors@^1.0.0: resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== -ajv-keywords@^3.1.0, ajv-keywords@^3.5.2: +ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv-keywords@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" - integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== - -ajv@^6.1.0, ajv@^6.12.4, ajv@^6.12.5: +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.5.5: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2570,16 +2555,6 @@ ajv@^6.1.0, ajv@^6.12.4, ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.12.2, ajv@^6.5.5: - version "6.12.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" - integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" @@ -5518,19 +5493,10 @@ enhanced-resolve@4.1.0: memory-fs "^0.4.0" tapable "^1.0.0" -enhanced-resolve@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66" - integrity sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA== - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.5.0" - tapable "^1.0.0" - -enhanced-resolve@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz#3b806f3bfafc1ec7de69551ef93cca46c1704126" - integrity sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ== +enhanced-resolve@^4.0.0, enhanced-resolve@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" + integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg== dependencies: graceful-fs "^4.1.2" memory-fs "^0.5.0" @@ -5801,15 +5767,7 @@ eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-scope@^5.0.0, eslint-scope@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5" - integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-scope@^5.1.1: +eslint-scope@^5.0.0, eslint-scope@^5.1.0, eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -15335,10 +15293,10 @@ webpack-sources@^2.2.0: source-list-map "^2.0.1" source-map "^0.6.1" -webpack@^4.44.2: - version "4.44.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.44.2.tgz#6bfe2b0af055c8b2d1e90ed2cd9363f841266b72" - integrity sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q== +webpack@^4.46.0: + version "4.46.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" + integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q== dependencies: "@webassemblyjs/ast" "1.9.0" "@webassemblyjs/helper-module-context" "1.9.0" @@ -15348,7 +15306,7 @@ webpack@^4.44.2: ajv "^6.10.2" ajv-keywords "^3.4.1" chrome-trace-event "^1.0.2" - enhanced-resolve "^4.3.0" + enhanced-resolve "^4.5.0" eslint-scope "^4.0.3" json-parse-better-errors "^1.0.2" loader-runner "^2.4.0" From c1554d90f2b8a8a170f18615b075def1b26205e9 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 19 Jul 2021 00:34:18 -0400 Subject: [PATCH 54/80] Catch Cluster create error in cluster-manager (#3401) * Catch Cluster create error in cluster-manager - Only warn if the file is missing. The file must have disapeared betweeen kubeconfig-sync detecting it and cluster-manager performing the addCluster call - For all other errors log an error Signed-off-by: Sebastian Malton * Fix spelling Signed-off-by: Sebastian Malton * Use logger Signed-off-by: Sebastian Malton --- src/main/cluster-manager.ts | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index 73d2c50f46..628bcb22f6 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -32,6 +32,8 @@ import { KubernetesCluster, KubernetesClusterPrometheusMetrics, KubernetesCluste import { ipcMainOn } from "../common/ipc"; import { once } from "lodash"; +const logPrefix = "[CLUSTER-MANAGER]:"; + export class ClusterManager extends Singleton { private store = ClusterStore.getInstance(); deleting = observable.set(); @@ -73,7 +75,7 @@ export class ClusterManager extends Singleton { if (removedClusters.length > 0) { const meta = removedClusters.map(cluster => cluster.getMeta()); - logger.info(`[CLUSTER-MANAGER]: removing clusters`, meta); + logger.info(`${logPrefix} removing clusters`, meta); removedClusters.forEach(cluster => cluster.disconnect()); this.store.removedClusters.clear(); } @@ -161,14 +163,22 @@ export class ClusterManager extends Singleton { const cluster = this.store.getById(entity.metadata.uid); if (!cluster) { - this.store.addCluster({ - id: entity.metadata.uid, - preferences: { - clusterName: entity.metadata.name - }, - kubeConfigPath: entity.spec.kubeconfigPath, - contextName: entity.spec.kubeconfigContext - }); + try { + this.store.addCluster({ + id: entity.metadata.uid, + preferences: { + clusterName: entity.metadata.name + }, + kubeConfigPath: entity.spec.kubeconfigPath, + contextName: entity.spec.kubeconfigContext + }); + } catch (error) { + if (error.code === "ENOENT" && error.path === entity.spec.kubeconfigPath) { + logger.warn(`${logPrefix} kubeconfig file disappeared`, { path: entity.spec.kubeconfigPath }); + } else { + logger.error(`${logPrefix} failed to add cluster: ${error}`); + } + } } else { cluster.kubeConfigPath = entity.spec.kubeconfigPath; cluster.contextName = entity.spec.kubeconfigContext; @@ -179,7 +189,7 @@ export class ClusterManager extends Singleton { } protected onNetworkOffline = () => { - logger.info("[CLUSTER-MANAGER]: network is offline"); + logger.info(`${logPrefix} network is offline`); this.store.clustersList.forEach((cluster) => { if (!cluster.disconnected) { cluster.online = false; @@ -190,7 +200,7 @@ export class ClusterManager extends Singleton { }; protected onNetworkOnline = () => { - logger.info("[CLUSTER-MANAGER]: network is online"); + logger.info(`${logPrefix} network is online`); this.store.clustersList.forEach((cluster) => { if (!cluster.disconnected) { cluster.refreshConnectionStatus().catch((e) => e); From c5040657439d72f84aaf0763e7e6e52114a96531 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 19 Jul 2021 00:46:55 -0400 Subject: [PATCH 55/80] Check metadata labels is an object in getRoleLabels (#3416) Signed-off-by: Sebastian Malton --- src/renderer/api/endpoints/nodes.api.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/renderer/api/endpoints/nodes.api.ts b/src/renderer/api/endpoints/nodes.api.ts index 17a7571209..d2c35761ca 100644 --- a/src/renderer/api/endpoints/nodes.api.ts +++ b/src/renderer/api/endpoints/nodes.api.ts @@ -156,9 +156,13 @@ export class Node extends KubeObject { } getRoleLabels() { - const roleLabels = Object.keys(this.metadata.labels).filter(key => - key.includes("node-role.kubernetes.io") - ).map(key => key.match(/([^/]+$)/)[0]); // all after last slash + if (!this.metadata?.labels || typeof this.metadata.labels !== "object") { + return ""; + } + + const roleLabels = Object.keys(this.metadata.labels) + .filter(key => key.includes("node-role.kubernetes.io")) + .map(key => key.match(/([^/]+$)/)[0]); // all after last slash if (this.metadata.labels["kubernetes.io/role"] != undefined) { roleLabels.push(this.metadata.labels["kubernetes.io/role"]); From 48797b4a572175ab1c428b795bea4ceb0480ad11 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 19 Jul 2021 00:47:54 -0400 Subject: [PATCH 56/80] Check KubeObject.metadata is defined in getOwnerRefs (#3412) Signed-off-by: Sebastian Malton --- src/renderer/api/kube-object.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/renderer/api/kube-object.ts b/src/renderer/api/kube-object.ts index df249f64e6..024651c4d9 100644 --- a/src/renderer/api/kube-object.ts +++ b/src/renderer/api/kube-object.ts @@ -254,12 +254,10 @@ export class KubeObject ({ - ...ownerRef, - namespace: this.getNs(), - })); + return refs.map(ownerRef => ({ ...ownerRef, namespace })); } getSearchFields() { From 106c9d4a37f266562262578cf75a15a7635eeb06 Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Mon, 19 Jul 2021 11:01:38 +0300 Subject: [PATCH 57/80] fix KubeObjectStore loadAll error message (#3421) Signed-off-by: Jari Kolehmainen --- src/renderer/kube-object.store.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/kube-object.store.ts b/src/renderer/kube-object.store.ts index 62dd1cb117..d94ba51bdb 100644 --- a/src/renderer/kube-object.store.ts +++ b/src/renderer/kube-object.store.ts @@ -195,7 +195,7 @@ export abstract class KubeObjectStore extends ItemSt if (error.message) { Notifications.error(error.message); } - console.error("Loading store items failed", { error }); + console.error("[KubeObjectStore] loadAll failed", this.api.apiBase, error); this.resetOnError(error); this.failedLoading = true; } finally { From ba0581d98250372c5f685438a867d83481541f1f Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Mon, 19 Jul 2021 16:35:51 +0300 Subject: [PATCH 58/80] Skip previously bundled extensions (#3420) Signed-off-by: Jari Kolehmainen --- src/extensions/extension-compatibility.ts | 4 ++++ src/extensions/extension-discovery.ts | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/extensions/extension-compatibility.ts b/src/extensions/extension-compatibility.ts index 9ca48a3f2d..cc5db5515e 100644 --- a/src/extensions/extension-compatibility.ts +++ b/src/extensions/extension-compatibility.ts @@ -31,3 +31,7 @@ export function isCompatibleExtension(manifest: LensExtensionManifest): boolean return false; } + +export function isCompatibleBundledExtension(manifest: LensExtensionManifest): boolean { + return manifest.version === appSemVer.raw; +} diff --git a/src/extensions/extension-discovery.ts b/src/extensions/extension-discovery.ts index 70f32de110..077f29d694 100644 --- a/src/extensions/extension-discovery.ts +++ b/src/extensions/extension-discovery.ts @@ -35,7 +35,7 @@ import { ExtensionsStore } from "./extensions-store"; import { ExtensionLoader } from "./extension-loader"; import type { LensExtensionId, LensExtensionManifest } from "./lens-extension"; import { isProduction } from "../common/vars"; -import { isCompatibleExtension } from "./extension-compatibility"; +import { isCompatibleBundledExtension, isCompatibleExtension } from "./extension-compatibility"; export interface InstalledExtension { id: LensExtensionId; @@ -361,7 +361,7 @@ export class ExtensionDiscovery extends Singleton { const extensionDir = path.dirname(manifestPath); const npmPackage = path.join(extensionDir, `${manifest.name}-${manifest.version}.tgz`); const absolutePath = (isProduction && await fse.pathExists(npmPackage)) ? npmPackage : extensionDir; - const isCompatible = isBundled || isCompatibleExtension(manifest); + const isCompatible = (isBundled && isCompatibleBundledExtension(manifest)) || isCompatibleExtension(manifest); return { id, From e767c392a41b329ebc26917e8db1300d78c4c9d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Jul 2021 09:39:23 -0400 Subject: [PATCH 59/80] Bump typescript-plugin-css-modules from 3.2.0 to 3.4.0 (#3382) Bumps [typescript-plugin-css-modules](https://github.com/mrmckeb/typescript-plugin-css-modules) from 3.2.0 to 3.4.0. - [Release notes](https://github.com/mrmckeb/typescript-plugin-css-modules/releases) - [Commits](https://github.com/mrmckeb/typescript-plugin-css-modules/compare/v3.2.0...v3.4.0) --- updated-dependencies: - dependency-name: typescript-plugin-css-modules 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.json | 2 +- yarn.lock | 118 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 78 insertions(+), 42 deletions(-) diff --git a/package.json b/package.json index e51b56986d..067cef3a94 100644 --- a/package.json +++ b/package.json @@ -375,7 +375,7 @@ "typedoc-plugin-markdown": "^3.9.0", "typeface-roboto": "^1.1.13", "typescript": "^4.3.2", - "typescript-plugin-css-modules": "^3.2.0", + "typescript-plugin-css-modules": "^3.4.0", "url-loader": "^4.1.0", "webpack": "^4.46.0", "webpack-cli": "^3.3.11", diff --git a/yarn.lock b/yarn.lock index 41166efdd7..4ac75156c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5258,6 +5258,11 @@ dotenv-expand@^5.1.0: resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== +dotenv@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" + integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== + dotenv@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef" @@ -7439,7 +7444,7 @@ iconv-corefoundation@^1.1.5: cli-truncate "^1.1.0" node-addon-api "^1.6.3" -iconv-lite@0.4.24, iconv-lite@^0.4.17: +iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -7460,13 +7465,6 @@ icss-utils@^3.0.1: dependencies: postcss "^6.0.2" -icss-utils@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" - integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA== - dependencies: - postcss "^7.0.14" - icss-utils@^5.0.0, icss-utils@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" @@ -7538,6 +7536,13 @@ import-cwd@^2.0.0: dependencies: import-from "^2.1.0" +import-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-3.0.0.tgz#20845547718015126ea9b3676b7592fb8bd4cf92" + integrity sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg== + dependencies: + import-from "^3.0.0" + import-fresh@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" @@ -7577,6 +7582,13 @@ import-from@^2.1.0: dependencies: resolve-from "^3.0.0" +import-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/import-from/-/import-from-3.0.0.tgz#055cfec38cd5a27d8057ca51376d7d3bf0891966" + integrity sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ== + dependencies: + resolve-from "^5.0.0" + import-lazy@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" @@ -9202,12 +9214,13 @@ lcid@^2.0.0: dependencies: invert-kv "^2.0.0" -less@^3.11.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/less/-/less-3.13.1.tgz#0ebc91d2a0e9c0c6735b83d496b0ab0583077909" - integrity sha512-SwA1aQXGUvp+P5XdZslUOhhLnClSLIjWvJhmd+Vgib5BFIr9lMNlQwmwUNOjXThF/A0x+MCYYPeWEfeWiLRnTw== +less@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/less/-/less-4.1.1.tgz#15bf253a9939791dc690888c3ff424f3e6c7edba" + integrity sha512-w09o8tZFPThBscl5d0Ggp3RcrKIouBoQscnOMgFH3n5V3kN/CXGHNfCkRPtxJk6nKryDXaV9aHLK55RXuH4sAw== dependencies: copy-anything "^2.0.1" + parse-node-version "^1.0.1" tslib "^1.10.0" optionalDependencies: errno "^0.1.1" @@ -9215,7 +9228,7 @@ less@^3.11.1: image-size "~0.5.0" make-dir "^2.1.0" mime "^1.4.1" - native-request "^1.0.5" + needle "^2.5.2" source-map "~0.6.0" leven@^3.1.0: @@ -9387,6 +9400,11 @@ lie@~3.3.0: dependencies: immediate "~3.0.5" +lilconfig@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.3.tgz#68f3005e921dafbd2a2afb48379986aa6d2579fd" + integrity sha512-EHKqr/+ZvdKCifpNrJCKxBTgk5XupZA3y/aCPY9mxfgBzmgh93Mt/WqjjQ38oMxXuvDokaKiM3lAgvSH2sjtHg== + lines-and-columns@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" @@ -10226,11 +10244,6 @@ napi-build-utils@^1.0.1: resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== -native-request@^1.0.5: - version "1.0.8" - resolved "https://registry.yarnpkg.com/native-request/-/native-request-1.0.8.tgz#8f66bf606e0f7ea27c0e5995eb2f5d03e33ae6fb" - integrity sha512-vU2JojJVelUGp6jRcLwToPoWGxSx23z/0iX+I77J3Ht17rf2INGjrhOoQnjVo60nQd8wVsgzKkPfRXBiVdD2ag== - native-url@^0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/native-url/-/native-url-0.2.6.tgz#ca1258f5ace169c716ff44eccbddb674e10399ae" @@ -10243,6 +10256,15 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +needle@^2.5.2: + version "2.8.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.8.0.tgz#1c8ef9c1a2c29dcc1e83d73809d7bc681c80a048" + integrity sha512-ZTq6WYkN/3782H1393me3utVYdq2XyqNUFBsprEE3VMAT0+hP/cItpnITpqsY6ep2yeFE4Tqtqwc74VqUlUYtw== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + negotiator@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" @@ -11362,6 +11384,11 @@ parse-json@^5.0.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" +parse-node-version@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" + integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== + parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" @@ -11652,7 +11679,7 @@ postcss-js@^3.0.3: camelcase-css "^2.0.1" postcss "^8.1.6" -postcss-load-config@^2.0.0, postcss-load-config@^2.1.0: +postcss-load-config@^2.0.0: version "2.1.2" resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.2.tgz#c5ea504f2c4aef33c7359a34de3573772ad7502a" integrity sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw== @@ -11660,6 +11687,15 @@ postcss-load-config@^2.0.0, postcss-load-config@^2.1.0: cosmiconfig "^5.0.0" import-cwd "^2.0.0" +postcss-load-config@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.0.tgz#d39c47091c4aec37f50272373a6a648ef5e97829" + integrity sha512-ipM8Ds01ZUophjDTQYSVP70slFSYg3T0/zyfII5vzhN6V57YSxMgG5syXuwi5VtS8wSf3iL30v0uBdoIVx4Q0g== + dependencies: + import-cwd "^3.0.0" + lilconfig "^2.0.3" + yaml "^1.10.2" + postcss-loader@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" @@ -11741,7 +11777,7 @@ postcss@^6.0.14, postcss@^6.0.2, postcss@^6.0.9: source-map "^0.6.1" supports-color "^5.4.0" -postcss@^7.0.0, postcss@^7.0.14, postcss@^7.0.27: +postcss@^7.0.0: version "7.0.35" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.35.tgz#d2be00b998f7f211d8a276974079f2e92b970e24" integrity sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg== @@ -11750,10 +11786,10 @@ postcss@^7.0.0, postcss@^7.0.14, postcss@^7.0.27: source-map "^0.6.1" supports-color "^6.1.0" -postcss@^8.1.6, postcss@^8.2.1, postcss@^8.2.14, postcss@^8.2.15: - version "8.3.0" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.0.tgz#b1a713f6172ca427e3f05ef1303de8b65683325f" - integrity sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ== +postcss@^8.1.6, postcss@^8.2.1, postcss@^8.2.14, postcss@^8.2.15, postcss@^8.3.0: + version "8.3.5" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.5.tgz#982216b113412bc20a86289e91eb994952a5b709" + integrity sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA== dependencies: colorette "^1.2.2" nanoid "^3.1.23" @@ -12981,10 +13017,10 @@ sass-loader@^8.0.2: schema-utils "^2.6.1" semver "^6.3.0" -sass@^1.26.5: - version "1.32.12" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.32.12.tgz#a2a47ad0f1c168222db5206444a30c12457abb9f" - integrity sha512-zmXn03k3hN0KaiVTjohgkg98C3UowhL1/VSGdj4/VAAiMKGQOE80PFPxFP2Kyq0OUskPKcY5lImkhBKEHlypJA== +sass@^1.32.13: + version "1.35.2" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.35.2.tgz#b732314fcdaf7ef8d0f1698698adc378043cb821" + integrity sha512-jhO5KAR+AMxCEwIH3v+4zbB2WB0z67V1X0jbapfVwQQdjHZUGUyukpnoM6+iCMfsIUC016w9OPKQ5jrNOS9uXw== dependencies: chokidar ">=3.0.0 <4.0.0" @@ -13982,7 +14018,7 @@ style-loader@^2.0.0: loader-utils "^2.0.0" schema-utils "^3.0.0" -stylus@^0.54.7: +stylus@^0.54.8: version "0.54.8" resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.54.8.tgz#3da3e65966bc567a7b044bfe0eece653e099d147" integrity sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg== @@ -14681,23 +14717,23 @@ typeface-roboto@^1.1.13: resolved "https://registry.yarnpkg.com/typeface-roboto/-/typeface-roboto-1.1.13.tgz#9c4517cb91e311706c74823e857b4bac9a764ae5" integrity sha512-YXvbd3a1QTREoD+FJoEkl0VQNJoEjewR2H11IjVv4bp6ahuIcw0yyw/3udC4vJkHw3T3cUh85FTg8eWef3pSaw== -typescript-plugin-css-modules@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/typescript-plugin-css-modules/-/typescript-plugin-css-modules-3.2.0.tgz#44241064395d565f242689b96eb50bf413e68ddf" - integrity sha512-oMe5IDKuPvLBOeaYupAqqq8UMTu7Jo5e0InqkQSSKXuZCcRm0+LQfUVMyM62IFpgzxHLuN32a7YdBxAaSXZrRQ== +typescript-plugin-css-modules@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/typescript-plugin-css-modules/-/typescript-plugin-css-modules-3.4.0.tgz#4ff6905d88028684d1608c05c62cb6346e5548cc" + integrity sha512-2MdjfSg4MGex1csCWRUwKD+MpgnvcvLLr9bSAMemU/QYGqBsXdez0cc06H/fFhLtRoKJjXg6PSTur3Gy1Umhpw== dependencies: - dotenv "^8.2.0" - icss-utils "^4.1.1" - less "^3.11.1" + dotenv "^10.0.0" + icss-utils "^5.1.0" + less "^4.1.1" lodash.camelcase "^4.3.0" - postcss "^7.0.27" + postcss "^8.3.0" postcss-filter-plugins "^3.0.1" postcss-icss-keyframes "^0.2.1" postcss-icss-selectors "^2.0.3" - postcss-load-config "^2.1.0" + postcss-load-config "^3.0.1" reserved-words "^0.1.2" - sass "^1.26.5" - stylus "^0.54.7" + sass "^1.32.13" + stylus "^0.54.8" tsconfig-paths "^3.9.0" typescript@^4.0.3: @@ -15656,7 +15692,7 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^1.7.2: +yaml@^1.10.2, yaml@^1.7.2: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== From 868373563066a990c358c7c169aa4a6a545573bb Mon Sep 17 00:00:00 2001 From: Violetta Shakirova <38247153+vshakirova@users.noreply.github.com> Date: Mon, 19 Jul 2021 19:38:44 +0400 Subject: [PATCH 60/80] Fix HPA visibility (#3426) Signed-off-by: vshakirova --- src/common/rbac.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/common/rbac.ts b/src/common/rbac.ts index 55b8ca414c..9d8242cd42 100644 --- a/src/common/rbac.ts +++ b/src/common/rbac.ts @@ -40,14 +40,14 @@ export interface KubeApiResourceData { export const apiResourceRecord: Record = { "clusterroles": { kind: "ClusterRole", group: "rbac.authorization.k8s.io" }, "clusterrolebindings": { kind: "ClusterRoleBinding", group: "rbac.authorization.k8s.io" }, - "configmaps": { kind: "ConfigMap" }, + "configmaps": { kind: "ConfigMap" }, //empty group means "core" "cronjobs": { kind: "CronJob", group: "batch" }, "customresourcedefinitions": { kind: "CustomResourceDefinition", group: "apiextensions.k8s.io" }, "daemonsets": { kind: "DaemonSet", group: "apps" }, "deployments": { kind: "Deployment", group: "apps" }, "endpoints": { kind: "Endpoint" }, "events": { kind: "Event" }, - "horizontalpodautoscalers": { kind: "HorizontalPodAutoscaler" }, + "horizontalpodautoscalers": { kind: "HorizontalPodAutoscaler", group: "autoscaling" }, "ingresses": { kind: "Ingress", group: "networking.k8s.io" }, "jobs": { kind: "Job", group: "batch" }, "namespaces": { kind: "Namespace" }, @@ -58,13 +58,13 @@ export const apiResourceRecord: Record = { "persistentvolumeclaims": { kind: "PersistentVolumeClaim" }, "pods": { kind: "Pod" }, "poddisruptionbudgets": { kind: "PodDisruptionBudget", group: "policy" }, - "podsecuritypolicies": { kind: "PodSecurityPolicy" }, + "podsecuritypolicies": { kind: "PodSecurityPolicy", group: "policy" }, "resourcequotas": { kind: "ResourceQuota" }, "replicasets": { kind: "ReplicaSet", group: "apps" }, "roles": { kind: "Role", group: "rbac.authorization.k8s.io" }, "rolebindings": { kind: "RoleBinding", group: "rbac.authorization.k8s.io" }, "secrets": { kind: "Secret" }, - "serviceaccounts": { kind: "ServiceAccount", group: "core" }, + "serviceaccounts": { kind: "ServiceAccount" }, "services": { kind: "Service" }, "statefulsets": { kind: "StatefulSet", group: "apps" }, "storageclasses": { kind: "StorageClass", group: "storage.k8s.io" }, From 600d2c8607a5b5d27473bc6017e6fe2825954f20 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 19 Jul 2021 13:40:47 -0400 Subject: [PATCH 61/80] Log as errors the places where getPortFrom can fail (#3425) Signed-off-by: Sebastian Malton --- src/main/proxy/lens-proxy.ts | 6 ++++-- src/main/routes/port-forward-route.ts | 17 ++++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/proxy/lens-proxy.ts b/src/main/proxy/lens-proxy.ts index 480a4b047a..9ffff0fd6a 100644 --- a/src/main/proxy/lens-proxy.ts +++ b/src/main/proxy/lens-proxy.ts @@ -61,7 +61,8 @@ export class LensProxy extends Singleton { if (req.url.startsWith(`${apiPrefix}?`)) { handleWsUpgrade(req, socket, head); } else { - this.handleProxyUpgrade(proxy, req, socket, head); + this.handleProxyUpgrade(proxy, req, socket, head) + .catch(error => logger.error(`[LENS-PROXY]: failed to handle proxy upgrade: ${error}`)); } }); } @@ -194,7 +195,8 @@ export class LensProxy extends Singleton { logger.debug(`Retrying proxy request to url: ${reqId}`); setTimeout(() => { this.retryCounters.set(reqId, retryCount + 1); - this.handleRequest(proxy, req, res); + this.handleRequest(proxy, req, res) + .catch(error => logger.error(`[LENS-PROXY]: failed to handle request on proxy error: ${error}`)); }, timeoutMs); } } diff --git a/src/main/routes/port-forward-route.ts b/src/main/routes/port-forward-route.ts index cfd88e771f..e97b4171cb 100644 --- a/src/main/routes/port-forward-route.ts +++ b/src/main/routes/port-forward-route.ts @@ -134,11 +134,22 @@ export class PortForwardRoute { name: resourceName, port, }); - const started = await portForward.start(); - if (!started) { + try { + const started = await portForward.start(); + + if (!started) { + logger.warn("[PORT-FORWARD-ROUTE]: failed to start a port-forward", { namespace, port, resourceType, resourceName }); + + return respondJson(response, { + message: "Failed to open port-forward" + }, 400); + } + } catch (error) { + logger.warn(`[PORT-FORWARD-ROUTE]: failed to open a port-forward: ${error}`, { namespace, port, resourceType, resourceName }); + return respondJson(response, { - message: "Failed to open port-forward" + message: error?.toString() || "Failed to open port-forward", }, 400); } } From 4873b856476bd778bc32c408ad261a471ea02b20 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 19 Jul 2021 16:15:58 -0400 Subject: [PATCH 62/80] release v5.1.2 (#3431) Signed-off-by: Sebastian Malton --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 067cef3a94..e7ff4d9abc 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "OpenLens", "description": "OpenLens - Open Source IDE for Kubernetes", "homepage": "https://github.com/lensapp/lens", - "version": "5.1.1", + "version": "5.1.2", "main": "static/build/main.js", "copyright": "Š 2021 OpenLens Authors", "license": "MIT", From 078583412ba462e78fe5d6fe3239e84320c63db4 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 20 Jul 2021 00:33:22 -0400 Subject: [PATCH 63/80] Use all namespaces for cluster overview warnings (#3441) Signed-off-by: Sebastian Malton --- src/renderer/components/+cluster/cluster-issues.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/renderer/components/+cluster/cluster-issues.tsx b/src/renderer/components/+cluster/cluster-issues.tsx index 90a8a1a74b..f35f8bea61 100644 --- a/src/renderer/components/+cluster/cluster-issues.tsx +++ b/src/renderer/components/+cluster/cluster-issues.tsx @@ -22,7 +22,7 @@ import "./cluster-issues.scss"; import React from "react"; -import { observer } from "mobx-react"; +import { disposeOnUnmount, observer } from "mobx-react"; import { computed, makeObservable } from "mobx"; import { Icon } from "../icon"; import { SubHeader } from "../layout/sub-header"; @@ -35,6 +35,7 @@ import { Spinner } from "../spinner"; import { ThemeStore } from "../../theme.store"; import { lookupApiLink } from "../../api/kube-api"; import { kubeSelectedUrlParam, showDetails } from "../kube-object"; +import { kubeWatchApi } from "../../api/kube-watch-api"; interface Props { className?: string; @@ -65,6 +66,10 @@ export class ClusterIssues extends React.Component { constructor(props: Props) { super(props); makeObservable(this); + + disposeOnUnmount(this, [ + kubeWatchApi.subscribeStores([eventStore, nodesStore]) + ]); } @computed get warnings() { From 70448159d3f8cf1b5b2389a34411080bc2acc4ae Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 20 Jul 2021 00:33:38 -0400 Subject: [PATCH 64/80] Failing to loadAll should only warn (#3442) Signed-off-by: Sebastian Malton --- src/renderer/kube-object.store.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/kube-object.store.ts b/src/renderer/kube-object.store.ts index d94ba51bdb..881a9ae6f3 100644 --- a/src/renderer/kube-object.store.ts +++ b/src/renderer/kube-object.store.ts @@ -195,7 +195,7 @@ export abstract class KubeObjectStore extends ItemSt if (error.message) { Notifications.error(error.message); } - console.error("[KubeObjectStore] loadAll failed", this.api.apiBase, error); + console.warn("[KubeObjectStore] loadAll failed", this.api.apiBase, error); this.resetOnError(error); this.failedLoading = true; } finally { From c590bccffaf6ba4fde7d35cfdeb794cc6b7d6117 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 20 Jul 2021 00:34:23 -0400 Subject: [PATCH 65/80] Fix permissions issue on ServiceDetails under RBAC (#3433) - Only watch the namespace that the service is in instead of all of them Signed-off-by: Sebastian Malton --- src/renderer/components/+network-services/service-details.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/renderer/components/+network-services/service-details.tsx b/src/renderer/components/+network-services/service-details.tsx index 6450850076..ec10cd5f94 100644 --- a/src/renderer/components/+network-services/service-details.tsx +++ b/src/renderer/components/+network-services/service-details.tsx @@ -39,9 +39,12 @@ interface Props extends KubeObjectDetailsProps { @observer export class ServiceDetails extends React.Component { componentDidMount() { + const { object: service } = this.props; + disposeOnUnmount(this, [ kubeWatchApi.subscribeStores([endpointStore], { preload: true, + namespaces: [service.getNs()], }), ]); } From c4aeaf5bb71e73d2747f5d5ff8f0b54645d8799f Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 20 Jul 2021 00:40:02 -0400 Subject: [PATCH 66/80] Fix styling on cluster roles and bindings (#3434) Signed-off-by: Sebastian Malton --- .../+user-management/+cluster-role-bindings/details.scss | 4 ++-- .../+user-management/+cluster-role-bindings/details.tsx | 2 +- .../+user-management/+cluster-roles/add-dialog.scss | 4 ++-- .../+user-management/+cluster-roles/add-dialog.tsx | 6 +++--- .../components/+user-management/+cluster-roles/details.scss | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/renderer/components/+user-management/+cluster-role-bindings/details.scss b/src/renderer/components/+user-management/+cluster-role-bindings/details.scss index 1efb4412a2..1afe80f236 100644 --- a/src/renderer/components/+user-management/+cluster-role-bindings/details.scss +++ b/src/renderer/components/+user-management/+cluster-role-bindings/details.scss @@ -19,5 +19,5 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -.RoleBindingDetails { -} \ No newline at end of file +.ClusterRoleBindingDetails { +} diff --git a/src/renderer/components/+user-management/+cluster-role-bindings/details.tsx b/src/renderer/components/+user-management/+cluster-role-bindings/details.tsx index 08087324cc..7dea8c083e 100644 --- a/src/renderer/components/+user-management/+cluster-role-bindings/details.tsx +++ b/src/renderer/components/+user-management/+cluster-role-bindings/details.tsx @@ -81,7 +81,7 @@ export class ClusterRoleBindingDetails extends React.Component { const subjects = clusterRoleBinding.getSubjects(); return ( -
+
diff --git a/src/renderer/components/+user-management/+cluster-roles/add-dialog.scss b/src/renderer/components/+user-management/+cluster-roles/add-dialog.scss index 4b94e11c4b..cc0e3fcdd6 100644 --- a/src/renderer/components/+user-management/+cluster-roles/add-dialog.scss +++ b/src/renderer/components/+user-management/+cluster-roles/add-dialog.scss @@ -19,8 +19,8 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -.AddRoleDialog { +.AddClusterRoleDialog { .AceEditor { min-height: 200px; } -} \ No newline at end of file +} diff --git a/src/renderer/components/+user-management/+cluster-roles/add-dialog.tsx b/src/renderer/components/+user-management/+cluster-roles/add-dialog.tsx index 4006334903..f6866355b3 100644 --- a/src/renderer/components/+user-management/+cluster-roles/add-dialog.tsx +++ b/src/renderer/components/+user-management/+cluster-roles/add-dialog.tsx @@ -76,12 +76,12 @@ export class AddClusterRoleDialog extends React.Component { return ( - Create ClusterRole} + Create ClusterRole} done={AddClusterRoleDialog.close} > Date: Tue, 20 Jul 2021 09:57:51 +0300 Subject: [PATCH 67/80] Bump @types/tar from 4.0.4 to 4.0.5 (#3443) Bumps [@types/tar](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/tar) from 4.0.4 to 4.0.5. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/tar) --- updated-dependencies: - dependency-name: "@types/tar" 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.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e7ff4d9abc..c1ff6091d2 100644 --- a/package.json +++ b/package.json @@ -299,7 +299,7 @@ "@types/sharp": "^0.28.3", "@types/shelljs": "^0.8.8", "@types/spdy": "^3.4.4", - "@types/tar": "^4.0.4", + "@types/tar": "^4.0.5", "@types/tcp-port-used": "^1.0.0", "@types/tempy": "^0.3.0", "@types/url-parse": "^1.4.3", diff --git a/yarn.lock b/yarn.lock index 4ac75156c9..8f10484d9a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2004,10 +2004,10 @@ resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.5.tgz#9adbc12950582aa65ead76bffdf39fe0c27a3c02" integrity sha512-/gG2M/Imw7cQFp8PGvz/SwocNrmKFjFsm5Pb8HdbHkZ1K8pmuPzOX4VeVoiEecFCVf4CsN1r3/BRvx+6sNqwtQ== -"@types/tar@^4.0.3", "@types/tar@^4.0.4": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@types/tar/-/tar-4.0.4.tgz#d680de60855e7778a51c672b755869a3b8d2889f" - integrity sha512-0Xv+xcmkTsOZdIF4yCnd7RkOOyfyqPaqJ7RZFKnwdxfDbkN3eAAE9sHl8zJFqBz4VhxolW9EErbjR1oyH7jK2A== +"@types/tar@^4.0.3", "@types/tar@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@types/tar/-/tar-4.0.5.tgz#5f953f183e36a15c6ce3f336568f6051b7b183f3" + integrity sha512-cgwPhNEabHaZcYIy5xeMtux2EmYBitfqEceBUi2t5+ETy4dW6kswt6WX4+HqLeiiKOo42EXbGiDmVJ2x+vi37Q== dependencies: "@types/minipass" "*" "@types/node" "*" From cf3aceb465a3980e3a4af1337f9f478e2f38ff4e Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 20 Jul 2021 03:19:52 -0400 Subject: [PATCH 68/80] Sort cronjob last scheduled time by number (#3430) Signed-off-by: Sebastian Malton --- src/renderer/components/+workloads-cronjobs/cronjobs.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx index b1a812cc4f..b1c5e3424c 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx @@ -37,6 +37,7 @@ import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { ConfirmDialog } from "../confirm-dialog/confirm-dialog"; import { Notifications } from "../notifications/notifications"; import type { CronJobsRouteParams } from "../../../common/routes"; +import moment from "moment"; enum columnId { name = "name", @@ -65,7 +66,11 @@ export class CronJobs extends React.Component { [columnId.namespace]: (cronJob: CronJob) => cronJob.getNs(), [columnId.suspend]: (cronJob: CronJob) => cronJob.getSuspendFlag(), [columnId.active]: (cronJob: CronJob) => cronJobStore.getActiveJobsNum(cronJob), - [columnId.lastSchedule]: (cronJob: CronJob) => cronJob.getLastScheduleTime(), + [columnId.lastSchedule]: (cronJob: CronJob) => ( + cronJob.status?.lastScheduleTime + ? moment().diff(cronJob.status.lastScheduleTime) + : 0 + ), [columnId.age]: (cronJob: CronJob) => cronJob.getTimeDiffFromNow(), }} searchFilters={[ From bf4e0397431fbbd052c901b0c594a26e3b190315 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Jul 2021 10:31:46 +0300 Subject: [PATCH 69/80] Bump ts-jest from 26.3.0 to 26.5.6 (#3449) Bumps [ts-jest](https://github.com/kulshekhar/ts-jest) from 26.3.0 to 26.5.6. - [Release notes](https://github.com/kulshekhar/ts-jest/releases) - [Changelog](https://github.com/kulshekhar/ts-jest/blob/master/CHANGELOG.md) - [Commits](https://github.com/kulshekhar/ts-jest/compare/v26.3.0...v26.5.6) --- updated-dependencies: - dependency-name: ts-jest 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.json | 2 +- yarn.lock | 142 +++++++++------------------------------------------ 2 files changed, 26 insertions(+), 118 deletions(-) diff --git a/package.json b/package.json index c1ff6091d2..f4d7d8a699 100644 --- a/package.json +++ b/package.json @@ -366,7 +366,7 @@ "spectron": "11.0.0", "style-loader": "^2.0.0", "tailwindcss": "^2.1.2", - "ts-jest": "26.3.0", + "ts-jest": "26.5.6", "ts-loader": "^7.0.5", "ts-node": "^8.10.2", "type-fest": "^1.0.2", diff --git a/yarn.lock b/yarn.lock index 8f10484d9a..ec84b175ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -766,27 +766,6 @@ source-map "^0.6.1" write-file-atomic "^3.0.0" -"@jest/types@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d" - integrity sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^15.0.0" - chalk "^3.0.0" - -"@jest/types@^26.3.0": - version "26.3.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.3.0.tgz#97627bf4bdb72c55346eef98e3b3f7ddc4941f71" - integrity sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^15.0.0" - chalk "^4.0.0" - "@jest/types@^26.6.1": version "26.6.1" resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.1.tgz#2638890e8031c0bc8b4681e0357ed986e2f866c5" @@ -1565,14 +1544,6 @@ dependencies: "@types/istanbul-lib-coverage" "*" -"@types/istanbul-reports@^1.1.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" - integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== - dependencies: - "@types/istanbul-lib-coverage" "*" - "@types/istanbul-lib-report" "*" - "@types/istanbul-reports@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz#508b13aa344fa4976234e75dddcc34925737d821" @@ -1588,14 +1559,6 @@ jest-diff "^26.0.0" pretty-format "^26.0.0" -"@types/jest@26.x": - version "26.0.13" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.13.tgz#5a7b9d5312f5dd521a38329c38ee9d3802a0b85e" - integrity sha512-sCzjKow4z9LILc6DhBvn5AkIfmQzDZkgtVVKmGwVrs5tuid38ws281D4l+7x1kP487+FlKDh5kfMZ8WSPAdmdA== - dependencies: - jest-diff "^25.2.1" - pretty-format "^25.2.1" - "@types/jest@^26.0.22": version "26.0.22" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.22.tgz#8308a1debdf1b807aa47be2838acdcd91e88fbe6" @@ -5039,11 +5002,6 @@ didyoumean@^1.2.1: resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.1.tgz#e92edfdada6537d484d73c0172fd1eba0c4976ff" integrity sha1-6S7f2tplN9SE1zwBcv0eugxJdv8= -diff-sequences@^25.2.6: - version "25.2.6" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" - integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== - diff-sequences@^26.5.0: version "26.5.0" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.5.0.tgz#ef766cf09d43ed40406611f11c6d8d9dd8b2fefd" @@ -8411,16 +8369,6 @@ jest-config@^26.6.3: micromatch "^4.0.2" pretty-format "^26.6.2" -jest-diff@^25.2.1: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.5.0.tgz#1dd26ed64f96667c068cef026b677dfa01afcfa9" - integrity sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A== - dependencies: - chalk "^3.0.0" - diff-sequences "^25.2.6" - jest-get-type "^25.2.6" - pretty-format "^25.5.0" - jest-diff@^26.0.0: version "26.6.1" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.1.tgz#38aa194979f454619bb39bdee299fb64ede5300c" @@ -8492,11 +8440,6 @@ jest-fetch-mock@^3.0.3: cross-fetch "^3.0.4" promise-polyfill "^8.1.3" -jest-get-type@^25.2.6: - version "25.2.6" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" - integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== - jest-get-type@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" @@ -8717,19 +8660,7 @@ jest-snapshot@^26.6.2: pretty-format "^26.6.2" semver "^7.3.2" -jest-util@26.x: - version "26.3.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.3.0.tgz#a8974b191df30e2bf523ebbfdbaeb8efca535b3e" - integrity sha512-4zpn6bwV0+AMFN0IYhH/wnzIQzRaYVrz1A8sYnRnj4UXDXbOVtWmlaZkO9mipFqZ13okIfN87aDoJWB7VH6hcw== - dependencies: - "@jest/types" "^26.3.0" - "@types/node" "*" - chalk "^4.0.0" - graceful-fs "^4.2.4" - is-ci "^2.0.0" - micromatch "^4.0.2" - -jest-util@^26.6.2: +jest-util@^26.1.0, jest-util@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== @@ -8947,10 +8878,10 @@ json3@^3.3.2: resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== -json5@2.x, json5@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" - integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== +json5@2.x, json5@^2.1.2, json5@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== dependencies: minimist "^1.2.5" @@ -8966,13 +8897,6 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" -json5@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" - jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -9557,11 +9481,6 @@ lodash.isequal@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= -lodash.memoize@4.x: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= - lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" @@ -9592,7 +9511,7 @@ lodash.without@~4.4.0: resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw= -lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.8.0, lodash@~4.17.10: +lodash@4.x, lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.8.0, lodash@~4.17.10: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -11849,16 +11768,6 @@ pretty-error@^2.1.1: renderkid "^2.0.1" utila "~0.4" -pretty-format@^25.2.1, pretty-format@^25.5.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a" - integrity sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ== - dependencies: - "@jest/types" "^25.5.0" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^16.12.0" - pretty-format@^26.0.0, pretty-format@^26.6.1: version "26.6.1" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.1.tgz#af9a2f63493a856acddeeb11ba6bcf61989660a8" @@ -12226,7 +12135,7 @@ react-input-autosize@^2.2.2: dependencies: prop-types "^15.5.8" -react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: +react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -14508,22 +14417,21 @@ ts-essentials@^4.0.0: resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-4.0.0.tgz#506c42b270bbd0465574b90416533175b09205ab" integrity sha512-uQJX+SRY9mtbKU+g9kl5Fi7AEMofPCvHfJkQlaygpPmHPZrtgaBqbWFOYyiA47RhnSwwnXdepUJrgqUYxoUyhQ== -ts-jest@26.3.0: - version "26.3.0" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.3.0.tgz#6b2845045347dce394f069bb59358253bc1338a9" - integrity sha512-Jq2uKfx6bPd9+JDpZNMBJMdMQUC3sJ08acISj8NXlVgR2d5OqslEHOR2KHMgwymu8h50+lKIm0m0xj/ioYdW2Q== +ts-jest@26.5.6: + version "26.5.6" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.6.tgz#c32e0746425274e1dfe333f43cd3c800e014ec35" + integrity sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA== dependencies: - "@types/jest" "26.x" bs-logger "0.x" buffer-from "1.x" fast-json-stable-stringify "2.x" - jest-util "26.x" + jest-util "^26.1.0" json5 "2.x" - lodash.memoize "4.x" + lodash "4.x" make-error "1.x" mkdirp "1.x" semver "7.x" - yargs-parser "18.x" + yargs-parser "20.x" ts-loader@^7.0.5: version "7.0.5" @@ -15697,13 +15605,10 @@ yaml@^1.10.2, yaml@^1.7.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yargs-parser@18.x, yargs-parser@^18.1.2: - version "18.1.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" - integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" +yargs-parser@20.x, yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== yargs-parser@^13.1.0, yargs-parser@^13.1.2: version "13.1.2" @@ -15721,10 +15626,13 @@ yargs-parser@^15.0.1: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^20.2.2: - version "20.2.7" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a" - integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw== +yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" yargs-parser@^7.0.0: version "7.0.0" From 686ae32dcb7b75b9f096101486aff3d8cb195ce0 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 20 Jul 2021 03:32:15 -0400 Subject: [PATCH 70/80] When viewing a specific release, select its namespace (#3440) Signed-off-by: Sebastian Malton --- src/renderer/components/+apps-releases/release.store.ts | 4 ++++ src/renderer/components/+apps-releases/releases.tsx | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/src/renderer/components/+apps-releases/release.store.ts b/src/renderer/components/+apps-releases/release.store.ts index 9b450a7465..9d704566e7 100644 --- a/src/renderer/components/+apps-releases/release.store.ts +++ b/src/renderer/components/+apps-releases/release.store.ts @@ -55,12 +55,16 @@ export class ReleaseStore extends ItemStore { this.loadFromContextNamespaces(); } this.releaseSecrets.replace(newSecrets); + }, { + fireImmediately: true, }); } watchSelectedNamespaces(): (() => void) { return reaction(() => namespaceStore.context.contextNamespaces, namespaces => { this.loadAll(namespaces); + }, { + fireImmediately: true, }); } diff --git a/src/renderer/components/+apps-releases/releases.tsx b/src/renderer/components/+apps-releases/releases.tsx index 453983e8d0..c39807d73e 100644 --- a/src/renderer/components/+apps-releases/releases.tsx +++ b/src/renderer/components/+apps-releases/releases.tsx @@ -36,6 +36,7 @@ import { secretsStore } from "../+config-secrets/secrets.store"; import { NamespaceSelectFilter } from "../+namespaces/namespace-select-filter"; import type { ReleaseRouteParams } from "../../../common/routes"; import { releaseURL } from "../../../common/routes"; +import { namespaceStore } from "../+namespaces/namespace.store"; enum columnId { name = "name", @@ -54,6 +55,12 @@ interface Props extends RouteComponentProps { @observer export class HelmReleases extends Component { componentDidMount() { + const { match: { params: { namespace } } } = this.props; + + if (namespace) { + namespaceStore.selectNamespaces(namespace); + } + disposeOnUnmount(this, [ releaseStore.watchAssociatedSecrets(), releaseStore.watchSelectedNamespaces(), From 10ab882fedb95e0a79a3aac85417a3d7e2ac90cd Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Tue, 20 Jul 2021 12:23:45 +0300 Subject: [PATCH 71/80] Replace ... to smaller … HTML character (#3450) Signed-off-by: Alex Andreev --- src/renderer/components/cluster-manager/cluster-status.scss | 6 +++++- src/renderer/components/cluster-manager/cluster-status.tsx | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/renderer/components/cluster-manager/cluster-status.scss b/src/renderer/components/cluster-manager/cluster-status.scss index 86527eb75f..77d6e7693f 100644 --- a/src/renderer/components/cluster-manager/cluster-status.scss +++ b/src/renderer/components/cluster-manager/cluster-status.scss @@ -33,10 +33,14 @@ max-width: 70vw; max-height: 40vh; white-space: pre-line; + + p { + margin-bottom: $margin; + } } .Spinner { - --spinner-size: 48px; + --spinner-size: 38px; --spinner-border: calc(var(--spinner-size) / 10); } diff --git a/src/renderer/components/cluster-manager/cluster-status.tsx b/src/renderer/components/cluster-manager/cluster-status.tsx index 30065e2dd0..366a809b59 100644 --- a/src/renderer/components/cluster-manager/cluster-status.tsx +++ b/src/renderer/components/cluster-manager/cluster-status.tsx @@ -102,7 +102,7 @@ export class ClusterStatus extends React.Component { <>
-            

{this.isReconnecting ? "Reconnecting..." : "Connecting..."}

+

{this.isReconnecting ? "Reconnecting" : "Connecting"}…

{authOutput.map(({ data, error }, index) => { return

{data}

; })} From 2ea589a5998123b4a4705995116a958ebd8ea433 Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Tue, 20 Jul 2021 15:01:58 +0300 Subject: [PATCH 72/80] Removing depenendency @types/shelljs (#3448) Signed-off-by: Alex Andreev --- package.json | 1 - yarn.lock | 16 ---------------- 2 files changed, 17 deletions(-) diff --git a/package.json b/package.json index f4d7d8a699..e722ef45ab 100644 --- a/package.json +++ b/package.json @@ -297,7 +297,6 @@ "@types/request-promise-native": "^1.0.17", "@types/semver": "^7.2.0", "@types/sharp": "^0.28.3", - "@types/shelljs": "^0.8.8", "@types/spdy": "^3.4.4", "@types/tar": "^4.0.5", "@types/tcp-port-used": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index ec84b175ab..74d0e68e39 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1417,14 +1417,6 @@ dependencies: "@types/node" "*" -"@types/glob@*": - version "7.1.2" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.2.tgz#06ca26521353a545d94a0adc74f38a59d232c987" - integrity sha512-VgNIkxK+j7Nz5P7jvUZlRvhuPSmsEfS03b0alKcq5V/STUKAa3Plemsn5mrQUO7am6OErJ4rhGEGJbACclrtRA== - dependencies: - "@types/minimatch" "*" - "@types/node" "*" - "@types/glob@^7.1.1": version "7.1.3" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" @@ -1923,14 +1915,6 @@ dependencies: "@types/node" "*" -"@types/shelljs@^0.8.8": - version "0.8.8" - resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.8.tgz#e439c69929b88a2c8123c1a55e09eb708315addf" - integrity sha512-lD3LWdg6j8r0VRBFahJVaxoW0SIcswxKaFUrmKl33RJVeeoNYQAz4uqCJ5Z6v4oIBOsC5GozX+I5SorIKiTcQA== - dependencies: - "@types/glob" "*" - "@types/node" "*" - "@types/shot@*": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/shot/-/shot-4.0.0.tgz#7545500c489b65c69b5bc5446ba4fef3bd26af92" From 14b70a6c539c6508050eadd1441c04c609184448 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 20 Jul 2021 08:39:44 -0400 Subject: [PATCH 73/80] Cleanup (#3338) --- src/common/__tests__/event-emitter.test.ts | 102 +++++++++++++++++++++ src/common/event-emitter.ts | 26 +++--- 2 files changed, 113 insertions(+), 15 deletions(-) create mode 100644 src/common/__tests__/event-emitter.test.ts diff --git a/src/common/__tests__/event-emitter.test.ts b/src/common/__tests__/event-emitter.test.ts new file mode 100644 index 0000000000..b54df2af98 --- /dev/null +++ b/src/common/__tests__/event-emitter.test.ts @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import { EventEmitter } from "../event-emitter"; + +describe("EventEmitter", () => { + it("should stop early if a listener returns false", () => { + let called = false; + const e = new EventEmitter<[]>(); + + e.addListener(() => false, {}); + e.addListener(() => { called = true; }, {}); + e.emit(); + + expect(called).toBe(false); + }); + + it("shouldn't stop early if a listener returns 0", () => { + let called = false; + const e = new EventEmitter<[]>(); + + e.addListener(() => 0 as any, {}); + e.addListener(() => { called = true; }, {}); + e.emit(); + + expect(called).toBe(true); + }); + + it("prepended listeners should be called before others", () => { + const callOrder: number[] = []; + const e = new EventEmitter<[]>(); + + e.addListener(() => { callOrder.push(1); }, {}); + e.addListener(() => { callOrder.push(2); }, {}); + e.addListener(() => { callOrder.push(3); }, { prepend: true }); + e.emit(); + + expect(callOrder).toStrictEqual([3, 1, 2]); + }); + + it("once listeners should be called only once", () => { + const callOrder: number[] = []; + const e = new EventEmitter<[]>(); + + e.addListener(() => { callOrder.push(1); }, {}); + e.addListener(() => { callOrder.push(2); }, {}); + e.addListener(() => { callOrder.push(3); }, { once: true }); + e.emit(); + e.emit(); + + expect(callOrder).toStrictEqual([1, 2, 3, 1, 2]); + }); + + it("removeListener should stop the listener from being called", () => { + const callOrder: number[] = []; + const e = new EventEmitter<[]>(); + const r = () => { callOrder.push(3); }; + + e.addListener(() => { callOrder.push(1); }, {}); + e.addListener(() => { callOrder.push(2); }, {}); + e.addListener(r); + + e.emit(); + e.removeListener(r); + e.emit(); + + expect(callOrder).toStrictEqual([1, 2, 3, 1, 2]); + }); + + it("removeAllListeners should stop the all listeners from being called", () => { + const callOrder: number[] = []; + const e = new EventEmitter<[]>(); + + e.addListener(() => { callOrder.push(1); }); + e.addListener(() => { callOrder.push(2); }); + e.addListener(() => { callOrder.push(3); }); + + e.emit(); + e.removeAllListeners(); + e.emit(); + + expect(callOrder).toStrictEqual([1, 2, 3]); + }); +}); diff --git a/src/common/event-emitter.ts b/src/common/event-emitter.ts index 5ff785d431..4e1fb45151 100644 --- a/src/common/event-emitter.ts +++ b/src/common/event-emitter.ts @@ -29,35 +29,31 @@ interface Options { type Callback = (...data: D) => void | boolean; export class EventEmitter { - protected listeners = new Map, Options>(); + protected listeners: [Callback, Options][] = []; addListener(callback: Callback, options: Options = {}) { - if (options.prepend) { - const listeners = [...this.listeners]; + const fn = options.prepend ? "unshift" : "push"; - listeners.unshift([callback, options]); - this.listeners = new Map(listeners); - } - else { - this.listeners.set(callback, options); - } + this.listeners[fn]([callback, options]); } removeListener(callback: Callback) { - this.listeners.delete(callback); + this.listeners = this.listeners.filter(([cb]) => cb !== callback); } removeAllListeners() { - this.listeners.clear(); + this.listeners.length = 0; } emit(...data: D) { - [...this.listeners].every(([callback, options]) => { - if (options.once) { + for (const [callback, { once }] of this.listeners) { + if (once) { this.removeListener(callback); } - return callback(...data) !== false; - }); + if (callback(...data) === false) { + break; + } + } } } From a4f252864b51bd76555cd4c9e746250cdcfbab77 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 20 Jul 2021 09:30:02 -0400 Subject: [PATCH 74/80] Add ability to trim the value from (#3333) - If set (default = false) then the input will be trimmed of whitespace before validation and before submit - Use trim on all input's that use the systemName validator Signed-off-by: Sebastian Malton --- .../add-quota-dialog.tsx | 1 + .../+config-secrets/add-secret-dialog.tsx | 1 + .../+namespaces/add-namespace-dialog.tsx | 1 + .../+preferences/add-helm-repo-dialog.tsx | 1 + .../+service-accounts/create-dialog.tsx | 4 +++- .../cronjob-trigger-dialog.tsx | 1 + src/renderer/components/input/input.tsx | 24 ++++++++++--------- 7 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx b/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx index 17dc3e5eae..b341d2c86a 100644 --- a/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx +++ b/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx @@ -175,6 +175,7 @@ export class AddQuotaDialog extends React.Component { this.quotaName = v.toLowerCase()} className="box grow" diff --git a/src/renderer/components/+config-secrets/add-secret-dialog.tsx b/src/renderer/components/+config-secrets/add-secret-dialog.tsx index bfd7a3262e..23adfaf804 100644 --- a/src/renderer/components/+config-secrets/add-secret-dialog.tsx +++ b/src/renderer/components/+config-secrets/add-secret-dialog.tsx @@ -223,6 +223,7 @@ export class AddSecretDialog extends React.Component { this.name = v} /> diff --git a/src/renderer/components/+namespaces/add-namespace-dialog.tsx b/src/renderer/components/+namespaces/add-namespace-dialog.tsx index 213891c233..2427c9fd9b 100644 --- a/src/renderer/components/+namespaces/add-namespace-dialog.tsx +++ b/src/renderer/components/+namespaces/add-namespace-dialog.tsx @@ -100,6 +100,7 @@ export class AddNamespaceDialog extends React.Component { required autoFocus iconLeft="layers" placeholder="Namespace" + trim validators={systemName} value={namespace} onChange={v => this.namespace = v.toLowerCase()} /> diff --git a/src/renderer/components/+preferences/add-helm-repo-dialog.tsx b/src/renderer/components/+preferences/add-helm-repo-dialog.tsx index 44ef32b9af..36388088e1 100644 --- a/src/renderer/components/+preferences/add-helm-repo-dialog.tsx +++ b/src/renderer/components/+preferences/add-helm-repo-dialog.tsx @@ -177,6 +177,7 @@ export class AddHelmRepoDialog extends React.Component { this.helmRepo.name = v} /> diff --git a/src/renderer/components/+user-management/+service-accounts/create-dialog.tsx b/src/renderer/components/+user-management/+service-accounts/create-dialog.tsx index e812068506..1f50e717c6 100644 --- a/src/renderer/components/+user-management/+service-accounts/create-dialog.tsx +++ b/src/renderer/components/+user-management/+service-accounts/create-dialog.tsx @@ -88,8 +88,10 @@ export class CreateServiceAccountDialog extends React.Component { this.name = v.toLowerCase()} /> diff --git a/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx b/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx index f4006bd89f..0e2f98d16a 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx @@ -123,6 +123,7 @@ export class CronJobTriggerDialog extends Component { this.jobName = v.toLowerCase()} diff --git a/src/renderer/components/input/input.tsx b/src/renderer/components/input/input.tsx index d182a8c202..91b58c24b5 100644 --- a/src/renderer/components/input/input.tsx +++ b/src/renderer/components/input/input.tsx @@ -41,11 +41,13 @@ export type { InputValidator }; type InputElement = HTMLInputElement | HTMLTextAreaElement; type InputElementProps = InputHTMLAttributes & TextareaHTMLAttributes & DOMAttributes; -export type InputProps = Omit & { +export type InputProps = Omit & { theme?: "round-black" | "round"; className?: string; - value?: T; - autoSelectOnFocus?: boolean + value?: string; + trim?: boolean; + autoSelectOnFocus?: boolean; + defaultValue?: string; multiLine?: boolean; // use text-area as input field maxRows?: number; // when multiLine={true} define max rows size dirty?: boolean; // show validation errors even if the field wasn't touched yet @@ -55,8 +57,8 @@ export type InputProps = Omit): void; - onSubmit?(value: T, evt: React.KeyboardEvent): void; + onChange?(value: string, evt: React.ChangeEvent): void; + onSubmit?(value: string, evt: React.KeyboardEvent): void; }; interface State { @@ -73,6 +75,7 @@ const defaultProps: Partial = { maxRows: 10000, showValidationLine: true, validators: [], + defaultValue: "", }; export class Input extends React.Component { @@ -102,12 +105,10 @@ export class Input extends React.Component { } getValue(): string { - const { value, defaultValue = "" } = this.props; + const { trim, value, defaultValue } = this.props; + const rawValue = value ?? this.input?.value ?? defaultValue; - if (value !== undefined) return value; // controlled input - if (this.input) return this.input.value; // uncontrolled input - - return defaultValue as string; + return trim ? rawValue.trim() : rawValue; } focus() { @@ -138,7 +139,8 @@ export class Input extends React.Component { private validationId: string; - async validate(value = this.getValue()) { + async validate() { + const value = this.getValue(); let validationId = (this.validationId = ""); // reset every time for async validators const asyncValidators: Promise[] = []; const errors: React.ReactNode[] = []; From f03cc59688e6aaa7147334f9d076ab643bd410f6 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 20 Jul 2021 09:32:37 -0400 Subject: [PATCH 75/80] Wait for a file to be stable before computing diff (#3427) Signed-off-by: Sebastian Malton --- src/main/catalog-sources/kubeconfig-sync.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/catalog-sources/kubeconfig-sync.ts b/src/main/catalog-sources/kubeconfig-sync.ts index 6a6f4120f9..e60d9400de 100644 --- a/src/main/catalog-sources/kubeconfig-sync.ts +++ b/src/main/catalog-sources/kubeconfig-sync.ts @@ -264,6 +264,12 @@ async function watchFileChanges(filePath: string): Promise<[IComputedValue>(); const derivedSource = computed(() => Array.from(iter.flatMap(rootSource.values(), from => iter.map(from.values(), child => child[1])))); From aeae2dcf984b2dc81cdbe638a3fabf99c05ff63a Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Tue, 20 Jul 2021 19:19:39 +0300 Subject: [PATCH 76/80] Enable codeql analysis (#3455) --- .github/workflows/codeql-analysis.yml | 71 +++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000000..fc2692be70 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,71 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + schedule: + - cron: '41 3 * * 2' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'javascript' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 From 27f2bd7181cfca05d3010a7d189a89345c7e9bf9 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 20 Jul 2021 15:25:18 -0400 Subject: [PATCH 77/80] Wait for shell to bring up prompt before sending commands (#3337) --- src/renderer/api/terminal-api.ts | 65 ++++++++++++------- .../components/dock/terminal.store.ts | 35 +++++++--- 2 files changed, 70 insertions(+), 30 deletions(-) diff --git a/src/renderer/api/terminal-api.ts b/src/renderer/api/terminal-api.ts index 3b2c8a1cd9..347dfac224 100644 --- a/src/renderer/api/terminal-api.ts +++ b/src/renderer/api/terminal-api.ts @@ -19,11 +19,13 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { stringify } from "querystring"; import { boundMethod, base64, EventEmitter } from "../utils"; import { WebSocketApi } from "./websocket-api"; import isEqual from "lodash/isEqual"; import { isDevelopment } from "../../common/vars"; +import url from "url"; +import { makeObservable, observable } from "mobx"; +import type { ParsedUrlQueryInput } from "querystring"; export enum TerminalChannels { STDIN = 0, @@ -55,7 +57,9 @@ export class TerminalApi extends WebSocketApi { protected size: { Width: number; Height: number }; public onReady = new EventEmitter<[]>(); - public isReady = false; + @observable public isReady = false; + @observable public shellRunCommandsFinished = false; + public readonly url: string; constructor(protected options: TerminalApiQuery) { super({ @@ -63,34 +67,33 @@ export class TerminalApi extends WebSocketApi { flushOnOpen: false, pingIntervalSeconds: 30, }); - } + makeObservable(this); - async getUrl() { - let { port } = location; - const { hostname, protocol } = location; - const { id, node } = this.options; - const wss = `ws${protocol === "https:" ? "s" : ""}://`; - const query: TerminalApiQuery = { id }; + const { hostname, protocol, port } = location; + const query: ParsedUrlQueryInput = { + id: options.id, + }; - if (port) { - port = `:${port}`; + if (options.node) { + query.node = options.node; + query.type = options.type || "node"; } - if (node) { - query.node = node; - query.type = "node"; - } - - return `${wss}${hostname}${port}/api?${stringify(query)}`; + this.url = url.format({ + protocol: protocol.includes("https") ? "wss" : "ws", + hostname, + port, + pathname: "/api", + query, + slashes: true, + }); } - async connect() { - const apiUrl = await this.getUrl(); - + connect() { this.emitStatus("Connecting ..."); this.onData.addListener(this._onReady, { prepend: true }); - - return super.connect(apiUrl); + this.onData.addListener(this._onShellRunCommandsFinished); + super.connect(this.url); } destroy() { @@ -106,6 +109,24 @@ export class TerminalApi extends WebSocketApi { this.onReady.removeAllListeners(); } + _onShellRunCommandsFinished = (data: string) => { + if (!data) { + return; + } + + /** + * This is a heuistic for ditermining when a shell has finished executing + * its own rc file (or RunCommands file) such as `.bashrc` or `.zshrc`. + * + * This heuistic assumes that the prompt line of a terminal is a single line + * and ends with a whitespace character. + */ + if (data.match(/\r?\n/) === null && data.match(/\s$/)) { + this.shellRunCommandsFinished = true; + this.onData.removeListener(this._onShellRunCommandsFinished); + } + }; + @boundMethod protected _onReady(data: string) { if (!data) return true; diff --git a/src/renderer/components/dock/terminal.store.ts b/src/renderer/components/dock/terminal.store.ts index fb3359368d..dd5251bac2 100644 --- a/src/renderer/components/dock/terminal.store.ts +++ b/src/renderer/components/dock/terminal.store.ts @@ -19,12 +19,13 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { autorun, observable } from "mobx"; -import { autoBind, Singleton } from "../../utils"; +import { autorun, observable, when } from "mobx"; +import { autoBind, noop, Singleton } from "../../utils"; import { Terminal } from "./terminal"; import { TerminalApi } from "../../api/terminal-api"; import { dockStore, DockTab, DockTabCreateSpecific, TabId, TabKind } from "./dock.store"; import { WebSocketApiState } from "../../api/websocket-api"; +import { Notifications } from "../notifications"; export interface ITerminalTab extends DockTab { node?: string; // activate node shell mode @@ -64,7 +65,7 @@ export class TerminalStore extends Singleton { }); } - async connect(tabId: TabId) { + connect(tabId: TabId) { if (this.isConnected(tabId)) { return; } @@ -104,18 +105,36 @@ export class TerminalStore extends Singleton { return this.connections.get(tabId)?.readyState === WebSocketApiState.CLOSED; } - sendCommand(command: string, options: { enter?: boolean; newTab?: boolean; tabId?: TabId } = {}) { + async sendCommand(command: string, options: { enter?: boolean; newTab?: boolean; tabId?: TabId } = {}) { const { enter, newTab, tabId } = options; - const { selectTab, getTabById } = dockStore; - const tab = tabId && getTabById(tabId); - if (tab) selectTab(tabId); - if (newTab) createTerminalTab(); + if (tabId) { + dockStore.selectTab(tabId); + } + + if (newTab) { + const tab = createTerminalTab(); + + await when(() => this.connections.has(tab.id)); + + const rcIsFinished = when(() => this.connections.get(tab.id).shellRunCommandsFinished); + const notifyVeryLong = setTimeout(() => { + rcIsFinished.cancel(); + Notifications.info("Terminal shell is taking a long time to complete startup. Please check your .rc file. Bypassing shell completion check.", { + timeout: 4_000, + }); + }, 10_000); + + await rcIsFinished.catch(noop); + clearTimeout(notifyVeryLong); + } const terminalApi = this.connections.get(dockStore.selectedTabId); if (terminalApi) { terminalApi.sendCommand(command + (enter ? "\r" : "")); + } else { + console.warn("The selected tab is does not have a connection. Cannot send command.", { tabId: dockStore.selectedTabId, command }); } } From 66820a20fcb7f691670b98b1dbaa2e949ecdf4e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Jul 2021 15:35:55 -0400 Subject: [PATCH 78/80] Bump @types/progress-bar-webpack-plugin from 2.1.0 to 2.1.2 (#3342) Bumps [@types/progress-bar-webpack-plugin](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/progress-bar-webpack-plugin) from 2.1.0 to 2.1.2. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/progress-bar-webpack-plugin) --- updated-dependencies: - dependency-name: "@types/progress-bar-webpack-plugin" 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.json | 2 +- yarn.lock | 40 ++++++++++++++++++++++++---------------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index e722ef45ab..d7b29bea77 100644 --- a/package.json +++ b/package.json @@ -281,7 +281,7 @@ "@types/module-alias": "^2.0.0", "@types/node": "12.20", "@types/npm": "^2.0.31", - "@types/progress-bar-webpack-plugin": "^2.1.0", + "@types/progress-bar-webpack-plugin": "^2.1.2", "@types/proper-lockfile": "^4.1.1", "@types/randomcolor": "^0.5.5", "@types/react": "^17.0.0", diff --git a/yarn.lock b/yarn.lock index 74d0e68e39..15ed4d41d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1199,11 +1199,6 @@ "@babel/runtime" "^7.12.5" "@testing-library/dom" "^7.28.1" -"@types/anymatch@*": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" - integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== - "@types/aria-query@^4.2.0": version "4.2.0" resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.0.tgz#14264692a9d6e2fa4db3df5e56e94b5e25647ac0" @@ -1718,13 +1713,13 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.0.1.tgz#b6e98083f13faa1e5231bfa3bdb1b0feff536b6d" integrity sha512-boy4xPNEtiw6N3abRhBi/e7hNvy3Tt8E9ZRAQrwAGzoCGZS/1wjo9KY7JHhnfnEsG5wSjDbymCozUM9a3ea7OQ== -"@types/progress-bar-webpack-plugin@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@types/progress-bar-webpack-plugin/-/progress-bar-webpack-plugin-2.1.0.tgz#f95b7e1199b5f5e8156321d2411f6fb06c833559" - integrity sha512-HCyeEuuFzsXvIkbchGKJUhXRBGio7BlvVn0ULuBRE50UofuFy2Q8HvR+Q8C2w+QlBUoM+AjerGJU8DhyqYVw7g== +"@types/progress-bar-webpack-plugin@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@types/progress-bar-webpack-plugin/-/progress-bar-webpack-plugin-2.1.2.tgz#1097946f06efcc087fb2563b153ee61240d9e1dd" + integrity sha512-zSmm7M96PAwwD/YZp7ML9KOtfaRRC2HcU8mrddySWLlSpIGQPynVoc7V97lS0U4tIxlXl02FDQbLSzZq52BEAg== dependencies: "@types/progress" "*" - "@types/webpack" "*" + "@types/webpack" "^4" "@types/progress@*": version "2.0.3" @@ -1951,6 +1946,11 @@ resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.5.tgz#9adbc12950582aa65ead76bffdf39fe0c27a3c02" integrity sha512-/gG2M/Imw7cQFp8PGvz/SwocNrmKFjFsm5Pb8HdbHkZ1K8pmuPzOX4VeVoiEecFCVf4CsN1r3/BRvx+6sNqwtQ== +"@types/tapable@^1": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.8.tgz#b94a4391c85666c7b73299fd3ad79d4faa435310" + integrity sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ== + "@types/tar@^4.0.3", "@types/tar@^4.0.5": version "4.0.5" resolved "https://registry.yarnpkg.com/@types/tar/-/tar-4.0.5.tgz#5f953f183e36a15c6ce3f336568f6051b7b183f3" @@ -2054,16 +2054,16 @@ "@types/source-list-map" "*" source-map "^0.7.3" -"@types/webpack@*", "@types/webpack@^4.41.17", "@types/webpack@^4.41.8": - version "4.41.17" - resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.17.tgz#0a69005e644d657c85b7d6ec1c826a71bebd1c93" - integrity sha512-6FfeCidTSHozwKI67gIVQQ5Mp0g4X96c2IXxX75hYEQJwST/i6NyZexP//zzMOBb+wG9jJ7oO8fk9yObP2HWAw== +"@types/webpack@*", "@types/webpack@^4", "@types/webpack@^4.41.17", "@types/webpack@^4.41.8": + version "4.41.30" + resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.30.tgz#fd3db6d0d41e145a8eeeafcd3c4a7ccde9068ddc" + integrity sha512-GUHyY+pfuQ6haAfzu4S14F+R5iGRwN6b2FRNJY7U0NilmFAqbsOfK6j1HwuLBAqwRIT+pVdNDJGJ6e8rpp0KHA== dependencies: - "@types/anymatch" "*" "@types/node" "*" - "@types/tapable" "*" + "@types/tapable" "^1" "@types/uglify-js" "*" "@types/webpack-sources" "*" + anymatch "^3.0.0" source-map "^0.6.0" "@types/ws@^6.0.1": @@ -2606,6 +2606,14 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" +anymatch@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + anymatch@^3.0.3, anymatch@~3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" From b7a24f452032d14f9c40cb9d8e2f2c0d1e454b6f Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 21 Jul 2021 00:19:23 -0400 Subject: [PATCH 79/80] Default to empty array for 500Beta13 migration (#3461) Signed-off-by: Sebastian Malton --- src/migrations/cluster-store/5.0.0-beta.13.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/migrations/cluster-store/5.0.0-beta.13.ts b/src/migrations/cluster-store/5.0.0-beta.13.ts index 25e0cd1543..e6f260db1b 100644 --- a/src/migrations/cluster-store/5.0.0-beta.13.ts +++ b/src/migrations/cluster-store/5.0.0-beta.13.ts @@ -108,7 +108,7 @@ export default { run(store) { const folder = path.resolve(app.getPath("userData"), "lens-local-storage"); - const oldClusters: ClusterModel[] = store.get("clusters"); + const oldClusters: ClusterModel[] = store.get("clusters") ?? []; const clusters = new Map(); for (const { id: oldId, ...cluster } of oldClusters) { From fe33296ba5faa45b7cdbd8edcd09d81c8a0e702d Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 21 Jul 2021 00:19:46 -0400 Subject: [PATCH 80/80] Bundled extensions are always compatible in dev mode (#3459) Signed-off-by: Sebastian Malton --- src/extensions/extension-compatibility.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/extensions/extension-compatibility.ts b/src/extensions/extension-compatibility.ts index cc5db5515e..3d958072dc 100644 --- a/src/extensions/extension-compatibility.ts +++ b/src/extensions/extension-compatibility.ts @@ -20,7 +20,7 @@ */ import semver from "semver"; -import { appSemVer } from "../common/vars"; +import { appSemVer, isProduction } from "../common/vars"; import type { LensExtensionManifest } from "./lens-extension"; export function isCompatibleExtension(manifest: LensExtensionManifest): boolean { @@ -33,5 +33,5 @@ export function isCompatibleExtension(manifest: LensExtensionManifest): boolean } export function isCompatibleBundledExtension(manifest: LensExtensionManifest): boolean { - return manifest.version === appSemVer.raw; + return !isProduction || manifest.version === appSemVer.raw; }