From a930d5f14fedebfa1c5c1c11ca8447720231df62 Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Thu, 13 May 2021 10:24:58 +0300 Subject: [PATCH 01/21] Hotbar disabled items (#2710) * Saving more entity data to HotbarItem Signed-off-by: Alex Andreev * Adding generic MaterialTooltip component Signed-off-by: Alex Andreev * Move HotbarCell to separate component Signed-off-by: Alex Andreev * Abstract out HotbarEntityIcon from HotbarIcon Signed-off-by: Alex Andreev * Styling disabled hotbar items Signed-off-by: Alex Andreev * Migration for adding extra data to hotbar items Signed-off-by: Alex Andreev * Testing migration Signed-off-by: Alex Andreev * Some cleaning up Signed-off-by: Alex Andreev * Bump migration version Signed-off-by: Alex Andreev * Bump app version in package.json Signed-off-by: Alex Andreev --- package.json | 2 +- src/common/__tests__/hotbar-store.test.ts | 139 +++++++++++ src/common/hotbar-store.ts | 10 +- src/migrations/hotbar-store/5.0.0-beta.5.ts | 30 +++ src/migrations/hotbar-store/index.ts | 4 +- .../material-tooltip/material-tooltip.tsx | 28 +++ .../components/hotbar/hotbar-cell.tsx | 32 +++ .../components/hotbar/hotbar-entity-icon.tsx | 115 +++++++++ .../components/hotbar/hotbar-icon.scss | 12 + .../components/hotbar/hotbar-icon.tsx | 233 ++++++++---------- .../components/hotbar/hotbar-menu.tsx | 76 +++--- .../components/hotbar/hotbar-selector.tsx | 18 +- src/renderer/themes/lens-dark.json | 3 +- src/renderer/themes/lens-light.json | 3 +- 14 files changed, 501 insertions(+), 204 deletions(-) create mode 100644 src/migrations/hotbar-store/5.0.0-beta.5.ts create mode 100644 src/renderer/components/+catalog/material-tooltip/material-tooltip.tsx create mode 100644 src/renderer/components/hotbar/hotbar-cell.tsx create mode 100644 src/renderer/components/hotbar/hotbar-entity-icon.tsx diff --git a/package.json b/package.json index 5d2d231392..a3ee10c9fd 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "open-lens", "productName": "OpenLens", "description": "OpenLens - Open Source IDE for Kubernetes", - "version": "5.0.0-beta.4", + "version": "5.0.0-beta.5", "main": "static/build/main.js", "copyright": "© 2021 OpenLens Authors", "license": "MIT", diff --git a/src/common/__tests__/hotbar-store.test.ts b/src/common/__tests__/hotbar-store.test.ts index 0512b200fb..92e5a3f35b 100644 --- a/src/common/__tests__/hotbar-store.test.ts +++ b/src/common/__tests__/hotbar-store.test.ts @@ -24,6 +24,27 @@ import { CatalogEntityItem } from "../../renderer/components/+catalog/catalog-en import { ClusterStore } from "../cluster-store"; import { HotbarStore } from "../hotbar-store"; +jest.mock("../../renderer/api/catalog-entity-registry", () => ({ + catalogEntityRegistry: { + items: [ + { + metadata: { + uid: "1dfa26e2ebab15780a3547e9c7fa785c", + name: "mycluster", + source: "local" + } + }, + { + metadata: { + uid: "55b42c3c7ba3b04193416cda405269a5", + name: "my_shiny_cluster", + source: "remote" + } + } + ] + } +})); + const testCluster = { uid: "test", name: "test", @@ -87,6 +108,17 @@ const awsCluster = { } }; +jest.mock("electron", () => { + return { + app: { + getVersion: () => "99.99.99", + getPath: () => "tmp", + getLocale: () => "en", + setLoginItemSettings: (): void => void 0, + } + }; +}); + describe("HotbarStore", () => { beforeEach(() => { ClusterStore.resetInstance(); @@ -264,4 +296,111 @@ describe("HotbarStore", () => { console.error = err; }); }); + + describe("pre beta-5 migrations", () => { + beforeEach(() => { + HotbarStore.resetInstance(); + const mockOpts = { + "tmp": { + "lens-hotbar-store.json": JSON.stringify({ + __internal__: { + migrations: { + version: "5.0.0-beta.3" + } + }, + "hotbars": [ + { + "id": "3caac17f-aec2-4723-9694-ad204465d935", + "name": "myhotbar", + "items": [ + { + "entity": { + "uid": "1dfa26e2ebab15780a3547e9c7fa785c" + } + }, + { + "entity": { + "uid": "55b42c3c7ba3b04193416cda405269a5" + } + }, + { + "entity": { + "uid": "176fd331968660832f62283219d7eb6e" + } + }, + { + "entity": { + "uid": "61c4fb45528840ebad1badc25da41d14", + "name": "user1-context", + "source": "local" + } + }, + { + "entity": { + "uid": "27d6f99fe9e7548a6e306760bfe19969", + "name": "foo2", + "source": "local" + } + }, + null, + { + "entity": { + "uid": "c0b20040646849bb4dcf773e43a0bf27", + "name": "multinode-demo", + "source": "local" + } + }, + null, + null, + null, + null, + null + ] + } + ], + }) + } + }; + + mockFs(mockOpts); + + return HotbarStore.createInstance().load(); + }); + + afterEach(() => { + mockFs.restore(); + }); + + it("allows to retrieve a hotbar", () => { + const hotbar = HotbarStore.getInstance().getById("3caac17f-aec2-4723-9694-ad204465d935"); + + expect(hotbar.id).toBe("3caac17f-aec2-4723-9694-ad204465d935"); + }); + + it("clears cells without entity", () => { + const items = HotbarStore.getInstance().hotbars[0].items; + + expect(items[2]).toBeNull(); + }); + + it("adds extra data to cells with according entity", () => { + const items = HotbarStore.getInstance().hotbars[0].items; + + expect(items[0]).toEqual({ + entity: { + name: "mycluster", + source: "local", + uid: "1dfa26e2ebab15780a3547e9c7fa785c" + } + }); + + expect(items[1]).toEqual({ + entity: { + name: "my_shiny_cluster", + source: "remote", + uid: "55b42c3c7ba3b04193416cda405269a5" + } + }); + }); + }); }); diff --git a/src/common/hotbar-store.ts b/src/common/hotbar-store.ts index 4270756d97..2841c16046 100644 --- a/src/common/hotbar-store.ts +++ b/src/common/hotbar-store.ts @@ -29,6 +29,8 @@ import isNull from "lodash/isNull"; export interface HotbarItem { entity: { uid: string; + name?: string; + source?: string; }; params?: { [key: string]: string; @@ -144,9 +146,14 @@ export class HotbarStore extends BaseStore { } } + @action addToHotbar(item: CatalogEntityItem, cellIndex = -1) { const hotbar = this.getActive(); - const newItem = { entity: { uid: item.id }}; + const newItem = { entity: { + uid: item.id, + name: item.name, + source: item.source + }}; if (hotbar.items.find(i => i?.entity.uid === item.id)) { return; @@ -167,6 +174,7 @@ export class HotbarStore extends BaseStore { } } + @action removeFromHotbar(uid: string) { const hotbar = this.getActive(); const index = hotbar.items.findIndex((i) => i?.entity.uid === uid); diff --git a/src/migrations/hotbar-store/5.0.0-beta.5.ts b/src/migrations/hotbar-store/5.0.0-beta.5.ts new file mode 100644 index 0000000000..fe6ff8dd68 --- /dev/null +++ b/src/migrations/hotbar-store/5.0.0-beta.5.ts @@ -0,0 +1,30 @@ +import type { Hotbar } from "../../common/hotbar-store"; +import { migration } from "../migration-wrapper"; +import { catalogEntityRegistry } from "../../renderer/api/catalog-entity-registry"; + +export default migration({ + version: "5.0.0-beta.5", + run(store) { + const hotbars: Hotbar[] = store.get("hotbars"); + + hotbars.forEach((hotbar, hotbarIndex) => { + hotbar.items.forEach((item, itemIndex) => { + const entity = catalogEntityRegistry.items.find((entity) => entity.metadata.uid === item?.entity.uid); + + if (!entity) { + // Clear disabled item + hotbars[hotbarIndex].items[itemIndex] = null; + } else { + // Save additional data + hotbars[hotbarIndex].items[itemIndex].entity = { + ...item.entity, + name: entity.metadata.name, + source: entity.metadata.source + }; + } + }); + }); + + store.set("hotbars", hotbars); + } +}); diff --git a/src/migrations/hotbar-store/index.ts b/src/migrations/hotbar-store/index.ts index 842f144a18..d6824e8df0 100644 --- a/src/migrations/hotbar-store/index.ts +++ b/src/migrations/hotbar-store/index.ts @@ -2,8 +2,10 @@ import version500alpha0 from "./5.0.0-alpha.0"; import version500alpha2 from "./5.0.0-alpha.2"; +import version500beta5 from "./5.0.0-beta.5"; export default { ...version500alpha0, - ...version500alpha2 + ...version500alpha2, + ...version500beta5, }; diff --git a/src/renderer/components/+catalog/material-tooltip/material-tooltip.tsx b/src/renderer/components/+catalog/material-tooltip/material-tooltip.tsx new file mode 100644 index 0000000000..dbfd8b5323 --- /dev/null +++ b/src/renderer/components/+catalog/material-tooltip/material-tooltip.tsx @@ -0,0 +1,28 @@ +import React from "react"; +import { makeStyles, Tooltip, TooltipProps } from "@material-ui/core"; + +const useStyles = makeStyles(() => ({ + arrow: { + color: "var(--tooltipBackground)", + }, + tooltip: { + fontSize: 12, + backgroundColor: "var(--tooltipBackground)", + color: "var(--textColorAccent)", + padding: 8, + boxShadow: "0 8px 16px rgba(0,0,0,0.24)" + }, +})); + +export function MaterialTooltip(props: TooltipProps) { + const classes = useStyles(); + + return ( + + ); +} + +MaterialTooltip.defaultProps = { + arrow: true +}; + diff --git a/src/renderer/components/hotbar/hotbar-cell.tsx b/src/renderer/components/hotbar/hotbar-cell.tsx new file mode 100644 index 0000000000..aa19faa052 --- /dev/null +++ b/src/renderer/components/hotbar/hotbar-cell.tsx @@ -0,0 +1,32 @@ +import "./hotbar-menu.scss"; +import "./hotbar.commands"; + +import React, { HTMLAttributes, ReactNode, useState } from "react"; + +import { cssNames } from "../../utils"; + +interface Props extends HTMLAttributes { + children?: ReactNode; + index: number; + innerRef?: React.LegacyRef; +} + +export function HotbarCell({ innerRef, children, className, ...rest }: Props) { + const [animating, setAnimating] = useState(false); + const onAnimationEnd = () => { setAnimating(false); }; + const onClick = () => { + setAnimating(!className.includes("isDraggingOver")); + }; + + return ( +
+ {children} +
+ ); +} diff --git a/src/renderer/components/hotbar/hotbar-entity-icon.tsx b/src/renderer/components/hotbar/hotbar-entity-icon.tsx new file mode 100644 index 0000000000..52a93990ee --- /dev/null +++ b/src/renderer/components/hotbar/hotbar-entity-icon.tsx @@ -0,0 +1,115 @@ +import "./hotbar-icon.scss"; + +import React, { DOMAttributes } from "react"; +import { observable } from "mobx"; +import { observer } from "mobx-react"; +import randomColor from "randomcolor"; + +import { CatalogEntity, CatalogEntityContextMenu, CatalogEntityContextMenuContext } from "../../../common/catalog"; +import { catalogCategoryRegistry } from "../../api/catalog-category-registry"; +import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; +import { navigate } from "../../navigation"; +import { cssNames, IClassName } from "../../utils"; +import { ConfirmDialog } from "../confirm-dialog"; +import { Icon } from "../icon"; +import { HotbarIcon } from "./hotbar-icon"; + +interface Props extends DOMAttributes { + entity: CatalogEntity; + className?: IClassName; + errorClass?: IClassName; + remove: (uid: string) => void; +} + +@observer +export class HotbarEntityIcon extends React.Component { + @observable.deep private contextMenu: CatalogEntityContextMenuContext; + + componentDidMount() { + this.contextMenu = { + menuItems: [], + navigate: (url: string) => navigate(url) + }; + } + + get kindIcon() { + const className = "badge"; + const category = catalogCategoryRegistry.getCategoryForEntity(this.props.entity); + + if (!category) { + return ; + } + + if (category.metadata.icon.includes("; + } else { + return ; + } + } + + get ledIcon() { + const className = cssNames("led", { online: this.props.entity.status.phase == "connected"}); // TODO: make it more generic + + return
; + } + + isActive(item: CatalogEntity) { + return catalogEntityRegistry.activeEntity?.metadata?.uid == item.getId(); + } + + onMenuItemClick(menuItem: CatalogEntityContextMenu) { + if (menuItem.confirm) { + ConfirmDialog.open({ + okButtonProps: { + primary: false, + accent: true, + }, + ok: () => { + menuItem.onClick(); + }, + message: menuItem.confirm.message + }); + } else { + menuItem.onClick(); + } + } + + generateAvatarStyle(entity: CatalogEntity): React.CSSProperties { + return { + "backgroundColor": randomColor({ seed: `${entity.metadata.name}-${entity.metadata.source}`, luminosity: "dark" }) + }; + } + + render() { + const { + entity, errorClass, remove, + children, ...elemProps + } = this.props; + const className = cssNames("HotbarEntityIcon", this.props.className, { + interactive: true, + active: this.isActive(entity), + disabled: !entity + }); + const onOpen = async () => { + await entity.onContextMenuOpen(this.contextMenu); + }; + const menuItems = this.contextMenu?.menuItems.filter((menuItem) => !menuItem.onlyVisibleForSource || menuItem.onlyVisibleForSource === entity.metadata.source); + + return ( + + { this.ledIcon } + { this.kindIcon } + + ); + } +} diff --git a/src/renderer/components/hotbar/hotbar-icon.scss b/src/renderer/components/hotbar/hotbar-icon.scss index e06eb9f553..bd2c7bd5d9 100644 --- a/src/renderer/components/hotbar/hotbar-icon.scss +++ b/src/renderer/components/hotbar/hotbar-icon.scss @@ -41,6 +41,18 @@ transition: all 0s 0.8s; } + &.disabled { + opacity: 0.4; + cursor: default; + filter: grayscale(0.7); + + &:hover { + &:not(.active) { + box-shadow: none; + } + } + } + &.active, &.interactive:hover { img { opacity: 1; diff --git a/src/renderer/components/hotbar/hotbar-icon.tsx b/src/renderer/components/hotbar/hotbar-icon.tsx index c0396c4328..74154505e3 100644 --- a/src/renderer/components/hotbar/hotbar-icon.tsx +++ b/src/renderer/components/hotbar/hotbar-icon.tsx @@ -21,28 +21,51 @@ import "./hotbar-icon.scss"; -import React, { DOMAttributes } from "react"; -import { observer } from "mobx-react"; -import { cssNames, IClassName, iter } from "../../utils"; -import { Tooltip } from "../tooltip"; +import React, { DOMAttributes, useState } from "react"; import { Avatar } from "@material-ui/core"; -import { CatalogEntity, CatalogEntityContextMenu, CatalogEntityContextMenuContext } from "../../../common/catalog"; -import { Menu, MenuItem } from "../menu"; -import { Icon } from "../icon"; -import { computed, observable } from "mobx"; -import { navigate } from "../../navigation"; -import { HotbarStore } from "../../../common/hotbar-store"; -import { ConfirmDialog } from "../confirm-dialog"; import randomColor from "randomcolor"; -import { catalogCategoryRegistry } from "../../api/catalog-category-registry"; import GraphemeSplitter from "grapheme-splitter"; +import { CatalogEntityContextMenu } from "../../../common/catalog"; +import { cssNames, IClassName, iter } from "../../utils"; +import { ConfirmDialog } from "../confirm-dialog"; +import { Icon } from "../icon"; +import { Menu, MenuItem } from "../menu"; +import { MaterialTooltip } from "../+catalog/material-tooltip/material-tooltip"; + interface Props extends DOMAttributes { - entity: CatalogEntity; - index: number; + uid: string; + title: string; + source: string; + remove: (uid: string) => void; + onMenuOpen?: () => void; className?: IClassName; - errorClass?: IClassName; - isActive?: boolean; + active?: boolean; + menuItems?: CatalogEntityContextMenu[]; + disabled?: boolean; +} + +function generateAvatarStyle(seed: string): React.CSSProperties { + return { + "backgroundColor": randomColor({ seed, luminosity: "dark" }) + }; +} + +function onMenuItemClick(menuItem: CatalogEntityContextMenu) { + if (menuItem.confirm) { + ConfirmDialog.open({ + okButtonProps: { + primary: false, + accent: true, + }, + ok: () => { + menuItem.onClick(); + }, + message: menuItem.confirm.message + }); + } else { + menuItem.onClick(); + } } function getNameParts(name: string): string[] { @@ -61,20 +84,17 @@ function getNameParts(name: string): string[] { return name.split(/@+/); } -@observer -export class HotbarIcon extends React.Component { - @observable.deep private contextMenu: CatalogEntityContextMenuContext; - @observable menuOpen = false; +export function HotbarIcon(props: Props) { + const { uid, title, className, source, active, remove, disabled, menuItems, onMenuOpen, children, ...rest } = props; + const id = `hotbarIcon-${uid}`; + const [menuOpen, setMenuOpen] = useState(false); - componentDidMount() { - this.contextMenu = { - menuItems: [], - navigate: (url: string) => navigate(url) - }; - } + const toggleMenu = () => { + setMenuOpen(!menuOpen); + }; - @computed get iconString() { - const [rawFirst, rawSecond, rawThird] = getNameParts(this.props.entity.metadata.name); + const getIconString = () => { + const [rawFirst, rawSecond, rawThird] = getNameParts(title); const splitter = new GraphemeSplitter(); const first = splitter.iterateGraphemes(rawFirst); const second = rawSecond ? splitter.iterateGraphemes(rawSecond): first; @@ -85,114 +105,53 @@ export class HotbarIcon extends React.Component { ...iter.take(second, 1), ...iter.take(third, 1), ].filter(Boolean).join(""); - } + }; - get kindIcon() { - const className = "badge"; - const category = catalogCategoryRegistry.getCategoryForEntity(this.props.entity); - - if (!category) { - return ; - } - - if (category.metadata.icon.includes("; - } else { - return ; - } - } - - get ledIcon() { - const className = cssNames("led", { online: this.props.entity.status.phase == "connected"}); // TODO: make it more generic - - return
; - } - - toggleMenu() { - this.menuOpen = !this.menuOpen; - } - - remove(item: CatalogEntity) { - const hotbar = HotbarStore.getInstance(); - - hotbar.removeFromHotbar(item.getId()); - } - - onMenuItemClick(menuItem: CatalogEntityContextMenu) { - if (menuItem.confirm) { - ConfirmDialog.open({ - okButtonProps: { - primary: false, - accent: true, - }, - ok: () => { - menuItem.onClick(); - }, - message: menuItem.confirm.message - }); - } else { - menuItem.onClick(); - } - } - - generateAvatarStyle(entity: CatalogEntity): React.CSSProperties { - return { - "backgroundColor": randomColor({ seed: `${entity.metadata.name}-${entity.metadata.source}`, luminosity: "dark" }) - }; - } - - render() { - const { - entity, errorClass, isActive, - children, ...elemProps - } = this.props; - const entityIconId = `hotbar-icon-${this.props.index}`; - const className = cssNames("HotbarIcon flex inline", this.props.className, { - interactive: true, - active: isActive, - }); - const onOpen = async () => { - await entity.onContextMenuOpen(this.contextMenu); - this.toggleMenu(); - }; - const menuItems = this.contextMenu?.menuItems.filter((menuItem) => !menuItem.onlyVisibleForSource || menuItem.onlyVisibleForSource === entity.metadata.source); - - return ( -
- {entity.metadata.name} ({entity.metadata.source || "local"}) - - {this.iconString} - - { this.ledIcon } - { this.kindIcon } - onOpen()} - close={() => this.toggleMenu()}> - this.remove(entity) }> - Remove from Hotbar - - { this.contextMenu && menuItems.map((menuItem) => { - return ( - this.onMenuItemClick(menuItem) }> - {menuItem.title} - - ); - })} - - {children} -
- ); - } + return ( +
+ +
+ + {getIconString()} + + {children} +
+
+ { + onMenuOpen?.(); + toggleMenu(); + }} + close={() => toggleMenu()}> + { + evt.stopPropagation(); + remove(uid); + }}> + Remove from Hotbar + + { menuItems.map((menuItem) => { + return ( + onMenuItemClick(menuItem) }> + {menuItem.title} + + ); + })} + +
+ ); } + +HotbarIcon.defaultProps = { + menuItems: [] +}; diff --git a/src/renderer/components/hotbar/hotbar-menu.tsx b/src/renderer/components/hotbar/hotbar-menu.tsx index e2c1e45cdb..319b05f946 100644 --- a/src/renderer/components/hotbar/hotbar-menu.tsx +++ b/src/renderer/components/hotbar/hotbar-menu.tsx @@ -22,15 +22,17 @@ import "./hotbar-menu.scss"; import "./hotbar.commands"; -import React, { HTMLAttributes, ReactNode, useState } from "react"; +import React from "react"; import { observer } from "mobx-react"; -import { HotbarIcon } from "./hotbar-icon"; +import { HotbarEntityIcon } from "./hotbar-entity-icon"; import { cssNames, IClassName } from "../../utils"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; import { defaultHotbarCells, HotbarItem, HotbarStore } from "../../../common/hotbar-store"; -import { CatalogEntity, catalogEntityRunContext } from "../../api/catalog-entity"; +import { catalogEntityRunContext } from "../../api/catalog-entity"; import { DragDropContext, Draggable, Droppable, DropResult } from "react-beautiful-dnd"; import { HotbarSelector } from "./hotbar-selector"; +import { HotbarCell } from "./hotbar-cell"; +import { HotbarIcon } from "./hotbar-icon"; interface Props { className?: IClassName; @@ -42,10 +44,6 @@ export class HotbarMenu extends React.Component { return HotbarStore.getInstance().getActive(); } - isActive(item: CatalogEntity) { - return catalogEntityRegistry.activeEntity?.metadata?.uid == item.getId(); - } - getEntity(item: HotbarItem) { const hotbar = HotbarStore.getInstance().getActive(); @@ -69,6 +67,12 @@ export class HotbarMenu extends React.Component { HotbarStore.getInstance().restackItems(from, to); } + removeItem(uid: string) { + const hotbar = HotbarStore.getInstance(); + + hotbar.removeFromHotbar(uid); + } + getMoveAwayDirection(entityId: string, cellIndex: number) { const draggableItemIndex = this.hotbar.items.findIndex(item => item?.entity.uid == entityId); @@ -78,7 +82,6 @@ export class HotbarMenu extends React.Component { renderGrid() { return this.hotbar.items.map((item, index) => { const entity = this.getEntity(item); - const isActive = !entity ? false : this.isActive(entity); return ( @@ -93,7 +96,7 @@ export class HotbarMenu extends React.Component { }, this.getMoveAwayDirection(snapshot.draggingOverWith, index))} {...provided.droppableProps} > - {entity && ( + {item && ( {(provided, snapshot) => { const style = { @@ -110,14 +113,23 @@ export class HotbarMenu extends React.Component { {...provided.dragHandleProps} style={style} > - entity.onRun(catalogEntityRunContext)} - className={cssNames({ isDragging: snapshot.isDragging })} - /> + {entity ? ( + entity.onRun(catalogEntityRunContext)} + className={cssNames({ isDragging: snapshot.isDragging })} + remove={this.removeItem} + /> + ) : ( + + )}
); }} @@ -148,33 +160,3 @@ export class HotbarMenu extends React.Component { ); } } - -interface HotbarCellProps extends HTMLAttributes { - children?: ReactNode; - index: number; - innerRef?: React.LegacyRef; -} - -function HotbarCell({ innerRef, children, className, ...rest }: HotbarCellProps) { - const [animating, setAnimating] = useState(false); - const onAnimationEnd = () => { setAnimating(false); }; - const onClick = () => { - if (className.includes("isDraggingOver")) { - return; - } - - setAnimating(true); - }; - - return ( -
- {children} -
- ); -} diff --git a/src/renderer/components/hotbar/hotbar-selector.tsx b/src/renderer/components/hotbar/hotbar-selector.tsx index 108db0c85e..a602cea6e6 100644 --- a/src/renderer/components/hotbar/hotbar-selector.tsx +++ b/src/renderer/components/hotbar/hotbar-selector.tsx @@ -23,43 +23,31 @@ import "./hotbar-selector.scss"; import React from "react"; import { Icon } from "../icon"; import { Badge } from "../badge"; -import { makeStyles, Tooltip } from "@material-ui/core"; import { Hotbar, HotbarStore } from "../../../common/hotbar-store"; import { CommandOverlay } from "../command-palette"; import { HotbarSwitchCommand } from "./hotbar-switch-command"; +import { MaterialTooltip } from "../+catalog/material-tooltip/material-tooltip"; interface Props { hotbar: Hotbar; } -const useStyles = makeStyles(() => ({ - arrow: { - color: "#222", - }, - tooltip: { - fontSize: 12, - backgroundColor: "#222", - }, -})); - - export function HotbarSelector({ hotbar }: Props) { const store = HotbarStore.getInstance(); const activeIndexDisplay = store.activeHotbarIndex + 1; - const classes = useStyles(); return (
store.switchToPrevious()} />
- + CommandOverlay.open()} /> - +
store.switchToNext()} />
diff --git a/src/renderer/themes/lens-dark.json b/src/renderer/themes/lens-dark.json index 0082f9ce63..f96eb81453 100644 --- a/src/renderer/themes/lens-dark.json +++ b/src/renderer/themes/lens-dark.json @@ -128,6 +128,7 @@ "settingsColor": "#909ba6", "navSelectedBackground": "#262b2e", "navHoverColor": "#dcddde", - "hrColor": "#ffffff0f" + "hrColor": "#ffffff0f", + "tooltipBackground": "#18191c" } } diff --git a/src/renderer/themes/lens-light.json b/src/renderer/themes/lens-light.json index 5a4365b500..d3b5938de3 100644 --- a/src/renderer/themes/lens-light.json +++ b/src/renderer/themes/lens-light.json @@ -130,6 +130,7 @@ "settingsColor": "#555555", "navSelectedBackground": "#ffffff", "navHoverColor": "#2e3135", - "hrColor": "#06060714" + "hrColor": "#06060714", + "tooltipBackground": "#ffffff" } } From 761e3a8f522d07e1b5f96e46271659fc02a3af24 Mon Sep 17 00:00:00 2001 From: Lauri Nevala Date: Fri, 14 May 2021 21:39:19 +0300 Subject: [PATCH 02/21] Add kubectl 1.21 to version map (#2772) Signed-off-by: Lauri Nevala --- src/main/kubectl.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/kubectl.ts b/src/main/kubectl.ts index f29eb7584a..1a00d2919d 100644 --- a/src/main/kubectl.ts +++ b/src/main/kubectl.ts @@ -47,7 +47,8 @@ const kubectlMap: Map = new Map([ ["1.17", "1.17.17"], ["1.18", bundledVersion], ["1.19", "1.19.7"], - ["1.20", "1.20.2"] + ["1.20", "1.20.2"], + ["1.21", "1.21.1"] ]); const packageMirrors: Map = new Map([ ["default", "https://storage.googleapis.com/kubernetes-release/release"], From 623973add07bc83769708bd2a76f6eb74ddad2b8 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 17 May 2021 00:19:45 -0400 Subject: [PATCH 03/21] Add license header to more files (#2776) Signed-off-by: Sebastian Malton --- .github/workflows/license-header.yml | 3 +++ src/jest.setup.ts | 21 ++++++++++++++++++ src/migrations/cluster-store/2.0.0-beta.2.ts | 21 ++++++++++++++++++ src/migrations/cluster-store/2.4.1.ts | 21 ++++++++++++++++++ src/migrations/cluster-store/2.6.0-beta.2.ts | 21 ++++++++++++++++++ src/migrations/cluster-store/2.6.0-beta.3.ts | 22 ++++++++++++++++++- src/migrations/cluster-store/2.7.0-beta.0.ts | 21 ++++++++++++++++++ src/migrations/cluster-store/2.7.0-beta.1.ts | 21 ++++++++++++++++++ src/migrations/cluster-store/3.6.0-beta.1.ts | 21 ++++++++++++++++++ src/migrations/cluster-store/index.ts | 21 ++++++++++++++++++ src/migrations/cluster-store/snap.ts | 21 ++++++++++++++++++ src/migrations/hotbar-store/5.0.0-alpha.0.ts | 21 ++++++++++++++++++ src/migrations/hotbar-store/5.0.0-alpha.2.ts | 21 ++++++++++++++++++ src/migrations/hotbar-store/5.0.0-beta.5.ts | 21 ++++++++++++++++++ src/migrations/hotbar-store/index.ts | 21 ++++++++++++++++++ src/migrations/migration-wrapper.ts | 21 ++++++++++++++++++ src/migrations/user-store/2.1.0-beta.4.ts | 21 ++++++++++++++++++ src/migrations/user-store/5.0.0-alpha.3.ts | 21 ++++++++++++++++++ .../user-store/file-name-migration.ts | 21 ++++++++++++++++++ src/migrations/user-store/index.ts | 21 ++++++++++++++++++ 20 files changed, 402 insertions(+), 1 deletion(-) diff --git a/.github/workflows/license-header.yml b/.github/workflows/license-header.yml index 92db815acd..2e35317360 100644 --- a/.github/workflows/license-header.yml +++ b/.github/workflows/license-header.yml @@ -25,6 +25,9 @@ jobs: addlicense -check -l mit -c "OpenLens Authors" *.ts* + addlicense -check -l mit -c "OpenLens Authors" src/migrations/**/*.ts* + addlicense -check -l mit -c "OpenLens Authors" src/*.ts* + addlicense -check -l mit -c "OpenLens Authors" src/common/**/*.ts* addlicense -check -l mit -c "OpenLens Authors" src/common/**/*.?css diff --git a/src/jest.setup.ts b/src/jest.setup.ts index d8c6ce9161..4feade0f1f 100644 --- a/src/jest.setup.ts +++ b/src/jest.setup.ts @@ -1,3 +1,24 @@ +/** + * 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 fetchMock from "jest-fetch-mock"; // rewire global.fetch to call 'fetchMock' fetchMock.enableMocks(); diff --git a/src/migrations/cluster-store/2.0.0-beta.2.ts b/src/migrations/cluster-store/2.0.0-beta.2.ts index ccc8932e70..0d54588194 100644 --- a/src/migrations/cluster-store/2.0.0-beta.2.ts +++ b/src/migrations/cluster-store/2.0.0-beta.2.ts @@ -1,3 +1,24 @@ +/** + * 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. + */ + /* Early store format had the kubeconfig directly under context name, this moves it under the kubeConfig key */ diff --git a/src/migrations/cluster-store/2.4.1.ts b/src/migrations/cluster-store/2.4.1.ts index aa6936e432..59d4ef21dc 100644 --- a/src/migrations/cluster-store/2.4.1.ts +++ b/src/migrations/cluster-store/2.4.1.ts @@ -1,3 +1,24 @@ +/** + * 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. + */ + // Cleans up a store that had the state related data stored import { migration } from "../migration-wrapper"; diff --git a/src/migrations/cluster-store/2.6.0-beta.2.ts b/src/migrations/cluster-store/2.6.0-beta.2.ts index 596d16c31f..ffe303a28d 100644 --- a/src/migrations/cluster-store/2.6.0-beta.2.ts +++ b/src/migrations/cluster-store/2.6.0-beta.2.ts @@ -1,3 +1,24 @@ +/** + * 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. + */ + // Move cluster icon from root to preferences import { migration } from "../migration-wrapper"; diff --git a/src/migrations/cluster-store/2.6.0-beta.3.ts b/src/migrations/cluster-store/2.6.0-beta.3.ts index 779fff7e7d..9ec844fe65 100644 --- a/src/migrations/cluster-store/2.6.0-beta.3.ts +++ b/src/migrations/cluster-store/2.6.0-beta.3.ts @@ -1,3 +1,24 @@ +/** + * 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 { migration } from "../migration-wrapper"; import yaml from "js-yaml"; @@ -42,4 +63,3 @@ export default migration({ } } }); - diff --git a/src/migrations/cluster-store/2.7.0-beta.0.ts b/src/migrations/cluster-store/2.7.0-beta.0.ts index 2f02a047f4..a23d3be991 100644 --- a/src/migrations/cluster-store/2.7.0-beta.0.ts +++ b/src/migrations/cluster-store/2.7.0-beta.0.ts @@ -1,3 +1,24 @@ +/** + * 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. + */ + // Add existing clusters to "default" workspace import { migration } from "../migration-wrapper"; diff --git a/src/migrations/cluster-store/2.7.0-beta.1.ts b/src/migrations/cluster-store/2.7.0-beta.1.ts index cb3934d422..06439063c6 100644 --- a/src/migrations/cluster-store/2.7.0-beta.1.ts +++ b/src/migrations/cluster-store/2.7.0-beta.1.ts @@ -1,3 +1,24 @@ +/** + * 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. + */ + // Add id for clusters and store them to array import { migration } from "../migration-wrapper"; import { v4 as uuid } from "uuid"; diff --git a/src/migrations/cluster-store/3.6.0-beta.1.ts b/src/migrations/cluster-store/3.6.0-beta.1.ts index ca2d0ccbed..df51510f23 100644 --- a/src/migrations/cluster-store/3.6.0-beta.1.ts +++ b/src/migrations/cluster-store/3.6.0-beta.1.ts @@ -1,3 +1,24 @@ +/** + * 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. + */ + // Move embedded kubeconfig into separate file and add reference to it to cluster settings // convert file path cluster icons to their base64 encoded versions diff --git a/src/migrations/cluster-store/index.ts b/src/migrations/cluster-store/index.ts index 4a71d4f7ad..b80911bbfe 100644 --- a/src/migrations/cluster-store/index.ts +++ b/src/migrations/cluster-store/index.ts @@ -1,3 +1,24 @@ +/** + * 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. + */ + // Cluster store migrations import version200Beta2 from "./2.0.0-beta.2"; diff --git a/src/migrations/cluster-store/snap.ts b/src/migrations/cluster-store/snap.ts index 74b89aad9c..c0a0430603 100644 --- a/src/migrations/cluster-store/snap.ts +++ b/src/migrations/cluster-store/snap.ts @@ -1,3 +1,24 @@ +/** + * 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. + */ + // Fix embedded kubeconfig paths under snap config import { migration } from "../migration-wrapper"; diff --git a/src/migrations/hotbar-store/5.0.0-alpha.0.ts b/src/migrations/hotbar-store/5.0.0-alpha.0.ts index 58d7073761..2e666fe54c 100644 --- a/src/migrations/hotbar-store/5.0.0-alpha.0.ts +++ b/src/migrations/hotbar-store/5.0.0-alpha.0.ts @@ -1,3 +1,24 @@ +/** + * 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. + */ + // Cleans up a store that had the state related data stored import { Hotbar } from "../../common/hotbar-store"; import { ClusterStore } from "../../common/cluster-store"; diff --git a/src/migrations/hotbar-store/5.0.0-alpha.2.ts b/src/migrations/hotbar-store/5.0.0-alpha.2.ts index 060fa9f542..57459de8c8 100644 --- a/src/migrations/hotbar-store/5.0.0-alpha.2.ts +++ b/src/migrations/hotbar-store/5.0.0-alpha.2.ts @@ -1,3 +1,24 @@ +/** + * 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. + */ + // Cleans up a store that had the state related data stored import { Hotbar } from "../../common/hotbar-store"; import { migration } from "../migration-wrapper"; diff --git a/src/migrations/hotbar-store/5.0.0-beta.5.ts b/src/migrations/hotbar-store/5.0.0-beta.5.ts index fe6ff8dd68..33e39f2a13 100644 --- a/src/migrations/hotbar-store/5.0.0-beta.5.ts +++ b/src/migrations/hotbar-store/5.0.0-beta.5.ts @@ -1,3 +1,24 @@ +/** + * 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 { Hotbar } from "../../common/hotbar-store"; import { migration } from "../migration-wrapper"; import { catalogEntityRegistry } from "../../renderer/api/catalog-entity-registry"; diff --git a/src/migrations/hotbar-store/index.ts b/src/migrations/hotbar-store/index.ts index d6824e8df0..fabedee4b7 100644 --- a/src/migrations/hotbar-store/index.ts +++ b/src/migrations/hotbar-store/index.ts @@ -1,3 +1,24 @@ +/** + * 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. + */ + // Hotbar store migrations import version500alpha0 from "./5.0.0-alpha.0"; diff --git a/src/migrations/migration-wrapper.ts b/src/migrations/migration-wrapper.ts index 39015b81fb..db363513de 100644 --- a/src/migrations/migration-wrapper.ts +++ b/src/migrations/migration-wrapper.ts @@ -1,3 +1,24 @@ +/** + * 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 Config from "conf"; import { isTestEnv } from "../common/vars"; diff --git a/src/migrations/user-store/2.1.0-beta.4.ts b/src/migrations/user-store/2.1.0-beta.4.ts index e8f6500b05..eace0dd367 100644 --- a/src/migrations/user-store/2.1.0-beta.4.ts +++ b/src/migrations/user-store/2.1.0-beta.4.ts @@ -1,3 +1,24 @@ +/** + * 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. + */ + // Add / reset "lastSeenAppVersion" import { migration } from "../migration-wrapper"; diff --git a/src/migrations/user-store/5.0.0-alpha.3.ts b/src/migrations/user-store/5.0.0-alpha.3.ts index ae90b85525..57692c0bc0 100644 --- a/src/migrations/user-store/5.0.0-alpha.3.ts +++ b/src/migrations/user-store/5.0.0-alpha.3.ts @@ -1,3 +1,24 @@ +/** + * 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. + */ + // Switch representation of hiddenTableColumns in store import { migration } from "../migration-wrapper"; diff --git a/src/migrations/user-store/file-name-migration.ts b/src/migrations/user-store/file-name-migration.ts index 0abe6b280b..e0c848d3a8 100644 --- a/src/migrations/user-store/file-name-migration.ts +++ b/src/migrations/user-store/file-name-migration.ts @@ -1,3 +1,24 @@ +/** + * 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 fse from "fs-extra"; import { app, remote } from "electron"; import path from "path"; diff --git a/src/migrations/user-store/index.ts b/src/migrations/user-store/index.ts index c8733fdd8a..cf345b1bfb 100644 --- a/src/migrations/user-store/index.ts +++ b/src/migrations/user-store/index.ts @@ -1,3 +1,24 @@ +/** + * 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. + */ + // User store migrations import version210Beta4 from "./2.1.0-beta.4"; From c594844b9b4d2da540d245eb1edf51297bf83e8b Mon Sep 17 00:00:00 2001 From: Jim Ehrismann <40840436+jim-docker@users.noreply.github.com> Date: Mon, 17 May 2021 00:40:32 -0400 Subject: [PATCH 04/21] include the hotbar index in the label displayed for a hotbar (#2770) * include the hotbar index in the label displayed for a hotbar Signed-off-by: Jim Ehrismann * address review comments for hotbarDisplayLabel() Signed-off-by: Jim Ehrismann * tweaks to hotbarDisplayLabel() Signed-off-by: Jim Ehrismann --- src/common/hotbar-store.ts | 6 +++- .../components/hotbar/hotbar-display-label.ts | 36 +++++++++++++++++++ .../hotbar/hotbar-remove-command.tsx | 3 +- .../components/hotbar/hotbar-selector.tsx | 4 +-- .../hotbar/hotbar-switch-command.tsx | 3 +- 5 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 src/renderer/components/hotbar/hotbar-display-label.ts diff --git a/src/common/hotbar-store.ts b/src/common/hotbar-store.ts index 2841c16046..b2d5af0f2a 100644 --- a/src/common/hotbar-store.ts +++ b/src/common/hotbar-store.ts @@ -81,8 +81,12 @@ export class HotbarStore extends BaseStore { } } + hotbarIndex(id: string) { + return this.hotbars.findIndex((hotbar) => hotbar.id === id); + } + get activeHotbarIndex() { - return this.hotbars.findIndex((hotbar) => hotbar.id === this.activeHotbarId); + return this.hotbarIndex(this.activeHotbarId); } get initialItems() { diff --git a/src/renderer/components/hotbar/hotbar-display-label.ts b/src/renderer/components/hotbar/hotbar-display-label.ts new file mode 100644 index 0000000000..0489e2600f --- /dev/null +++ b/src/renderer/components/hotbar/hotbar-display-label.ts @@ -0,0 +1,36 @@ +/** + * 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 { HotbarStore } from "../../../common/hotbar-store"; + +function hotbarIndex(id: string) { + return HotbarStore.getInstance().hotbarIndex(id) + 1; +} + +export function hotbarDisplayLabel(id: string) : string { + const hotbar = HotbarStore.getInstance().getById(id); + + return `${hotbarIndex(id)}: ${hotbar.name}`; +} + +export function hotbarDisplayIndex(id: string) : string { + return hotbarIndex(id).toString(); +} diff --git a/src/renderer/components/hotbar/hotbar-remove-command.tsx b/src/renderer/components/hotbar/hotbar-remove-command.tsx index f8b0bb993d..e60dc2bfaf 100644 --- a/src/renderer/components/hotbar/hotbar-remove-command.tsx +++ b/src/renderer/components/hotbar/hotbar-remove-command.tsx @@ -24,6 +24,7 @@ import { observer } from "mobx-react"; import { Select } from "../select"; import { computed } from "mobx"; import { HotbarStore } from "../../../common/hotbar-store"; +import { hotbarDisplayLabel } from "./hotbar-display-label"; import { CommandOverlay } from "../command-palette"; import { ConfirmDialog } from "../confirm-dialog"; @@ -31,7 +32,7 @@ import { ConfirmDialog } from "../confirm-dialog"; export class HotbarRemoveCommand extends React.Component { @computed get options() { return HotbarStore.getInstance().hotbars.map((hotbar) => { - return { value: hotbar.id, label: hotbar.name }; + return { value: hotbar.id, label: hotbarDisplayLabel(hotbar.id) }; }); } diff --git a/src/renderer/components/hotbar/hotbar-selector.tsx b/src/renderer/components/hotbar/hotbar-selector.tsx index a602cea6e6..63041a5d38 100644 --- a/src/renderer/components/hotbar/hotbar-selector.tsx +++ b/src/renderer/components/hotbar/hotbar-selector.tsx @@ -26,6 +26,7 @@ import { Badge } from "../badge"; import { Hotbar, HotbarStore } from "../../../common/hotbar-store"; import { CommandOverlay } from "../command-palette"; import { HotbarSwitchCommand } from "./hotbar-switch-command"; +import { hotbarDisplayIndex } from "./hotbar-display-label"; import { MaterialTooltip } from "../+catalog/material-tooltip/material-tooltip"; interface Props { @@ -34,7 +35,6 @@ interface Props { export function HotbarSelector({ hotbar }: Props) { const store = HotbarStore.getInstance(); - const activeIndexDisplay = store.activeHotbarIndex + 1; return (
@@ -44,7 +44,7 @@ export function HotbarSelector({ hotbar }: Props) { CommandOverlay.open()} /> diff --git a/src/renderer/components/hotbar/hotbar-switch-command.tsx b/src/renderer/components/hotbar/hotbar-switch-command.tsx index 93a7906585..1d11a02c80 100644 --- a/src/renderer/components/hotbar/hotbar-switch-command.tsx +++ b/src/renderer/components/hotbar/hotbar-switch-command.tsx @@ -27,6 +27,7 @@ import { HotbarStore } from "../../../common/hotbar-store"; import { CommandOverlay } from "../command-palette"; import { HotbarAddCommand } from "./hotbar-add-command"; import { HotbarRemoveCommand } from "./hotbar-remove-command"; +import { hotbarDisplayLabel } from "./hotbar-display-label"; @observer export class HotbarSwitchCommand extends React.Component { @@ -36,7 +37,7 @@ export class HotbarSwitchCommand extends React.Component { @computed get options() { const hotbarStore = HotbarStore.getInstance(); const options = hotbarStore.hotbars.map((hotbar) => { - return { value: hotbar.id, label: hotbar.name }; + return { value: hotbar.id, label: hotbarDisplayLabel(hotbar.id) }; }); options.push({ value: HotbarSwitchCommand.addActionId, label: "Add hotbar ..." }); From f8b939bf5909db4deb2873dcbd81b8def2c8c8ca Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Mon, 17 May 2021 16:43:53 +0300 Subject: [PATCH 05/21] Check license header using eslint (#2780) Signed-off-by: Jari Kolehmainen --- .eslintrc.js | 29 ++++++++++++++++++- .github/workflows/license-header.yml | 19 ++---------- __mocks__/@linguiMacro.ts | 20 +++++++++++++ __mocks__/electron.ts | 20 +++++++++++++ __mocks__/imageMock.ts | 20 +++++++++++++ __mocks__/styleMock.ts | 20 +++++++++++++ build/build_tray_icon.ts | 22 ++++++++++++-- build/download_helm.ts | 20 +++++++++++++ build/download_kubectl.ts | 20 +++++++++++++ build/notarize.js | 20 +++++++++++++ build/set_build_version.ts | 20 +++++++++++++ build/set_npm_version.ts | 20 +++++++++++++ .../webpack.config.js | 20 +++++++++++++ .../metrics-cluster-feature/webpack.config.js | 20 +++++++++++++ extensions/node-menu/webpack.config.js | 20 +++++++++++++ extensions/pod-menu/webpack.config.js | 20 +++++++++++++ integration/__tests__/app.tests.ts | 19 +++++++++++- integration/__tests__/cluster-pages.tests.ts | 26 +++++++++++++---- .../__tests__/command-palette.tests.ts | 20 +++++++++++++ integration/helpers/minikube.ts | 20 +++++++++++++ integration/helpers/utils.ts | 20 +++++++++++++ license-header | 22 ++++++++++++++ package.json | 1 + .../material-tooltip/material-tooltip.tsx | 20 +++++++++++++ .../components/hotbar/hotbar-cell.tsx | 20 +++++++++++++ .../components/hotbar/hotbar-entity-icon.tsx | 20 +++++++++++++ types/command-exists.d.ts | 24 ++++++++++++--- types/dom.d.ts | 20 +++++++++++++ types/font-face.d.ts | 22 ++++++++++++-- types/mocks.d.ts | 21 +++++++++++++- yarn.lock | 5 ++++ 31 files changed, 576 insertions(+), 34 deletions(-) create mode 100644 license-header diff --git a/.eslintrc.js b/.eslintrc.js index 4854713f0e..33d28967ff 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,3 +1,24 @@ +/** + * 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. + */ + const packageJson = require("./package.json"); module.exports = { @@ -27,9 +48,11 @@ module.exports = { sourceType: "module", }, plugins: [ - "unused-imports" + "header", + "unused-imports", ], rules: { + "header/header": [2, "./license-header"], "indent": ["error", 2, { "SwitchCase": 1, }], @@ -72,6 +95,7 @@ module.exports = { "plugin:@typescript-eslint/recommended", ], plugins: [ + "header", "unused-imports" ], parserOptions: { @@ -79,6 +103,7 @@ module.exports = { sourceType: "module", }, rules: { + "header/header": [2, "./license-header"], "no-invalid-this": "off", "@typescript-eslint/no-invalid-this": ["error"], "@typescript-eslint/explicit-function-return-type": "off", @@ -127,6 +152,7 @@ module.exports = { ], parser: "@typescript-eslint/parser", plugins: [ + "header", "unused-imports" ], extends: [ @@ -139,6 +165,7 @@ module.exports = { jsx: true, }, rules: { + "header/header": [2, "./license-header"], "no-invalid-this": "off", "@typescript-eslint/no-invalid-this": ["error"], "@typescript-eslint/explicit-function-return-type": "off", diff --git a/.github/workflows/license-header.yml b/.github/workflows/license-header.yml index 2e35317360..daba6a9ca9 100644 --- a/.github/workflows/license-header.yml +++ b/.github/workflows/license-header.yml @@ -7,7 +7,7 @@ on: branches: - master jobs: - test: + css: runs-on: ubuntu-latest steps: @@ -23,19 +23,4 @@ jobs: set -e export PATH=${PATH}:`go env GOPATH`/bin - addlicense -check -l mit -c "OpenLens Authors" *.ts* - - addlicense -check -l mit -c "OpenLens Authors" src/migrations/**/*.ts* - addlicense -check -l mit -c "OpenLens Authors" src/*.ts* - - addlicense -check -l mit -c "OpenLens Authors" src/common/**/*.ts* - addlicense -check -l mit -c "OpenLens Authors" src/common/**/*.?css - - addlicense -check -l mit -c "OpenLens Authors" src/main/**/*.ts* - - addlicense -check -l mit -c "OpenLens Authors" src/renderer/**/*.ts* - addlicense -check -l mit -c "OpenLens Authors" src/renderer/**/*.?css - - addlicense -check -l mit -c "OpenLens Authors" src/extensions/**/*.ts* - - addlicense -check -l mit -c "OpenLens Authors" extensions/**/*.ts* + addlicense -check -l mit -c "OpenLens Authors" src/**/*.?css diff --git a/__mocks__/@linguiMacro.ts b/__mocks__/@linguiMacro.ts index a1154b42dd..88be664f85 100644 --- a/__mocks__/@linguiMacro.ts +++ b/__mocks__/@linguiMacro.ts @@ -1,3 +1,23 @@ +/** + * 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. + */ module.exports = { Trans: ({ children }: { children: React.ReactNode }) => children, t: (message: string) => message diff --git a/__mocks__/electron.ts b/__mocks__/electron.ts index 1b531fb8d7..8a8408db88 100644 --- a/__mocks__/electron.ts +++ b/__mocks__/electron.ts @@ -1,3 +1,23 @@ +/** + * 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. + */ module.exports = { require: jest.fn(), match: jest.fn(), diff --git a/__mocks__/imageMock.ts b/__mocks__/imageMock.ts index f053ebf797..31effc071f 100644 --- a/__mocks__/imageMock.ts +++ b/__mocks__/imageMock.ts @@ -1 +1,21 @@ +/** + * 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. + */ module.exports = {}; diff --git a/__mocks__/styleMock.ts b/__mocks__/styleMock.ts index f053ebf797..31effc071f 100644 --- a/__mocks__/styleMock.ts +++ b/__mocks__/styleMock.ts @@ -1 +1,21 @@ +/** + * 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. + */ module.exports = {}; diff --git a/build/build_tray_icon.ts b/build/build_tray_icon.ts index 3aded6fdf5..9669783631 100644 --- a/build/build_tray_icon.ts +++ b/build/build_tray_icon.ts @@ -1,5 +1,23 @@ -// Generate tray icons from SVG to PNG + different sizes and colors (B&W) -// Command: `yarn build:tray-icons` +/** + * 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 path from "path"; import sharp from "sharp"; import jsdom from "jsdom"; diff --git a/build/download_helm.ts b/build/download_helm.ts index 7a3dc62a72..703684066b 100644 --- a/build/download_helm.ts +++ b/build/download_helm.ts @@ -1,3 +1,23 @@ +/** + * 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 { helmCli } from "../src/main/helm/helm-cli"; helmCli.ensureBinary(); diff --git a/build/download_kubectl.ts b/build/download_kubectl.ts index f046b23e30..c4ae90a702 100644 --- a/build/download_kubectl.ts +++ b/build/download_kubectl.ts @@ -1,3 +1,23 @@ +/** + * 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 packageInfo from "../package.json"; import fs from "fs"; import request from "request"; diff --git a/build/notarize.js b/build/notarize.js index ef4144993c..959f526ddd 100644 --- a/build/notarize.js +++ b/build/notarize.js @@ -1,3 +1,23 @@ +/** + * 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. + */ const { notarize } = require("electron-notarize"); exports.default = async function notarizing(context) { diff --git a/build/set_build_version.ts b/build/set_build_version.ts index c18abbca9c..df48a1da13 100644 --- a/build/set_build_version.ts +++ b/build/set_build_version.ts @@ -1,3 +1,23 @@ +/** + * 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 * as fs from "fs"; import * as path from "path"; import appInfo from "../package.json"; diff --git a/build/set_npm_version.ts b/build/set_npm_version.ts index 9b433349fb..b7614103a2 100644 --- a/build/set_npm_version.ts +++ b/build/set_npm_version.ts @@ -1,3 +1,23 @@ +/** + * 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 * as fs from "fs"; import * as path from "path"; import packageInfo from "../src/extensions/npm/extensions/package.json"; diff --git a/extensions/kube-object-event-status/webpack.config.js b/extensions/kube-object-event-status/webpack.config.js index 6d5de7a2f8..33fd38ade7 100644 --- a/extensions/kube-object-event-status/webpack.config.js +++ b/extensions/kube-object-event-status/webpack.config.js @@ -1,3 +1,23 @@ +/** + * 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. + */ const path = require("path"); module.exports = [ diff --git a/extensions/metrics-cluster-feature/webpack.config.js b/extensions/metrics-cluster-feature/webpack.config.js index 2df74b3e35..0c42651e40 100644 --- a/extensions/metrics-cluster-feature/webpack.config.js +++ b/extensions/metrics-cluster-feature/webpack.config.js @@ -1,3 +1,23 @@ +/** + * 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. + */ const path = require("path"); module.exports = [ diff --git a/extensions/node-menu/webpack.config.js b/extensions/node-menu/webpack.config.js index 6d5de7a2f8..33fd38ade7 100644 --- a/extensions/node-menu/webpack.config.js +++ b/extensions/node-menu/webpack.config.js @@ -1,3 +1,23 @@ +/** + * 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. + */ const path = require("path"); module.exports = [ diff --git a/extensions/pod-menu/webpack.config.js b/extensions/pod-menu/webpack.config.js index 6d5de7a2f8..33fd38ade7 100644 --- a/extensions/pod-menu/webpack.config.js +++ b/extensions/pod-menu/webpack.config.js @@ -1,3 +1,23 @@ +/** + * 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. + */ const path = require("path"); module.exports = [ diff --git a/integration/__tests__/app.tests.ts b/integration/__tests__/app.tests.ts index 5f0fe9df04..c3a93200d2 100644 --- a/integration/__tests__/app.tests.ts +++ b/integration/__tests__/app.tests.ts @@ -1,5 +1,22 @@ /** - * @jest-environment node + * 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. */ /* diff --git a/integration/__tests__/cluster-pages.tests.ts b/integration/__tests__/cluster-pages.tests.ts index e2e9d14e2a..e0afc15c4c 100644 --- a/integration/__tests__/cluster-pages.tests.ts +++ b/integration/__tests__/cluster-pages.tests.ts @@ -1,9 +1,23 @@ -/* - Cluster tests are run if there is a pre-existing minikube cluster. Before running cluster tests the TEST_NAMESPACE - namespace is removed, if it exists, from the minikube cluster. Resources are created as part of the cluster tests in the - TEST_NAMESPACE namespace. This is done to minimize destructive impact of the cluster tests on an existing minikube - cluster and vice versa. -*/ +/** + * 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 { Application } from "spectron"; import * as utils from "../helpers/utils"; import { minikubeReady, waitForMinikubeDashboard } from "../helpers/minikube"; diff --git a/integration/__tests__/command-palette.tests.ts b/integration/__tests__/command-palette.tests.ts index 6f924f5524..118897b842 100644 --- a/integration/__tests__/command-palette.tests.ts +++ b/integration/__tests__/command-palette.tests.ts @@ -1,3 +1,23 @@ +/** + * 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 { Application } from "spectron"; import * as utils from "../helpers/utils"; diff --git a/integration/helpers/minikube.ts b/integration/helpers/minikube.ts index df2110ba92..50e325ccf0 100644 --- a/integration/helpers/minikube.ts +++ b/integration/helpers/minikube.ts @@ -1,3 +1,23 @@ +/** + * 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 { spawnSync } from "child_process"; import { Application } from "spectron"; diff --git a/integration/helpers/utils.ts b/integration/helpers/utils.ts index bb41e65bdd..9ce33b21c3 100644 --- a/integration/helpers/utils.ts +++ b/integration/helpers/utils.ts @@ -1,3 +1,23 @@ +/** + * 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 { Application } from "spectron"; import * as util from "util"; import { exec } from "child_process"; diff --git a/license-header b/license-header new file mode 100644 index 0000000000..1300dcadc0 --- /dev/null +++ b/license-header @@ -0,0 +1,22 @@ +/** + * 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. + */ + + diff --git a/package.json b/package.json index a3ee10c9fd..bf85e16fec 100644 --- a/package.json +++ b/package.json @@ -315,6 +315,7 @@ "electron-builder": "^22.10.5", "electron-notarize": "^0.3.0", "eslint": "^7.7.0", + "eslint-plugin-header": "^3.1.1", "eslint-plugin-react": "^7.21.5", "eslint-plugin-unused-imports": "^1.0.1", "file-loader": "^6.0.0", diff --git a/src/renderer/components/+catalog/material-tooltip/material-tooltip.tsx b/src/renderer/components/+catalog/material-tooltip/material-tooltip.tsx index dbfd8b5323..0427f1ca78 100644 --- a/src/renderer/components/+catalog/material-tooltip/material-tooltip.tsx +++ b/src/renderer/components/+catalog/material-tooltip/material-tooltip.tsx @@ -1,3 +1,23 @@ +/** + * 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 { makeStyles, Tooltip, TooltipProps } from "@material-ui/core"; diff --git a/src/renderer/components/hotbar/hotbar-cell.tsx b/src/renderer/components/hotbar/hotbar-cell.tsx index aa19faa052..e3328dcbed 100644 --- a/src/renderer/components/hotbar/hotbar-cell.tsx +++ b/src/renderer/components/hotbar/hotbar-cell.tsx @@ -1,3 +1,23 @@ +/** + * 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 "./hotbar-menu.scss"; import "./hotbar.commands"; diff --git a/src/renderer/components/hotbar/hotbar-entity-icon.tsx b/src/renderer/components/hotbar/hotbar-entity-icon.tsx index 52a93990ee..7e2b7f79bf 100644 --- a/src/renderer/components/hotbar/hotbar-entity-icon.tsx +++ b/src/renderer/components/hotbar/hotbar-entity-icon.tsx @@ -1,3 +1,23 @@ +/** + * 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 "./hotbar-icon.scss"; import React, { DOMAttributes } from "react"; diff --git a/types/command-exists.d.ts b/types/command-exists.d.ts index 634d2a035e..8f07bb978e 100644 --- a/types/command-exists.d.ts +++ b/types/command-exists.d.ts @@ -1,7 +1,23 @@ -// Type definitions for command-exists 1.2 -// Project: https://github.com/mathisonian/command-exists -// Definitions by: BendingBender -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +/** + * 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. + */ export = commandExists; diff --git a/types/dom.d.ts b/types/dom.d.ts index 40926b249b..bb829706f0 100644 --- a/types/dom.d.ts +++ b/types/dom.d.ts @@ -1,3 +1,23 @@ +/** + * 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. + */ export {}; declare global { diff --git a/types/font-face.d.ts b/types/font-face.d.ts index ca4282ae97..001b031477 100644 --- a/types/font-face.d.ts +++ b/types/font-face.d.ts @@ -1,5 +1,23 @@ -// https://www.w3.org/TR/css-font-loading/ -// https://developer.mozilla.org/en-US/docs/Web/API/FontFace +/** + * 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. + */ export {}; declare global { diff --git a/types/mocks.d.ts b/types/mocks.d.ts index 7ddd25267b..f29ca29975 100644 --- a/types/mocks.d.ts +++ b/types/mocks.d.ts @@ -1,4 +1,23 @@ -// Black-boxed modules without type safety +/** + * 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. + */ declare module "mac-ca" declare module "win-ca" declare module "@hapi/call" diff --git a/yarn.lock b/yarn.lock index 26dba32559..7492bed758 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5278,6 +5278,11 @@ escodegen@^1.14.1, escodegen@^1.8.1: optionalDependencies: source-map "~0.6.1" +eslint-plugin-header@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-header/-/eslint-plugin-header-3.1.1.tgz#6ce512432d57675265fac47292b50d1eff11acd6" + integrity sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg== + eslint-plugin-react@^7.21.5: version "7.21.5" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz#50b21a412b9574bfe05b21db176e8b7b3b15bff3" From 6a33944f527f607a7e3a14a8cfdf863276228b46 Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Mon, 17 May 2021 16:57:52 +0300 Subject: [PATCH 06/21] Remove universal analytics types (#2781) Signed-off-by: Jari Kolehmainen --- package.json | 1 - yarn.lock | 5 ----- 2 files changed, 6 deletions(-) diff --git a/package.json b/package.json index bf85e16fec..cc4e278557 100644 --- a/package.json +++ b/package.json @@ -291,7 +291,6 @@ "@types/tar": "^4.0.4", "@types/tcp-port-used": "^1.0.0", "@types/tempy": "^0.3.0", - "@types/universal-analytics": "^0.4.4", "@types/url-parse": "^1.4.3", "@types/uuid": "^8.3.0", "@types/webdriverio": "^4.13.0", diff --git a/yarn.lock b/yarn.lock index 7492bed758..2be3cbfbcb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1803,11 +1803,6 @@ resolved "https://registry.yarnpkg.com/@types/underscore/-/underscore-1.10.0.tgz#5cb0dff2a5f616fc8e0c61b482bf01fa20a03cec" integrity sha512-ZAbqul7QAKpM2h1PFGa5ETN27ulmqtj0QviYHasw9LffvXZvVHuraOx/FOsIPPDNGZN0Qo1nASxxSfMYOtSoCw== -"@types/universal-analytics@^0.4.4": - version "0.4.4" - resolved "https://registry.yarnpkg.com/@types/universal-analytics/-/universal-analytics-0.4.4.tgz#496a52b92b599a0112bec7c12414062de6ea8449" - integrity sha512-9g3F0SGxVr4UDd6y07bWtFnkpSSX1Ake7U7AGHgSFrwM6pF53/fV85bfxT2JLWS/3sjLCcyzoYzQlCxpkVo7wA== - "@types/url-parse@^1.4.3": version "1.4.3" resolved "https://registry.yarnpkg.com/@types/url-parse/-/url-parse-1.4.3.tgz#fba49d90f834951cb000a674efee3d6f20968329" From e188cf45e607f382f461c5a21e0088414c36774f Mon Sep 17 00:00:00 2001 From: Lauri Nevala Date: Tue, 18 May 2021 12:23:17 +0300 Subject: [PATCH 07/21] Delete node shell container on exit (#2793) Signed-off-by: Lauri Nevala --- src/main/shell-session/node-shell-session.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/shell-session/node-shell-session.ts b/src/main/shell-session/node-shell-session.ts index 1848716380..72413c7953 100644 --- a/src/main/shell-session/node-shell-session.ts +++ b/src/main/shell-session/node-shell-session.ts @@ -120,6 +120,11 @@ export class NodeShellSession extends ShellSession { }); } + protected exit() { + super.exit(); + this.deleteNodeShellPod(); + } + protected deleteNodeShellPod() { this .kc From 6be465858b438813887222f60bc2927eaaf6b637 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 18 May 2021 05:24:43 -0400 Subject: [PATCH 08/21] Add IPC capabilities for Extensions (#2775) * Add IPC capabilities for Extensions Signed-off-by: Sebastian Malton * revert onA|D change: Signed-off-by: Sebastian Malton * Switch to pushing the disposer in the methods Signed-off-by: Sebastian Malton * improve documentation, switch to a singleton instead of extension methods Signed-off-by: Sebastian Malton * fix build Signed-off-by: Sebastian Malton * make exported class abstract, improve guide Signed-off-by: Sebastian Malton * fix docs Signed-off-by: Sebastian Malton * fix lint Signed-off-by: Sebastian Malton * Change guide demo to initialization in constructor Signed-off-by: Sebastian Malton --- docs/extensions/guides/README.md | 1 + docs/extensions/guides/ipc.md | 131 ++++++++++++++++++++++++++ mkdocs.yml | 1 + src/common/ipc/ipc.ts | 40 ++++---- src/common/ipc/type-enforced-ipc.ts | 68 +++++++++---- src/extensions/core-api/index.ts | 2 + src/extensions/core-api/stores.ts | 2 + src/extensions/core-api/types.ts | 24 +++++ src/extensions/ipc-store.ts | 39 ++++++++ src/extensions/lens-extension.ts | 27 +++--- src/extensions/lens-main-extension.ts | 2 +- src/extensions/main-ipc-store.ts | 45 +++++++++ src/extensions/registries/index.ts | 1 + src/extensions/renderer-ipc-store.ts | 44 +++++++++ 14 files changed, 375 insertions(+), 52 deletions(-) create mode 100644 docs/extensions/guides/ipc.md create mode 100644 src/extensions/core-api/types.ts create mode 100644 src/extensions/ipc-store.ts create mode 100644 src/extensions/main-ipc-store.ts create mode 100644 src/extensions/renderer-ipc-store.ts diff --git a/docs/extensions/guides/README.md b/docs/extensions/guides/README.md index 06bbbe9e3c..012794a39e 100644 --- a/docs/extensions/guides/README.md +++ b/docs/extensions/guides/README.md @@ -24,6 +24,7 @@ Each guide or code sample includes the following: | [KubeObjectListLayout](kube-object-list-layout.md) | | | [Working with mobx](working-with-mobx.md) | | | [Protocol Handlers](protocol-handlers.md) | | +| [Sending Data between main and renderer](ipc.md) | | ## Samples diff --git a/docs/extensions/guides/ipc.md b/docs/extensions/guides/ipc.md new file mode 100644 index 0000000000..91d811bdf0 --- /dev/null +++ b/docs/extensions/guides/ipc.md @@ -0,0 +1,131 @@ +# Inter Process Communication + +A Lens Extension can utilize IPC to send information between its `LensRendererExtension` and its `LensMainExtension`. +This is useful when wanting to communicate directly within your extension. +For example, if a user logs into a service that your extension is a facade for and `main` needs to know some information so that you can start syncing items to the `Catalog`, this would be a good way to send that information along. + +IPC channels are blocked off per extension. +Meaning that each extension can only communicate with itself. + +## Types of IPC + +There are two flavours of IPC that are provided: + +- Event based +- Request based + +### Event Based IPC + +This is the same as an [Event Emitter](https://nodejs.org/api/events.html#events_class_eventemitter) but is not limited to just one Javascript process. +This is a good option when you need to report that something has happened but you don't need a response. + +This is a fully two-way form of communication. +Both `LensMainExtension` and `LensRendererExtension` can do this sort of IPC. + +### Request Based IPC + +This is more like a Remote Procedure Call (RPC). +With this sort of IPC the caller waits for the result from the other side. +This is accomplished by returning a `Promise` which needs to be `await`-ed. + +This is a unidirectional form of communication. +Only `LensRendererExtension` can initiate this kind of request, and only `LensMainExtension` can and respond this this kind of request. + +## Registering IPC Handlers and Listeners + +The general terminology is as follows: + +- A "handler" is the function that responds to a "Request Based IPC" event. +- A "listener" is the function that is called when a "Event Based IPC" event is emitted. + +To register either a handler or a listener, you should do something like the following: + +`main.ts`: +```typescript +import { LensMainExtension, Interface, Types, Store } from "@k8slens/extensions"; +import { registerListeners, IpcMain } from "./helpers/main"; + +export class ExampleExtensionMain extends LensMainExtension { + onActivate() { + IpcMain.createInstance(this); + } +} +``` + +This file shows that you need to create an instance of the store to be able to use IPC. +Lens will automatically clean up that store and all the handlers on deactivation and uninstall. + +--- + +`helpers/main.ts`: +```typescript +import { Store } from "@k8slens/extensions"; + +export class IpcMain extends Store.MainIpcStore { + constructor(extension: LensMainExtension) { + super(extension); + + this.listenIpc("initialize", onInitialize); + } +} + +function onInitialize(event: Types.IpcMainEvent, id: string) { + console.log(`starting to initialize: ${id}`); +} +``` + +In other files, it is not necessary to pass around any instances. +It should be able to just call `getInstance()` everywhere in your extension as needed. + +--- + +`renderer.ts`: +```typescript +import { LensRendererExtension, Interface, Types } from "@k8slens/extensions"; +import { IpcRenderer } from "./helpers/renderer"; + +export class ExampleExtensionRenderer extends LensRendererExtension { + onActivate() { + const ipc = IpcRenderer.createInstance(this); + + setTimeout(() => ipc.broadcastIpc("initialize", "an-id"), 5000); + } +} +``` + +It is also needed to create an instance to broadcast messages too. + +--- + +`helpers/renderer.ts`: +```typescript +import { Store } from "@k8slens/extensions"; + +export class IpcMain extends Store.RendererIpcStore {} +``` + +It is necessary to create child classes of these `abstract class`'s in your extension before you can use them. + +--- + +As this example shows: the channel names *must* be the same. +It should also be noted that "listeners" and "handlers" are specific to either `LensRendererExtension` and `LensMainExtension`. +There is no behind the scenes transfer of these functions. + +If you want to register a "handler" you would call `Store.MainIpcStore.handleIpc(...)` instead. +The cleanup of these handlers is handled by Lens itself. + +`Store.RendererIpcStore.broadcastIpc(...)` and `Store.MainIpcStore.broadcastIpc(...)` sends an event to all renderer frames and to main. +Because of this, no matter where you broadcast from, all listeners in `main` and `renderer` will be notified. + +### Allowed Values + +This IPC mechanism utilizes the [Structured Clone Algorithm](developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) for serialization. +This means that more types than what are JSON serializable can be used, but not all the information will be passed through. + +## Using IPC + +Calling IPC is very simple. +If you are meaning to do an event based call, merely call `broadcastIpc(, ...)` from within your extension. + +If you are meaning to do a request based call from `renderer`, you should do `const res = await Store.RendererIpcStore.invokeIpc(, ...));` instead. diff --git a/mkdocs.yml b/mkdocs.yml index 0496f3001e..fe42cbccf5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -35,6 +35,7 @@ nav: - Stores: extensions/guides/stores.md - Working with MobX: extensions/guides/working-with-mobx.md - Protocol Handlers: extensions/guides/protocol-handlers.md + - IPC: extensions/guides/ipc.md - Testing and Publishing: - Testing Extensions: extensions/testing-and-publishing/testing.md - Publishing Extensions: extensions/testing-and-publishing/publishing.md diff --git a/src/common/ipc/ipc.ts b/src/common/ipc/ipc.ts index 74305e0484..66e591e765 100644 --- a/src/common/ipc/ipc.ts +++ b/src/common/ipc/ipc.ts @@ -42,35 +42,33 @@ function getSubFrames(): ClusterFrameInfo[] { return toJS(Array.from(clusterFrameMap.values()), { recurseEverything: true }); } -export async function broadcastMessage(channel: string, ...args: any[]) { +export function broadcastMessage(channel: string, ...args: any[]) { const views = (webContents || remote?.webContents)?.getAllWebContents(); if (!views) return; - if (ipcRenderer) { - ipcRenderer.send(channel, ...args); - } else if (ipcMain) { - ipcMain.emit(channel, ...args); - } + ipcRenderer?.send(channel, ...args); + ipcMain?.emit(channel, ...args); - for (const view of views) { - const type = view.getType(); + const subFramesP = ipcRenderer + ? requestMain(subFramesChannel) + : Promise.resolve(getSubFrames()); - logger.silly(`[IPC]: broadcasting "${channel}" to ${type}=${view.id}`, { args }); - view.send(channel, ...args); + subFramesP + .then(subFrames => { + for (const view of views) { + try { + logger.silly(`[IPC]: broadcasting "${channel}" to ${view.getType()}=${view.id}`, { args }); + view.send(channel, ...args); - try { - const subFrames: ClusterFrameInfo[] = ipcRenderer - ? await requestMain(subFramesChannel) - : getSubFrames(); - - for (const frameInfo of subFrames) { - view.sendToFrame([frameInfo.processId, frameInfo.frameId], channel, ...args); + for (const frameInfo of subFrames) { + view.sendToFrame([frameInfo.processId, frameInfo.frameId], channel, ...args); + } + } catch (error) { + logger.error("[IPC]: failed to send IPC message", { error: String(error) }); + } } - } catch (error) { - logger.error("[IPC]: failed to send IPC message", { error: String(error) }); - } - } + }); } export function subscribeToBroadcast(channel: string, listener: (...args: any[]) => any) { diff --git a/src/common/ipc/type-enforced-ipc.ts b/src/common/ipc/type-enforced-ipc.ts index 1c4c7d301d..035ffcd77e 100644 --- a/src/common/ipc/type-enforced-ipc.ts +++ b/src/common/ipc/type-enforced-ipc.ts @@ -19,10 +19,12 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +import { ipcMain } from "electron"; import { EventEmitter } from "events"; import logger from "../../main/logger"; +import { Disposer } from "../utils"; -export type HandlerEvent = Parameters[1]>[0]; +export type ListenerEvent = Parameters[1]>[0]; export type ListVerifier = (args: unknown[]) => args is T; export type Rest = T extends [any, ...infer R] ? R : []; @@ -34,22 +36,22 @@ export type Rest = T extends [any, ...infer R] ? R : []; * @param verifier The function to be called to verify that the args are the correct type */ export function onceCorrect< - EM extends EventEmitter, - L extends (event: HandlerEvent, ...args: any[]) => any + IPC extends EventEmitter, + Listener extends (event: ListenerEvent, ...args: any[]) => any >({ source, channel, listener, verifier, }: { - source: EM, - channel: string | symbol, - listener: L, - verifier: ListVerifier>>, + source: IPC, + channel: string, + listener: Listener, + verifier: ListVerifier>>, }): void { - function handler(event: HandlerEvent, ...args: unknown[]): void { + function wrappedListener(event: ListenerEvent, ...args: unknown[]): void { if (verifier(args)) { - source.removeListener(channel, handler); // remove immediately + source.removeListener(channel, wrappedListener); // remove immediately (async () => (listener(event, ...args)))() // might return a promise, or throw, or reject .catch((error: any) => logger.error("[IPC]: channel once handler threw error", { channel, error })); @@ -58,7 +60,7 @@ export function onceCorrect< } } - source.on(channel, handler); + source.on(channel, wrappedListener); } /** @@ -68,25 +70,53 @@ export function onceCorrect< * @param verifier The function to be called to verify that the args are the correct type */ export function onCorrect< - EM extends EventEmitter, - L extends (event: HandlerEvent, ...args: any[]) => any + IPC extends EventEmitter, + Listener extends (event: ListenerEvent, ...args: any[]) => any >({ source, channel, listener, verifier, }: { - source: EM, - channel: string | symbol, - listener: L, - verifier: ListVerifier>>, -}): void { - source.on(channel, (event, ...args: unknown[]) => { + source: IPC, + channel: string, + listener: Listener, + verifier: ListVerifier>>, +}): Disposer { + function wrappedListener(event: ListenerEvent, ...args: unknown[]) { if (verifier(args)) { (async () => (listener(event, ...args)))() // might return a promise, or throw, or reject .catch(error => logger.error("[IPC]: channel on handler threw error", { channel, error })); } else { logger.error("[IPC]: channel was emitted with invalid data", { channel, args }); } - }); + } + + source.on(channel, wrappedListener); + + return () => source.off(channel, wrappedListener); +} + +export function handleCorrect< + Handler extends (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any, +>({ + channel, + handler, + verifier, +}: { + channel: string, + handler: Handler, + verifier: ListVerifier>>, +}): Disposer { + function wrappedHandler(event: Electron.IpcMainInvokeEvent, ...args: unknown[]): ReturnType { + if (verifier(args)) { + return handler(event, ...args); + } + + throw new TypeError(`Invalid args for invoke on channel: ${channel}`); + } + + ipcMain.handle(channel, wrappedHandler); + + return () => ipcMain.removeHandler(channel); } diff --git a/src/extensions/core-api/index.ts b/src/extensions/core-api/index.ts index 258fdbb6af..4fdca344d9 100644 --- a/src/extensions/core-api/index.ts +++ b/src/extensions/core-api/index.ts @@ -31,6 +31,7 @@ import * as Util from "./utils"; import * as ClusterFeature from "./cluster-feature"; import * as Interface from "../interfaces"; import * as Catalog from "./catalog"; +import * as Types from "./types"; export { App, @@ -39,5 +40,6 @@ export { ClusterFeature, Interface, Store, + Types, Util, }; diff --git a/src/extensions/core-api/stores.ts b/src/extensions/core-api/stores.ts index 17eac539d6..a9dfe9bf1e 100644 --- a/src/extensions/core-api/stores.ts +++ b/src/extensions/core-api/stores.ts @@ -20,3 +20,5 @@ */ export { ExtensionStore } from "../extension-store"; +export { MainIpcStore } from "../main-ipc-store"; +export { RendererIpcStore } from "../renderer-ipc-store"; diff --git a/src/extensions/core-api/types.ts b/src/extensions/core-api/types.ts new file mode 100644 index 0000000000..ed78b5c017 --- /dev/null +++ b/src/extensions/core-api/types.ts @@ -0,0 +1,24 @@ +/** + * 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. + */ + +export type IpcMainInvokeEvent = Electron.IpcMainInvokeEvent; +export type IpcRendererEvent = Electron.IpcRendererEvent; +export type IpcMainEvent = Electron.IpcMainEvent; diff --git a/src/extensions/ipc-store.ts b/src/extensions/ipc-store.ts new file mode 100644 index 0000000000..541f7b2914 --- /dev/null +++ b/src/extensions/ipc-store.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. + */ +import { Singleton } from "../common/utils"; +import { LensExtension } from "./lens-extension"; +import { createHash } from "crypto"; +import { broadcastMessage } from "../common/ipc"; + +export const IpcPrefix = Symbol(); + +export abstract class IpcStore extends Singleton { + readonly [IpcPrefix]: string; + + constructor(protected extension: LensExtension) { + super(); + this[IpcPrefix] = createHash("sha256").update(extension.id).digest("hex"); + } + + broadcastIpc(channel: string, ...args: any[]): void { + broadcastMessage(`extensions@${this[IpcPrefix]}:${channel}`, ...args); + } +} diff --git a/src/extensions/lens-extension.ts b/src/extensions/lens-extension.ts index cf9077209c..d9df2c9993 100644 --- a/src/extensions/lens-extension.ts +++ b/src/extensions/lens-extension.ts @@ -23,7 +23,8 @@ import type { InstalledExtension } from "./extension-discovery"; import { action, observable, reaction } from "mobx"; import { FilesystemProvisionerStore } from "../main/extension-filesystem"; import logger from "../main/logger"; -import { ProtocolHandlerRegistration } from "./registries/protocol-handler-registry"; +import { ProtocolHandlerRegistration } from "./registries"; +import { disposer } from "../common/utils"; export type LensExtensionId = string; // path to manifest (package.json) export type LensExtensionConstructor = new (...args: ConstructorParameters) => LensExtension; @@ -37,6 +38,8 @@ export interface LensExtensionManifest { lens?: object; // fixme: add more required fields for validation } +export const Disposers = Symbol(); + export class LensExtension { readonly id: LensExtensionId; readonly manifest: LensExtensionManifest; @@ -46,6 +49,7 @@ export class LensExtension { protocolHandlers: ProtocolHandlerRegistration[] = []; @observable private isEnabled = false; + [Disposers] = disposer(); constructor({ id, manifest, manifestPath, isBundled }: InstalledExtension) { this.id = id; @@ -62,6 +66,10 @@ export class LensExtension { return this.manifest.version; } + get description() { + return this.manifest.description; + } + /** * getExtensionFileFolder returns the path to an already created folder. This * folder is for the sole use of this extension. @@ -73,15 +81,11 @@ export class LensExtension { return FilesystemProvisionerStore.getInstance().requestDirectory(this.id); } - get description() { - return this.manifest.description; - } - @action async enable() { if (this.isEnabled) return; this.isEnabled = true; - this.onActivate(); + this.onActivate?.(); logger.info(`[EXTENSION]: enabled ${this.name}@${this.version}`); } @@ -89,7 +93,8 @@ export class LensExtension { async disable() { if (!this.isEnabled) return; this.isEnabled = false; - this.onDeactivate(); + this.onDeactivate?.(); + this[Disposers](); logger.info(`[EXTENSION]: disabled ${this.name}@${this.version}`); } @@ -125,12 +130,12 @@ export class LensExtension { }; } - protected onActivate() { - // mock + protected onActivate(): void { + return; } - protected onDeactivate() { - // mock + protected onDeactivate(): void { + return; } } diff --git a/src/extensions/lens-main-extension.ts b/src/extensions/lens-main-extension.ts index 7ae2f06693..b02456c6d4 100644 --- a/src/extensions/lens-main-extension.ts +++ b/src/extensions/lens-main-extension.ts @@ -19,12 +19,12 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import type { MenuRegistration } from "./registries/menu-registry"; import { LensExtension } from "./lens-extension"; import { WindowManager } from "../main/window-manager"; import { getExtensionPageUrl } from "./registries/page-registry"; import { CatalogEntity, catalogEntityRegistry } from "../common/catalog"; import { IObservableArray } from "mobx"; +import { MenuRegistration } from "./registries"; export class LensMainExtension extends LensExtension { appMenus: MenuRegistration[] = []; diff --git a/src/extensions/main-ipc-store.ts b/src/extensions/main-ipc-store.ts new file mode 100644 index 0000000000..1f9241a8b1 --- /dev/null +++ b/src/extensions/main-ipc-store.ts @@ -0,0 +1,45 @@ +/** + * 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 { ipcMain } from "electron"; +import { IpcPrefix, IpcStore } from "./ipc-store"; +import { Disposers } from "./lens-extension"; +import { LensMainExtension } from "./lens-main-extension"; + +export abstract class MainIpcStore extends IpcStore { + constructor(extension: LensMainExtension) { + super(extension); + extension[Disposers].push(() => MainIpcStore.resetInstance()); + } + + handleIpc(channel: string, handler: (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any): void { + const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`; + + ipcMain.handle(prefixedChannel, handler); + this.extension[Disposers].push(() => ipcMain.removeHandler(prefixedChannel)); + } + + listenIpc(channel: string, listener: (event: Electron.IpcMainEvent, ...args: any[]) => any): void { + const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`; + + ipcMain.addListener(prefixedChannel, listener); + this.extension[Disposers].push(() => ipcMain.removeListener(prefixedChannel, listener)); + } +} diff --git a/src/extensions/registries/index.ts b/src/extensions/registries/index.ts index 13d07b2249..7056206daf 100644 --- a/src/extensions/registries/index.ts +++ b/src/extensions/registries/index.ts @@ -32,3 +32,4 @@ export * from "./kube-object-status-registry"; export * from "./command-registry"; export * from "./entity-setting-registry"; export * from "./welcome-menu-registry"; +export * from "./protocol-handler-registry"; diff --git a/src/extensions/renderer-ipc-store.ts b/src/extensions/renderer-ipc-store.ts new file mode 100644 index 0000000000..930027d0e2 --- /dev/null +++ b/src/extensions/renderer-ipc-store.ts @@ -0,0 +1,44 @@ +/** + * 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 { ipcRenderer } from "electron"; +import { IpcPrefix, IpcStore } from "./ipc-store"; +import { Disposers } from "./lens-extension"; +import { LensRendererExtension } from "./lens-renderer-extension"; + +export abstract class RendererIpcStore extends IpcStore { + constructor(extension: LensRendererExtension) { + super(extension); + extension[Disposers].push(() => RendererIpcStore.resetInstance()); + } + + listenIpc(channel: string, listener: (event: Electron.IpcRendererEvent, ...args: any[]) => any): void { + const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`; + + ipcRenderer.addListener(prefixedChannel, listener); + this.extension[Disposers].push(() => ipcRenderer.removeListener(prefixedChannel, listener)); + } + + invokeIpc(channel: string, ...args: any[]): Promise { + const prefixedChannel = `extensions@${this[IpcPrefix]}:${channel}`; + + return ipcRenderer.invoke(prefixedChannel, ...args); + } +} From 0537792c56f395ba990f61f14c73da25d862dc77 Mon Sep 17 00:00:00 2001 From: Lauri Nevala Date: Tue, 18 May 2021 12:26:29 +0300 Subject: [PATCH 09/21] Update node shell to use Alpine 3.13 (#2792) Signed-off-by: Lauri Nevala --- src/main/shell-session/node-shell-session.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/shell-session/node-shell-session.ts b/src/main/shell-session/node-shell-session.ts index 72413c7953..92831939ed 100644 --- a/src/main/shell-session/node-shell-session.ts +++ b/src/main/shell-session/node-shell-session.ts @@ -77,7 +77,7 @@ export class NodeShellSession extends ShellSession { }], containers: [{ name: "shell", - image: "docker.io/alpine:3.12", + image: "docker.io/alpine:3.13", securityContext: { privileged: true, }, From d08d5a24d7b1f1b07ef64cc46549e04451b2aea5 Mon Sep 17 00:00:00 2001 From: steve richards Date: Tue, 18 May 2021 10:29:13 +0100 Subject: [PATCH 10/21] Remove custom GA Tags script. Use built in GA. (#2794) Signed-off-by: Steve Richards --- docs/custom_theme/main.html | 11 ----------- mkdocs.yml | 3 +++ 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/docs/custom_theme/main.html b/docs/custom_theme/main.html index b6ad2467dd..94d9808cc7 100644 --- a/docs/custom_theme/main.html +++ b/docs/custom_theme/main.html @@ -1,12 +1 @@ {% extends "base.html" %} - -{% block analytics %} - - - -{% endblock %} \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index fe42cbccf5..7001e41ce5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -7,6 +7,9 @@ repo_name: GitHub repo_url: https://github.com/lensapp/lens copyright: Copyright © 2021 Mirantis Inc. - All rights reserved. edit_uri: "" +google_analytics: + - UA-159377374-2 + - auto nav: - Overview: README.md - Getting Started: getting-started/README.md From 752f49821a1217dc22d7d3ea13e787dbbb2b2fab Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Tue, 18 May 2021 13:13:33 +0300 Subject: [PATCH 11/21] Show active item in hotbar & allow to pin/unpin (#2790) * show active item in hotbar & allow to pin it Signed-off-by: Jari Kolehmainen * cleanup Signed-off-by: Jari Kolehmainen * fix styles Signed-off-by: Jari Kolehmainen --- src/common/__tests__/hotbar-store.test.ts | 52 +++++---------- src/common/hotbar-store.ts | 12 ++-- src/renderer/components/+catalog/catalog.tsx | 4 +- .../components/hotbar/hotbar-entity-icon.tsx | 64 +++++++++---------- .../components/hotbar/hotbar-icon.scss | 32 ++++------ .../components/hotbar/hotbar-icon.tsx | 18 ++---- .../components/hotbar/hotbar-menu.tsx | 38 +++++++++-- 7 files changed, 109 insertions(+), 111 deletions(-) diff --git a/src/common/__tests__/hotbar-store.test.ts b/src/common/__tests__/hotbar-store.test.ts index 92e5a3f35b..51002fee23 100644 --- a/src/common/__tests__/hotbar-store.test.ts +++ b/src/common/__tests__/hotbar-store.test.ts @@ -20,7 +20,6 @@ */ import mockFs from "mock-fs"; -import { CatalogEntityItem } from "../../renderer/components/+catalog/catalog-entity.store"; import { ClusterStore } from "../cluster-store"; import { HotbarStore } from "../hotbar-store"; @@ -159,10 +158,9 @@ describe("HotbarStore", () => { it("adds items", () => { const hotbarStore = HotbarStore.createInstance(); - const entity = new CatalogEntityItem(testCluster); hotbarStore.load(); - hotbarStore.addToHotbar(entity); + hotbarStore.addToHotbar(testCluster); const items = hotbarStore.getActive().items.filter(Boolean); expect(items.length).toEqual(1); @@ -170,10 +168,9 @@ describe("HotbarStore", () => { it("removes items", () => { const hotbarStore = HotbarStore.createInstance(); - const entity = new CatalogEntityItem(testCluster); hotbarStore.load(); - hotbarStore.addToHotbar(entity); + hotbarStore.addToHotbar(testCluster); hotbarStore.removeFromHotbar("test"); const items = hotbarStore.getActive().items.filter(Boolean); @@ -182,10 +179,9 @@ describe("HotbarStore", () => { it("does nothing if removing with invalid uid", () => { const hotbarStore = HotbarStore.createInstance(); - const entity = new CatalogEntityItem(testCluster); hotbarStore.load(); - hotbarStore.addToHotbar(entity); + hotbarStore.addToHotbar(testCluster); hotbarStore.removeFromHotbar("invalid uid"); const items = hotbarStore.getActive().items.filter(Boolean); @@ -194,14 +190,11 @@ describe("HotbarStore", () => { it("moves item to empty cell", () => { const hotbarStore = HotbarStore.createInstance(); - const test = new CatalogEntityItem(testCluster); - const minikube = new CatalogEntityItem(minikubeCluster); - const aws = new CatalogEntityItem(awsCluster); hotbarStore.load(); - hotbarStore.addToHotbar(test); - hotbarStore.addToHotbar(minikube); - hotbarStore.addToHotbar(aws); + hotbarStore.addToHotbar(testCluster); + hotbarStore.addToHotbar(minikubeCluster); + hotbarStore.addToHotbar(awsCluster); expect(hotbarStore.getActive().items[5]).toBeNull(); @@ -213,14 +206,11 @@ describe("HotbarStore", () => { it("moves items down", () => { const hotbarStore = HotbarStore.createInstance(); - const test = new CatalogEntityItem(testCluster); - const minikube = new CatalogEntityItem(minikubeCluster); - const aws = new CatalogEntityItem(awsCluster); hotbarStore.load(); - hotbarStore.addToHotbar(test); - hotbarStore.addToHotbar(minikube); - hotbarStore.addToHotbar(aws); + hotbarStore.addToHotbar(testCluster); + hotbarStore.addToHotbar(minikubeCluster); + hotbarStore.addToHotbar(awsCluster); // aws -> test hotbarStore.restackItems(2, 0); @@ -232,14 +222,11 @@ describe("HotbarStore", () => { it("moves items up", () => { const hotbarStore = HotbarStore.createInstance(); - const test = new CatalogEntityItem(testCluster); - const minikube = new CatalogEntityItem(minikubeCluster); - const aws = new CatalogEntityItem(awsCluster); hotbarStore.load(); - hotbarStore.addToHotbar(test); - hotbarStore.addToHotbar(minikube); - hotbarStore.addToHotbar(aws); + hotbarStore.addToHotbar(testCluster); + hotbarStore.addToHotbar(minikubeCluster); + hotbarStore.addToHotbar(awsCluster); // test -> aws hotbarStore.restackItems(0, 2); @@ -251,10 +238,9 @@ describe("HotbarStore", () => { it("does nothing when item moved to same cell", () => { const hotbarStore = HotbarStore.createInstance(); - const test = new CatalogEntityItem(testCluster); hotbarStore.load(); - hotbarStore.addToHotbar(test); + hotbarStore.addToHotbar(testCluster); hotbarStore.restackItems(0, 0); expect(hotbarStore.getActive().items[0].entity.uid).toEqual("test"); @@ -262,15 +248,12 @@ describe("HotbarStore", () => { it("new items takes first empty cell", () => { const hotbarStore = HotbarStore.createInstance(); - const test = new CatalogEntityItem(testCluster); - const minikube = new CatalogEntityItem(minikubeCluster); - const aws = new CatalogEntityItem(awsCluster); hotbarStore.load(); - hotbarStore.addToHotbar(test); - hotbarStore.addToHotbar(aws); + hotbarStore.addToHotbar(testCluster); + hotbarStore.addToHotbar(awsCluster); hotbarStore.restackItems(0, 3); - hotbarStore.addToHotbar(minikube); + hotbarStore.addToHotbar(minikubeCluster); expect(hotbarStore.getActive().items[0].entity.uid).toEqual("minikube"); }); @@ -282,10 +265,9 @@ describe("HotbarStore", () => { console.error = jest.fn(); const hotbarStore = HotbarStore.createInstance(); - const test = new CatalogEntityItem(testCluster); hotbarStore.load(); - hotbarStore.addToHotbar(test); + hotbarStore.addToHotbar(testCluster); expect(() => hotbarStore.restackItems(-5, 0)).toThrow(); expect(() => hotbarStore.restackItems(2, -1)).toThrow(); diff --git a/src/common/hotbar-store.ts b/src/common/hotbar-store.ts index b2d5af0f2a..53c1c5b3ef 100644 --- a/src/common/hotbar-store.ts +++ b/src/common/hotbar-store.ts @@ -23,8 +23,8 @@ import { action, comparer, observable, toJS } from "mobx"; import { BaseStore } from "./base-store"; import migrations from "../migrations/hotbar-store"; import * as uuid from "uuid"; -import { CatalogEntityItem } from "../renderer/components/+catalog/catalog-entity.store"; import isNull from "lodash/isNull"; +import { CatalogEntity } from "./catalog"; export interface HotbarItem { entity: { @@ -151,15 +151,15 @@ export class HotbarStore extends BaseStore { } @action - addToHotbar(item: CatalogEntityItem, cellIndex = -1) { + addToHotbar(item: CatalogEntity, cellIndex = -1) { const hotbar = this.getActive(); const newItem = { entity: { - uid: item.id, - name: item.name, - source: item.source + uid: item.metadata.uid, + name: item.metadata.name, + source: item.metadata.source }}; - if (hotbar.items.find(i => i?.entity.uid === item.id)) { + if (hotbar.items.find(i => i?.entity.uid === item.metadata.uid)) { return; } diff --git a/src/renderer/components/+catalog/catalog.tsx b/src/renderer/components/+catalog/catalog.tsx index 2fb6ce8f9f..3f0505d3c1 100644 --- a/src/renderer/components/+catalog/catalog.tsx +++ b/src/renderer/components/+catalog/catalog.tsx @@ -68,7 +68,7 @@ export class Catalog extends React.Component { } addToHotbar(item: CatalogEntityItem): void { - HotbarStore.getInstance().addToHotbar(item); + HotbarStore.getInstance().addToHotbar(item.entity); } onDetails(item: CatalogEntityItem) { @@ -137,7 +137,7 @@ export class Catalog extends React.Component { return ( item.onContextMenuOpen(this.contextMenu)}> this.addToHotbar(item) }> - Add to Hotbar + Pin to Hotbar { menuItems.map((menuItem, index) => ( diff --git a/src/renderer/components/hotbar/hotbar-entity-icon.tsx b/src/renderer/components/hotbar/hotbar-entity-icon.tsx index 7e2b7f79bf..e71ab2fdb2 100644 --- a/src/renderer/components/hotbar/hotbar-entity-icon.tsx +++ b/src/renderer/components/hotbar/hotbar-entity-icon.tsx @@ -18,26 +18,26 @@ * 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 "./hotbar-icon.scss"; import React, { DOMAttributes } from "react"; import { observable } from "mobx"; import { observer } from "mobx-react"; -import randomColor from "randomcolor"; -import { CatalogEntity, CatalogEntityContextMenu, CatalogEntityContextMenuContext } from "../../../common/catalog"; +import { CatalogEntity, CatalogEntityContextMenuContext } from "../../../common/catalog"; import { catalogCategoryRegistry } from "../../api/catalog-category-registry"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; import { navigate } from "../../navigation"; import { cssNames, IClassName } from "../../utils"; -import { ConfirmDialog } from "../confirm-dialog"; import { Icon } from "../icon"; import { HotbarIcon } from "./hotbar-icon"; +import { HotbarStore } from "../../../common/hotbar-store"; interface Props extends DOMAttributes { entity: CatalogEntity; + index: number; className?: IClassName; errorClass?: IClassName; + add: (item: CatalogEntity, index: number) => void; remove: (uid: string) => void; } @@ -77,33 +77,18 @@ export class HotbarEntityIcon extends React.Component { return catalogEntityRegistry.activeEntity?.metadata?.uid == item.getId(); } - onMenuItemClick(menuItem: CatalogEntityContextMenu) { - if (menuItem.confirm) { - ConfirmDialog.open({ - okButtonProps: { - primary: false, - accent: true, - }, - ok: () => { - menuItem.onClick(); - }, - message: menuItem.confirm.message - }); - } else { - menuItem.onClick(); - } - } - - generateAvatarStyle(entity: CatalogEntity): React.CSSProperties { - return { - "backgroundColor": randomColor({ seed: `${entity.metadata.name}-${entity.metadata.source}`, luminosity: "dark" }) - }; + isPersisted(entity: CatalogEntity) { + return HotbarStore.getInstance().getActive().items.find((item) => item?.entity?.uid === entity.metadata.uid) !== undefined; } render() { + if (!this.contextMenu) { + return null; + } + const { - entity, errorClass, remove, - children, ...elemProps + entity, errorClass, add, remove, + index, children, ...elemProps } = this.props; const className = cssNames("HotbarEntityIcon", this.props.className, { interactive: true, @@ -113,16 +98,31 @@ export class HotbarEntityIcon extends React.Component { const onOpen = async () => { await entity.onContextMenuOpen(this.contextMenu); }; + const isActive = this.isActive(entity); + const isPersisted = this.isPersisted(entity); const menuItems = this.contextMenu?.menuItems.filter((menuItem) => !menuItem.onlyVisibleForSource || menuItem.onlyVisibleForSource === entity.metadata.source); + if (!isPersisted) { + menuItems.unshift({ + title: "Pin to Hotbar", + icon: "push_pin", + onClick: () => add(entity, index) + }); + } else { + menuItems.unshift({ + title: "Unpin from Hotbar", + icon: "push_pin", + onClick: () => remove(entity.metadata.uid) + }); + } + return ( .led { + div.MuiAvatar-root { + &.active { + box-shadow: 0 0 0px 3px var(--clusterMenuBackground), 0 0 0px 6px var(--textColorAccent); + transition: all 0s 0.8s; + } + + &:hover { + &:not(.active) { + box-shadow: 0 0 0px 3px var(--clusterMenuBackground), 0 0 0px 6px #ffffff30; + } + } + } + + .led { position: absolute; left: 3px; top: 3px; diff --git a/src/renderer/components/hotbar/hotbar-icon.tsx b/src/renderer/components/hotbar/hotbar-icon.tsx index 74154505e3..2f681a05c1 100644 --- a/src/renderer/components/hotbar/hotbar-icon.tsx +++ b/src/renderer/components/hotbar/hotbar-icon.tsx @@ -32,12 +32,12 @@ import { ConfirmDialog } from "../confirm-dialog"; import { Icon } from "../icon"; import { Menu, MenuItem } from "../menu"; import { MaterialTooltip } from "../+catalog/material-tooltip/material-tooltip"; +import { observer } from "mobx-react"; interface Props extends DOMAttributes { uid: string; title: string; source: string; - remove: (uid: string) => void; onMenuOpen?: () => void; className?: IClassName; active?: boolean; @@ -84,8 +84,8 @@ function getNameParts(name: string): string[] { return name.split(/@+/); } -export function HotbarIcon(props: Props) { - const { uid, title, className, source, active, remove, disabled, menuItems, onMenuOpen, children, ...rest } = props; +export const HotbarIcon = observer(({menuItems = [], ...props}: Props) => { + const { uid, title, active, className, source, disabled, onMenuOpen, children, ...rest } = props; const id = `hotbarIcon-${uid}`; const [menuOpen, setMenuOpen] = useState(false); @@ -134,12 +134,6 @@ export function HotbarIcon(props: Props) { toggleMenu(); }} close={() => toggleMenu()}> - { - evt.stopPropagation(); - remove(uid); - }}> - Remove from Hotbar - { menuItems.map((menuItem) => { return ( onMenuItemClick(menuItem) }> @@ -150,8 +144,4 @@ export function HotbarIcon(props: Props) {
); -} - -HotbarIcon.defaultProps = { - menuItems: [] -}; +}); diff --git a/src/renderer/components/hotbar/hotbar-menu.tsx b/src/renderer/components/hotbar/hotbar-menu.tsx index 319b05f946..33a8d4e0b7 100644 --- a/src/renderer/components/hotbar/hotbar-menu.tsx +++ b/src/renderer/components/hotbar/hotbar-menu.tsx @@ -28,11 +28,12 @@ import { HotbarEntityIcon } from "./hotbar-entity-icon"; import { cssNames, IClassName } from "../../utils"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; import { defaultHotbarCells, HotbarItem, HotbarStore } from "../../../common/hotbar-store"; -import { catalogEntityRunContext } from "../../api/catalog-entity"; +import { CatalogEntity, catalogEntityRunContext } from "../../api/catalog-entity"; import { DragDropContext, Draggable, Droppable, DropResult } from "react-beautiful-dnd"; import { HotbarSelector } from "./hotbar-selector"; import { HotbarCell } from "./hotbar-cell"; import { HotbarIcon } from "./hotbar-icon"; +import { computed } from "mobx"; interface Props { className?: IClassName; @@ -64,6 +65,10 @@ export class HotbarMenu extends React.Component { const from = parseInt(source.droppableId); const to = parseInt(destination.droppableId); + if (!this.hotbar.items[from]) { // Dropped non-persisted item + this.hotbar.items[from] = this.items[from]; + } + HotbarStore.getInstance().restackItems(from, to); } @@ -73,14 +78,38 @@ export class HotbarMenu extends React.Component { hotbar.removeFromHotbar(uid); } + addItem(entity: CatalogEntity, index = -1) { + const hotbar = HotbarStore.getInstance(); + + hotbar.addToHotbar(entity, index); + } + getMoveAwayDirection(entityId: string, cellIndex: number) { const draggableItemIndex = this.hotbar.items.findIndex(item => item?.entity.uid == entityId); return draggableItemIndex > cellIndex ? "animateDown" : "animateUp"; } + @computed get items() { + const items = this.hotbar.items; + const activeEntity = catalogEntityRegistry.activeEntity; + + if (!activeEntity) return items; + + const emptyIndex = items.indexOf(null); + + if (emptyIndex === -1) return items; + if (items.find((item) => item?.entity?.uid === activeEntity.metadata.uid)) return items; + + const modifiedItems = [...items]; + + modifiedItems.splice(emptyIndex, 1, { entity: { uid: activeEntity.metadata.uid }}); + + return modifiedItems; + } + renderGrid() { - return this.hotbar.items.map((item, index) => { + return this.items.map((item, index) => { const entity = this.getEntity(item); return ( @@ -116,17 +145,18 @@ export class HotbarMenu extends React.Component { {entity ? ( entity.onRun(catalogEntityRunContext)} className={cssNames({ isDragging: snapshot.isDragging })} remove={this.removeItem} + add={this.addItem} /> ) : ( )} @@ -151,7 +181,7 @@ export class HotbarMenu extends React.Component { return (
- + {this.renderGrid()}
From ef4bae341f157c66327a2412cd7a048b254a0795 Mon Sep 17 00:00:00 2001 From: Lauri Nevala Date: Tue, 18 May 2021 13:25:10 +0300 Subject: [PATCH 12/21] Re-implement deployment revisions (#2795) * Re-implement deployment revisions * Fix css Signed-off-by: Lauri Nevala --- .../deployment-details.tsx | 5 + .../deployment-replicasets.scss | 36 ++++++ .../deployment-replicasets.tsx | 119 ++++++++++++++++++ 3 files changed, 160 insertions(+) create mode 100644 src/renderer/components/+workloads-deployments/deployment-replicasets.scss create mode 100644 src/renderer/components/+workloads-deployments/deployment-replicasets.tsx diff --git a/src/renderer/components/+workloads-deployments/deployment-details.tsx b/src/renderer/components/+workloads-deployments/deployment-details.tsx index 641eae79e7..112953e63a 100644 --- a/src/renderer/components/+workloads-deployments/deployment-details.tsx +++ b/src/renderer/components/+workloads-deployments/deployment-details.tsx @@ -42,6 +42,8 @@ import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting"; import { ClusterStore } from "../../../common/cluster-store"; +import { replicaSetStore } from "../+workloads-replicasets/replicasets.store"; +import { DeploymentReplicaSets } from "./deployment-replicasets"; interface Props extends KubeObjectDetailsProps { } @@ -55,6 +57,7 @@ export class DeploymentDetails extends React.Component { componentDidMount() { podsStore.reloadAll(); + replicaSetStore.reloadAll(); } componentWillUnmount() { @@ -69,6 +72,7 @@ export class DeploymentDetails extends React.Component { const nodeSelector = deployment.getNodeSelectors(); const selectors = deployment.getSelectors(); const childPods = deploymentStore.getChildPods(deployment); + const replicaSets = replicaSetStore.getReplicaSetsByOwner(deployment); const metrics = deploymentStore.metrics; const isMetricHidden = ClusterStore.getInstance().isMetricHidden(ResourceType.Deployment); @@ -131,6 +135,7 @@ export class DeploymentDetails extends React.Component { +
); diff --git a/src/renderer/components/+workloads-deployments/deployment-replicasets.scss b/src/renderer/components/+workloads-deployments/deployment-replicasets.scss new file mode 100644 index 0000000000..0c04f54709 --- /dev/null +++ b/src/renderer/components/+workloads-deployments/deployment-replicasets.scss @@ -0,0 +1,36 @@ +.DeploymentDetails { + .ReplicaSets { + position: relative; + min-height: 80px; + + .Table { + margin: 0 (-$margin * 3); + } + + .TableCell { + &:first-child { + margin-left: $margin; + } + + &:last-child { + margin-right: $margin; + } + + &.name { + flex-grow: 2; + } + + &.warning { + @include table-cell-warning; + } + + &.namespace { + flex-grow: 1.2; + } + + &.actions { + @include table-cell-action; + } + } + } +} diff --git a/src/renderer/components/+workloads-deployments/deployment-replicasets.tsx b/src/renderer/components/+workloads-deployments/deployment-replicasets.tsx new file mode 100644 index 0000000000..8fbce9564d --- /dev/null +++ b/src/renderer/components/+workloads-deployments/deployment-replicasets.tsx @@ -0,0 +1,119 @@ +/** + * 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 "./deployment-replicasets.scss"; + +import React from "react"; +import { observer } from "mobx-react"; +import { ReplicaSet } from "../../api/endpoints"; +import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object/kube-object-menu"; +import { Spinner } from "../spinner"; +import { prevDefault, stopPropagation } from "../../utils"; +import { DrawerTitle } from "../drawer"; +import { Table, TableCell, TableHead, TableRow } from "../table"; +import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import { replicaSetStore } from "../+workloads-replicasets/replicasets.store"; +import { showDetails } from "../kube-object"; + + +enum sortBy { + name = "name", + namespace = "namespace", + pods = "pods", + age = "age", +} + +interface Props { + replicaSets: ReplicaSet[]; +} + +@observer +export class DeploymentReplicaSets extends React.Component { + private sortingCallbacks = { + [sortBy.name]: (replicaSet: ReplicaSet) => replicaSet.getName(), + [sortBy.namespace]: (replicaSet: ReplicaSet) => replicaSet.getNs(), + [sortBy.age]: (replicaSet: ReplicaSet) => replicaSet.metadata.creationTimestamp, + [sortBy.pods]: (replicaSet: ReplicaSet) => this.getPodsLength(replicaSet), + }; + + getPodsLength(replicaSet: ReplicaSet) { + return replicaSetStore.getChildPods(replicaSet).length; + } + + render() { + const { replicaSets } = this.props; + + if (!replicaSets.length && !replicaSetStore.isLoaded) return ( +
+ ); + if (!replicaSets.length) return null; + + return ( +
+ + + + Name + + Namespace + Pods + Age + + + { + replicaSets.map(replica => { + return ( + showDetails(replica.selfLink, false))} + > + {replica.getName()} + + {replica.getNs()} + {this.getPodsLength(replica)} + {replica.getAge()} + + + + + ); + }) + } +
+
+ ); + } +} + +export function ReplicaSetMenu(props: KubeObjectMenuProps) { + return ( + + ); +} From b6b1b467e0abd79f6478fb85d8a658a0459c0617 Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Tue, 18 May 2021 13:42:33 +0300 Subject: [PATCH 13/21] Add connect/disconnect methods to KubernetesCluster kind (#2758) * add connect/disconnect methods to kubernetes cluster Signed-off-by: Jari Kolehmainen * return void Signed-off-by: Jari Kolehmainen --- .../catalog-entities/kubernetes-cluster.ts | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/common/catalog-entities/kubernetes-cluster.ts b/src/common/catalog-entities/kubernetes-cluster.ts index cd217d3a02..7c6727ada5 100644 --- a/src/common/catalog-entities/kubernetes-cluster.ts +++ b/src/common/catalog-entities/kubernetes-cluster.ts @@ -21,11 +21,12 @@ import { catalogCategoryRegistry } from "../catalog/catalog-category-registry"; import { CatalogEntity, CatalogEntityActionContext, CatalogEntityAddMenuContext, CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog"; -import { clusterDisconnectHandler } from "../cluster-ipc"; +import { clusterActivateHandler, clusterDisconnectHandler } from "../cluster-ipc"; import { ClusterStore } from "../cluster-store"; import { requestMain } from "../ipc"; import { productName } from "../vars"; import { CatalogCategory, CatalogCategorySpec } from "../catalog"; +import { app } from "electron"; export type KubernetesClusterSpec = { kubeconfigPath: string; @@ -40,6 +41,38 @@ export class KubernetesCluster extends CatalogEntity { + if (app) { + const cluster = ClusterStore.getInstance().getById(this.metadata.uid); + + if (!cluster) return; + + await cluster.activate(); + + return; + } + + await requestMain(clusterActivateHandler, this.metadata.uid, false); + + return; + } + + async disconnect(): Promise { + if (app) { + const cluster = ClusterStore.getInstance().getById(this.metadata.uid); + + if (!cluster) return; + + cluster.disconnect(); + + return; + } + + await requestMain(clusterDisconnectHandler, this.metadata.uid, false); + + return; + } + async onRun(context: CatalogEntityActionContext) { context.navigate(`/cluster/${this.metadata.uid}`); } From d9c6e5c52fcb6282847b4093f9cee695362e433e Mon Sep 17 00:00:00 2001 From: chh <1474479+chenhunghan@users.noreply.github.com> Date: Tue, 18 May 2021 14:13:07 +0300 Subject: [PATCH 14/21] Catalog entity WebLink.kind 'KubernetesCluster' > 'WebLink' (#2799) Signed-off-by: Hung-Han (Henry) Chen --- src/common/catalog-entities/web-link.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/catalog-entities/web-link.ts b/src/common/catalog-entities/web-link.ts index 6223b6dbfc..7e0f024421 100644 --- a/src/common/catalog-entities/web-link.ts +++ b/src/common/catalog-entities/web-link.ts @@ -32,7 +32,7 @@ export type WebLinkSpec = { export class WebLink extends CatalogEntity { public readonly apiVersion = "entity.k8slens.dev/v1alpha1"; - public readonly kind = "KubernetesCluster"; + public readonly kind = "WebLink"; async onRun() { window.open(this.spec.url, "_blank"); From 683e5926e061ae8bbce0fd42d278f1005931ae6a Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Tue, 18 May 2021 16:12:45 +0300 Subject: [PATCH 15/21] Show lens-metrics on cluster settings (#2714) * show lens-metrics on cluster settings Signed-off-by: Jari Kolehmainen * remove ClusterFeature Signed-off-by: Jari Kolehmainen * remove ClusterFeature Signed-off-by: Jari Kolehmainen * tweak resource applier/stack Signed-off-by: Jari Kolehmainen * update metrics stack components Signed-off-by: Jari Kolehmainen * fix Signed-off-by: Jari Kolehmainen * fix drawer menu styles Signed-off-by: Jari Kolehmainen * cleanup Signed-off-by: Jari Kolehmainen * cleanup Signed-off-by: Jari Kolehmainen * clarify ui Signed-off-by: Jari Kolehmainen * built-in -> bundled Signed-off-by: Jari Kolehmainen * splitterError -> splitError Signed-off-by: Jari Kolehmainen * support multi-doc yamls Signed-off-by: Jari Kolehmainen * dedicated action button Signed-off-by: Jari Kolehmainen * fix headers Signed-off-by: Jari Kolehmainen * cleanup Signed-off-by: Jari Kolehmainen * async file operations Signed-off-by: Jari Kolehmainen * cleanup Signed-off-by: Jari Kolehmainen * fix bugs Signed-off-by: Jari Kolehmainen --- .../metrics-cluster-feature/renderer.tsx | 66 +---- .../{01-namespace.yml => 01-namespace.yml.hb} | 2 + .../{03-service.yml => 03-service.yml.hb} | 2 + .../resources/03-statefulset.yml.hb | 6 +- .../resources/10-node-exporter-ds.yml.hb | 2 +- .../14-kube-state-metrics-deployment.yml.hb | 4 +- .../src/metrics-feature.ts | 93 +++--- .../src/metrics-settings.tsx | 279 ++++++++++++++++++ .../metrics-cluster-feature/tsconfig.json | 4 +- .../catalog-entities/kubernetes-cluster.ts | 27 +- src/common/catalog/catalog-entity.ts | 7 +- src/common/cluster-ipc.ts | 30 +- src/common/k8s/resource-stack.ts | 152 ++++++++++ src/extensions/cluster-feature.ts | 156 ---------- src/extensions/core-api/cluster-feature.ts | 23 -- src/extensions/core-api/index.ts | 2 - .../registries/entity-setting-registry.ts | 7 +- src/extensions/renderer-api/components.ts | 1 + src/extensions/renderer-api/k8s-api.ts | 1 + src/main/cluster-manager.ts | 15 +- src/main/resource-applier.ts | 29 +- src/renderer/api/catalog-entity.ts | 1 + .../+catalog/catalog-add-button.tsx | 4 +- src/renderer/components/+catalog/catalog.tsx | 9 +- .../+entity-settings/entity-settings.tsx | 35 ++- .../cluster-settings/cluster-settings.tsx | 5 + .../components/cluster-metrics-setting.scss | 33 --- .../components/cluster-metrics-setting.tsx | 2 - .../components/cluster-prometheus-setting.tsx | 34 +-- .../components/remove-cluster-button.tsx | 57 ---- .../components/show-metrics.tsx | 2 - src/renderer/components/drawer/drawer.scss | 6 +- .../components/hotbar/hotbar-entity-icon.tsx | 2 - .../components/hotbar/hotbar-icon.tsx | 3 +- src/renderer/components/menu/menu.scss | 4 +- 35 files changed, 662 insertions(+), 443 deletions(-) rename extensions/metrics-cluster-feature/resources/{01-namespace.yml => 01-namespace.yml.hb} (53%) rename extensions/metrics-cluster-feature/resources/{03-service.yml => 03-service.yml.hb} (88%) create mode 100644 extensions/metrics-cluster-feature/src/metrics-settings.tsx create mode 100644 src/common/k8s/resource-stack.ts delete mode 100644 src/extensions/cluster-feature.ts delete mode 100644 src/extensions/core-api/cluster-feature.ts delete mode 100644 src/renderer/components/cluster-settings/components/cluster-metrics-setting.scss delete mode 100644 src/renderer/components/cluster-settings/components/remove-cluster-button.tsx diff --git a/extensions/metrics-cluster-feature/renderer.tsx b/extensions/metrics-cluster-feature/renderer.tsx index 129e60ebff..f0d227f0a7 100644 --- a/extensions/metrics-cluster-feature/renderer.tsx +++ b/extensions/metrics-cluster-feature/renderer.tsx @@ -19,58 +19,24 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { LensRendererExtension, Interface, Component, Catalog} from "@k8slens/extensions"; -import { MetricsFeature } from "./src/metrics-feature"; +import React from "react"; +import { LensRendererExtension, Catalog } from "@k8slens/extensions"; +import { MetricsSettings } from "./src/metrics-settings"; export default class ClusterMetricsFeatureExtension extends LensRendererExtension { - onActivate() { - const category = Catalog.catalogCategories.getForGroupKind("entity.k8slens.dev", "KubernetesCluster"); - - if (!category) { - return; - } - - category.on("contextMenuOpen", this.clusterContextMenuOpen.bind(this)); - } - - async clusterContextMenuOpen(cluster: Catalog.KubernetesCluster, ctx: Interface.CatalogEntityContextMenuContext) { - if (!cluster.status.active) { - return; - } - - const metricsFeature = new MetricsFeature(); - - await metricsFeature.updateStatus(cluster); - - if (metricsFeature.status.installed) { - if (metricsFeature.status.canUpgrade) { - ctx.menuItems.unshift({ - icon: "refresh", - title: "Upgrade Lens Metrics stack", - onClick: async () => { - metricsFeature.upgrade(cluster); - } - }); + entitySettings = [ + { + apiVersions: ["entity.k8slens.dev/v1alpha1"], + kind: "KubernetesCluster", + title: "Lens Metrics", + priority: 5, + components: { + View: ({ entity = null }: { entity: Catalog.KubernetesCluster}) => { + return ( + + ); + } } - ctx.menuItems.unshift({ - icon: "toggle_off", - title: "Uninstall Lens Metrics stack", - onClick: async () => { - await metricsFeature.uninstall(cluster); - - Component.Notifications.info(`Lens Metrics has been removed from ${cluster.metadata.name}`, { timeout: 10_000 }); - } - }); - } else { - ctx.menuItems.unshift({ - icon: "toggle_on", - title: "Install Lens Metrics stack", - onClick: async () => { - metricsFeature.install(cluster); - - Component.Notifications.info(`Lens Metrics is now installed to ${cluster.metadata.name}`, { timeout: 10_000 }); - } - }); } - } + ]; } diff --git a/extensions/metrics-cluster-feature/resources/01-namespace.yml b/extensions/metrics-cluster-feature/resources/01-namespace.yml.hb similarity index 53% rename from extensions/metrics-cluster-feature/resources/01-namespace.yml rename to extensions/metrics-cluster-feature/resources/01-namespace.yml.hb index 85d13c1046..dd3816fdff 100644 --- a/extensions/metrics-cluster-feature/resources/01-namespace.yml +++ b/extensions/metrics-cluster-feature/resources/01-namespace.yml.hb @@ -2,3 +2,5 @@ apiVersion: v1 kind: Namespace metadata: name: lens-metrics + annotations: + extensionVersion: "{{ version }}" diff --git a/extensions/metrics-cluster-feature/resources/03-service.yml b/extensions/metrics-cluster-feature/resources/03-service.yml.hb similarity index 88% rename from extensions/metrics-cluster-feature/resources/03-service.yml rename to extensions/metrics-cluster-feature/resources/03-service.yml.hb index 1eb0cb5117..3cdcdbc260 100644 --- a/extensions/metrics-cluster-feature/resources/03-service.yml +++ b/extensions/metrics-cluster-feature/resources/03-service.yml.hb @@ -1,3 +1,4 @@ +{{#if prometheus.enabled}} apiVersion: v1 kind: Service metadata: @@ -14,3 +15,4 @@ spec: protocol: TCP port: 80 targetPort: 9090 +{{/if}} diff --git a/extensions/metrics-cluster-feature/resources/03-statefulset.yml.hb b/extensions/metrics-cluster-feature/resources/03-statefulset.yml.hb index dba437ee7d..ee68619a30 100644 --- a/extensions/metrics-cluster-feature/resources/03-statefulset.yml.hb +++ b/extensions/metrics-cluster-feature/resources/03-statefulset.yml.hb @@ -1,3 +1,4 @@ +{{#if prometheus.enabled}} apiVersion: apps/v1 kind: StatefulSet metadata: @@ -46,14 +47,14 @@ spec: serviceAccountName: prometheus initContainers: - name: chown - image: docker.io/alpine:3.9 + image: docker.io/alpine:3.12 command: ["chown", "-R", "65534:65534", "/var/lib/prometheus"] volumeMounts: - name: data mountPath: /var/lib/prometheus containers: - name: prometheus - image: quay.io/prometheus/prometheus:v2.19.3 + image: quay.io/prometheus/prometheus:v2.26.0 args: - --web.listen-address=0.0.0.0:9090 - --config.file=/etc/prometheus/prometheus.yaml @@ -114,3 +115,4 @@ spec: requests: storage: {{persistence.size}} {{/if}} +{{/if}} diff --git a/extensions/metrics-cluster-feature/resources/10-node-exporter-ds.yml.hb b/extensions/metrics-cluster-feature/resources/10-node-exporter-ds.yml.hb index 2c6786d816..2ff46d8d0b 100644 --- a/extensions/metrics-cluster-feature/resources/10-node-exporter-ds.yml.hb +++ b/extensions/metrics-cluster-feature/resources/10-node-exporter-ds.yml.hb @@ -41,7 +41,7 @@ spec: hostPID: true containers: - name: node-exporter - image: quay.io/prometheus/node-exporter:v1.0.1 + image: quay.io/prometheus/node-exporter:v1.1.2 args: - --path.procfs=/host/proc - --path.sysfs=/host/sys diff --git a/extensions/metrics-cluster-feature/resources/14-kube-state-metrics-deployment.yml.hb b/extensions/metrics-cluster-feature/resources/14-kube-state-metrics-deployment.yml.hb index 763649f4f1..c895c9831c 100644 --- a/extensions/metrics-cluster-feature/resources/14-kube-state-metrics-deployment.yml.hb +++ b/extensions/metrics-cluster-feature/resources/14-kube-state-metrics-deployment.yml.hb @@ -39,7 +39,7 @@ spec: serviceAccountName: kube-state-metrics containers: - name: kube-state-metrics - image: quay.io/coreos/kube-state-metrics:v1.9.7 + image: quay.io/coreos/kube-state-metrics:v1.9.8 ports: - name: metrics containerPort: 8080 @@ -52,7 +52,7 @@ spec: resources: requests: cpu: 10m - memory: 150Mi + memory: 32Mi limits: cpu: 200m memory: 150Mi diff --git a/extensions/metrics-cluster-feature/src/metrics-feature.ts b/extensions/metrics-cluster-feature/src/metrics-feature.ts index ed20801f19..655c8e60ed 100644 --- a/extensions/metrics-cluster-feature/src/metrics-feature.ts +++ b/extensions/metrics-cluster-feature/src/metrics-feature.ts @@ -19,12 +19,15 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { ClusterFeature, Catalog, K8sApi } from "@k8slens/extensions"; +import { Catalog, K8sApi } from "@k8slens/extensions"; import semver from "semver"; import * as path from "path"; export interface MetricsConfiguration { // Placeholder for Metrics config structure + prometheus: { + enabled: boolean; + }; persistence: { enabled: boolean; storageClass: string; @@ -43,78 +46,72 @@ export interface MetricsConfiguration { alertManagers: string[]; replicas: number; storageClass: string; + version?: string; } -export class MetricsFeature extends ClusterFeature.Feature { - name = "metrics"; - latestVersion = "v2.19.3-lens1"; +export interface MetricsStatus { + installed: boolean; + canUpgrade: boolean; +} - templateContext: MetricsConfiguration = { - persistence: { - enabled: false, - storageClass: null, - size: "20G", - }, - nodeExporter: { - enabled: true, - }, - retention: { - time: "2d", - size: "5GB", - }, - kubeStateMetrics: { - enabled: true, - }, - alertManagers: null, - replicas: 1, - storageClass: null, - }; +export class MetricsFeature { + name = "lens-metrics"; + latestVersion = "v2.26.0-lens1"; - async install(cluster: Catalog.KubernetesCluster): Promise { + protected stack: K8sApi.ResourceStack; + + constructor(protected cluster: Catalog.KubernetesCluster) { + this.stack = new K8sApi.ResourceStack(cluster, this.name); + } + + get resourceFolder() { + return path.join(__dirname, "../resources/"); + } + + async install(config: MetricsConfiguration): Promise { // Check if there are storageclasses - const storageClassApi = K8sApi.forCluster(cluster, K8sApi.StorageClass); + const storageClassApi = K8sApi.forCluster(this.cluster, K8sApi.StorageClass); const scs = await storageClassApi.list(); - this.templateContext.persistence.enabled = scs.some(sc => ( + config.persistence.enabled = scs.some(sc => ( sc.metadata?.annotations?.["storageclass.kubernetes.io/is-default-class"] === "true" || sc.metadata?.annotations?.["storageclass.beta.kubernetes.io/is-default-class"] === "true" )); - super.applyResources(cluster, path.join(__dirname, "../resources/")); + config.version = this.latestVersion; + + return this.stack.kubectlApplyFolder(this.resourceFolder, config, ["--prune"]); } - async upgrade(cluster: Catalog.KubernetesCluster): Promise { - return this.install(cluster); + async upgrade(config: MetricsConfiguration): Promise { + return this.install(config); } - async updateStatus(cluster: Catalog.KubernetesCluster): Promise { + async getStatus(): Promise { + const status: MetricsStatus = { installed: false, canUpgrade: false}; + try { - const statefulSet = K8sApi.forCluster(cluster, K8sApi.StatefulSet); - const prometheus = await statefulSet.get({name: "prometheus", namespace: "lens-metrics"}); + const namespaceApi = K8sApi.forCluster(this.cluster, K8sApi.Namespace); + const namespace = await namespaceApi.get({name: "lens-metrics"}); - if (prometheus?.kind) { - this.status.installed = true; - this.status.currentVersion = prometheus.spec.template.spec.containers[0].image.split(":")[1]; - this.status.canUpgrade = semver.lt(this.status.currentVersion, this.latestVersion, true); + if (namespace?.kind) { + const currentVersion = namespace.metadata.annotations?.extensionVersion || "0.0.0"; + + status.installed = true; + status.canUpgrade = semver.lt(currentVersion, this.latestVersion, true); } else { - this.status.installed = false; + status.installed = false; } } catch(e) { if (e?.error?.code === 404) { - this.status.installed = false; + status.installed = false; } } - return this.status; + return status; } - async uninstall(cluster: Catalog.KubernetesCluster): Promise { - const namespaceApi = K8sApi.forCluster(cluster, K8sApi.Namespace); - const clusterRoleBindingApi = K8sApi.forCluster(cluster, K8sApi.ClusterRoleBinding); - const clusterRoleApi = K8sApi.forCluster(cluster, K8sApi.ClusterRole); - - await namespaceApi.delete({name: "lens-metrics"}); - await clusterRoleBindingApi.delete({name: "lens-prometheus"}); - await clusterRoleApi.delete({name: "lens-prometheus"}); + async uninstall(config: MetricsConfiguration): Promise { + return this.stack.kubectlDeleteFolder(this.resourceFolder, config); } } diff --git a/extensions/metrics-cluster-feature/src/metrics-settings.tsx b/extensions/metrics-cluster-feature/src/metrics-settings.tsx new file mode 100644 index 0000000000..f98cb66403 --- /dev/null +++ b/extensions/metrics-cluster-feature/src/metrics-settings.tsx @@ -0,0 +1,279 @@ +/** + * 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 { Component, Catalog, K8sApi } from "@k8slens/extensions"; +import { observer } from "mobx-react"; +import { computed, observable } from "mobx"; +import { MetricsFeature, MetricsConfiguration } from "./metrics-feature"; + +interface Props { + cluster: Catalog.KubernetesCluster; +} + +@observer +export class MetricsSettings extends React.Component { + @observable featureStates = { + prometheus: false, + kubeStateMetrics: false, + nodeExporter: false + }; + @observable canUpgrade = false; + @observable upgrading = false; + @observable changed = false; + @observable inProgress = false; + + config: MetricsConfiguration = { + prometheus: { + enabled: false + }, + persistence: { + enabled: false, + storageClass: null, + size: "20G", + }, + nodeExporter: { + enabled: false, + }, + retention: { + time: "2d", + size: "5GB", + }, + kubeStateMetrics: { + enabled: false, + }, + alertManagers: null, + replicas: 1, + storageClass: null, + }; + feature: MetricsFeature; + + @computed get isTogglable() { + if (this.inProgress) return false; + if (!this.props.cluster.status.active) return false; + if (this.canUpgrade) return false; + if (!this.isActiveMetricsProvider) return false; + + return true; + } + + get metricsProvider() { + return this.props.cluster.spec?.metrics?.prometheus?.type || ""; + } + + get isActiveMetricsProvider() { + return (!this.metricsProvider || this.metricsProvider === "lens"); + } + + async componentDidMount() { + this.feature = new MetricsFeature(this.props.cluster); + + await this.updateFeatureStates(); + } + + async updateFeatureStates() { + const status = await this.feature.getStatus(); + + this.canUpgrade = status.canUpgrade; + + if (this.canUpgrade) { + this.changed = true; + } + + const statefulSet = K8sApi.forCluster(this.props.cluster, K8sApi.StatefulSet); + + try { + await statefulSet.get({name: "prometheus", namespace: "lens-metrics"}); + this.featureStates.prometheus = true; + } catch(e) { + if (e?.error?.code === 404) { + this.featureStates.prometheus = false; + } else { + this.featureStates.prometheus = undefined; + } + } + + const deployment = K8sApi.forCluster(this.props.cluster, K8sApi.Deployment); + + try { + await deployment.get({name: "kube-state-metrics", namespace: "lens-metrics"}); + this.featureStates.kubeStateMetrics = true; + } catch(e) { + if (e?.error?.code === 404) { + this.featureStates.kubeStateMetrics = false; + } else { + this.featureStates.kubeStateMetrics = undefined; + } + } + + const daemonSet = K8sApi.forCluster(this.props.cluster, K8sApi.DaemonSet); + + try { + await daemonSet.get({name: "node-exporter", namespace: "lens-metrics"}); + this.featureStates.nodeExporter = true; + } catch(e) { + if (e?.error?.code === 404) { + this.featureStates.nodeExporter = false; + } else { + this.featureStates.nodeExporter = undefined; + } + } + } + + async save() { + this.config.prometheus.enabled = !!this.featureStates.prometheus; + this.config.kubeStateMetrics.enabled = !!this.featureStates.kubeStateMetrics; + this.config.nodeExporter.enabled = !!this.featureStates.nodeExporter; + + this.inProgress = true; + + try { + if (!this.config.prometheus.enabled && !this.config.kubeStateMetrics.enabled && !this.config.nodeExporter.enabled) { + await this.feature.uninstall(this.config); + } else { + await this.feature.install(this.config); + } + } finally { + this.inProgress = false; + this.changed = false; + + await this.updateFeatureStates(); + } + } + + async togglePrometheus(enabled: boolean) { + this.featureStates.prometheus = enabled; + this.changed = true; + } + + async toggleKubeStateMetrics(enabled: boolean) { + this.featureStates.kubeStateMetrics = enabled; + this.changed = true; + } + + async toggleNodeExporter(enabled: boolean) { + this.featureStates.nodeExporter = enabled; + this.changed = true; + } + + @computed get buttonLabel() { + const allDisabled = !this.featureStates.kubeStateMetrics && !this.featureStates.nodeExporter && !this.featureStates.prometheus; + + if (this.inProgress && this.canUpgrade) return "Upgrading ..."; + if (this.inProgress && allDisabled) return "Uninstalling ..."; + if (this.inProgress) return "Applying ..."; + if (this.canUpgrade) return "Upgrade"; + + if (this.changed && allDisabled) { + return "Uninstall"; + } + + return "Apply"; + } + + render() { + return ( + <> + { !this.props.cluster.status.active && ( +
+

+ Lens Metrics settings requires established connection to the cluster. +

+
+ )} + { !this.isActiveMetricsProvider && ( +
+

+ Other metrics provider is currently active. See "Metrics" tab for details. +

+
+ )} +
+ + this.togglePrometheus(v.target.checked)} + name="prometheus" + /> + } + label="Enable bundled Prometheus metrics stack" + /> + + Enable timeseries data visualization (Prometheus stack) for your cluster. + +
+ +
+ + this.toggleKubeStateMetrics(v.target.checked)} + name="node-exporter" + /> + } + label="Enable bundled kube-state-metrics stack" + /> + + Enable Kubernetes API object metrics for your cluster. + Enable this only if you don't have existing kube-state-metrics stack installed. + +
+ +
+ + this.toggleNodeExporter(v.target.checked)} + name="node-exporter" + /> + } + label="Enable bundled node-exporter stack" + /> + + Enable node level metrics for your cluster. + Enable this only if you don't have existing node-exporter stack installed. + +
+ +
+ this.save()} + primary + disabled={!this.changed} /> + + {this.canUpgrade && ( + An update is available for enabled metrics components. + )} +
+ + ); + } +} diff --git a/extensions/metrics-cluster-feature/tsconfig.json b/extensions/metrics-cluster-feature/tsconfig.json index a93ad6fe9f..016d32b0ba 100644 --- a/extensions/metrics-cluster-feature/tsconfig.json +++ b/extensions/metrics-cluster-feature/tsconfig.json @@ -16,8 +16,8 @@ "jsx": "react" }, "include": [ - "./*.ts", - "./*.tsx" + "./**/*.ts", + "./**/*.tsx" ], "exclude": [ "node_modules", diff --git a/src/common/catalog-entities/kubernetes-cluster.ts b/src/common/catalog-entities/kubernetes-cluster.ts index 7c6727ada5..43fee50eaf 100644 --- a/src/common/catalog-entities/kubernetes-cluster.ts +++ b/src/common/catalog-entities/kubernetes-cluster.ts @@ -28,9 +28,24 @@ import { productName } from "../vars"; import { CatalogCategory, CatalogCategorySpec } from "../catalog"; import { app } from "electron"; + +export type KubernetesClusterPrometheusMetrics = { + address?: { + namespace: string; + service: string; + port: number; + prefix: string; + }; + type?: string; +}; + export type KubernetesClusterSpec = { kubeconfigPath: string; kubeconfigContext: string; + metrics?: { + source: string; + prometheus?: KubernetesClusterPrometheusMetrics; + } }; export interface KubernetesClusterStatus extends CatalogEntityStatus { @@ -88,7 +103,6 @@ export class KubernetesCluster extends CatalogEntity context.navigate(`/entity/${this.metadata.uid}/settings`) @@ -97,7 +111,6 @@ export class KubernetesCluster extends CatalogEntity ClusterStore.getInstance().removeById(this.metadata.uid), @@ -108,14 +121,20 @@ export class KubernetesCluster extends CatalogEntity { ClusterStore.getInstance().deactivate(this.metadata.uid); requestMain(clusterDisconnectHandler, this.metadata.uid); } }); + } else { + context.menuItems.push({ + title: "Connect", + onClick: async () => { + context.navigate(`/cluster/${this.metadata.uid}`); + } + }); } const category = catalogCategoryRegistry.getCategoryForEntity(this); diff --git a/src/common/catalog/catalog-entity.ts b/src/common/catalog/catalog-entity.ts index ee80b91786..51660a3d3d 100644 --- a/src/common/catalog/catalog-entity.ts +++ b/src/common/catalog/catalog-entity.ts @@ -83,7 +83,6 @@ export interface CatalogEntityActionContext { } export interface CatalogEntityContextMenu { - icon: string; title: string; onlyVisibleForSource?: string; // show only if empty or if matches with entity source onClick: () => void | Promise; @@ -92,6 +91,10 @@ export interface CatalogEntityContextMenu { } } +export interface CatalogEntityAddMenu extends CatalogEntityContextMenu { + icon: string; +} + export interface CatalogEntitySettingsMenu { group?: string; title: string; @@ -111,7 +114,7 @@ export interface CatalogEntitySettingsContext { export interface CatalogEntityAddMenuContext { navigate: (url: string) => void; - menuItems: CatalogEntityContextMenu[]; + menuItems: CatalogEntityAddMenu[]; } export type CatalogEntitySpec = Record; diff --git a/src/common/cluster-ipc.ts b/src/common/cluster-ipc.ts index d308de3f41..863ddafcd0 100644 --- a/src/common/cluster-ipc.ts +++ b/src/common/cluster-ipc.ts @@ -31,6 +31,7 @@ export const clusterSetFrameIdHandler = "cluster:set-frame-id"; export const clusterRefreshHandler = "cluster:refresh"; export const clusterDisconnectHandler = "cluster:disconnect"; export const clusterKubectlApplyAllHandler = "cluster:kubectl-apply-all"; +export const clusterKubectlDeleteAllHandler = "cluster:kubectl-delete-all"; if (ipcMain) { handleRequest(clusterActivateHandler, (event, clusterId: ClusterId, force = false) => { @@ -67,14 +68,39 @@ if (ipcMain) { } }); - handleRequest(clusterKubectlApplyAllHandler, (event, clusterId: ClusterId, resources: string[]) => { + handleRequest(clusterKubectlApplyAllHandler, async (event, clusterId: ClusterId, resources: string[], extraArgs: string[]) => { appEventBus.emit({name: "cluster", action: "kubectl-apply-all"}); const cluster = ClusterStore.getInstance().getById(clusterId); if (cluster) { const applier = new ResourceApplier(cluster); - applier.kubectlApplyAll(resources); + try { + const stdout = await applier.kubectlApplyAll(resources, extraArgs); + + return { stdout }; + } catch (error: any) { + return { stderr: error }; + } + } else { + throw `${clusterId} is not a valid cluster id`; + } + }); + + handleRequest(clusterKubectlDeleteAllHandler, async (event, clusterId: ClusterId, resources: string[], extraArgs: string[]) => { + appEventBus.emit({name: "cluster", action: "kubectl-delete-all"}); + const cluster = ClusterStore.getInstance().getById(clusterId); + + if (cluster) { + const applier = new ResourceApplier(cluster); + + try { + const stdout = await applier.kubectlDeleteAll(resources, extraArgs); + + return { stdout }; + } catch (error: any) { + return { stderr: error }; + } } else { throw `${clusterId} is not a valid cluster id`; } diff --git a/src/common/k8s/resource-stack.ts b/src/common/k8s/resource-stack.ts new file mode 100644 index 0000000000..01c7ee84b8 --- /dev/null +++ b/src/common/k8s/resource-stack.ts @@ -0,0 +1,152 @@ +/** + * 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 fse from "fs-extra"; +import path from "path"; +import hb from "handlebars"; +import { ResourceApplier } from "../../main/resource-applier"; +import { KubernetesCluster } from "../catalog-entities"; +import logger from "../../main/logger"; +import { app } from "electron"; +import { requestMain } from "../ipc"; +import { clusterKubectlApplyAllHandler, clusterKubectlDeleteAllHandler } from "../cluster-ipc"; +import { ClusterStore } from "../cluster-store"; +import yaml from "js-yaml"; +import { productName } from "../vars"; + +export class ResourceStack { + constructor(protected cluster: KubernetesCluster, protected name: string) {} + + /** + * + * @param folderPath folder path that is searched for files defining kubernetes resources. + * @param templateContext sets the template parameters that are to be applied to any templated kubernetes resources that are to be applied. + */ + async kubectlApplyFolder(folderPath: string, templateContext?: any, extraArgs?: string[]): Promise { + const resources = await this.renderTemplates(folderPath, templateContext); + + return this.applyResources(resources, extraArgs); + } + + /** + * + * @param folderPath folder path that is searched for files defining kubernetes resources. + * @param templateContext sets the template parameters that are to be applied to any templated kubernetes resources that are to be applied. + */ + async kubectlDeleteFolder(folderPath: string, templateContext?: any, extraArgs?: string[]): Promise { + const resources = await this.renderTemplates(folderPath, templateContext); + + return this.deleteResources(resources, extraArgs); + } + + protected async applyResources(resources: string[], extraArgs?: string[]): Promise { + const clusterModel = ClusterStore.getInstance().getById(this.cluster.metadata.uid); + + if (!clusterModel) { + throw new Error(`cluster not found`); + } + + let kubectlArgs = extraArgs || []; + + kubectlArgs = this.appendKubectlArgs(kubectlArgs); + + if (app) { + return await new ResourceApplier(clusterModel).kubectlApplyAll(resources, kubectlArgs); + } else { + const response = await requestMain(clusterKubectlApplyAllHandler, this.cluster.metadata.uid, resources, kubectlArgs); + + if (response.stderr) { + throw new Error(response.stderr); + } + + return response.stdout; + } + } + + protected async deleteResources(resources: string[], extraArgs?: string[]): Promise { + const clusterModel = ClusterStore.getInstance().getById(this.cluster.metadata.uid); + + if (!clusterModel) { + throw new Error(`cluster not found`); + } + + let kubectlArgs = extraArgs || []; + + kubectlArgs = this.appendKubectlArgs(kubectlArgs); + + if (app) { + return await new ResourceApplier(clusterModel).kubectlDeleteAll(resources, kubectlArgs); + } else { + const response = await requestMain(clusterKubectlDeleteAllHandler, this.cluster.metadata.uid, resources, kubectlArgs); + + if (response.stderr) { + throw new Error(response.stderr); + } + + return response.stdout; + } + } + + protected appendKubectlArgs(kubectlArgs: string[]) { + if (!kubectlArgs.includes("-l") && !kubectlArgs.includes("--label")) { + return kubectlArgs.concat(["-l", `app.kubernetes.io/name=${this.name}`]); + } + + return kubectlArgs; + } + + protected async renderTemplates(folderPath: string, templateContext: any): Promise { + const resources: string[] = []; + + logger.info(`[RESOURCE-STACK]: render templates from ${folderPath}`); + const files = await fse.readdir(folderPath); + + for(const filename of files) { + const file = path.join(folderPath, filename); + const raw = await fse.readFile(file); + let resourceData: string; + + if (filename.endsWith(".hb")) { + const template = hb.compile(raw.toString()); + + resourceData = template(templateContext); + } else { + resourceData = raw.toString(); + } + + if (!resourceData.trim()) continue; + + const resourceArray = yaml.safeLoadAll(resourceData.toString()); + + resourceArray.forEach((resource) => { + if (resource?.metadata) { + resource.metadata.labels ||= {}; + resource.metadata.labels["app.kubernetes.io/name"] = this.name; + resource.metadata.labels["app.kubernetes.io/managed-by"] = productName; + resource.metadata.labels["app.kubernetes.io/created-by"] = "resource-stack"; + } + + resources.push(yaml.safeDump(resource)); + }); + } + + return resources; + } +} diff --git a/src/extensions/cluster-feature.ts b/src/extensions/cluster-feature.ts deleted file mode 100644 index 2a1c289076..0000000000 --- a/src/extensions/cluster-feature.ts +++ /dev/null @@ -1,156 +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 fs from "fs"; -import path from "path"; -import hb from "handlebars"; -import { observable } from "mobx"; -import { ResourceApplier } from "../main/resource-applier"; -import { KubernetesCluster } from "./core-api/catalog"; -import logger from "../main/logger"; -import { app } from "electron"; -import { requestMain } from "../common/ipc"; -import { clusterKubectlApplyAllHandler } from "../common/cluster-ipc"; -import { ClusterStore } from "../common/cluster-store"; - -export interface ClusterFeatureStatus { - /** feature's current version, as set by the implementation */ - currentVersion: string; - /** feature's latest version, as set by the implementation */ - latestVersion: string; - /** whether the feature is installed or not, as set by the implementation */ - installed: boolean; - /** whether the feature can be upgraded or not, as set by the implementation */ - canUpgrade: boolean; -} - -export abstract class ClusterFeature { - - /** - * this field sets the template parameters that are to be applied to any templated kubernetes resources that are to be installed for the feature. - * See the renderTemplates() method for more details - */ - templateContext: any; - - /** - * this field holds the current feature status, is accessed directly by Lens - */ - @observable status: ClusterFeatureStatus = { - currentVersion: null, - installed: false, - latestVersion: null, - canUpgrade: false - }; - - /** - * to be implemented in the derived class, this method is typically called by Lens when a user has indicated that this feature is to be installed. The implementation - * of this method should install kubernetes resources using the applyResources() method, or by directly accessing the kubernetes api (K8sApi) - * - * @param cluster the cluster that the feature is to be installed on - */ - abstract install(cluster: KubernetesCluster): Promise; - - /** - * to be implemented in the derived class, this method is typically called by Lens when a user has indicated that this feature is to be upgraded. The implementation - * of this method should upgrade the kubernetes resources already installed, if relevant to the feature - * - * @param cluster the cluster that the feature is to be upgraded on - */ - abstract upgrade(cluster: KubernetesCluster): Promise; - - /** - * to be implemented in the derived class, this method is typically called by Lens when a user has indicated that this feature is to be uninstalled. The implementation - * of this method should uninstall kubernetes resources using the kubernetes api (K8sApi) - * - * @param cluster the cluster that the feature is to be uninstalled from - */ - abstract uninstall(cluster: KubernetesCluster): Promise; - - /** - * to be implemented in the derived class, this method is called periodically by Lens to determine details about the feature's current status. The implementation - * of this method should provide the current status information. The currentVersion and latestVersion fields may be displayed by Lens in describing the feature. - * The installed field should be set to true if the feature has been installed, otherwise false. Also, Lens relies on the canUpgrade field to determine if the feature - * can be upgraded so the implementation should set the canUpgrade field according to specific rules for the feature, if relevant. - * - * @param cluster the cluster that the feature may be installed on - * - * @return a promise, resolved with the updated ClusterFeatureStatus - */ - abstract updateStatus(cluster: KubernetesCluster): Promise; - - /** - * this is a helper method that conveniently applies kubernetes resources to the cluster. - * - * @param cluster the cluster that the resources are to be applied to - * @param resourceSpec as a string type this is a folder path that is searched for files specifying kubernetes resources. The files are read and if any of the resource - * files are templated, the template parameters are filled using the templateContext field (See renderTemplate() method). Finally the resources are applied to the - * cluster. As a string[] type resourceSpec is treated as an array of fully formed (not templated) kubernetes resources that are applied to the cluster - */ - protected async applyResources(cluster: KubernetesCluster, resourceSpec: string | string[]) { - let resources: string[]; - - const clusterModel = ClusterStore.getInstance().getById(cluster.metadata.uid); - - if (!clusterModel) { - throw new Error(`cluster not found`); - } - - if ( typeof resourceSpec === "string" ) { - resources = this.renderTemplates(resourceSpec); - } else { - resources = resourceSpec; - } - - if (app) { - await new ResourceApplier(clusterModel).kubectlApplyAll(resources); - } else { - await requestMain(clusterKubectlApplyAllHandler, cluster.metadata.uid, resources); - } - } - - /** - * this is a helper method that conveniently reads kubernetes resource files into a string array. It also fills templated resource files with the template parameter values - * specified by the templateContext field. Templated files must end with the extension '.hb' and the template syntax must be compatible with handlebars.js - * - * @param folderPath this is a folder path that is searched for files defining kubernetes resources. - * - * @return an array of strings, each string being the contents of a resource file found in the folder path. This can be passed directly to applyResources() - */ - protected renderTemplates(folderPath: string): string[] { - const resources: string[] = []; - - logger.info(`[FEATURE]: render templates from ${folderPath}`); - fs.readdirSync(folderPath).forEach(filename => { - const file = path.join(folderPath, filename); - const raw = fs.readFileSync(file); - - if (filename.endsWith(".hb")) { - const template = hb.compile(raw.toString()); - - resources.push(template(this.templateContext)); - } else { - resources.push(raw.toString()); - } - }); - - return resources; - } -} diff --git a/src/extensions/core-api/cluster-feature.ts b/src/extensions/core-api/cluster-feature.ts deleted file mode 100644 index 25608d69ba..0000000000 --- a/src/extensions/core-api/cluster-feature.ts +++ /dev/null @@ -1,23 +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. - */ - -export { ClusterFeature as Feature } from "../cluster-feature"; -export type { ClusterFeatureStatus as FeatureStatus } from "../cluster-feature"; diff --git a/src/extensions/core-api/index.ts b/src/extensions/core-api/index.ts index 4fdca344d9..56e4076ddb 100644 --- a/src/extensions/core-api/index.ts +++ b/src/extensions/core-api/index.ts @@ -28,7 +28,6 @@ import * as App from "./app"; import * as EventBus from "./event-bus"; import * as Store from "./stores"; import * as Util from "./utils"; -import * as ClusterFeature from "./cluster-feature"; import * as Interface from "../interfaces"; import * as Catalog from "./catalog"; import * as Types from "./types"; @@ -37,7 +36,6 @@ export { App, EventBus, Catalog, - ClusterFeature, Interface, Store, Types, diff --git a/src/extensions/registries/entity-setting-registry.ts b/src/extensions/registries/entity-setting-registry.ts index f2de7a3876..4854b97006 100644 --- a/src/extensions/registries/entity-setting-registry.ts +++ b/src/extensions/registries/entity-setting-registry.ts @@ -32,13 +32,14 @@ export interface EntitySettingComponents { } export interface EntitySettingRegistration { - title: string; - kind: string; apiVersions: string[]; - source?: string; + kind: string; + title: string; components: EntitySettingComponents; + source?: string; id?: string; priority?: number; + group?: string; } export interface RegisteredEntitySetting extends EntitySettingRegistration { diff --git a/src/extensions/renderer-api/components.ts b/src/extensions/renderer-api/components.ts index f2648a1b3c..110b40bbb2 100644 --- a/src/extensions/renderer-api/components.ts +++ b/src/extensions/renderer-api/components.ts @@ -30,6 +30,7 @@ export * from "../../renderer/components/checkbox"; export * from "../../renderer/components/radio"; export * from "../../renderer/components/select"; export * from "../../renderer/components/slider"; +export * from "../../renderer/components/switch"; export * from "../../renderer/components/input/input"; // command-overlay diff --git a/src/extensions/renderer-api/k8s-api.ts b/src/extensions/renderer-api/k8s-api.ts index f7d25a48b9..511597ba57 100644 --- a/src/extensions/renderer-api/k8s-api.ts +++ b/src/extensions/renderer-api/k8s-api.ts @@ -20,6 +20,7 @@ */ export { isAllowedResource } from "../../common/rbac"; +export { ResourceStack } from "../../common/k8s/resource-stack"; export { apiManager } from "../../renderer/api/api-manager"; export { KubeObjectStore } from "../../renderer/kube-object.store"; export { KubeApi, forCluster, IKubeApiCluster } from "../../renderer/api/kube-api"; diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index eae7ea68ba..0d8cd3535c 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -29,7 +29,7 @@ import logger from "./logger"; import { apiKubePrefix } from "../common/vars"; import { Singleton } from "../common/utils"; import { catalogEntityRegistry } from "../common/catalog"; -import { KubernetesCluster } from "../common/catalog-entities/kubernetes-cluster"; +import { KubernetesCluster, KubernetesClusterPrometheusMetrics } from "../common/catalog-entities/kubernetes-cluster"; export class ClusterManager extends Singleton { constructor() { @@ -68,7 +68,7 @@ export class ClusterManager extends Singleton { const index = catalogEntityRegistry.items.findIndex((entity) => entity.metadata.uid === cluster.id); if (index !== -1) { - const entity = catalogEntityRegistry.items[index]; + const entity = catalogEntityRegistry.items[index] as KubernetesCluster; entity.status.phase = cluster.disconnected ? "disconnected" : "connected"; entity.status.active = !cluster.disconnected; @@ -76,6 +76,17 @@ export class ClusterManager extends Singleton { if (cluster.preferences?.clusterName) { entity.metadata.name = cluster.preferences.clusterName; } + + entity.spec.metrics ||= { source: "local" }; + + if (entity.spec.metrics.source === "local") { + const prometheus: KubernetesClusterPrometheusMetrics = entity.spec?.metrics?.prometheus || {}; + + prometheus.type = cluster.preferences.prometheusProvider?.type; + prometheus.address = cluster.preferences.prometheus; + entity.spec.metrics.prometheus = prometheus; + } + catalogEntityRegistry.items.splice(index, 1, entity); } } diff --git a/src/main/resource-applier.ts b/src/main/resource-applier.ts index beebd8cea5..f1c64f388c 100644 --- a/src/main/resource-applier.ts +++ b/src/main/resource-applier.ts @@ -73,7 +73,15 @@ export class ResourceApplier { }); } - public async kubectlApplyAll(resources: string[]): Promise { + public async kubectlApplyAll(resources: string[], extraArgs = ["-o", "json"]): Promise { + return this.kubectlCmdAll("apply", resources, extraArgs); + } + + public async kubectlDeleteAll(resources: string[], extraArgs?: string[]): Promise { + return this.kubectlCmdAll("delete", resources, extraArgs); + } + + protected async kubectlCmdAll(subCmd: string, resources: string[], args: string[] = []): Promise { const { kubeCtl } = this.cluster; const kubectlPath = await kubeCtl.getPath(); const proxyKubeconfigPath = await this.cluster.getProxyKubeconfigPath(); @@ -85,19 +93,24 @@ export class ResourceApplier { resources.forEach((resource, index) => { fs.writeFileSync(path.join(tmpDir, `${index}.yaml`), resource); }); - const cmd = `"${kubectlPath}" apply --kubeconfig "${proxyKubeconfigPath}" -o json -f "${tmpDir}"`; + args.push("-f", `"${tmpDir}"`); + const cmd = `"${kubectlPath}" ${subCmd} --kubeconfig "${proxyKubeconfigPath}" ${args.join(" ")}`; - console.log("shooting manifests with:", cmd); - exec(cmd, (error, stdout, stderr) => { + logger.info(`[RESOURCE-APPLIER] running cmd ${cmd}`); + exec(cmd, (error, stdout) => { if (error) { - reject(`Error applying manifests:${error}`); - } + logger.error(`[RESOURCE-APPLIER] cmd errored: ${error}`); + const splitError = error.toString().split(`.yaml": `); - if (stderr != "") { - reject(stderr); + if (splitError[1]) { + reject(splitError[1]); + } else { + reject(error); + } return; } + resolve(stdout); }); }); diff --git a/src/renderer/api/catalog-entity.ts b/src/renderer/api/catalog-entity.ts index 77517fb168..493099d6c8 100644 --- a/src/renderer/api/catalog-entity.ts +++ b/src/renderer/api/catalog-entity.ts @@ -30,6 +30,7 @@ export { CatalogEntityKindData, CatalogEntityActionContext, CatalogEntityAddMenuContext, + CatalogEntityAddMenu, CatalogEntityContextMenu, CatalogEntityContextMenuContext } from "../../common/catalog"; diff --git a/src/renderer/components/+catalog/catalog-add-button.tsx b/src/renderer/components/+catalog/catalog-add-button.tsx index bfd5f9aa6e..5329702832 100644 --- a/src/renderer/components/+catalog/catalog-add-button.tsx +++ b/src/renderer/components/+catalog/catalog-add-button.tsx @@ -26,7 +26,7 @@ import { Icon } from "../icon"; import { disposeOnUnmount, observer } from "mobx-react"; import { observable, reaction } from "mobx"; import { autobind } from "../../../common/utils"; -import { CatalogCategory, CatalogEntityAddMenuContext, CatalogEntityContextMenu } from "../../api/catalog-entity"; +import { CatalogCategory, CatalogEntityAddMenuContext, CatalogEntityAddMenu } from "../../api/catalog-entity"; import { EventEmitter } from "events"; import { navigate } from "../../navigation"; @@ -37,7 +37,7 @@ export type CatalogAddButtonProps = { @observer export class CatalogAddButton extends React.Component { @observable protected isOpen = false; - protected menuItems = observable.array([]); + protected menuItems = observable.array([]); componentDidMount() { disposeOnUnmount(this, [ diff --git a/src/renderer/components/+catalog/catalog.tsx b/src/renderer/components/+catalog/catalog.tsx index 3f0505d3c1..63239eb5d1 100644 --- a/src/renderer/components/+catalog/catalog.tsx +++ b/src/renderer/components/+catalog/catalog.tsx @@ -29,7 +29,6 @@ import { navigate } from "../../navigation"; import { kebabCase } from "lodash"; import { PageLayout } from "../layout/page-layout"; import { MenuItem, MenuActions } from "../menu"; -import { Icon } from "../icon"; import { CatalogEntityContextMenu, CatalogEntityContextMenuContext, catalogEntityRunContext } from "../../api/catalog-entity"; import { Badge } from "../badge"; import { HotbarStore } from "../../../common/hotbar-store"; @@ -136,16 +135,16 @@ export class Catalog extends React.Component { return ( item.onContextMenuOpen(this.contextMenu)}> - this.addToHotbar(item) }> - Pin to Hotbar - { menuItems.map((menuItem, index) => ( this.onMenuItemClick(menuItem)}> - {menuItem.title} + {menuItem.title} )) } + this.addToHotbar(item) }> + Pin to Hotbar + ); } diff --git a/src/renderer/components/+entity-settings/entity-settings.tsx b/src/renderer/components/+entity-settings/entity-settings.tsx index 7719b7b45d..779cce45d6 100644 --- a/src/renderer/components/+entity-settings/entity-settings.tsx +++ b/src/renderer/components/+entity-settings/entity-settings.tsx @@ -32,6 +32,7 @@ import { CatalogEntity } from "../../api/catalog-entity"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; import { entitySettingRegistry } from "../../../extensions/registries"; import { EntitySettingsRouteParams } from "./entity-settings.route"; +import { groupBy } from "lodash"; interface Props extends RouteComponentProps { } @@ -57,9 +58,15 @@ export class EntitySettings extends React.Component { async componentDidMount() { const { hash } = navigation.location; - this.ensureActiveTab(); + if (hash) { + const item = this.menuItems.find((item) => item.title === hash.slice(1)); - document.getElementById(hash.slice(1))?.scrollIntoView(); + if (item) { + this.activeTab = item.id; + } + } + + this.ensureActiveTab(); } onTabChange = (tabId: string) => { @@ -67,18 +74,24 @@ export class EntitySettings extends React.Component { }; renderNavigation() { + const groups = Object.entries(groupBy(this.menuItems, (item) => item.group || "Extensions")); + return ( <>

{this.entity.metadata.name}

-
Settings
- { this.menuItems.map((setting) => ( - + { groups.map((group) => ( + <> +
{group[0]}
+ { group[1].map((setting, index) => ( + + ))} + ))}
@@ -111,7 +124,7 @@ export class EntitySettings extends React.Component {

{activeSetting.title}

- +
diff --git a/src/renderer/components/cluster-settings/cluster-settings.tsx b/src/renderer/components/cluster-settings/cluster-settings.tsx index 9d029388d8..d0aaf18e5c 100644 --- a/src/renderer/components/cluster-settings/cluster-settings.tsx +++ b/src/renderer/components/cluster-settings/cluster-settings.tsx @@ -43,6 +43,7 @@ entitySettingRegistry.add([ kind: "KubernetesCluster", source: "local", title: "General", + group: "Settings", components: { View: (props: { entity: CatalogEntity }) => { const cluster = getClusterForEntity(props.entity); @@ -68,6 +69,7 @@ entitySettingRegistry.add([ apiVersions: ["entity.k8slens.dev/v1alpha1"], kind: "KubernetesCluster", title: "Proxy", + group: "Settings", components: { View: (props: { entity: CatalogEntity }) => { const cluster = getClusterForEntity(props.entity); @@ -88,6 +90,7 @@ entitySettingRegistry.add([ apiVersions: ["entity.k8slens.dev/v1alpha1"], kind: "KubernetesCluster", title: "Terminal", + group: "Settings", components: { View: (props: { entity: CatalogEntity }) => { const cluster = getClusterForEntity(props.entity); @@ -108,6 +111,7 @@ entitySettingRegistry.add([ apiVersions: ["entity.k8slens.dev/v1alpha1"], kind: "KubernetesCluster", title: "Namespaces", + group: "Settings", components: { View: (props: { entity: CatalogEntity }) => { const cluster = getClusterForEntity(props.entity); @@ -128,6 +132,7 @@ entitySettingRegistry.add([ apiVersions: ["entity.k8slens.dev/v1alpha1"], kind: "KubernetesCluster", title: "Metrics", + group: "Settings", components: { View: (props: { entity: CatalogEntity }) => { const cluster = getClusterForEntity(props.entity); diff --git a/src/renderer/components/cluster-settings/components/cluster-metrics-setting.scss b/src/renderer/components/cluster-settings/components/cluster-metrics-setting.scss deleted file mode 100644 index e6a2ed51c7..0000000000 --- a/src/renderer/components/cluster-settings/components/cluster-metrics-setting.scss +++ /dev/null @@ -1,33 +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. - */ - -.MetricsSelect { - $spacing: $padding; - --flex-gap: #{$spacing}; - - .Badge { - margin-top: $spacing; - } - - .Button { - margin-top: $spacing; - } -} diff --git a/src/renderer/components/cluster-settings/components/cluster-metrics-setting.tsx b/src/renderer/components/cluster-settings/components/cluster-metrics-setting.tsx index 8c9f40f71d..bfa4630032 100644 --- a/src/renderer/components/cluster-settings/components/cluster-metrics-setting.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-metrics-setting.tsx @@ -19,8 +19,6 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import "./cluster-metrics-setting.scss"; - import React from "react"; import { disposeOnUnmount, observer } from "mobx-react"; import { Select, SelectOption } from "../../select/select"; diff --git a/src/renderer/components/cluster-settings/components/cluster-prometheus-setting.tsx b/src/renderer/components/cluster-settings/components/cluster-prometheus-setting.tsx index 4c65506083..36395f1bdb 100644 --- a/src/renderer/components/cluster-settings/components/cluster-prometheus-setting.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-prometheus-setting.tsx @@ -27,6 +27,7 @@ import { SubTitle } from "../../layout/sub-title"; import { Select, SelectOption } from "../../select"; import { Input } from "../../input"; import { observable, computed, autorun } from "mobx"; +import { productName } from "../../../../common/vars"; const options: SelectOption[] = [ { value: "", label: "Auto detect" }, @@ -102,23 +103,20 @@ export class ClusterPrometheusSetting extends React.Component { render() { return ( <> - -

- Use pre-installed Prometheus service for metrics. Please refer to the{" "} - guide{" "} - for possible configuration changes. -

- { + this.provider = value; + this.onSaveProvider(); + }} + options={options} + /> + What query format is used to fetch metrics from Prometheus + {this.canEditPrometheusPath && ( - <> +

Prometheus service address.

{ /> An address to an existing Prometheus installation{" "} - ({"/:"}). Lens tries to auto-detect address if left empty. + ({"/:"}). {productName} tries to auto-detect address if left empty. - +
)} ); diff --git a/src/renderer/components/cluster-settings/components/remove-cluster-button.tsx b/src/renderer/components/cluster-settings/components/remove-cluster-button.tsx deleted file mode 100644 index fc3e683c17..0000000000 --- a/src/renderer/components/cluster-settings/components/remove-cluster-button.tsx +++ /dev/null @@ -1,57 +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 React from "react"; -import { observer } from "mobx-react"; -import { ClusterStore } from "../../../../common/cluster-store"; -import { Cluster } from "../../../../main/cluster"; -import { autobind } from "../../../utils"; -import { Button } from "../../button"; -import { ConfirmDialog } from "../../confirm-dialog"; - -interface Props { - cluster: Cluster; -} - -@observer -export class RemoveClusterButton extends React.Component { - @autobind() - confirmRemoveCluster() { - const { cluster } = this.props; - - ConfirmDialog.open({ - message:

Are you sure you want to remove {cluster.preferences.clusterName} from Lens?

, - labelOk: "Yes", - labelCancel: "No", - ok: async () => { - await ClusterStore.getInstance().removeById(cluster.id); - } - }); - } - - render() { - return ( - - ); - } -} diff --git a/src/renderer/components/cluster-settings/components/show-metrics.tsx b/src/renderer/components/cluster-settings/components/show-metrics.tsx index 3ac4a237ef..e744875810 100644 --- a/src/renderer/components/cluster-settings/components/show-metrics.tsx +++ b/src/renderer/components/cluster-settings/components/show-metrics.tsx @@ -19,8 +19,6 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import "./cluster-metrics-setting.scss"; - import React from "react"; import { disposeOnUnmount, observer } from "mobx-react"; import { Cluster } from "../../../../main/cluster"; diff --git a/src/renderer/components/drawer/drawer.scss b/src/renderer/components/drawer/drawer.scss index 4c972bdd3c..47168df569 100644 --- a/src/renderer/components/drawer/drawer.scss +++ b/src/renderer/components/drawer/drawer.scss @@ -83,6 +83,10 @@ .MenuActions.toolbar .Icon { color: $drawerTitleText; } + + .Menu { + box-shadow: none; + } } .drawer-content { @@ -99,4 +103,4 @@ width: var(--full-size) } } -} \ No newline at end of file +} diff --git a/src/renderer/components/hotbar/hotbar-entity-icon.tsx b/src/renderer/components/hotbar/hotbar-entity-icon.tsx index e71ab2fdb2..41b0a69da0 100644 --- a/src/renderer/components/hotbar/hotbar-entity-icon.tsx +++ b/src/renderer/components/hotbar/hotbar-entity-icon.tsx @@ -105,13 +105,11 @@ export class HotbarEntityIcon extends React.Component { if (!isPersisted) { menuItems.unshift({ title: "Pin to Hotbar", - icon: "push_pin", onClick: () => add(entity, index) }); } else { menuItems.unshift({ title: "Unpin from Hotbar", - icon: "push_pin", onClick: () => remove(entity.metadata.uid) }); } diff --git a/src/renderer/components/hotbar/hotbar-icon.tsx b/src/renderer/components/hotbar/hotbar-icon.tsx index 2f681a05c1..ddfa512dcd 100644 --- a/src/renderer/components/hotbar/hotbar-icon.tsx +++ b/src/renderer/components/hotbar/hotbar-icon.tsx @@ -29,7 +29,6 @@ import GraphemeSplitter from "grapheme-splitter"; import { CatalogEntityContextMenu } from "../../../common/catalog"; import { cssNames, IClassName, iter } from "../../utils"; import { ConfirmDialog } from "../confirm-dialog"; -import { Icon } from "../icon"; import { Menu, MenuItem } from "../menu"; import { MaterialTooltip } from "../+catalog/material-tooltip/material-tooltip"; import { observer } from "mobx-react"; @@ -137,7 +136,7 @@ export const HotbarIcon = observer(({menuItems = [], ...props}: Props) => { { menuItems.map((menuItem) => { return ( onMenuItemClick(menuItem) }> - {menuItem.title} + {menuItem.title} ); })} diff --git a/src/renderer/components/menu/menu.scss b/src/renderer/components/menu/menu.scss index 6682d2ad60..d94cbff63e 100644 --- a/src/renderer/components/menu/menu.scss +++ b/src/renderer/components/menu/menu.scss @@ -20,7 +20,7 @@ */ .Menu { - --bgc: #{$contentColor}; + --bgc: #{$layoutBackground}; position: absolute; display: flex; @@ -29,6 +29,8 @@ list-style: none; border: 1px solid $borderColor; z-index: 101; + box-shadow: rgba(0,0,0,0.24) 0px 8px 16px 0px; + border-radius: 4px; &.portal { left: -1000px; From eacf9399c8ff108475d65d8eafc33b6db83e15b9 Mon Sep 17 00:00:00 2001 From: Mario Sarcher Date: Tue, 18 May 2021 17:26:13 +0200 Subject: [PATCH 16/21] Adopt docs color palette to lens styleguide + makes dark theme default (#2804) Signed-off-by: Mario Sarcher --- docs/stylesheets/extra.css | 27 ++++++++++++++++++++++++++- mkdocs.yml | 8 ++++---- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index f727034bbd..3f7e4560d7 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -5,13 +5,38 @@ :root > * { /* Footer */ - --md-footer-bg-color: #3d90ce; + --md-footer-bg-color: #e8e8e8; + --md-footer-bg-color--dark: #cccdcf; + --md-footer-fg-color: #3d90ce; + --md-footer-fg-color--light: #fff; + + /* Background */ + --md-default-bg-color: #f1f1f1; +} + +[data-md-color-scheme="slate"] { + /* Footer */ + --md-footer-bg-color: #2e3136; + --md-footer-bg-color--dark: #262b2f; + --md-footer-fg-color: #3d90ce; + --md-footer-fg-color--light: #fff; + + /* Background */ + --md-default-bg-color: #1e2124; } .md-version__list { overflow: auto; } +.md-header-nav__title { + margin-left: 0; +} + +.md-header__title { + margin-left: 0; +} + ul.video-list { counter-reset: section; list-style: none; diff --git a/mkdocs.yml b/mkdocs.yml index 7001e41ce5..ab6b98d7aa 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -59,13 +59,13 @@ theme: favicon: img/favicon.ico logo: img/lens-logo-icon.svg palette: - - scheme: default - toggle: - icon: material/toggle-switch - name: Switch to light mode - scheme: slate toggle: icon: material/toggle-switch-off-outline + name: Switch to light mode + - scheme: default + toggle: + icon: material/toggle-switch name: Switch to dark mode features: - toc.autohide From 08db118832db2bc87bf01c7909d55fc4af799c5d Mon Sep 17 00:00:00 2001 From: Mario Sarcher Date: Wed, 19 May 2021 08:23:34 +0200 Subject: [PATCH 17/21] Removes links to ClusterFeature API docs as these no longer exist >=Lens.5.0.0-beta.5 (#2809) Signed-off-by: Mario Sarcher --- docs/extensions/guides/renderer-extension.md | 1 - docs/extensions/typedoc-readme.md.tpl | 1 - 2 files changed, 2 deletions(-) diff --git a/docs/extensions/guides/renderer-extension.md b/docs/extensions/guides/renderer-extension.md index 48bcaa5d0c..d95ef15933 100644 --- a/docs/extensions/guides/renderer-extension.md +++ b/docs/extensions/guides/renderer-extension.md @@ -10,7 +10,6 @@ The custom Lens UI elements that you can add include: * [Cluster page menus](#clusterpagemenus) * [Global pages](#globalpages) * [Global page menus](#globalpagemenus) -* [Cluster features](#clusterfeatures) * [App preferences](#apppreferences) * [Status bar items](#statusbaritems) * [KubeObject menu items](#kubeobjectmenuitems) diff --git a/docs/extensions/typedoc-readme.md.tpl b/docs/extensions/typedoc-readme.md.tpl index 6e23d197d5..6ebdf51de1 100644 --- a/docs/extensions/typedoc-readme.md.tpl +++ b/docs/extensions/typedoc-readme.md.tpl @@ -3,7 +3,6 @@ ## Modules * [App](modules/_core_api_app_.md) -* [ClusterFeature](modules/_core_api_cluster_feature_.md) * [EventBus](modules/_core_api_event_bus_.md) * [Store](modules/_core_api_stores_.md) * [Util](modules/_core_api_utils_.md) From f168f137e52193fe493d94f5a5b2204208a8f44b Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Wed, 19 May 2021 09:40:09 +0300 Subject: [PATCH 18/21] Bundle in-tree extensions as npm/tgz (#2807) Signed-off-by: Jari Kolehmainen --- Makefile | 1 + extensions/.gitignore | 1 + .../package-lock.json | 49 - .../kube-object-event-status/package.json | 11 +- .../webpack.config.js | 3 +- .../metrics-cluster-feature/package-lock.json | 1729 ++++++++++++----- .../metrics-cluster-feature/package.json | 15 +- .../metrics-cluster-feature/webpack.config.js | 3 +- extensions/node-menu/package-lock.json | 45 - extensions/node-menu/package.json | 9 +- extensions/node-menu/webpack.config.js | 3 +- extensions/pod-menu/package-lock.json | 45 - extensions/pod-menu/package.json | 9 +- extensions/pod-menu/webpack.config.js | 3 +- package.json | 4 +- src/extensions/extension-discovery.ts | 5 +- 16 files changed, 1237 insertions(+), 698 deletions(-) create mode 100644 extensions/.gitignore diff --git a/Makefile b/Makefile index d7223e2bc7..f4538b256c 100644 --- a/Makefile +++ b/Makefile @@ -125,6 +125,7 @@ docs: clean-extensions: $(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), rm -rf $(dir)/dist) $(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), rm -rf $(dir)/node_modules) + $(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), rm $(dir)/*.tgz || true) .PHONY: clean-npm clean-npm: diff --git a/extensions/.gitignore b/extensions/.gitignore new file mode 100644 index 0000000000..193cfa4791 --- /dev/null +++ b/extensions/.gitignore @@ -0,0 +1 @@ +*/*.tgz diff --git a/extensions/kube-object-event-status/package-lock.json b/extensions/kube-object-event-status/package-lock.json index c5aa87ef6c..e79ce0872f 100644 --- a/extensions/kube-object-event-status/package-lock.json +++ b/extensions/kube-object-event-status/package-lock.json @@ -1661,12 +1661,6 @@ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -1721,15 +1715,6 @@ "path-exists": "^3.0.0" } }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -1896,12 +1881,6 @@ "minimist": "^1.2.5" } }, - "mobx": { - "version": "5.15.7", - "resolved": "https://registry.npmjs.org/mobx/-/mobx-5.15.7.tgz", - "integrity": "sha512-wyM3FghTkhmC+hQjyPGGFdpehrcX1KOXsDuERhfK2YbJemkUhEB+6wzEN639T21onxlfYBmriA1PFnvxTUhcKw==", - "dev": true - }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -2213,17 +2192,6 @@ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", "dev": true }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -2322,23 +2290,6 @@ "safe-buffer": "^5.1.0" } }, - "react": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", - "dev": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" - } - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", diff --git a/extensions/kube-object-event-status/package.json b/extensions/kube-object-event-status/package.json index 86f9c296b0..e6ab1bb688 100644 --- a/extensions/kube-object-event-status/package.json +++ b/extensions/kube-object-event-status/package.json @@ -8,17 +8,18 @@ "styles": [] }, "scripts": { - "build": "webpack --config webpack.config.js", - "dev": "npm run build --watch", + "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", - "mobx": "^5.15.5", - "react": "^16.13.1" + "webpack": "^4.44.2" } } diff --git a/extensions/kube-object-event-status/webpack.config.js b/extensions/kube-object-event-status/webpack.config.js index 33fd38ade7..b49801a1fb 100644 --- a/extensions/kube-object-event-status/webpack.config.js +++ b/extensions/kube-object-event-status/webpack.config.js @@ -42,7 +42,8 @@ module.exports = [ { "@k8slens/extensions": "var global.LensExtensions", "react": "var global.React", - "mobx": "var global.Mobx" + "mobx": "var global.Mobx", + "mobx-react": "var global.MobxReact" } ], resolve: { diff --git a/extensions/metrics-cluster-feature/package-lock.json b/extensions/metrics-cluster-feature/package-lock.json index c0c18bb359..150e9cbb89 100644 --- a/extensions/metrics-cluster-feature/package-lock.json +++ b/extensions/metrics-cluster-feature/package-lock.json @@ -5,42 +5,47 @@ "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", "dev": true, "requires": { - "@babel/highlight": "^7.10.4" + "@babel/highlight": "^7.12.13" } }, + "@babel/compat-data": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.0.tgz", + "integrity": "sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q==", + "dev": true + }, "@babel/core": { - "version": "7.12.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.3.tgz", - "integrity": "sha512-0qXcZYKZp3/6N2jKYVxZv0aNCsxTSVCiK72DTiTYZAu7sjg73W0/aynWjMbiGd87EQL4WyA8reiJVh92AVla9g==", + "version": "7.14.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.3.tgz", + "integrity": "sha512-jB5AmTKOCSJIZ72sd78ECEhuPiDMKlQdDI/4QRI6lzYATx5SSogS1oQA2AoPecRCknm30gHi2l+QVvNUu3wZAg==", "dev": true, "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.1", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.1", - "@babel/parser": "^7.12.3", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1", + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.14.3", + "@babel/helper-compilation-targets": "^7.13.16", + "@babel/helper-module-transforms": "^7.14.2", + "@babel/helpers": "^7.14.0", + "@babel/parser": "^7.14.3", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.14.2", + "@babel/types": "^7.14.2", "convert-source-map": "^1.7.0", "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", + "gensync": "^1.0.0-beta.2", "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", + "semver": "^6.3.0", "source-map": "^0.5.0" }, "dependencies": { "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, "source-map": { @@ -52,12 +57,12 @@ } }, "@babel/generator": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz", - "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==", + "version": "7.14.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.3.tgz", + "integrity": "sha512-bn0S6flG/j0xtQdz3hsjJ624h3W0r3llttBMfyHX3YrZ/KtLYr15bjA0FXkgW7FpvrDuTuElXeVjiKlYRpnOFA==", "dev": true, "requires": { - "@babel/types": "^7.12.5", + "@babel/types": "^7.14.2", "jsesc": "^2.5.1", "source-map": "^0.5.0" }, @@ -70,130 +75,155 @@ } } }, - "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", - "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "@babel/helper-compilation-targets": { + "version": "7.13.16", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz", + "integrity": "sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/compat-data": "^7.13.15", + "@babel/helper-validator-option": "^7.12.17", + "browserslist": "^4.14.5", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-function-name": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.2.tgz", + "integrity": "sha512-NYZlkZRydxw+YT56IlhIcS8PAhb+FEUiOzuhFTfqDyPmzAhRge6ua0dQYT/Uh0t/EDHq05/i+e5M2d4XvjgarQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.12.13", + "@babel/template": "^7.12.13", + "@babel/types": "^7.14.2" } }, "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", - "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", + "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", "dev": true, "requires": { - "@babel/types": "^7.10.4" + "@babel/types": "^7.12.13" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.1.tgz", - "integrity": "sha512-k0CIe3tXUKTRSoEx1LQEPFU9vRQfqHtl+kf8eNnDqb4AUJEy5pz6aIiog+YWtVm2jpggjS1laH68bPsR+KWWPQ==", + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz", + "integrity": "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==", "dev": true, "requires": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.13.12" } }, "@babel/helper-module-imports": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", - "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz", + "integrity": "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==", "dev": true, "requires": { - "@babel/types": "^7.12.5" + "@babel/types": "^7.13.12" } }, "@babel/helper-module-transforms": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz", - "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==", + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.14.2.tgz", + "integrity": "sha512-OznJUda/soKXv0XhpvzGWDnml4Qnwp16GN+D/kZIdLsWoHj05kyu8Rm5kXmMef+rVJZ0+4pSGLkeixdqNUATDA==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.12.1", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-simple-access": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/helper-validator-identifier": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1", - "lodash": "^4.17.19" + "@babel/helper-module-imports": "^7.13.12", + "@babel/helper-replace-supers": "^7.13.12", + "@babel/helper-simple-access": "^7.13.12", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/helper-validator-identifier": "^7.14.0", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.14.2", + "@babel/types": "^7.14.2" } }, "@babel/helper-optimise-call-expression": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", - "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", + "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", "dev": true, "requires": { - "@babel/types": "^7.10.4" + "@babel/types": "^7.12.13" } }, "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", + "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", "dev": true }, "@babel/helper-replace-supers": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz", - "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==", + "version": "7.14.3", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.3.tgz", + "integrity": "sha512-Rlh8qEWZSTfdz+tgNV/N4gz1a0TMNwCUcENhMjHTHKp3LseYH5Jha0NSlyTQWMnjbYcwFt+bqAMqSLHVXkQ6UA==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.12.1", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.12.5", - "@babel/types": "^7.12.5" + "@babel/helper-member-expression-to-functions": "^7.13.12", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/traverse": "^7.14.2", + "@babel/types": "^7.14.2" } }, "@babel/helper-simple-access": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz", - "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==", + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz", + "integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==", "dev": true, "requires": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.13.12" } }, "@babel/helper-split-export-declaration": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", - "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", + "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", "dev": true, "requires": { - "@babel/types": "^7.11.0" + "@babel/types": "^7.12.13" } }, "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", + "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", + "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", "dev": true }, "@babel/helpers": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", - "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.0.tgz", + "integrity": "sha512-+ufuXprtQ1D1iZTO/K9+EBRn+qPWMJjZSw/S0KlFrxCw4tkrzv9grgpDHkY9MeQTjTY8i2sp7Jep8DfU6tN9Mg==", "dev": true, "requires": { - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.5", - "@babel/types": "^7.12.5" + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.14.0", + "@babel/types": "^7.14.0" } }, "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", + "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/helper-validator-identifier": "^7.14.0", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -251,9 +281,9 @@ } }, "@babel/parser": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.5.tgz", - "integrity": "sha512-FVM6RZQ0mn2KCf1VUED7KepYeUWoVShczewOCfm3nzoBybaih51h+sYVVGthW9M6lPByEPTQf+xm27PBdlpwmQ==", + "version": "7.14.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.3.tgz", + "integrity": "sha512-7MpZDIfI7sUC5zWo2+foJ50CSI5lcqDehZ0lVgIhSi4bFEk94fLAKlF3Q0nzSQQ+ca0lm+O6G9ztKVBeu8PMRQ==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -275,12 +305,12 @@ } }, "@babel/plugin-syntax-class-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz", - "integrity": "sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-syntax-import-meta": { @@ -356,50 +386,48 @@ } }, "@babel/plugin-syntax-top-level-await": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz", - "integrity": "sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz", + "integrity": "sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/template": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", - "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", + "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", "dev": true, "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/code-frame": "^7.12.13", + "@babel/parser": "^7.12.13", + "@babel/types": "^7.12.13" } }, "@babel/traverse": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.5.tgz", - "integrity": "sha512-xa15FbQnias7z9a62LwYAA5SZZPkHIXpd42C6uW68o8uTuua96FHZy1y61Va5P/i83FAAcMpW8+A/QayntzuqA==", + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.2.tgz", + "integrity": "sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA==", "dev": true, "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.12.5", - "@babel/types": "^7.12.5", + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.14.2", + "@babel/helper-function-name": "^7.14.2", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/parser": "^7.14.2", + "@babel/types": "^7.14.2", "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" + "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.12.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.6.tgz", - "integrity": "sha512-hwyjw6GvjBLiyy3W0YQf0Z5Zf4NpYejUnKFcfcUhZCSffoBBp30w6wP2Wn6pk31jMYZvcOrB/1b7cGXvEoKogA==", + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.2.tgz", + "integrity": "sha512-SdjAG/3DikRHpUOjxZgnkbR11xUlyDMUFJdvnIgZEE16mqmY0BINMmc4//JMJglEmn6i7sq6p+mGrFWyZ98EEw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "lodash": "^4.17.19", + "@babel/helper-validator-identifier": "^7.14.0", "to-fast-properties": "^2.0.0" } }, @@ -433,9 +461,9 @@ } }, "@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true }, "@jest/console": { @@ -632,12 +660,696 @@ }, "@k8slens/extensions": { "version": "file:../../src/extensions/npm/extensions", - "dev": true + "dev": true, + "requires": { + "@material-ui/core": "*", + "@types/node": "*", + "@types/react-select": "*", + "conf": "^7.0.1" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", + "integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", + "dev": true + }, + "@emotion/memoize": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz", + "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==", + "dev": true + }, + "@emotion/serialize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.2.tgz", + "integrity": "sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==", + "dev": true, + "requires": { + "@emotion/hash": "^0.8.0", + "@emotion/memoize": "^0.7.4", + "@emotion/unitless": "^0.7.5", + "@emotion/utils": "^1.0.0", + "csstype": "^3.0.2" + }, + "dependencies": { + "csstype": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", + "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==", + "dev": true + } + } + }, + "@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", + "dev": true + }, + "@emotion/utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz", + "integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==", + "dev": true + }, + "@material-ui/core": { + "version": "4.11.4", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.4.tgz", + "integrity": "sha512-oqb+lJ2Dl9HXI9orc6/aN8ZIAMkeThufA5iZELf2LQeBn2NtjVilF5D2w7e9RpntAzDb4jK5DsVhkfOvFY/8fg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.11.4", + "@material-ui/system": "^4.11.3", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.2", + "@types/react-transition-group": "^4.2.0", + "clsx": "^1.0.4", + "hoist-non-react-statics": "^3.3.2", + "popper.js": "1.16.1-lts", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0", + "react-transition-group": "^4.4.0" + } + }, + "@material-ui/styles": { + "version": "4.11.4", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.4.tgz", + "integrity": "sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==", + "dev": true, + "requires": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.2", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.5.1", + "jss-plugin-camel-case": "^10.5.1", + "jss-plugin-default-unit": "^10.5.1", + "jss-plugin-global": "^10.5.1", + "jss-plugin-nested": "^10.5.1", + "jss-plugin-props-sort": "^10.5.1", + "jss-plugin-rule-value-function": "^10.5.1", + "jss-plugin-vendor-prefixer": "^10.5.1", + "prop-types": "^15.7.2" + } + }, + "@material-ui/system": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.11.3.tgz", + "integrity": "sha512-SY7otguNGol41Mu2Sg6KbBP1ZRFIbFLHGK81y4KYbsV2yIcaEPOmsCK6zwWlp+2yTV3J/VwT6oSBARtGIVdXPw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.11.2", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + } + }, + "@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==", + "dev": true + }, + "@material-ui/utils": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz", + "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + } + }, + "@types/node": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", + "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==", + "dev": true + }, + "@types/prop-types": { + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", + "dev": true + }, + "@types/react": { + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.6.tgz", + "integrity": "sha512-u/TtPoF/hrvb63LdukET6ncaplYsvCvmkceasx8oG84/ZCsoLxz9Z/raPBP4lTAiWW1Jb889Y9svHmv8R26dWw==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + }, + "dependencies": { + "csstype": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", + "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==", + "dev": true + } + } + }, + "@types/react-dom": { + "version": "17.0.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.5.tgz", + "integrity": "sha512-ikqukEhH4H9gr4iJCmQVNzTB307kROe3XFfHAOTxOXPOw7lAoEXnM5KWTkzeANGL5Ce6ABfiMl/zJBYNi7ObmQ==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/react-select": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@types/react-select/-/react-select-4.0.15.tgz", + "integrity": "sha512-GPyBFYGMVFCtF4eg9riodEco+s2mflR10Nd5csx69+bcdvX6Uo9H/jgrIqovBU9yxBppB9DS66OwD6xxgVqOYQ==", + "dev": true, + "requires": { + "@emotion/serialize": "^1.0.0", + "@types/react": "*", + "@types/react-dom": "*", + "@types/react-transition-group": "*" + } + }, + "@types/react-transition-group": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz", + "integrity": "sha512-vIo69qKKcYoJ8wKCJjwSgCTM+z3chw3g18dkrDfVX665tMH7tmbDxEAnPdey4gTlwZz5QuHGzd+hul0OVZDqqQ==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/scheduler": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz", + "integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "atomically": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz", + "integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==", + "dev": true + }, + "clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==", + "dev": true + }, + "conf": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/conf/-/conf-7.1.2.tgz", + "integrity": "sha512-r8/HEoWPFn4CztjhMJaWNAe5n+gPUCSaJ0oufbqDLFKsA1V8JjAG7G+p0pgoDFAws9Bpk2VtVLLXqOBA7WxLeg==", + "dev": true, + "requires": { + "ajv": "^6.12.2", + "atomically": "^1.3.1", + "debounce-fn": "^4.0.0", + "dot-prop": "^5.2.0", + "env-paths": "^2.2.0", + "json-schema-typed": "^7.0.3", + "make-dir": "^3.1.0", + "onetime": "^5.1.0", + "pkg-up": "^3.1.0", + "semver": "^7.3.2" + } + }, + "css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, + "csstype": { + "version": "2.6.17", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.17.tgz", + "integrity": "sha512-u1wmTI1jJGzCJzWndZo8mk4wnPTZd1eOIYTYvuEyOQGfmDl3TrabCCfKnOC86FZwW/9djqTl933UF/cS425i9A==", + "dev": true + }, + "debounce-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz", + "integrity": "sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==", + "dev": true, + "requires": { + "mimic-fn": "^3.0.0" + } + }, + "dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + }, + "dependencies": { + "csstype": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", + "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==", + "dev": true + } + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dev": true, + "requires": { + "react-is": "^16.7.0" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + } + } + }, + "hyphenate-style-name": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", + "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==", + "dev": true + }, + "indefinite-observable": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/indefinite-observable/-/indefinite-observable-2.0.1.tgz", + "integrity": "sha512-G8vgmork+6H9S8lUAg1gtXEj2JxIQTo0g2PbFiYOdjkziSI0F7UYBiVwhZRuixhBCNGczAls34+5HJPyZysvxQ==", + "dev": true, + "requires": { + "symbol-observable": "1.2.0" + } + }, + "is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-schema-typed": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-7.0.3.tgz", + "integrity": "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==", + "dev": true + }, + "jss": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.6.0.tgz", + "integrity": "sha512-n7SHdCozmxnzYGXBHe0NsO0eUf9TvsHVq2MXvi4JmTn3x5raynodDVE/9VQmBdWFyyj9HpHZ2B4xNZ7MMy7lkw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "indefinite-observable": "^2.0.1", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + }, + "dependencies": { + "csstype": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", + "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==", + "dev": true + } + } + }, + "jss-plugin-camel-case": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.6.0.tgz", + "integrity": "sha512-JdLpA3aI/npwj3nDMKk308pvnhoSzkW3PXlbgHAzfx0yHWnPPVUjPhXFtLJzgKZge8lsfkUxvYSQ3X2OYIFU6A==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.6.0" + } + }, + "jss-plugin-default-unit": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.6.0.tgz", + "integrity": "sha512-7y4cAScMHAxvslBK2JRK37ES9UT0YfTIXWgzUWD5euvR+JR3q+o8sQKzBw7GmkQRfZijrRJKNTiSt1PBsLI9/w==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0" + } + }, + "jss-plugin-global": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.6.0.tgz", + "integrity": "sha512-I3w7ji/UXPi3VuWrTCbHG9rVCgB4yoBQLehGDTmsnDfXQb3r1l3WIdcO8JFp9m0YMmyy2CU7UOV6oPI7/Tmu+w==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0" + } + }, + "jss-plugin-nested": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.6.0.tgz", + "integrity": "sha512-fOFQWgd98H89E6aJSNkEh2fAXquC9aZcAVjSw4q4RoQ9gU++emg18encR4AT4OOIFl4lQwt5nEyBBRn9V1Rk8g==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-props-sort": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.6.0.tgz", + "integrity": "sha512-oMCe7hgho2FllNc60d9VAfdtMrZPo9n1Iu6RNa+3p9n0Bkvnv/XX5San8fTPujrTBScPqv9mOE0nWVvIaohNuw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0" + } + }, + "jss-plugin-rule-value-function": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.6.0.tgz", + "integrity": "sha512-TKFqhRTDHN1QrPTMYRlIQUOC2FFQb271+AbnetURKlGvRl/eWLswcgHQajwuxI464uZk91sPiTtdGi7r7XaWfA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-vendor-prefixer": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.6.0.tgz", + "integrity": "sha512-doJ7MouBXT1lypLLctCwb4nJ6lDYqrTfVS3LtXgox42Xz0gXusXIIDboeh6UwnSmox90QpVnub7au8ybrb0krQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.6.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "mimic-fn": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", + "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + }, + "dependencies": { + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + } + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "popper.js": { + "version": "1.16.1-lts", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", + "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==", + "dev": true + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "react-transition-group": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", + "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true + }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", + "dev": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } }, "@sinonjs/commons": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", - "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", "dev": true, "requires": { "type-detect": "4.0.8" @@ -653,9 +1365,9 @@ } }, "@types/babel__core": { - "version": "7.1.12", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz", - "integrity": "sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ==", + "version": "7.1.14", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz", + "integrity": "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -675,9 +1387,9 @@ } }, "@types/babel__template": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.3.tgz", - "integrity": "sha512-uCoznIPDmnickEi6D0v11SBpW0OuVqHJCa7syXqQHy5uktSCreIlt0iglsCnmvz8yCb38hGcWeseA8cWJSwv5Q==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", + "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -685,18 +1397,18 @@ } }, "@types/babel__traverse": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.15.tgz", - "integrity": "sha512-Pzh9O3sTK8V6I1olsXpCfj2k/ygO2q1X0vhhnDrEQyYLHZesWz+zMZMVcwXLCYf0U36EtmyYaFGPfXlTtDHe3A==", + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.1.tgz", + "integrity": "sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==", "dev": true, "requires": { "@babel/types": "^7.3.0" } }, "@types/graceful-fs": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz", - "integrity": "sha512-mWA/4zFQhfvOA8zWkXobwJvBD7vzcxgrOQ0J5CH1votGqdq9m7+FwtGaqyCZqC3NyyBkc9z4m+iry4LlqcMWJg==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", "dev": true, "requires": { "@types/node": "*" @@ -727,9 +1439,9 @@ } }, "@types/node": { - "version": "14.14.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.7.tgz", - "integrity": "sha512-Zw1vhUSQZYw+7u5dAwNbIA9TuTotpzY/OF7sJM9FqPOF3SPjKnxrjoTktXDZgUjybf4cWVBP7O8wvKdSaGHweg==", + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", + "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==", "dev": true }, "@types/normalize-package-data": { @@ -739,9 +1451,9 @@ "dev": true }, "@types/prettier": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.5.tgz", - "integrity": "sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", + "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", "dev": true }, "@types/stack-utils": { @@ -751,18 +1463,18 @@ "dev": true }, "@types/yargs": { - "version": "15.0.9", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.9.tgz", - "integrity": "sha512-HmU8SeIRhZCWcnRskCs36Q1Q00KBV6Cqh/ora8WN1+22dY07AZdn6Gel8QZ3t26XYPImtcL8WV/eqjhVmMEw4g==", + "version": "15.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", + "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", "dev": true, "requires": { "@types/yargs-parser": "*" } }, "@types/yargs-parser": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", - "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", + "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", "dev": true }, "@webassemblyjs/ast": { @@ -959,9 +1671,9 @@ "dev": true }, "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.2.4.tgz", + "integrity": "sha512-Ibt84YwBDDA890eDiDCEqcbwvHlBvzzDkU2cGBBDDI1QWT12jTiXIOn2CIw5KK4i6N5Z2HUxwYjzriDyqaqqZg==", "dev": true }, "acorn-globals": { @@ -972,6 +1684,14 @@ "requires": { "acorn": "^7.1.1", "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + } } }, "acorn-walk": { @@ -1005,18 +1725,18 @@ "dev": true }, "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "requires": { - "type-fest": "^0.11.0" + "type-fest": "^0.21.3" }, "dependencies": { "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true } } @@ -1037,9 +1757,9 @@ } }, "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -1107,9 +1827,9 @@ }, "dependencies": { "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "dev": true } } @@ -1226,9 +1946,9 @@ } }, "babel-preset-current-node-syntax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.0.tgz", - "integrity": "sha512-mGkvkpocWJes1CmMKtgGUwCeeq0pOhALyymozzDWYomHTbDLwueDYG6p4TK1YOeYHCzBzYPsWkgTto10JubI1Q==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", "dev": true, "requires": { "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -1256,9 +1976,9 @@ } }, "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "base": { @@ -1338,9 +2058,9 @@ "dev": true }, "binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", - "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true, "optional": true }, @@ -1361,9 +2081,9 @@ "dev": true }, "bn.js": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", - "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==", "dev": true }, "brace-expansion": { @@ -1435,21 +2155,13 @@ } }, "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", "dev": true, "requires": { - "bn.js": "^4.1.0", + "bn.js": "^5.0.0", "randombytes": "^2.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", - "dev": true - } } }, "browserify-sign": { @@ -1497,6 +2209,19 @@ "pako": "~1.0.5" } }, + "browserslist": { + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" + } + }, "bser": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", @@ -1558,6 +2283,15 @@ "y18n": "^4.0.0" }, "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -1566,6 +2300,12 @@ "requires": { "glob": "^7.1.3" } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true } } }, @@ -1598,6 +2338,12 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, + "caniuse-lite": { + "version": "1.0.30001228", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz", + "integrity": "sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A==", + "dev": true + }, "capture-exit": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", @@ -1614,9 +2360,9 @@ "dev": true }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -1630,29 +2376,20 @@ "dev": true }, "chokidar": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", - "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", "dev": true, "optional": true, "requires": { "anymatch": "~3.1.1", "braces": "~3.0.2", - "fsevents": "~2.1.2", + "fsevents": "~2.3.1", "glob-parent": "~5.1.0", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.5.0" - }, - "dependencies": { - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "dev": true, - "optional": true - } } }, "chownr": { @@ -1662,13 +2399,10 @@ "dev": true }, "chrome-trace-event": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", - "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true }, "ci-info": { "version": "2.0.0", @@ -1763,6 +2497,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -1877,9 +2617,9 @@ }, "dependencies": { "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "dev": true } } @@ -2001,9 +2741,9 @@ } }, "debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -2120,9 +2860,9 @@ }, "dependencies": { "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "dev": true } } @@ -2172,6 +2912,12 @@ "safer-buffer": "^2.1.0" } }, + "electron-to-chromium": { + "version": "1.3.731", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.731.tgz", + "integrity": "sha512-dn1Nyd0DuFa3xhqZJr6/L9phyk+YXJpvrz6Vcu6mFxFqr5TQ9r/F3yvOYFUrEwY4Tbb1YBjN19TDKnSVCQvalA==", + "dev": true + }, "elliptic": { "version": "6.5.4", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", @@ -2223,9 +2969,9 @@ } }, "enhanced-resolve": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz", - "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -2234,9 +2980,9 @@ } }, "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, "requires": { "prr": "~1.0.1" @@ -2251,6 +2997,12 @@ "is-arrayish": "^0.2.1" } }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -2258,13 +3010,13 @@ "dev": true }, "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", "dev": true, "requires": { "esprima": "^4.0.1", - "estraverse": "^4.2.0", + "estraverse": "^5.2.0", "esutils": "^2.0.2", "optionator": "^0.8.1", "source-map": "~0.6.1" @@ -2278,6 +3030,14 @@ "requires": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } } }, "esprima": { @@ -2293,20 +3053,12 @@ "dev": true, "requires": { "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } } }, "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", "dev": true }, "esutils": { @@ -2316,9 +3068,9 @@ "dev": true }, "events": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", - "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true }, "evp_bytestokey": { @@ -2332,9 +3084,9 @@ } }, "exec-sh": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", - "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", + "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", "dev": true }, "execa": { @@ -2722,9 +3474,9 @@ "dev": true }, "fsevents": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.2.1.tgz", - "integrity": "sha512-bTLYHSeC0UH/EFXS9KqWnXuOl/wHK5Z/d+ghd5AsFMYN7wIGkUCOJyzy88+wJKkZPGON8u4Z9f6U4FdgURE9qA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "optional": true }, @@ -2777,9 +3529,9 @@ } }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -2791,9 +3543,9 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "optional": true, "requires": { @@ -2807,9 +3559,9 @@ "dev": true }, "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", "dev": true }, "growly": { @@ -3056,12 +3808,6 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true - }, "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", @@ -3114,9 +3860,9 @@ } }, "is-core-module": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz", - "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", "dev": true, "requires": { "has": "^1.0.3" @@ -3162,9 +3908,9 @@ } }, "is-docker": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", - "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, "optional": true }, @@ -3219,9 +3965,9 @@ } }, "is-potential-custom-element-name": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz", - "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, "is-stream": { @@ -3860,9 +4606,9 @@ "dev": true }, "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -3876,36 +4622,36 @@ "dev": true }, "jsdom": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.4.0.tgz", - "integrity": "sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==", + "version": "16.5.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.5.3.tgz", + "integrity": "sha512-Qj1H+PEvUsOtdPJ056ewXM4UJPCi4hhLA8wpiz9F2YvsRBhuFsXxtrIFAgGBDynQA9isAMGE91PfUYbdMPXuTA==", "dev": true, "requires": { - "abab": "^2.0.3", - "acorn": "^7.1.1", + "abab": "^2.0.5", + "acorn": "^8.1.0", "acorn-globals": "^6.0.0", "cssom": "^0.4.4", - "cssstyle": "^2.2.0", + "cssstyle": "^2.3.0", "data-urls": "^2.0.0", - "decimal.js": "^10.2.0", + "decimal.js": "^10.2.1", "domexception": "^2.0.1", - "escodegen": "^1.14.1", + "escodegen": "^2.0.0", "html-encoding-sniffer": "^2.0.1", "is-potential-custom-element-name": "^1.0.0", "nwsapi": "^2.2.0", - "parse5": "5.1.1", + "parse5": "6.0.1", "request": "^2.88.2", - "request-promise-native": "^1.0.8", - "saxes": "^5.0.0", + "request-promise-native": "^1.0.9", + "saxes": "^5.0.1", "symbol-tree": "^3.2.4", - "tough-cookie": "^3.0.1", + "tough-cookie": "^4.0.0", "w3c-hr-time": "^1.0.2", "w3c-xmlserializer": "^2.0.0", "webidl-conversions": "^6.1.0", "whatwg-encoding": "^1.0.5", "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0", - "ws": "^7.2.3", + "whatwg-url": "^8.5.0", + "ws": "^7.4.4", "xml-name-validator": "^3.0.0" } }, @@ -3946,9 +4692,9 @@ "dev": true }, "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "dev": true, "requires": { "minimist": "^1.2.5" @@ -4007,25 +4753,14 @@ "dev": true }, "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", "dev": true, "requires": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, - "dependencies": { - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - } + "json5": "^2.1.2" } }, "locate-path": { @@ -4043,28 +4778,13 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { - "yallist": "^3.0.2" + "yallist": "^4.0.0" } }, "make-dir": { @@ -4136,13 +4856,13 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", - "picomatch": "^2.0.5" + "picomatch": "^2.2.3" } }, "miller-rabin": { @@ -4156,26 +4876,26 @@ }, "dependencies": { "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "dev": true } } }, "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", + "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", "dev": true }, "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "version": "2.1.30", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", + "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", "dev": true, "requires": { - "mime-db": "1.44.0" + "mime-db": "1.47.0" } }, "mimic-fn": { @@ -4259,12 +4979,6 @@ "minimist": "^1.2.5" } }, - "mobx": { - "version": "5.15.7", - "resolved": "https://registry.npmjs.org/mobx/-/mobx-5.15.7.tgz", - "integrity": "sha512-wyM3FghTkhmC+hQjyPGGFdpehrcX1KOXsDuERhfK2YbJemkUhEB+6wzEN639T21onxlfYBmriA1PFnvxTUhcKw==", - "dev": true - }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -4392,9 +5106,9 @@ "dev": true }, "node-notifier": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.1.tgz", - "integrity": "sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", + "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", "dev": true, "optional": true, "requires": { @@ -4418,6 +5132,12 @@ } } }, + "node-releases": { + "version": "1.1.72", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz", + "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==", + "dev": true + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -4559,9 +5279,9 @@ "dev": true }, "p-each-series": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz", - "integrity": "sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", + "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", "dev": true }, "p-finally": { @@ -4625,9 +5345,9 @@ } }, "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -4637,9 +5357,9 @@ } }, "parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, "pascalcase": { @@ -4686,9 +5406,9 @@ "dev": true }, "pbkdf2": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", - "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", "dev": true, "requires": { "create-hash": "^1.1.2", @@ -4705,9 +5425,9 @@ "dev": true }, "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", + "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", "dev": true }, "pify": { @@ -4777,34 +5497,15 @@ "dev": true }, "prompts": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", - "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", + "integrity": "sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==", "dev": true, "requires": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - }, - "dependencies": { - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - } - } - }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -4832,9 +5533,9 @@ }, "dependencies": { "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", "dev": true } } @@ -4915,21 +5616,10 @@ "safe-buffer": "^5.1.0" } }, - "react": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", - "dev": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" - } - }, "react-is": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", - "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, "read-pkg": { @@ -5005,9 +5695,9 @@ "dev": true }, "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", "dev": true }, "repeat-string": { @@ -5107,12 +5797,12 @@ "dev": true }, "resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, "requires": { - "is-core-module": "^2.1.0", + "is-core-module": "^2.2.0", "path-parse": "^1.0.6" } }, @@ -5623,9 +6313,9 @@ } }, "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", "dev": true }, "spdx-correct": { @@ -5655,9 +6345,9 @@ } }, "spdx-license-ids": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", - "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.8.tgz", + "integrity": "sha512-NDgA96EnaLSvtbM7trJj+t1LUR3pirkDCcz9nOUlPb5DMBGsH7oES6C3hs3j7R9oHEa1EMvReS/BUAIT5Tcr0g==", "dev": true }, "split-string": { @@ -5702,9 +6392,9 @@ } }, "stack-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.2.tgz", - "integrity": "sha512-0H7QK2ECz3fyZMzQ8rH0j2ykpfbnd20BFtfg/SqVC2+sCTtcw0aDTGB7dk+de4U4uUeuz6nOtJcrkFFLG1B0Rg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", "dev": true, "requires": { "escape-string-regexp": "^2.0.0" @@ -5785,9 +6475,9 @@ "dev": true }, "string-length": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz", - "integrity": "sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, "requires": { "char-regex": "^1.0.2", @@ -5795,9 +6485,9 @@ } }, "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", "dev": true, "requires": { "emoji-regex": "^8.0.0", @@ -5851,9 +6541,9 @@ } }, "supports-hyperlinks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", - "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", "dev": true, "requires": { "has-flag": "^4.0.0", @@ -6014,14 +6704,14 @@ } }, "tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", "dev": true, "requires": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" } }, "tr46": { @@ -6034,82 +6724,29 @@ } }, "ts-loader": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.0.11.tgz", - "integrity": "sha512-06X+mWA2JXoXJHYAesUUL4mHFYhnmyoCdQVMXofXF552Lzd4wNwSGg7unJpttqUP7ziaruM8d7u8LUB6I1sgzA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.2.0.tgz", + "integrity": "sha512-ebXBFrNyMSmbWgjnb3WBloUBK+VSx1xckaXsMXxlZRDqce/OPdYBVN5efB0W3V0defq0Gcy4YuzvPGqRgjj85A==", "dev": true, "requires": { - "chalk": "^2.3.0", + "chalk": "^4.1.0", "enhanced-resolve": "^4.0.0", - "loader-utils": "^1.0.2", + "loader-utils": "^2.0.0", "micromatch": "^4.0.0", - "semver": "^6.0.0" + "semver": "^7.3.4" }, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "lru-cache": "^6.0.0" } } } }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "tty-browserify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", @@ -6168,9 +6805,9 @@ } }, "typescript": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.5.tgz", - "integrity": "sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", + "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", "dev": true }, "union-value": { @@ -6203,6 +6840,12 @@ "imurmurhash": "^0.1.4" } }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -6251,9 +6894,9 @@ "optional": true }, "uri-js": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", - "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "requires": { "punycode": "^2.1.0" @@ -6313,16 +6956,16 @@ "dev": true }, "uuid": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", - "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, "optional": true }, "v8-to-istanbul": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.0.0.tgz", - "integrity": "sha512-fLL2rFuQpMtm9r8hrAV2apXX/WqHJ6+IC4/eQVdMDGBUgH/YMV4Gv3duk3kjmyg6uiQWBAA9nJwue4iJUOkHeA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", + "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.1", @@ -6641,9 +7284,9 @@ "dev": true }, "webpack": { - "version": "4.44.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.2.tgz", - "integrity": "sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q==", + "version": "4.46.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz", + "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", "dev": true, "requires": { "@webassemblyjs/ast": "1.9.0", @@ -6654,7 +7297,7 @@ "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", @@ -6749,6 +7392,26 @@ } } }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, "memory-fs": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", @@ -6818,12 +7481,12 @@ "dev": true }, "whatwg-url": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz", - "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.5.0.tgz", + "integrity": "sha512-fy+R77xWv0AiqfLl4nuGUlQ3/6b5uNfQ4WAbGQVMYshCTCCPK9psC1nWh3XHuxGVCtlcDDQPQW1csmmIQo+fwg==", "dev": true, "requires": { - "lodash.sortby": "^4.7.0", + "lodash": "^4.7.0", "tr46": "^2.0.2", "webidl-conversions": "^6.1.0" } @@ -6888,9 +7551,9 @@ } }, "ws": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.0.tgz", - "integrity": "sha512-kyFwXuV/5ymf+IXhS6f0+eAFvydbaBW3zjpT6hUdAh/hbVjTIB5EHBGi0bPoCLSK2wcuz3BrEkB9LrYv1Nm4NQ==", + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", + "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==", "dev": true }, "xml-name-validator": { @@ -6918,9 +7581,9 @@ "dev": true }, "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, "yargs": { diff --git a/extensions/metrics-cluster-feature/package.json b/extensions/metrics-cluster-feature/package.json index 80a8ddd60a..9a95c5c253 100644 --- a/extensions/metrics-cluster-feature/package.json +++ b/extensions/metrics-cluster-feature/package.json @@ -8,18 +8,21 @@ "styles": [] }, "scripts": { - "build": "webpack --config webpack.config.js", - "dev": "npm run build --watch", - "test": "jest --passWithNoTests --env=jsdom src $@" + "build": "webpack && npm pack", + "dev": "webpack --watch", + "test": "jest --passWithNoTests --env=jsdom src $@", + "clean": "rm -rf dist/ && rm *.tgz" }, + "files": [ + "dist/**/*" + ], "devDependencies": { "@k8slens/extensions": "file:../../src/extensions/npm/extensions", "jest": "^26.6.3", - "mobx": "^5.15.5", - "react": "^16.13.1", "semver": "^7.3.2", "ts-loader": "^8.0.4", "typescript": "^4.0.3", "webpack": "^4.44.2" - } + }, + "dependencies": {} } diff --git a/extensions/metrics-cluster-feature/webpack.config.js b/extensions/metrics-cluster-feature/webpack.config.js index 0c42651e40..463d3acf9f 100644 --- a/extensions/metrics-cluster-feature/webpack.config.js +++ b/extensions/metrics-cluster-feature/webpack.config.js @@ -42,7 +42,8 @@ module.exports = [ { "@k8slens/extensions": "var global.LensExtensions", "react": "var global.React", - "mobx": "var global.Mobx" + "mobx": "var global.Mobx", + "mobx-react": "var global.MobxReact" } ], resolve: { diff --git a/extensions/node-menu/package-lock.json b/extensions/node-menu/package-lock.json index f14f34bf96..4c6f77874a 100644 --- a/extensions/node-menu/package-lock.json +++ b/extensions/node-menu/package-lock.json @@ -4037,15 +4037,6 @@ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", "dev": true }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -4247,12 +4238,6 @@ "minimist": "^1.2.5" } }, - "mobx": { - "version": "5.15.7", - "resolved": "https://registry.npmjs.org/mobx/-/mobx-5.15.7.tgz", - "integrity": "sha512-wyM3FghTkhmC+hQjyPGGFdpehrcX1KOXsDuERhfK2YbJemkUhEB+6wzEN639T21onxlfYBmriA1PFnvxTUhcKw==", - "dev": true - }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -4793,25 +4778,6 @@ "sisteransi": "^1.0.5" } }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - }, - "dependencies": { - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - } - } - }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -4922,17 +4888,6 @@ "safe-buffer": "^5.1.0" } }, - "react": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", - "dev": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" - } - }, "react-is": { "version": "17.0.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", diff --git a/extensions/node-menu/package.json b/extensions/node-menu/package.json index ba76c091d4..c0325ae92d 100644 --- a/extensions/node-menu/package.json +++ b/extensions/node-menu/package.json @@ -8,16 +8,17 @@ "styles": [] }, "scripts": { - "build": "webpack --config webpack.config.js", - "dev": "npm run build --watch", + "build": "webpack && npm pack", + "dev": "webpack --watch", "test": "jest --passWithNoTests --env=jsdom src $@" }, + "files": [ + "dist/**/*" + ], "dependencies": {}, "devDependencies": { "@k8slens/extensions": "file:../../src/extensions/npm/extensions", "jest": "^26.6.3", - "mobx": "^5.15.5", - "react": "^16.13.1", "ts-loader": "^8.0.4", "typescript": "^4.0.3", "webpack": "^4.44.2" diff --git a/extensions/node-menu/webpack.config.js b/extensions/node-menu/webpack.config.js index 33fd38ade7..b49801a1fb 100644 --- a/extensions/node-menu/webpack.config.js +++ b/extensions/node-menu/webpack.config.js @@ -42,7 +42,8 @@ module.exports = [ { "@k8slens/extensions": "var global.LensExtensions", "react": "var global.React", - "mobx": "var global.Mobx" + "mobx": "var global.Mobx", + "mobx-react": "var global.MobxReact" } ], resolve: { diff --git a/extensions/pod-menu/package-lock.json b/extensions/pod-menu/package-lock.json index b5fa04c49f..cc9d63f92c 100644 --- a/extensions/pod-menu/package-lock.json +++ b/extensions/pod-menu/package-lock.json @@ -4674,15 +4674,6 @@ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", "dev": true }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -4884,12 +4875,6 @@ "minimist": "^1.2.5" } }, - "mobx": { - "version": "5.15.7", - "resolved": "https://registry.npmjs.org/mobx/-/mobx-5.15.7.tgz", - "integrity": "sha512-wyM3FghTkhmC+hQjyPGGFdpehrcX1KOXsDuERhfK2YbJemkUhEB+6wzEN639T21onxlfYBmriA1PFnvxTUhcKw==", - "dev": true - }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -5430,25 +5415,6 @@ "sisteransi": "^1.0.5" } }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - }, - "dependencies": { - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - } - } - }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -5559,17 +5525,6 @@ "safe-buffer": "^5.1.0" } }, - "react": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", - "dev": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" - } - }, "react-is": { "version": "17.0.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", diff --git a/extensions/pod-menu/package.json b/extensions/pod-menu/package.json index 8418fdceb9..67e01ac481 100644 --- a/extensions/pod-menu/package.json +++ b/extensions/pod-menu/package.json @@ -8,16 +8,17 @@ "styles": [] }, "scripts": { - "build": "webpack --config webpack.config.js", - "dev": "npm run build --watch", + "build": "webpack && npm pack", + "dev": "webpack --watch", "test": "jest --passWithNoTests --env=jsdom src $@" }, + "files": [ + "dist/**/*" + ], "dependencies": {}, "devDependencies": { "@k8slens/extensions": "file:../../src/extensions/npm/extensions", "jest": "^26.6.3", - "mobx": "^5.15.5", - "react": "^16.13.1", "ts-loader": "^8.0.4", "typescript": "^4.0.3", "webpack": "^4.44.2" diff --git a/extensions/pod-menu/webpack.config.js b/extensions/pod-menu/webpack.config.js index 33fd38ade7..b49801a1fb 100644 --- a/extensions/pod-menu/webpack.config.js +++ b/extensions/pod-menu/webpack.config.js @@ -42,7 +42,8 @@ module.exports = [ { "@k8slens/extensions": "var global.LensExtensions", "react": "var global.React", - "mobx": "var global.Mobx" + "mobx": "var global.Mobx", + "mobx-react": "var global.MobxReact" } ], resolve: { diff --git a/package.json b/package.json index cc4e278557..05b6457357 100644 --- a/package.json +++ b/package.json @@ -98,8 +98,8 @@ "from": "extensions/", "to": "./extensions/", "filter": [ - "**/*.js*", - "**/*.yml*", + "**/*.tgz", + "**/package.json", "!**/node_modules" ] }, diff --git a/src/extensions/extension-discovery.ts b/src/extensions/extension-discovery.ts index fbeac75adc..bc1d5e5331 100644 --- a/src/extensions/extension-discovery.ts +++ b/src/extensions/extension-discovery.ts @@ -342,10 +342,13 @@ export class ExtensionDiscovery extends Singleton { const manifest = await fse.readJson(manifestPath); const installedManifestPath = this.getInstalledManifestPath(manifest.name); const isEnabled = isBundled || ExtensionsStore.getInstance().isEnabled(installedManifestPath); + const extensionDir = path.dirname(manifestPath); + const npmPackage = path.join(extensionDir, `${manifest.name}-${manifest.version}.tgz`); + const absolutePath = (await fse.pathExists(npmPackage)) ? npmPackage : extensionDir; return { id: installedManifestPath, - absolutePath: path.dirname(manifestPath), + absolutePath, manifestPath: installedManifestPath, manifest, isBundled, From 489cef9595a65aa7d716df884a2635a040f747e7 Mon Sep 17 00:00:00 2001 From: Mario Sarcher Date: Wed, 19 May 2021 16:47:58 +0200 Subject: [PATCH 19/21] Docs theme switch fix (#2810) * Fix the theme switch label in mkdocs Signed-off-by: Mario Sarcher --- mkdocs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index ab6b98d7aa..4251845a12 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -62,11 +62,11 @@ theme: - scheme: slate toggle: icon: material/toggle-switch-off-outline - name: Switch to light mode + name: Switch to dark mode - scheme: default toggle: icon: material/toggle-switch - name: Switch to dark mode + name: Switch to light mode features: - toc.autohide - search.suggest From 5ed4537979e05ee22727371393dcc7efda551ef4 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 19 May 2021 12:11:54 -0400 Subject: [PATCH 20/21] Turn on `noUnusedLocals`, `noImplicitReturns`, `importsNotUsedAsValues: error`, and `isolatedModules` (#2777) --- __mocks__/@linguiMacro.ts | 2 +- __mocks__/electron.ts | 2 +- __mocks__/imageMock.ts | 3 +- __mocks__/styleMock.ts | 2 +- integration/__tests__/app.tests.ts | 2 +- integration/__tests__/cluster-pages.tests.ts | 9 ++- .../__tests__/command-palette.tests.ts | 3 +- integration/helpers/minikube.ts | 2 +- src/common/__tests__/search-store.test.ts | 6 ++ src/common/base-store.ts | 2 +- src/common/catalog/catalog-entity-registry.ts | 2 +- src/common/cluster-ipc.ts | 17 +++--- src/common/cluster-store.ts | 4 +- src/common/event-emitter.ts | 9 ++- src/common/ipc/type-enforced-ipc.ts | 4 +- src/common/ipc/update-available.ipc.ts | 2 +- src/common/k8s/resource-stack.ts | 2 +- src/common/kube-helpers.ts | 2 +- src/common/protocol-handler/error.ts | 4 +- src/common/protocol-handler/router.ts | 6 +- src/common/utils/delay.ts | 2 +- src/common/utils/iter.ts | 36 +++++++++++- src/common/utils/saveToAppFiles.ts | 2 +- .../__tests__/extension-loader.test.ts | 2 + src/extensions/extension-loader.ts | 2 + src/extensions/extension-store.ts | 2 +- src/extensions/ipc-store.ts | 2 +- src/extensions/lens-extension.ts | 2 +- src/extensions/lens-main-extension.ts | 4 +- src/extensions/lens-renderer-extension.ts | 4 +- src/extensions/main-ipc-store.ts | 2 +- .../registries/entity-setting-registry.ts | 2 +- .../registries/kube-object-detail-registry.ts | 2 +- .../registries/kube-object-menu-registry.ts | 2 +- .../registries/kube-object-status-registry.ts | 2 +- src/extensions/registries/page-registry.ts | 6 +- .../registries/status-bar-registry.ts | 2 +- src/extensions/renderer-api/k8s-api.ts | 14 +++-- src/extensions/renderer-api/navigation.ts | 2 +- src/extensions/renderer-ipc-store.ts | 2 +- src/main/__test__/kube-auth-proxy.test.ts | 8 ++- src/main/__test__/kubeconfig-manager.test.ts | 14 ++++- src/main/catalog-pusher.ts | 4 +- .../__test__/kubeconfig-sync.test.ts | 4 +- src/main/catalog-sources/kubeconfig-sync.ts | 4 +- .../base-cluster-detector.ts | 4 +- .../cluster-detectors/detector-registry.ts | 6 +- src/main/cluster-manager.ts | 2 +- src/main/context-handler.ts | 11 ++-- src/main/extension-filesystem.ts | 2 +- src/main/helm/__mocks__/helm-chart-manager.ts | 2 +- src/main/helm/helm-release-manager.ts | 2 +- src/main/helm/helm-service.ts | 4 +- src/main/k8s-request.ts | 4 +- src/main/kubeconfig-manager.ts | 3 +- src/main/lens-binary.ts | 4 +- src/main/menu.ts | 2 +- src/main/prometheus/helm.ts | 6 +- src/main/prometheus/lens.ts | 8 +-- src/main/prometheus/operator.ts | 8 +-- src/main/prometheus/provider-registry.ts | 6 +- src/main/prometheus/stacklight.ts | 8 +-- src/main/protocol-handler/router.ts | 2 +- src/main/proxy/index.ts | 2 + src/main/proxy/lens-proxy.ts | 8 +-- src/main/proxy/ws-upgrade.ts | 4 +- src/main/resource-applier.ts | 2 +- src/main/router.ts | 4 +- src/main/routes/helm-route.ts | 2 +- src/main/routes/kubeconfig-route.ts | 4 +- src/main/routes/metrics-route.ts | 4 +- src/main/routes/port-forward-route.ts | 2 +- src/main/routes/resource-applier-route.ts | 2 +- src/main/routes/version-route.ts | 2 +- src/main/shell-session/node-shell-session.ts | 6 +- src/main/shell-session/shell-session.ts | 4 +- src/main/tray.ts | 2 +- src/main/utils/get-port.ts | 2 +- src/main/utils/http-responses.ts | 2 +- src/migrations/cluster-store/snap.ts | 2 +- src/migrations/hotbar-store/5.0.0-alpha.0.ts | 2 +- src/migrations/hotbar-store/5.0.0-alpha.2.ts | 2 +- src/migrations/migration-wrapper.ts | 2 +- src/renderer/api/__tests__/crd.test.ts | 2 +- src/renderer/api/catalog-entity.ts | 9 ++- src/renderer/api/endpoints/configmap.api.ts | 2 +- src/renderer/api/endpoints/cron-job.api.ts | 2 +- src/renderer/api/endpoints/daemon-set.api.ts | 2 +- .../api/endpoints/helm-releases.api.ts | 4 +- src/renderer/api/endpoints/job.api.ts | 10 +--- src/renderer/api/endpoints/metrics.api.ts | 6 +- .../endpoints/persistent-volume-claims.api.ts | 2 +- .../api/endpoints/persistent-volume.api.ts | 6 +- src/renderer/api/endpoints/replica-set.api.ts | 2 +- .../api/endpoints/resource-applier.api.ts | 2 +- .../api/endpoints/resource-quota.api.ts | 2 +- src/renderer/api/endpoints/secret.api.ts | 2 +- .../api/endpoints/stateful-set.api.ts | 2 +- src/renderer/api/kube-api.ts | 4 +- src/renderer/api/kube-object.ts | 6 +- src/renderer/api/kube-watch-api.ts | 4 +- src/renderer/api/terminal-api.ts | 2 +- .../+apps-helm-charts/helm-charts.tsx | 4 +- .../+apps-releases/release-menu.tsx | 4 +- .../+apps-releases/release.store.ts | 4 +- .../components/+apps-releases/releases.tsx | 4 +- .../+catalog/catalog-add-button.tsx | 2 +- .../+catalog/catalog-entity.store.ts | 2 +- .../components/+cluster/cluster-issues.tsx | 2 +- .../components/+cluster/cluster-metrics.tsx | 2 +- .../+config-autoscalers/hpa-details.tsx | 2 +- .../components/+config-autoscalers/hpa.tsx | 6 +- .../limit-range-details.tsx | 2 +- .../+config-limit-ranges/limit-ranges.tsx | 6 +- .../+config-maps/config-map-details.tsx | 6 +- .../components/+config-maps/config-maps.tsx | 6 +- .../pod-disruption-budgets-details.tsx | 4 +- .../pod-disruption-budgets.tsx | 2 +- .../resource-quota-details.tsx | 4 +- .../resource-quotas.tsx | 6 +- .../+config-secrets/add-secret-dialog.tsx | 2 +- .../+config-secrets/secret-details.tsx | 4 +- .../components/+config-secrets/secrets.tsx | 6 +- .../components/+config/config.route.ts | 4 +- .../+custom-resources/crd-details.tsx | 4 +- .../components/+custom-resources/crd-list.tsx | 2 +- .../crd-resource-details.tsx | 4 +- .../+custom-resources/crd-resource.store.ts | 2 +- .../+custom-resources/crd-resources.tsx | 8 +-- .../components/+custom-resources/crd.store.ts | 6 +- .../+entity-settings/entity-settings.tsx | 6 +- .../components/+events/event-details.tsx | 4 +- .../components/+events/event.store.ts | 4 +- src/renderer/components/+events/events.tsx | 6 +- .../components/+events/kube-event-details.tsx | 2 +- .../components/+events/kube-event-icon.tsx | 4 +- .../+extensions/extension-install.store.ts | 3 +- .../+extensions/extensions.route.ts | 2 +- .../components/+extensions/extensions.tsx | 2 +- .../+namespaces/add-namespace-dialog.tsx | 2 +- .../+namespaces/namespace-details.tsx | 4 +- .../+namespaces/namespace-select-filter.tsx | 2 +- .../components/+namespaces/namespaces.tsx | 4 +- .../+network-endpoints/endpoint-details.tsx | 6 +- .../+network-endpoints/endpoints.tsx | 6 +- .../+network-ingresses/ingress-charts.tsx | 4 +- .../+network-ingresses/ingress-details.tsx | 4 +- .../+network-ingresses/ingresses.tsx | 6 +- .../+network-policies/network-policies.tsx | 6 +- .../network-policy-details.tsx | 13 ++--- .../service-details-endpoint.tsx | 2 +- .../+network-services/service-details.tsx | 6 +- .../service-port-component.tsx | 2 +- .../components/+network-services/services.tsx | 6 +- .../components/+network/network.route.ts | 4 +- .../components/+nodes/node-charts.tsx | 4 +- .../components/+nodes/node-details.tsx | 6 +- src/renderer/components/+nodes/nodes.store.ts | 2 +- src/renderer/components/+nodes/nodes.tsx | 10 ++-- .../pod-security-policies.tsx | 2 +- .../pod-security-policy-details.tsx | 6 +- .../storage-class-details.tsx | 4 +- .../+storage-classes/storage-classes.tsx | 6 +- .../volume-claim-details.tsx | 2 +- .../volume-claim-disk-chart.tsx | 2 +- .../+storage-volume-claims/volume-claims.tsx | 4 +- .../+storage-volumes/volume-details-list.tsx | 2 +- .../+storage-volumes/volumes.store.ts | 2 +- .../components/+storage-volumes/volumes.tsx | 4 +- .../components/+storage/storage.route.ts | 4 +- .../add-role-binding-dialog.tsx | 2 +- .../role-binding-details.tsx | 4 +- .../role-bindings.tsx | 6 +- .../+user-management-roles/role-details.tsx | 6 +- .../+user-management-roles/roles.tsx | 6 +- .../service-accounts-secret.tsx | 2 +- .../service-accounts.tsx | 8 +-- .../+workloads-cronjobs/cronjob-details.tsx | 2 +- .../+workloads-cronjobs/cronjobs.tsx | 6 +- .../daemonset-details.tsx | 4 +- .../+workloads-daemonsets/daemonsets.tsx | 6 +- .../deployment-details.tsx | 4 +- .../deployment-replicasets.tsx | 2 +- .../+workloads-deployments/deployments.tsx | 6 +- .../+workloads-jobs/job-details.tsx | 2 +- .../components/+workloads-jobs/jobs.tsx | 6 +- .../overview-workload-status.tsx | 2 +- .../+workloads-overview/overview.tsx | 4 +- .../__tests__/pod-tolerations.test.tsx | 8 ++- .../+workloads-pods/container-charts.tsx | 2 +- .../components/+workloads-pods/pod-charts.tsx | 4 +- .../+workloads-pods/pod-container-env.tsx | 18 +++--- .../+workloads-pods/pod-container-port.tsx | 2 +- .../pod-details-affinities.tsx | 2 +- .../+workloads-pods/pod-details-container.tsx | 6 +- .../+workloads-pods/pod-details-list.tsx | 4 +- .../+workloads-pods/pod-details-statuses.tsx | 2 +- .../pod-details-tolerations.tsx | 2 +- .../+workloads-pods/pod-details.tsx | 2 +- .../+workloads-pods/pod-tolerations.tsx | 2 +- .../components/+workloads-pods/pods.store.ts | 4 +- .../components/+workloads-pods/pods.tsx | 4 +- .../replicaset-details.tsx | 4 +- .../+workloads-replicasets/replicasets.tsx | 8 +-- .../statefulset-details.tsx | 4 +- .../+workloads-statefulsets/statefulsets.tsx | 8 +-- .../components/+workloads/workloads.route.ts | 2 +- .../components/+workloads/workloads.stores.ts | 4 +- src/renderer/components/app.tsx | 4 ++ src/renderer/components/button/button.tsx | 7 +-- src/renderer/components/chart/bar-chart.tsx | 2 +- .../components/chart/zebra-stripes.plugin.ts | 4 +- .../cluster-manager/bottom-bar.test.tsx | 6 ++ .../components/cluster-manager/bottom-bar.tsx | 4 +- .../cluster-manager/cluster-status.tsx | 2 +- .../cluster-manager/cluster-view.tsx | 6 +- .../cluster-settings/cluster-settings.tsx | 2 +- .../cluster-accessible-namespaces.tsx | 2 +- .../components/cluster-home-dir-setting.tsx | 2 +- .../components/cluster-kubeconfig.tsx | 2 +- .../components/cluster-metrics-setting.tsx | 2 +- .../components/cluster-name-setting.tsx | 2 +- .../components/cluster-prometheus-setting.tsx | 2 +- .../components/cluster-proxy-setting.tsx | 2 +- .../components/show-metrics.tsx | 2 +- .../dock/__test__/dock-tabs.test.tsx | 6 ++ .../__test__/log-resource-selector.test.tsx | 8 ++- .../dock/__test__/log-tab.store.test.ts | 5 ++ .../components/dock/create-resource.store.ts | 4 -- .../components/dock/create-resource.tsx | 15 +++-- src/renderer/components/dock/dock-tabs.tsx | 36 +++++------- src/renderer/components/dock/dock.store.ts | 2 +- src/renderer/components/dock/dock.tsx | 40 ++++++++----- .../components/dock/edit-resource.store.ts | 8 +-- .../components/dock/edit-resource.tsx | 6 +- src/renderer/components/dock/editor-panel.tsx | 2 +- src/renderer/components/dock/info-panel.tsx | 2 +- .../components/dock/install-chart.store.ts | 12 ++-- src/renderer/components/dock/log-controls.tsx | 2 +- src/renderer/components/dock/log-list.tsx | 2 +- .../components/dock/log-resource-selector.tsx | 2 +- src/renderer/components/dock/log-tab.store.ts | 6 +- src/renderer/components/dock/log.store.ts | 6 +- src/renderer/components/dock/logs.tsx | 2 +- .../components/dock/terminal-window.tsx | 4 +- .../components/dock/terminal.store.ts | 20 ++----- src/renderer/components/dock/terminal.ts | 2 +- .../components/dock/upgrade-chart.store.ts | 25 +++----- .../components/dock/upgrade-chart.tsx | 8 +-- .../components/hotbar/hotbar-entity-icon.tsx | 2 +- .../components/hotbar/hotbar-icon.tsx | 2 +- src/renderer/components/icon/icon.tsx | 2 +- .../components/input/drop-file-input.tsx | 5 +- src/renderer/components/input/input.tsx | 5 +- .../components/input/input_validators.ts | 2 +- .../components/input/search-input-url.tsx | 2 +- .../item-object-list/item-list-layout.tsx | 16 ++--- .../kube-object-status-icon.tsx | 2 +- .../kube-object/kube-object-details.tsx | 2 +- .../kube-object/kube-object-list-layout.tsx | 4 +- .../kube-object/kube-object-menu.tsx | 4 +- .../kube-object/kube-object-meta.tsx | 2 +- .../kubeconfig-dialog/kubeconfig-dialog.tsx | 2 +- .../components/layout/main-layout-header.tsx | 2 +- .../components/layout/sidebar-item.tsx | 2 +- src/renderer/components/layout/sidebar.tsx | 2 +- src/renderer/components/menu/menu-actions.tsx | 2 +- .../notifications/notifications.store.tsx | 4 +- .../resource-metrics-text.tsx | 2 +- .../resource-metrics/resource-metrics.tsx | 2 +- .../components/scroll-spy/scroll-spy.tsx | 2 +- src/renderer/components/table/table-cell.tsx | 4 +- src/renderer/components/table/table-row.tsx | 2 +- .../components/table/table.storage.ts | 2 +- src/renderer/components/table/table.tsx | 58 ++++++++++--------- .../components/virtual-list/virtual-list.tsx | 4 +- src/renderer/components/wizard/wizard.tsx | 2 +- src/renderer/hooks/useMutationObserver.ts | 2 + src/renderer/hooks/useStorage.ts | 2 +- src/renderer/kube-object.store.ts | 12 ++-- src/renderer/navigation/page-param.ts | 2 +- src/renderer/utils/display-booleans.ts | 2 +- src/renderer/utils/prevDefault.ts | 2 +- src/renderer/utils/rbac.ts | 2 +- tsconfig.json | 6 +- webpack.extensions.ts | 2 +- webpack.main.ts | 2 +- 287 files changed, 704 insertions(+), 628 deletions(-) diff --git a/__mocks__/@linguiMacro.ts b/__mocks__/@linguiMacro.ts index 88be664f85..35fca119d9 100644 --- a/__mocks__/@linguiMacro.ts +++ b/__mocks__/@linguiMacro.ts @@ -18,7 +18,7 @@ * 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. */ -module.exports = { +export default { Trans: ({ children }: { children: React.ReactNode }) => children, t: (message: string) => message }; diff --git a/__mocks__/electron.ts b/__mocks__/electron.ts index 8a8408db88..0a369eea4e 100644 --- a/__mocks__/electron.ts +++ b/__mocks__/electron.ts @@ -18,7 +18,7 @@ * 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. */ -module.exports = { +export default { require: jest.fn(), match: jest.fn(), app: { diff --git a/__mocks__/imageMock.ts b/__mocks__/imageMock.ts index 31effc071f..f80e118413 100644 --- a/__mocks__/imageMock.ts +++ b/__mocks__/imageMock.ts @@ -18,4 +18,5 @@ * 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. */ -module.exports = {}; + +export default {}; diff --git a/__mocks__/styleMock.ts b/__mocks__/styleMock.ts index 31effc071f..375355db28 100644 --- a/__mocks__/styleMock.ts +++ b/__mocks__/styleMock.ts @@ -18,4 +18,4 @@ * 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. */ -module.exports = {}; +export default {}; diff --git a/integration/__tests__/app.tests.ts b/integration/__tests__/app.tests.ts index c3a93200d2..d433513f1e 100644 --- a/integration/__tests__/app.tests.ts +++ b/integration/__tests__/app.tests.ts @@ -25,7 +25,7 @@ TEST_NAMESPACE namespace. This is done to minimize destructive impact of the cluster tests on an existing minikube cluster and vice versa. */ -import { Application } from "spectron"; +import type { Application } from "spectron"; import * as utils from "../helpers/utils"; import { listHelmRepositories } from "../helpers/utils"; import { fail } from "assert"; diff --git a/integration/__tests__/cluster-pages.tests.ts b/integration/__tests__/cluster-pages.tests.ts index e0afc15c4c..ca5e2aaad3 100644 --- a/integration/__tests__/cluster-pages.tests.ts +++ b/integration/__tests__/cluster-pages.tests.ts @@ -18,7 +18,14 @@ * 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 { Application } from "spectron"; + +/* + Cluster tests are run if there is a pre-existing minikube cluster. Before running cluster tests the TEST_NAMESPACE + namespace is removed, if it exists, from the minikube cluster. Resources are created as part of the cluster tests in the + TEST_NAMESPACE namespace. This is done to minimize destructive impact of the cluster tests on an existing minikube + cluster and vice versa. +*/ +import type { Application } from "spectron"; import * as utils from "../helpers/utils"; import { minikubeReady, waitForMinikubeDashboard } from "../helpers/minikube"; import { exec } from "child_process"; diff --git a/integration/__tests__/command-palette.tests.ts b/integration/__tests__/command-palette.tests.ts index 118897b842..03ef6e23ae 100644 --- a/integration/__tests__/command-palette.tests.ts +++ b/integration/__tests__/command-palette.tests.ts @@ -18,7 +18,8 @@ * 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 { Application } from "spectron"; + +import type { Application } from "spectron"; import * as utils from "../helpers/utils"; jest.setTimeout(60000); diff --git a/integration/helpers/minikube.ts b/integration/helpers/minikube.ts index 50e325ccf0..c94b31aa93 100644 --- a/integration/helpers/minikube.ts +++ b/integration/helpers/minikube.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ import { spawnSync } from "child_process"; -import { Application } from "spectron"; +import type { Application } from "spectron"; export function minikubeReady(testNamespace: string): boolean { // determine if minikube is running diff --git a/src/common/__tests__/search-store.test.ts b/src/common/__tests__/search-store.test.ts index ac5f13e7cf..b4c99b7e19 100644 --- a/src/common/__tests__/search-store.test.ts +++ b/src/common/__tests__/search-store.test.ts @@ -23,6 +23,12 @@ import { SearchStore } from "../search-store"; import { Console } from "console"; import { stdout, stderr } from "process"; +jest.mock("electron", () => ({ + app: { + getPath: () => "/foo", + }, +})); + console = new Console(stdout, stderr); let searchStore: SearchStore = null; diff --git a/src/common/base-store.ts b/src/common/base-store.ts index f30a7c7bad..608862c2af 100644 --- a/src/common/base-store.ts +++ b/src/common/base-store.ts @@ -21,7 +21,7 @@ import path from "path"; import Config from "conf"; -import { Options as ConfOptions } from "conf/dist/source/types"; +import type { Options as ConfOptions } from "conf/dist/source/types"; import { app, ipcMain, IpcMainEvent, ipcRenderer, IpcRendererEvent, remote } from "electron"; import { IReactionOptions, observable, reaction, runInAction, when } from "mobx"; import Singleton from "./utils/singleton"; diff --git a/src/common/catalog/catalog-entity-registry.ts b/src/common/catalog/catalog-entity-registry.ts index 7438a43949..80a6c66a4c 100644 --- a/src/common/catalog/catalog-entity-registry.ts +++ b/src/common/catalog/catalog-entity-registry.ts @@ -20,7 +20,7 @@ */ import { action, computed, observable, IComputedValue, IObservableArray } from "mobx"; -import { CatalogEntity } from "./catalog-entity"; +import type { CatalogEntity } from "./catalog-entity"; import { iter } from "../utils"; export class CatalogEntityRegistry { diff --git a/src/common/cluster-ipc.ts b/src/common/cluster-ipc.ts index 863ddafcd0..718151c3ed 100644 --- a/src/common/cluster-ipc.ts +++ b/src/common/cluster-ipc.ts @@ -35,11 +35,9 @@ export const clusterKubectlDeleteAllHandler = "cluster:kubectl-delete-all"; if (ipcMain) { handleRequest(clusterActivateHandler, (event, clusterId: ClusterId, force = false) => { - const cluster = ClusterStore.getInstance().getById(clusterId); - - if (cluster) { - return cluster.activate(force); - } + return ClusterStore.getInstance() + .getById(clusterId) + ?.activate(force); }); handleRequest(clusterSetFrameIdHandler, (event: IpcMainInvokeEvent, clusterId: ClusterId) => { @@ -47,15 +45,14 @@ if (ipcMain) { if (cluster) { clusterFrameMap.set(cluster.id, { frameId: event.frameId, processId: event.processId }); - - return cluster.pushState(); + cluster.pushState(); } }); handleRequest(clusterRefreshHandler, (event, clusterId: ClusterId) => { - const cluster = ClusterStore.getInstance().getById(clusterId); - - if (cluster) return cluster.refresh({ refreshMetadata: true }); + return ClusterStore.getInstance() + .getById(clusterId) + ?.refresh({ refreshMetadata: true }); }); handleRequest(clusterDisconnectHandler, (event, clusterId: ClusterId) => { diff --git a/src/common/cluster-store.ts b/src/common/cluster-store.ts index 40c2168818..89c71255c2 100644 --- a/src/common/cluster-store.ts +++ b/src/common/cluster-store.ts @@ -30,9 +30,9 @@ import logger from "../main/logger"; import { appEventBus } from "./event-bus"; import { dumpConfigYaml } from "./kube-helpers"; import { saveToAppFiles } from "./utils/saveToAppFiles"; -import { KubeConfig } from "@kubernetes/client-node"; +import type { KubeConfig } from "@kubernetes/client-node"; import { handleRequest, requestMain, subscribeToBroadcast, unsubscribeAllFromBroadcast } from "./ipc"; -import { ResourceType } from "../renderer/components/cluster-settings/components/cluster-metrics-setting"; +import type { ResourceType } from "../renderer/components/cluster-settings/components/cluster-metrics-setting"; import { disposer, noop } from "./utils"; export interface ClusterIconUpload { diff --git a/src/common/event-emitter.ts b/src/common/event-emitter.ts index 628a37d44a..5ff785d431 100644 --- a/src/common/event-emitter.ts +++ b/src/common/event-emitter.ts @@ -53,12 +53,11 @@ export class EventEmitter { emit(...data: D) { [...this.listeners].every(([callback, options]) => { - if (options.once) this.removeListener(callback); - const result = callback(...data); + if (options.once) { + this.removeListener(callback); + } - if (result === false) return; // break cycle - - return true; + return callback(...data) !== false; }); } } diff --git a/src/common/ipc/type-enforced-ipc.ts b/src/common/ipc/type-enforced-ipc.ts index 035ffcd77e..a490b1d384 100644 --- a/src/common/ipc/type-enforced-ipc.ts +++ b/src/common/ipc/type-enforced-ipc.ts @@ -19,10 +19,10 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +import type { EventEmitter } from "events"; import { ipcMain } from "electron"; -import { EventEmitter } from "events"; import logger from "../../main/logger"; -import { Disposer } from "../utils"; +import type { Disposer } from "../utils"; export type ListenerEvent = Parameters[1]>[0]; export type ListVerifier = (args: unknown[]) => args is T; diff --git a/src/common/ipc/update-available.ipc.ts b/src/common/ipc/update-available.ipc.ts index 5fc1a17954..87ec740f44 100644 --- a/src/common/ipc/update-available.ipc.ts +++ b/src/common/ipc/update-available.ipc.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { UpdateInfo } from "electron-updater"; +import type { UpdateInfo } from "electron-updater"; export const UpdateAvailableChannel = "update-available"; export const AutoUpdateLogPrefix = "[UPDATE-CHECKER]"; diff --git a/src/common/k8s/resource-stack.ts b/src/common/k8s/resource-stack.ts index 01c7ee84b8..9ea9d2609f 100644 --- a/src/common/k8s/resource-stack.ts +++ b/src/common/k8s/resource-stack.ts @@ -22,7 +22,7 @@ import fse from "fs-extra"; import path from "path"; import hb from "handlebars"; import { ResourceApplier } from "../../main/resource-applier"; -import { KubernetesCluster } from "../catalog-entities"; +import type { KubernetesCluster } from "../catalog-entities"; import logger from "../../main/logger"; import { app } from "electron"; import { requestMain } from "../ipc"; diff --git a/src/common/kube-helpers.ts b/src/common/kube-helpers.ts index 0c2bde47e6..737c767cf2 100644 --- a/src/common/kube-helpers.ts +++ b/src/common/kube-helpers.ts @@ -230,7 +230,7 @@ export function getNodeWarningConditions(node: V1Node) { * * Note: This function returns an error instead of throwing it, returning `undefined` if the validation passes */ -export function validateKubeConfig(config: KubeConfig, contextName: string, validationOpts: KubeConfigValidationOpts = {}): Error | undefined { +export function validateKubeConfig(config: KubeConfig, contextName: string, validationOpts: KubeConfigValidationOpts = {}): Error | void { try { // we only receive a single context, cluster & user object here so lets validate them as this // will be called when we add a new cluster to Lens diff --git a/src/common/protocol-handler/error.ts b/src/common/protocol-handler/error.ts index c36106ae7a..c08d867766 100644 --- a/src/common/protocol-handler/error.ts +++ b/src/common/protocol-handler/error.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import Url from "url-parse"; +import type Url from "url-parse"; export enum RoutingErrorType { INVALID_PROTOCOL = "invalid-protocol", @@ -52,6 +52,8 @@ export class RoutingError extends Error { return "no extension ID"; case RoutingErrorType.MISSING_EXTENSION: return "extension not found"; + default: + return `unknown error: ${this.type}`; } } } diff --git a/src/common/protocol-handler/router.ts b/src/common/protocol-handler/router.ts index 30facd7649..59101b5aa7 100644 --- a/src/common/protocol-handler/router.ts +++ b/src/common/protocol-handler/router.ts @@ -24,12 +24,12 @@ import { countBy } from "lodash"; import { Singleton } from "../utils"; import { pathToRegexp } from "path-to-regexp"; import logger from "../../main/logger"; -import Url from "url-parse"; +import type Url from "url-parse"; import { RoutingError, RoutingErrorType } from "./error"; import { ExtensionsStore } from "../../extensions/extensions-store"; import { ExtensionLoader } from "../../extensions/extension-loader"; -import { LensExtension } from "../../extensions/lens-extension"; -import { RouteHandler, RouteParams } from "../../extensions/registries/protocol-handler-registry"; +import type { LensExtension } from "../../extensions/lens-extension"; +import type { RouteHandler, RouteParams } from "../../extensions/registries/protocol-handler-registry"; // IPC channel for protocol actions. Main broadcasts the open-url events to this channel. export const ProtocolHandlerIpcPrefix = "protocol-handler"; diff --git a/src/common/utils/delay.ts b/src/common/utils/delay.ts index c79d616dfe..409daca125 100644 --- a/src/common/utils/delay.ts +++ b/src/common/utils/delay.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { AbortController } from "abort-controller"; +import type { AbortController } from "abort-controller"; /** * Return a promise that will be resolved after at least `timeout` ms have diff --git a/src/common/utils/iter.ts b/src/common/utils/iter.ts index 5a7daaaecb..277c58213e 100644 --- a/src/common/utils/iter.ts +++ b/src/common/utils/iter.ts @@ -19,6 +19,8 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +export type Falsey = false | 0 | "" | null | undefined; + /** * Create a new type safe empty Iterable * @returns An `Iterable` that yields 0 items @@ -57,6 +59,36 @@ export function* map(src: Iterable, fn: (from: T) => U): Iterable { } } +/** + * The single layer flattening of an iterator, discarding `Falsey` values. + * @param src A type that can be iterated over + * @param fn The function that returns either an iterable over items that should be filtered out or a `Falsey` value indicating that it should be ignored + */ +export function* filterFlatMap(src: Iterable, fn: (from: T) => Iterable | Falsey): Iterable { + for (const from of src) { + if (!from) { + continue; + } + + const mapping = fn(from); + + if (!mapping) { + continue; + } + + for (const mapped of mapping) { + if (mapped) { + yield mapped; + } + } + } +} + +/** + * Returns a new iterator that yields the items that each call to `fn` would produce + * @param src A type that can be iterated over + * @param fn A function that returns an iterator + */ export function* flatMap(src: Iterable, fn: (from: T) => Iterable): Iterable { for (const from of src) { yield* fn(from); @@ -83,7 +115,7 @@ export function* filter(src: Iterable, fn: (from: T) => any): Iterable * @param src A type that can be iterated over * @param fn The function that is called for each value */ -export function* filterMap(src: Iterable, fn: (from: T) => U): Iterable { +export function* filterMap(src: Iterable, fn: (from: T) => U | Falsey): Iterable { for (const from of src) { const res = fn(from); @@ -99,7 +131,7 @@ export function* filterMap(src: Iterable, fn: (from: T) => U): Iterable * @param src A type that can be iterated over * @param fn The function that is called for each value */ -export function* filterMapStrict(src: Iterable, fn: (from: T) => U): Iterable { +export function* filterMapStrict(src: Iterable, fn: (from: T) => U | null | undefined): Iterable { for (const from of src) { const res = fn(from); diff --git a/src/common/utils/saveToAppFiles.ts b/src/common/utils/saveToAppFiles.ts index f5e1710379..b957cdb38e 100644 --- a/src/common/utils/saveToAppFiles.ts +++ b/src/common/utils/saveToAppFiles.ts @@ -23,7 +23,7 @@ import path from "path"; import { app, remote } from "electron"; import { ensureDirSync, writeFileSync } from "fs-extra"; -import { WriteFileOptions } from "fs"; +import type { WriteFileOptions } from "fs"; export function saveToAppFiles(filePath: string, contents: any, options?: WriteFileOptions): string { const absPath = path.resolve((app || remote.app).getPath("userData"), filePath); diff --git a/src/extensions/__tests__/extension-loader.test.ts b/src/extensions/__tests__/extension-loader.test.ts index f0a631c2ee..5e0844d02d 100644 --- a/src/extensions/__tests__/extension-loader.test.ts +++ b/src/extensions/__tests__/extension-loader.test.ts @@ -77,6 +77,8 @@ jest.mock( ], ]; } + + return []; }), on: jest.fn( (channel: string, listener: (event: any, ...args: any[]) => void) => { diff --git a/src/extensions/extension-loader.ts b/src/extensions/extension-loader.ts index bbb62aec87..b024ddd761 100644 --- a/src/extensions/extension-loader.ts +++ b/src/extensions/extension-loader.ts @@ -325,6 +325,8 @@ export class ExtensionLoader extends Singleton { } catch (error) { logger.error(`${logModule}: can't load extension main at ${extAbsolutePath}: ${error}`, { extension, error }); } + + return null; } getExtension(extId: LensExtensionId): InstalledExtension { diff --git a/src/extensions/extension-store.ts b/src/extensions/extension-store.ts index 7317706691..2c5eb44262 100644 --- a/src/extensions/extension-store.ts +++ b/src/extensions/extension-store.ts @@ -21,7 +21,7 @@ import { BaseStore } from "../common/base-store"; import * as path from "path"; -import { LensExtension } from "./lens-extension"; +import type { LensExtension } from "./lens-extension"; export abstract class ExtensionStore extends BaseStore { protected extension: LensExtension; diff --git a/src/extensions/ipc-store.ts b/src/extensions/ipc-store.ts index 541f7b2914..275522338c 100644 --- a/src/extensions/ipc-store.ts +++ b/src/extensions/ipc-store.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ import { Singleton } from "../common/utils"; -import { LensExtension } from "./lens-extension"; +import type { LensExtension } from "./lens-extension"; import { createHash } from "crypto"; import { broadcastMessage } from "../common/ipc"; diff --git a/src/extensions/lens-extension.ts b/src/extensions/lens-extension.ts index d9df2c9993..b6faf2e491 100644 --- a/src/extensions/lens-extension.ts +++ b/src/extensions/lens-extension.ts @@ -23,7 +23,7 @@ import type { InstalledExtension } from "./extension-discovery"; import { action, observable, reaction } from "mobx"; import { FilesystemProvisionerStore } from "../main/extension-filesystem"; import logger from "../main/logger"; -import { ProtocolHandlerRegistration } from "./registries"; +import type { ProtocolHandlerRegistration } from "./registries"; import { disposer } from "../common/utils"; export type LensExtensionId = string; // path to manifest (package.json) diff --git a/src/extensions/lens-main-extension.ts b/src/extensions/lens-main-extension.ts index b02456c6d4..7e0ac71707 100644 --- a/src/extensions/lens-main-extension.ts +++ b/src/extensions/lens-main-extension.ts @@ -23,8 +23,8 @@ import { LensExtension } from "./lens-extension"; import { WindowManager } from "../main/window-manager"; import { getExtensionPageUrl } from "./registries/page-registry"; import { CatalogEntity, catalogEntityRegistry } from "../common/catalog"; -import { IObservableArray } from "mobx"; -import { MenuRegistration } from "./registries"; +import type { IObservableArray } from "mobx"; +import type { MenuRegistration } from "./registries"; export class LensMainExtension extends LensExtension { appMenus: MenuRegistration[] = []; diff --git a/src/extensions/lens-renderer-extension.ts b/src/extensions/lens-renderer-extension.ts index 232040ac9f..520ffae05b 100644 --- a/src/extensions/lens-renderer-extension.ts +++ b/src/extensions/lens-renderer-extension.ts @@ -26,8 +26,8 @@ import type { import type { Cluster } from "../main/cluster"; import { LensExtension } from "./lens-extension"; import { getExtensionPageUrl } from "./registries/page-registry"; -import { CommandRegistration } from "./registries/command-registry"; -import { EntitySettingRegistration } from "./registries/entity-setting-registry"; +import type { CommandRegistration } from "./registries/command-registry"; +import type { EntitySettingRegistration } from "./registries/entity-setting-registry"; export class LensRendererExtension extends LensExtension { globalPages: PageRegistration[] = []; diff --git a/src/extensions/main-ipc-store.ts b/src/extensions/main-ipc-store.ts index 1f9241a8b1..664fc0d965 100644 --- a/src/extensions/main-ipc-store.ts +++ b/src/extensions/main-ipc-store.ts @@ -21,7 +21,7 @@ import { ipcMain } from "electron"; import { IpcPrefix, IpcStore } from "./ipc-store"; import { Disposers } from "./lens-extension"; -import { LensMainExtension } from "./lens-main-extension"; +import type { LensMainExtension } from "./lens-main-extension"; export abstract class MainIpcStore extends IpcStore { constructor(extension: LensMainExtension) { diff --git a/src/extensions/registries/entity-setting-registry.ts b/src/extensions/registries/entity-setting-registry.ts index 4854b97006..80b20196c3 100644 --- a/src/extensions/registries/entity-setting-registry.ts +++ b/src/extensions/registries/entity-setting-registry.ts @@ -20,7 +20,7 @@ */ import type React from "react"; -import { CatalogEntity } from "../../common/catalog"; +import type { CatalogEntity } from "../../common/catalog"; import { BaseRegistry } from "./base-registry"; export interface EntitySettingViewProps { diff --git a/src/extensions/registries/kube-object-detail-registry.ts b/src/extensions/registries/kube-object-detail-registry.ts index 87e2338725..7cc17bbc7e 100644 --- a/src/extensions/registries/kube-object-detail-registry.ts +++ b/src/extensions/registries/kube-object-detail-registry.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import React from "react"; +import type React from "react"; import { BaseRegistry } from "./base-registry"; export interface KubeObjectDetailComponents { diff --git a/src/extensions/registries/kube-object-menu-registry.ts b/src/extensions/registries/kube-object-menu-registry.ts index c5606c3566..414d55db59 100644 --- a/src/extensions/registries/kube-object-menu-registry.ts +++ b/src/extensions/registries/kube-object-menu-registry.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import React from "react"; +import type React from "react"; import { BaseRegistry } from "./base-registry"; export interface KubeObjectMenuComponents { diff --git a/src/extensions/registries/kube-object-status-registry.ts b/src/extensions/registries/kube-object-status-registry.ts index 406b4b05f7..85373a25fd 100644 --- a/src/extensions/registries/kube-object-status-registry.ts +++ b/src/extensions/registries/kube-object-status-registry.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { KubeObject, KubeObjectStatus } from "../renderer-api/k8s-api"; +import type { KubeObject, KubeObjectStatus } from "../renderer-api/k8s-api"; import { BaseRegistry } from "./base-registry"; export interface KubeObjectStatusRegistration { diff --git a/src/extensions/registries/page-registry.ts b/src/extensions/registries/page-registry.ts index 6173527a3e..cff1c2d474 100644 --- a/src/extensions/registries/page-registry.ts +++ b/src/extensions/registries/page-registry.ts @@ -25,7 +25,7 @@ import React from "react"; import { observer } from "mobx-react"; import { BaseRegistry } from "./base-registry"; import { LensExtension, sanitizeExtensionName } from "../lens-extension"; -import { PageParam, PageParamInit } from "../../renderer/navigation/page-param"; +import type { PageParam, PageParamInit } from "../../renderer/navigation/page-param"; import { createPageParam } from "../../renderer/navigation/helpers"; export interface PageRegistration { @@ -119,9 +119,9 @@ export class PageRegistry extends BaseRegistry return components; } - protected normalizeParams(params?: PageParams): PageParams { + protected normalizeParams(params?: PageParams): PageParams | undefined { if (!params) { - return; + return undefined; } Object.entries(params).forEach(([name, value]) => { const paramInit: PageParamInit = typeof value === "object" diff --git a/src/extensions/registries/status-bar-registry.ts b/src/extensions/registries/status-bar-registry.ts index 3b91946988..0814f9cc7a 100644 --- a/src/extensions/registries/status-bar-registry.ts +++ b/src/extensions/registries/status-bar-registry.ts @@ -21,7 +21,7 @@ // Extensions API -> Status bar customizations -import React from "react"; +import type React from "react"; import { BaseRegistry } from "./base-registry"; interface StatusBarComponents { diff --git a/src/extensions/renderer-api/k8s-api.ts b/src/extensions/renderer-api/k8s-api.ts index 511597ba57..d16dbe83f5 100644 --- a/src/extensions/renderer-api/k8s-api.ts +++ b/src/extensions/renderer-api/k8s-api.ts @@ -23,9 +23,9 @@ export { isAllowedResource } from "../../common/rbac"; export { ResourceStack } from "../../common/k8s/resource-stack"; export { apiManager } from "../../renderer/api/api-manager"; export { KubeObjectStore } from "../../renderer/kube-object.store"; -export { KubeApi, forCluster, IKubeApiCluster } from "../../renderer/api/kube-api"; +export { KubeApi, forCluster } from "../../renderer/api/kube-api"; export { KubeObject } from "../../renderer/api/kube-object"; -export { Pod, podsApi, PodsApi, IPodContainer, IPodContainerStatus } from "../../renderer/api/endpoints"; +export { Pod, podsApi, PodsApi } from "../../renderer/api/endpoints"; export { Node, nodesApi, NodesApi } from "../../renderer/api/endpoints"; export { Deployment, deploymentApi, DeploymentApi } from "../../renderer/api/endpoints"; export { DaemonSet, daemonSetApi } from "../../renderer/api/endpoints"; @@ -33,7 +33,7 @@ export { StatefulSet, statefulSetApi } from "../../renderer/api/endpoints"; export { Job, jobApi } from "../../renderer/api/endpoints"; export { CronJob, cronJobApi } from "../../renderer/api/endpoints"; export { ConfigMap, configMapApi } from "../../renderer/api/endpoints"; -export { Secret, secretsApi, ISecretRef } from "../../renderer/api/endpoints"; +export { Secret, secretsApi } from "../../renderer/api/endpoints"; export { ReplicaSet, replicaSetApi } from "../../renderer/api/endpoints"; export { ResourceQuota, resourceQuotaApi } from "../../renderer/api/endpoints"; export { LimitRange, limitRangeApi } from "../../renderer/api/endpoints"; @@ -54,7 +54,13 @@ export { RoleBinding, roleBindingApi } from "../../renderer/api/endpoints"; export { ClusterRole, clusterRoleApi } from "../../renderer/api/endpoints"; export { ClusterRoleBinding, clusterRoleBindingApi } from "../../renderer/api/endpoints"; export { CustomResourceDefinition, crdApi } from "../../renderer/api/endpoints"; -export { KubeObjectStatus, KubeObjectStatusLevel } from "./kube-object-status"; +export { KubeObjectStatusLevel } from "./kube-object-status"; + +// types +export type { IKubeApiCluster } from "../../renderer/api/kube-api"; +export type { IPodContainer, IPodContainerStatus } from "../../renderer/api/endpoints"; +export type { ISecretRef } from "../../renderer/api/endpoints"; +export type { KubeObjectStatus } from "./kube-object-status"; // stores export type { EventStore } from "../../renderer/components/+events/event.store"; diff --git a/src/extensions/renderer-api/navigation.ts b/src/extensions/renderer-api/navigation.ts index f0a279227d..f8a338ac3f 100644 --- a/src/extensions/renderer-api/navigation.ts +++ b/src/extensions/renderer-api/navigation.ts @@ -25,7 +25,7 @@ import { navigation } from "../../renderer/navigation"; export type { PageParamInit, PageParam } from "../../renderer/navigation/page-param"; export { navigate, isActiveRoute } from "../../renderer/navigation/helpers"; export { hideDetails, showDetails, getDetailsUrl } from "../../renderer/components/kube-object/kube-object-details"; -export { IURLParams } from "../../common/utils/buildUrl"; +export type { IURLParams } from "../../common/utils/buildUrl"; // exporting to extensions-api version of helper without `isSystem` flag export function createPageParam(init: PageParamInit) { diff --git a/src/extensions/renderer-ipc-store.ts b/src/extensions/renderer-ipc-store.ts index 930027d0e2..75824fece7 100644 --- a/src/extensions/renderer-ipc-store.ts +++ b/src/extensions/renderer-ipc-store.ts @@ -21,7 +21,7 @@ import { ipcRenderer } from "electron"; import { IpcPrefix, IpcStore } from "./ipc-store"; import { Disposers } from "./lens-extension"; -import { LensRendererExtension } from "./lens-renderer-extension"; +import type { LensRendererExtension } from "./lens-renderer-extension"; export abstract class RendererIpcStore extends IpcStore { constructor(extension: LensRendererExtension) { diff --git a/src/main/__test__/kube-auth-proxy.test.ts b/src/main/__test__/kube-auth-proxy.test.ts index 080fd84c45..5006859637 100644 --- a/src/main/__test__/kube-auth-proxy.test.ts +++ b/src/main/__test__/kube-auth-proxy.test.ts @@ -44,6 +44,12 @@ jest.mock("winston", () => ({ } })); +jest.mock("electron", () => ({ + app: { + getPath: () => "/foo", + }, +})); + jest.mock("../../common/ipc"); jest.mock("child_process"); jest.mock("tcp-port-used"); @@ -56,7 +62,7 @@ import { ChildProcess, spawn } from "child_process"; import { bundledKubectlPath, Kubectl } from "../kubectl"; import { mock, MockProxy } from "jest-mock-extended"; import { waitUntilUsed } from "tcp-port-used"; -import { Readable } from "stream"; +import type { Readable } from "stream"; import { UserStore } from "../../common/user-store"; import { Console } from "console"; import { stdout, stderr } from "process"; diff --git a/src/main/__test__/kubeconfig-manager.test.ts b/src/main/__test__/kubeconfig-manager.test.ts index 011d0097d1..0d0bab04ad 100644 --- a/src/main/__test__/kubeconfig-manager.test.ts +++ b/src/main/__test__/kubeconfig-manager.test.ts @@ -28,6 +28,12 @@ const logger = { crit: jest.fn(), }; +jest.mock("electron", () => ({ + app: { + getPath: () => `/tmp`, + }, +})); + jest.mock("winston", () => ({ format: { colorize: jest.fn(), @@ -47,7 +53,7 @@ jest.mock("winston", () => ({ import { KubeconfigManager } from "../kubeconfig-manager"; import mockFs from "mock-fs"; import { Cluster } from "../cluster"; -import { ContextHandler } from "../context-handler"; +import type { ContextHandler } from "../context-handler"; import fse from "fs-extra"; import { loadYaml } from "@kubernetes/client-node"; import { Console } from "console"; @@ -91,7 +97,9 @@ describe("kubeconfig manager tests", () => { contextName: "minikube", kubeConfigPath: "minikube-config.yml", }); - contextHandler = jest.fn() as any; + contextHandler = { + ensureServer: () => Promise.resolve(), + } as any; jest.spyOn(KubeconfigManager.prototype, "resolveProxyUrl", "get").mockReturnValue("http://127.0.0.1:9191/foo"); }); @@ -103,7 +111,7 @@ describe("kubeconfig manager tests", () => { const kubeConfManager = new KubeconfigManager(cluster, contextHandler); expect(logger.error).not.toBeCalled(); - expect(await kubeConfManager.getPath()).toBe(`tmp${path.sep}kubeconfig-foo`); + expect(await kubeConfManager.getPath()).toBe(`${path.sep}tmp${path.sep}kubeconfig-foo`); // this causes an intermittent "ENXIO: no such device or address, read" error // const file = await fse.readFile(await kubeConfManager.getPath()); const file = fse.readFileSync(await kubeConfManager.getPath()); diff --git a/src/main/catalog-pusher.ts b/src/main/catalog-pusher.ts index 8d0b750ec6..362ba9a770 100644 --- a/src/main/catalog-pusher.ts +++ b/src/main/catalog-pusher.ts @@ -21,9 +21,9 @@ import { reaction, toJS } from "mobx"; import { broadcastMessage, subscribeToBroadcast, unsubscribeFromBroadcast } from "../common/ipc"; -import { CatalogEntityRegistry} from "../common/catalog"; +import type { CatalogEntityRegistry} from "../common/catalog"; import "../common/catalog-entities/kubernetes-cluster"; -import { Disposer } from "../common/utils"; +import type { Disposer } from "../common/utils"; export class CatalogPusher { static init(catalog: CatalogEntityRegistry) { diff --git a/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts b/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts index 80d7392eed..6f89e12c46 100644 --- a/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts +++ b/src/main/catalog-sources/__test__/kubeconfig-sync.test.ts @@ -20,9 +20,9 @@ */ import { ObservableMap } from "mobx"; -import { CatalogEntity } from "../../../common/catalog"; +import type { CatalogEntity } from "../../../common/catalog"; import { loadFromOptions } from "../../../common/kube-helpers"; -import { Cluster } from "../../cluster"; +import type { Cluster } from "../../cluster"; import { computeDiff, configToModels } from "../kubeconfig-sync"; import mockFs from "mock-fs"; import fs from "fs"; diff --git a/src/main/catalog-sources/kubeconfig-sync.ts b/src/main/catalog-sources/kubeconfig-sync.ts index ee22a748d9..c4a8b0a514 100644 --- a/src/main/catalog-sources/kubeconfig-sync.ts +++ b/src/main/catalog-sources/kubeconfig-sync.ts @@ -24,10 +24,10 @@ import { CatalogEntity, catalogEntityRegistry } from "../../common/catalog"; import { watch } from "chokidar"; import fs from "fs"; import fse from "fs-extra"; -import stream from "stream"; +import type stream from "stream"; import { Disposer, ExtendedObservableMap, iter, Singleton } from "../../common/utils"; import logger from "../logger"; -import { KubeConfig } from "@kubernetes/client-node"; +import type { KubeConfig } from "@kubernetes/client-node"; import { loadConfigFromString, splitConfig, validateKubeConfig } from "../../common/kube-helpers"; import { Cluster } from "../cluster"; import { catalogEntityFromCluster } from "../cluster-manager"; diff --git a/src/main/cluster-detectors/base-cluster-detector.ts b/src/main/cluster-detectors/base-cluster-detector.ts index 4f01698968..1edd971cfd 100644 --- a/src/main/cluster-detectors/base-cluster-detector.ts +++ b/src/main/cluster-detectors/base-cluster-detector.ts @@ -19,8 +19,8 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { RequestPromiseOptions } from "request-promise-native"; -import { Cluster } from "../cluster"; +import type { RequestPromiseOptions } from "request-promise-native"; +import type { Cluster } from "../cluster"; import { k8sRequest } from "../k8s-request"; export type ClusterDetectionResult = { diff --git a/src/main/cluster-detectors/detector-registry.ts b/src/main/cluster-detectors/detector-registry.ts index ba49d10f9e..82a09059e3 100644 --- a/src/main/cluster-detectors/detector-registry.ts +++ b/src/main/cluster-detectors/detector-registry.ts @@ -20,9 +20,9 @@ */ import { observable } from "mobx"; -import { ClusterMetadata } from "../../common/cluster-store"; -import { Cluster } from "../cluster"; -import { BaseClusterDetector, ClusterDetectionResult } from "./base-cluster-detector"; +import type { ClusterMetadata } from "../../common/cluster-store"; +import type { Cluster } from "../cluster"; +import type { BaseClusterDetector, ClusterDetectionResult } from "./base-cluster-detector"; import { ClusterIdDetector } from "./cluster-id-detector"; import { DistributionDetector } from "./distribution-detector"; import { LastSeenDetector } from "./last-seen-detector"; diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index 0d8cd3535c..211172a2a6 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -24,7 +24,7 @@ import type http from "http"; import { ipcMain } from "electron"; import { action, autorun, reaction, toJS } from "mobx"; import { ClusterStore, getClusterIdFromHost } from "../common/cluster-store"; -import { Cluster } from "./cluster"; +import type { Cluster } from "./cluster"; import logger from "./logger"; import { apiKubePrefix } from "../common/vars"; import { Singleton } from "../common/utils"; diff --git a/src/main/context-handler.ts b/src/main/context-handler.ts index f122c68e7c..6fa7ca1ef5 100644 --- a/src/main/context-handler.ts +++ b/src/main/context-handler.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import type { PrometheusProvider, PrometheusService } from "./prometheus/provider-registry"; +import type { PrometheusService } from "./prometheus/provider-registry"; import type { ClusterPrometheusPreferences } from "../common/cluster-store"; import type { Cluster } from "./cluster"; import type httpProxy from "http-proxy"; @@ -75,16 +75,15 @@ export class ContextHandler { return prometheusProviders.find(p => p.id === this.prometheusProvider); } - async getPrometheusService(): Promise { + async getPrometheusService(): Promise { const providers = this.prometheusProvider ? prometheusProviders.filter(provider => provider.id == this.prometheusProvider) : prometheusProviders; - const prometheusPromises: Promise[] = providers.map(async (provider: PrometheusProvider): Promise => { + const prometheusPromises: Promise[] = providers.map(async provider => { const apiClient = (await this.cluster.getProxyKubeconfig()).makeApiClient(CoreV1Api); - return await provider.getPrometheusService(apiClient); + return provider.getPrometheusService(apiClient); }); - const resolvedPrometheusServices = await Promise.all(prometheusPromises); - return resolvedPrometheusServices.filter(n => n)[0]; + return (await Promise.all(prometheusPromises)).find(Boolean); } async getPrometheusPath(): Promise { diff --git a/src/main/extension-filesystem.ts b/src/main/extension-filesystem.ts index 87aa67c435..5321bc791e 100644 --- a/src/main/extension-filesystem.ts +++ b/src/main/extension-filesystem.ts @@ -26,7 +26,7 @@ import fse from "fs-extra"; import { action, observable, toJS } from "mobx"; import path from "path"; import { BaseStore } from "../common/base-store"; -import { LensExtensionId } from "../extensions/lens-extension"; +import type { LensExtensionId } from "../extensions/lens-extension"; interface FSProvisionModel { extensions: Record; // extension names to paths diff --git a/src/main/helm/__mocks__/helm-chart-manager.ts b/src/main/helm/__mocks__/helm-chart-manager.ts index 8cc43e1172..7d4a5e2a65 100644 --- a/src/main/helm/__mocks__/helm-chart-manager.ts +++ b/src/main/helm/__mocks__/helm-chart-manager.ts @@ -22,7 +22,7 @@ import { HelmRepo, HelmRepoManager } from "../helm-repo-manager"; export class HelmChartManager { - private cache: any = {}; + cache: any = {}; private repo: HelmRepo; constructor(repo: HelmRepo){ diff --git a/src/main/helm/helm-release-manager.ts b/src/main/helm/helm-release-manager.ts index e35fc23b10..852c649ede 100644 --- a/src/main/helm/helm-release-manager.ts +++ b/src/main/helm/helm-release-manager.ts @@ -24,7 +24,7 @@ import fse from "fs-extra"; import * as yaml from "js-yaml"; import { promiseExec} from "../promise-exec"; import { helmCli } from "./helm-cli"; -import { Cluster } from "../cluster"; +import type { Cluster } from "../cluster"; import { toCamelCase } from "../../common/utils/camelCase"; export async function listReleases(pathToKubeconfig: string, namespace?: string) { diff --git a/src/main/helm/helm-service.ts b/src/main/helm/helm-service.ts index 2af6e7a347..73e93e5ac1 100644 --- a/src/main/helm/helm-service.ts +++ b/src/main/helm/helm-service.ts @@ -20,11 +20,11 @@ */ import semver from "semver"; -import { Cluster } from "../cluster"; +import type { Cluster } from "../cluster"; import logger from "../logger"; import { HelmRepoManager } from "./helm-repo-manager"; import { HelmChartManager } from "./helm-chart-manager"; -import { HelmChartList, RepoHelmChartList } from "../../renderer/api/endpoints/helm-charts.api"; +import type { HelmChartList, RepoHelmChartList } from "../../renderer/api/endpoints/helm-charts.api"; import { deleteRelease, getHistory, getRelease, getValues, installChart, listReleases, rollback, upgradeRelease } from "./helm-release-manager"; class HelmService { diff --git a/src/main/k8s-request.ts b/src/main/k8s-request.ts index 3206d6fca4..b501bd5ce1 100644 --- a/src/main/k8s-request.ts +++ b/src/main/k8s-request.ts @@ -21,9 +21,9 @@ import request, { RequestPromiseOptions } from "request-promise-native"; import { apiKubePrefix } from "../common/vars"; -import { IMetricsReqParams } from "../renderer/api/endpoints/metrics.api"; +import type { IMetricsReqParams } from "../renderer/api/endpoints/metrics.api"; import { LensProxy } from "./proxy/lens-proxy"; -import { Cluster } from "./cluster"; +import type { Cluster } from "./cluster"; export async function k8sRequest(cluster: Cluster, path: string, options: RequestPromiseOptions = {}): Promise { const kubeProxyUrl = `http://localhost:${LensProxy.getInstance().port}${apiKubePrefix}`; diff --git a/src/main/kubeconfig-manager.ts b/src/main/kubeconfig-manager.ts index 4332b69325..f06ee014c7 100644 --- a/src/main/kubeconfig-manager.ts +++ b/src/main/kubeconfig-manager.ts @@ -71,6 +71,7 @@ export class KubeconfigManager { await this.contextHandler.ensureServer(); this.tempFile = await this.createProxyKubeconfig(); } catch (err) { + console.log(err); logger.error(`Failed to created temp config for auth-proxy`, { err }); } } @@ -86,7 +87,7 @@ export class KubeconfigManager { protected async createProxyKubeconfig(): Promise { const { configDir, cluster } = this; const { contextName, kubeConfigPath, id } = cluster; - const tempFile = path.join(configDir, `kubeconfig-${id}`); + const tempFile = path.normalize(path.join(configDir, `kubeconfig-${id}`)); const kubeConfig = loadConfig(kubeConfigPath); const proxyConfig: Partial = { currentContext: contextName, diff --git a/src/main/lens-binary.ts b/src/main/lens-binary.ts index f989b780be..d5e9b943a7 100644 --- a/src/main/lens-binary.ts +++ b/src/main/lens-binary.ts @@ -25,7 +25,7 @@ import request from "request"; import { ensureDir, pathExists } from "fs-extra"; import * as tar from "tar"; import { isWindows } from "../common/vars"; -import winston from "winston"; +import type winston from "winston"; export type LensBinaryOpts = { version: string; @@ -204,7 +204,7 @@ export class LensBinary { throw(error); }); - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { file.on("close", () => { this.logger.debug(`${this.originalBinaryName} binary download closed`); if (!this.tarPath) fs.chmod(binaryPath, 0o755, (err) => { diff --git a/src/main/menu.ts b/src/main/menu.ts index 36dc088328..7070470679 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -21,7 +21,7 @@ import { app, BrowserWindow, dialog, ipcMain, IpcMainEvent, Menu, MenuItem, MenuItemConstructorOptions, webContents, shell } from "electron"; import { autorun } from "mobx"; -import { WindowManager } from "./window-manager"; +import type { WindowManager } from "./window-manager"; import { appName, isMac, isWindows, isTestEnv, docsUrl, supportUrl, productName } from "../common/vars"; import { addClusterURL } from "../renderer/components/+add-cluster/add-cluster.route"; import { preferencesURL } from "../renderer/components/+preferences/preferences.route"; diff --git a/src/main/prometheus/helm.ts b/src/main/prometheus/helm.ts index a4cb4b7921..0317b8499f 100644 --- a/src/main/prometheus/helm.ts +++ b/src/main/prometheus/helm.ts @@ -20,8 +20,8 @@ */ import { PrometheusLens } from "./lens"; -import { CoreV1Api } from "@kubernetes/client-node"; -import { PrometheusService } from "./provider-registry"; +import type { CoreV1Api } from "@kubernetes/client-node"; +import type { PrometheusService } from "./provider-registry"; import logger from "../logger"; export class PrometheusHelm extends PrometheusLens { @@ -29,7 +29,7 @@ export class PrometheusHelm extends PrometheusLens { name = "Helm"; rateAccuracy = "5m"; - public async getPrometheusService(client: CoreV1Api): Promise { + public async getPrometheusService(client: CoreV1Api): Promise { const labelSelector = "app=prometheus,component=server,heritage=Helm"; try { diff --git a/src/main/prometheus/lens.ts b/src/main/prometheus/lens.ts index 7b79b915c5..18c4763dc9 100644 --- a/src/main/prometheus/lens.ts +++ b/src/main/prometheus/lens.ts @@ -19,8 +19,8 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry"; -import { CoreV1Api } from "@kubernetes/client-node"; +import type { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry"; +import type { CoreV1Api } from "@kubernetes/client-node"; import logger from "../logger"; export class PrometheusLens implements PrometheusProvider { @@ -28,7 +28,7 @@ export class PrometheusLens implements PrometheusProvider { name = "Lens"; rateAccuracy = "1m"; - public async getPrometheusService(client: CoreV1Api): Promise { + public async getPrometheusService(client: CoreV1Api): Promise { try { const resp = await client.readNamespacedService("prometheus", "lens-metrics"); const service = resp.body; @@ -44,7 +44,7 @@ export class PrometheusLens implements PrometheusProvider { } } - public getQueries(opts: PrometheusQueryOpts): PrometheusQuery { + public getQueries(opts: PrometheusQueryOpts): PrometheusQuery | void { switch(opts.category) { case "cluster": return { diff --git a/src/main/prometheus/operator.ts b/src/main/prometheus/operator.ts index d3338ce856..dead850056 100644 --- a/src/main/prometheus/operator.ts +++ b/src/main/prometheus/operator.ts @@ -19,8 +19,8 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry"; -import { CoreV1Api, V1Service } from "@kubernetes/client-node"; +import type { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry"; +import type { CoreV1Api, V1Service } from "@kubernetes/client-node"; import logger from "../logger"; export class PrometheusOperator implements PrometheusProvider { @@ -28,7 +28,7 @@ export class PrometheusOperator implements PrometheusProvider { id = "operator"; name = "Prometheus Operator"; - public async getPrometheusService(client: CoreV1Api): Promise { + public async getPrometheusService(client: CoreV1Api): Promise { try { let service: V1Service; @@ -54,7 +54,7 @@ export class PrometheusOperator implements PrometheusProvider { } } - public getQueries(opts: PrometheusQueryOpts): PrometheusQuery { + public getQueries(opts: PrometheusQueryOpts): PrometheusQuery | void { switch(opts.category) { case "cluster": return { diff --git a/src/main/prometheus/provider-registry.ts b/src/main/prometheus/provider-registry.ts index 47c570d67e..db40ec460b 100644 --- a/src/main/prometheus/provider-registry.ts +++ b/src/main/prometheus/provider-registry.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { CoreV1Api } from "@kubernetes/client-node"; +import type { CoreV1Api } from "@kubernetes/client-node"; export type PrometheusClusterQuery = { memoryUsage: string; @@ -83,8 +83,8 @@ export type PrometheusService = { export interface PrometheusProvider { id: string; name: string; - getQueries(opts: PrometheusQueryOpts): PrometheusQuery; - getPrometheusService(client: CoreV1Api): Promise; + getQueries(opts: PrometheusQueryOpts): PrometheusQuery | void; + getPrometheusService(client: CoreV1Api): Promise; } export type PrometheusProviderList = { diff --git a/src/main/prometheus/stacklight.ts b/src/main/prometheus/stacklight.ts index ecb2467d88..0bdda6b96e 100644 --- a/src/main/prometheus/stacklight.ts +++ b/src/main/prometheus/stacklight.ts @@ -19,8 +19,8 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry"; -import { CoreV1Api } from "@kubernetes/client-node"; +import type { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry"; +import type { CoreV1Api } from "@kubernetes/client-node"; import logger from "../logger"; export class PrometheusStacklight implements PrometheusProvider { @@ -28,7 +28,7 @@ export class PrometheusStacklight implements PrometheusProvider { name = "Stacklight"; rateAccuracy = "1m"; - public async getPrometheusService(client: CoreV1Api): Promise { + public async getPrometheusService(client: CoreV1Api): Promise { try { const resp = await client.readNamespacedService("prometheus-server", "stacklight"); const service = resp.body; @@ -44,7 +44,7 @@ export class PrometheusStacklight implements PrometheusProvider { } } - public getQueries(opts: PrometheusQueryOpts): PrometheusQuery { + public getQueries(opts: PrometheusQueryOpts): PrometheusQuery | void { switch(opts.category) { case "cluster": return { diff --git a/src/main/protocol-handler/router.ts b/src/main/protocol-handler/router.ts index 3142afd4ed..afc0d063b6 100644 --- a/src/main/protocol-handler/router.ts +++ b/src/main/protocol-handler/router.ts @@ -22,7 +22,7 @@ import logger from "../logger"; import * as proto from "../../common/protocol-handler"; import Url from "url-parse"; -import { LensExtension } from "../../extensions/lens-extension"; +import type { LensExtension } from "../../extensions/lens-extension"; import { broadcastMessage } from "../../common/ipc"; import { observable, when } from "mobx"; diff --git a/src/main/proxy/index.ts b/src/main/proxy/index.ts index 7c8da355d1..def9c80b5a 100644 --- a/src/main/proxy/index.ts +++ b/src/main/proxy/index.ts @@ -21,3 +21,5 @@ // Don't export the contents here // It will break the extension webpack + +export default {}; diff --git a/src/main/proxy/lens-proxy.ts b/src/main/proxy/lens-proxy.ts index 578c3bf3d3..199d48398b 100644 --- a/src/main/proxy/lens-proxy.ts +++ b/src/main/proxy/lens-proxy.ts @@ -20,13 +20,13 @@ */ import net from "net"; -import http from "http"; +import type http from "http"; import spdy from "spdy"; import httpProxy from "http-proxy"; import url from "url"; import { apiPrefix, apiKubePrefix } from "../../common/vars"; import { Router } from "../router"; -import { ContextHandler } from "../context-handler"; +import type { ContextHandler } from "../context-handler"; import logger from "../logger"; import { Singleton } from "../../common/utils"; import { ClusterManager } from "../cluster-manager"; @@ -205,13 +205,13 @@ export class LensProxy extends Singleton { return proxy; } - protected async getProxyTarget(req: http.IncomingMessage, contextHandler: ContextHandler): Promise { + protected async getProxyTarget(req: http.IncomingMessage, contextHandler: ContextHandler): Promise { if (req.url.startsWith(apiKubePrefix)) { delete req.headers.authorization; req.url = req.url.replace(apiKubePrefix, ""); const isWatchRequest = req.url.includes("watch="); - return await contextHandler.getApiTarget(isWatchRequest); + return contextHandler.getApiTarget(isWatchRequest); } } diff --git a/src/main/proxy/ws-upgrade.ts b/src/main/proxy/ws-upgrade.ts index a16bb9aad0..595b05430d 100644 --- a/src/main/proxy/ws-upgrade.ts +++ b/src/main/proxy/ws-upgrade.ts @@ -26,8 +26,8 @@ */ import * as WebSocket from "ws"; -import http from "http"; -import net from "net"; +import type http from "http"; +import type net from "net"; import url from "url"; import { NodeShellSession, LocalShellSession } from "../shell-session"; import { ClusterManager } from "../cluster-manager"; diff --git a/src/main/resource-applier.ts b/src/main/resource-applier.ts index f1c64f388c..5dd02cc617 100644 --- a/src/main/resource-applier.ts +++ b/src/main/resource-applier.ts @@ -20,7 +20,7 @@ */ import type { Cluster } from "./cluster"; -import { KubernetesObject } from "@kubernetes/client-node"; +import type { KubernetesObject } from "@kubernetes/client-node"; import { exec } from "child_process"; import fs from "fs"; import * as yaml from "js-yaml"; diff --git a/src/main/router.ts b/src/main/router.ts index d5fb3c7056..33e8b39ec9 100644 --- a/src/main/router.ts +++ b/src/main/router.ts @@ -21,10 +21,10 @@ import Call from "@hapi/call"; import Subtext from "@hapi/subtext"; -import http from "http"; +import type http from "http"; import path from "path"; import { readFile } from "fs-extra"; -import { Cluster } from "./cluster"; +import type { Cluster } from "./cluster"; import { apiPrefix, appName, publicPath, isDevelopment, webpackDevServerPort } from "../common/vars"; import { HelmApiRoute, KubeconfigRoute, MetricsRoute, PortForwardRoute, ResourceApplierApiRoute, VersionRoute } from "./routes"; import logger from "./logger"; diff --git a/src/main/routes/helm-route.ts b/src/main/routes/helm-route.ts index 4e6f0df6d2..7a4033d4f0 100644 --- a/src/main/routes/helm-route.ts +++ b/src/main/routes/helm-route.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { LensApiRequest } from "../router"; +import type { LensApiRequest } from "../router"; import { helmService } from "../helm/helm-service"; import { respondJson, respondText } from "../utils/http-responses"; import logger from "../logger"; diff --git a/src/main/routes/kubeconfig-route.ts b/src/main/routes/kubeconfig-route.ts index ecc6ecd720..f4bd7f038e 100644 --- a/src/main/routes/kubeconfig-route.ts +++ b/src/main/routes/kubeconfig-route.ts @@ -19,9 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { LensApiRequest } from "../router"; +import type { LensApiRequest } from "../router"; import { respondJson } from "../utils/http-responses"; -import { Cluster } from "../cluster"; +import type { Cluster } from "../cluster"; import { CoreV1Api, V1Secret } from "@kubernetes/client-node"; function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster) { diff --git a/src/main/routes/metrics-route.ts b/src/main/routes/metrics-route.ts index 16293ad931..0599114219 100644 --- a/src/main/routes/metrics-route.ts +++ b/src/main/routes/metrics-route.ts @@ -20,10 +20,10 @@ */ import _ from "lodash"; -import { LensApiRequest } from "../router"; +import type { LensApiRequest } from "../router"; import { respondJson } from "../utils/http-responses"; import { Cluster, ClusterMetadataKey } from "../cluster"; -import { ClusterPrometheusMetadata } from "../../common/cluster-store"; +import type { ClusterPrometheusMetadata } from "../../common/cluster-store"; import logger from "../logger"; import { getMetrics } from "../k8s-request"; diff --git a/src/main/routes/port-forward-route.ts b/src/main/routes/port-forward-route.ts index 843f9ee527..cfd88e771f 100644 --- a/src/main/routes/port-forward-route.ts +++ b/src/main/routes/port-forward-route.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { LensApiRequest } from "../router"; +import type { LensApiRequest } from "../router"; import { spawn, ChildProcessWithoutNullStreams } from "child_process"; import { Kubectl } from "../kubectl"; import { shell } from "electron"; diff --git a/src/main/routes/resource-applier-route.ts b/src/main/routes/resource-applier-route.ts index 7119e30dc8..cb716cf1f5 100644 --- a/src/main/routes/resource-applier-route.ts +++ b/src/main/routes/resource-applier-route.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { LensApiRequest } from "../router"; +import type { LensApiRequest } from "../router"; import { respondJson, respondText } from "../utils/http-responses"; import { ResourceApplier } from "../resource-applier"; diff --git a/src/main/routes/version-route.ts b/src/main/routes/version-route.ts index f90c0929cb..14a1624489 100644 --- a/src/main/routes/version-route.ts +++ b/src/main/routes/version-route.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { LensApiRequest } from "../router"; +import type { LensApiRequest } from "../router"; import { respondJson } from "../utils/http-responses"; import { getAppVersion } from "../../common/utils"; diff --git a/src/main/shell-session/node-shell-session.ts b/src/main/shell-session/node-shell-session.ts index 92831939ed..a3cc918371 100644 --- a/src/main/shell-session/node-shell-session.ts +++ b/src/main/shell-session/node-shell-session.ts @@ -19,11 +19,11 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import * as WebSocket from "ws"; +import type * as WebSocket from "ws"; import { v4 as uuid } from "uuid"; import * as k8s from "@kubernetes/client-node"; -import { KubeConfig } from "@kubernetes/client-node"; -import { Cluster } from "../cluster"; +import type { KubeConfig } from "@kubernetes/client-node"; +import type { Cluster } from "../cluster"; import { ShellOpenError, ShellSession } from "./shell-session"; export class NodeShellSession extends ShellSession { diff --git a/src/main/shell-session/shell-session.ts b/src/main/shell-session/shell-session.ts index 3b6885592a..eaa95f0fd8 100644 --- a/src/main/shell-session/shell-session.ts +++ b/src/main/shell-session/shell-session.ts @@ -19,9 +19,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { Cluster } from "../cluster"; +import type { Cluster } from "../cluster"; import { Kubectl } from "../kubectl"; -import * as WebSocket from "ws"; +import type * as WebSocket from "ws"; import shellEnv from "shell-env"; import { app } from "electron"; import { clearKubeconfigEnvVars } from "../utils/clear-kube-env-vars"; diff --git a/src/main/tray.ts b/src/main/tray.ts index 90eaf9d15e..cca3090828 100644 --- a/src/main/tray.ts +++ b/src/main/tray.ts @@ -25,7 +25,7 @@ import { Menu, Tray } from "electron"; import { autorun } from "mobx"; import { showAbout } from "./menu"; import { checkForUpdates, isAutoUpdateEnabled } from "./app-updater"; -import { WindowManager } from "./window-manager"; +import type { WindowManager } from "./window-manager"; import { preferencesURL } from "../renderer/components/+preferences/preferences.route"; import logger from "./logger"; import { isDevelopment, isWindows, productName } from "../common/vars"; diff --git a/src/main/utils/get-port.ts b/src/main/utils/get-port.ts index 2f354f13e3..cdce0ce740 100644 --- a/src/main/utils/get-port.ts +++ b/src/main/utils/get-port.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { Readable } from "stream"; +import type { Readable } from "stream"; import URLParse from "url-parse"; interface GetPortArgs { diff --git a/src/main/utils/http-responses.ts b/src/main/utils/http-responses.ts index 9a1debe36f..36287806f1 100644 --- a/src/main/utils/http-responses.ts +++ b/src/main/utils/http-responses.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import http from "http"; +import type http from "http"; export function respondJson(res: http.ServerResponse, content: any, status = 200) { respond(res, JSON.stringify(content), "application/json", status); diff --git a/src/migrations/cluster-store/snap.ts b/src/migrations/cluster-store/snap.ts index c0a0430603..3dcf998f1c 100644 --- a/src/migrations/cluster-store/snap.ts +++ b/src/migrations/cluster-store/snap.ts @@ -22,7 +22,7 @@ // Fix embedded kubeconfig paths under snap config import { migration } from "../migration-wrapper"; -import { ClusterModel } from "../../common/cluster-store"; +import type { ClusterModel } from "../../common/cluster-store"; import { getAppVersion } from "../../common/utils/app-version"; import fs from "fs"; diff --git a/src/migrations/hotbar-store/5.0.0-alpha.0.ts b/src/migrations/hotbar-store/5.0.0-alpha.0.ts index 2e666fe54c..461d6e1886 100644 --- a/src/migrations/hotbar-store/5.0.0-alpha.0.ts +++ b/src/migrations/hotbar-store/5.0.0-alpha.0.ts @@ -20,7 +20,7 @@ */ // Cleans up a store that had the state related data stored -import { Hotbar } from "../../common/hotbar-store"; +import type { Hotbar } from "../../common/hotbar-store"; import { ClusterStore } from "../../common/cluster-store"; import { migration } from "../migration-wrapper"; import { v4 as uuid } from "uuid"; diff --git a/src/migrations/hotbar-store/5.0.0-alpha.2.ts b/src/migrations/hotbar-store/5.0.0-alpha.2.ts index 57459de8c8..83696d01b0 100644 --- a/src/migrations/hotbar-store/5.0.0-alpha.2.ts +++ b/src/migrations/hotbar-store/5.0.0-alpha.2.ts @@ -20,7 +20,7 @@ */ // Cleans up a store that had the state related data stored -import { Hotbar } from "../../common/hotbar-store"; +import type { Hotbar } from "../../common/hotbar-store"; import { migration } from "../migration-wrapper"; import * as uuid from "uuid"; diff --git a/src/migrations/migration-wrapper.ts b/src/migrations/migration-wrapper.ts index db363513de..26b17e0450 100644 --- a/src/migrations/migration-wrapper.ts +++ b/src/migrations/migration-wrapper.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import Config from "conf"; +import type Config from "conf"; import { isTestEnv } from "../common/vars"; export interface MigrationOpts { diff --git a/src/renderer/api/__tests__/crd.test.ts b/src/renderer/api/__tests__/crd.test.ts index 657434e93b..af7db4280c 100644 --- a/src/renderer/api/__tests__/crd.test.ts +++ b/src/renderer/api/__tests__/crd.test.ts @@ -20,7 +20,7 @@ */ import { CustomResourceDefinition } from "../endpoints"; -import { IKubeObjectMetadata } from "../kube-object"; +import type { IKubeObjectMetadata } from "../kube-object"; describe("Crds", () => { describe("getVersion", () => { diff --git a/src/renderer/api/catalog-entity.ts b/src/renderer/api/catalog-entity.ts index 493099d6c8..63a5ce62eb 100644 --- a/src/renderer/api/catalog-entity.ts +++ b/src/renderer/api/catalog-entity.ts @@ -21,18 +21,17 @@ import { navigate } from "../navigation"; import { commandRegistry } from "../../extensions/registries"; -import { CatalogEntity } from "../../common/catalog"; +import type { CatalogEntity } from "../../common/catalog"; -export { - CatalogCategory, - CatalogEntity, +export { CatalogCategory, CatalogEntity } from "../../common/catalog"; +export type { CatalogEntityData, CatalogEntityKindData, CatalogEntityActionContext, CatalogEntityAddMenuContext, CatalogEntityAddMenu, CatalogEntityContextMenu, - CatalogEntityContextMenuContext + CatalogEntityContextMenuContext, } from "../../common/catalog"; export const catalogEntityRunContext = { diff --git a/src/renderer/api/endpoints/configmap.api.ts b/src/renderer/api/endpoints/configmap.api.ts index decbad381d..2c96494c57 100644 --- a/src/renderer/api/endpoints/configmap.api.ts +++ b/src/renderer/api/endpoints/configmap.api.ts @@ -20,7 +20,7 @@ */ import { KubeObject } from "../kube-object"; -import { KubeJsonApiData } from "../kube-json-api"; +import type { KubeJsonApiData } from "../kube-json-api"; import { autobind } from "../../utils"; import { KubeApi } from "../kube-api"; diff --git a/src/renderer/api/endpoints/cron-job.api.ts b/src/renderer/api/endpoints/cron-job.api.ts index d0f9b9c3e0..09c18924d4 100644 --- a/src/renderer/api/endpoints/cron-job.api.ts +++ b/src/renderer/api/endpoints/cron-job.api.ts @@ -21,7 +21,7 @@ import moment from "moment"; import { KubeObject } from "../kube-object"; -import { IPodContainer } from "./pods.api"; +import type { IPodContainer } from "./pods.api"; import { formatDuration } from "../../utils/formatDuration"; import { autobind } from "../../utils"; import { KubeApi } from "../kube-api"; diff --git a/src/renderer/api/endpoints/daemon-set.api.ts b/src/renderer/api/endpoints/daemon-set.api.ts index fa22106e3a..1f2660b3c5 100644 --- a/src/renderer/api/endpoints/daemon-set.api.ts +++ b/src/renderer/api/endpoints/daemon-set.api.ts @@ -20,7 +20,7 @@ */ import get from "lodash/get"; -import { IPodContainer } from "./pods.api"; +import type { IPodContainer } from "./pods.api"; import { IAffinity, WorkloadKubeObject } from "../workload-kube-object"; import { autobind } from "../../utils"; import { KubeApi } from "../kube-api"; diff --git a/src/renderer/api/endpoints/helm-releases.api.ts b/src/renderer/api/endpoints/helm-releases.api.ts index 6958e7f8c3..45fc55a342 100644 --- a/src/renderer/api/endpoints/helm-releases.api.ts +++ b/src/renderer/api/endpoints/helm-releases.api.ts @@ -25,9 +25,9 @@ import { autobind, formatDuration } from "../../utils"; import capitalize from "lodash/capitalize"; import { apiBase } from "../index"; import { helmChartStore } from "../../components/+apps-helm-charts/helm-chart.store"; -import { ItemObject } from "../../item.store"; +import type { ItemObject } from "../../item.store"; import { KubeObject } from "../kube-object"; -import { JsonApiData } from "../json-api"; +import type { JsonApiData } from "../json-api"; interface IReleasePayload { name: string; diff --git a/src/renderer/api/endpoints/job.api.ts b/src/renderer/api/endpoints/job.api.ts index b9e7dfeafa..dac3cf7a71 100644 --- a/src/renderer/api/endpoints/job.api.ts +++ b/src/renderer/api/endpoints/job.api.ts @@ -22,9 +22,9 @@ import get from "lodash/get"; import { autobind } from "../../utils"; import { IAffinity, WorkloadKubeObject } from "../workload-kube-object"; -import { IPodContainer } from "./pods.api"; +import type { IPodContainer } from "./pods.api"; import { KubeApi } from "../kube-api"; -import { JsonApiParams } from "../json-api"; +import type { JsonApiParams } from "../json-api"; @autobind() export class Job extends WorkloadKubeObject { @@ -106,11 +106,7 @@ export class Job extends WorkloadKubeObject { getCondition() { // Type of Job condition could be only Complete or Failed // https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.14/#jobcondition-v1-batch - const { conditions } = this.status; - - if (!conditions) return; - - return conditions.find(({ status }) => status === "True"); + return this.status.conditions?.find(({ status }) => status === "True"); } getImages() { diff --git a/src/renderer/api/endpoints/metrics.api.ts b/src/renderer/api/endpoints/metrics.api.ts index f1d50a68b1..00408678e0 100644 --- a/src/renderer/api/endpoints/metrics.api.ts +++ b/src/renderer/api/endpoints/metrics.api.ts @@ -132,11 +132,11 @@ export function normalizeMetrics(metrics: IMetrics, frames = 60): IMetrics { return metrics; } -export function isMetricsEmpty(metrics: { [key: string]: IMetrics }) { +export function isMetricsEmpty(metrics: Record) { return Object.values(metrics).every(metric => !metric?.data?.result?.length); } -export function getItemMetrics(metrics: { [key: string]: IMetrics }, itemName: string): { [key: string]: IMetrics } { +export function getItemMetrics(metrics: Record, itemName: string): Record | void { if (!metrics) return; const itemMetrics = { ...metrics }; @@ -153,7 +153,7 @@ export function getItemMetrics(metrics: { [key: string]: IMetrics }, itemName: s return itemMetrics; } -export function getMetricLastPoints(metrics: { [key: string]: IMetrics }) { +export function getMetricLastPoints(metrics: Record) { const result: Partial<{ [metric: string]: number }> = {}; Object.keys(metrics).forEach(metricName => { diff --git a/src/renderer/api/endpoints/persistent-volume-claims.api.ts b/src/renderer/api/endpoints/persistent-volume-claims.api.ts index d1e37db5b9..92641945d7 100644 --- a/src/renderer/api/endpoints/persistent-volume-claims.api.ts +++ b/src/renderer/api/endpoints/persistent-volume-claims.api.ts @@ -22,7 +22,7 @@ import { KubeObject } from "../kube-object"; import { autobind } from "../../utils"; import { IMetrics, metricsApi } from "./metrics.api"; -import { Pod } from "./pods.api"; +import type { Pod } from "./pods.api"; import { KubeApi } from "../kube-api"; export class PersistentVolumeClaimsApi extends KubeApi { diff --git a/src/renderer/api/endpoints/persistent-volume.api.ts b/src/renderer/api/endpoints/persistent-volume.api.ts index c0402cef70..c2bf11e29f 100644 --- a/src/renderer/api/endpoints/persistent-volume.api.ts +++ b/src/renderer/api/endpoints/persistent-volume.api.ts @@ -61,7 +61,7 @@ export class PersistentVolume extends KubeObject { }; }; - status: { + status?: { phase: string; reason?: string; }; @@ -79,9 +79,7 @@ export class PersistentVolume extends KubeObject { } getStatus() { - if (!this.status) return; - - return this.status.phase || "-"; + return this.status?.phase || "-"; } getStorageClass(): string { diff --git a/src/renderer/api/endpoints/replica-set.api.ts b/src/renderer/api/endpoints/replica-set.api.ts index 5e9fe2fc82..cf79c85308 100644 --- a/src/renderer/api/endpoints/replica-set.api.ts +++ b/src/renderer/api/endpoints/replica-set.api.ts @@ -22,7 +22,7 @@ import get from "lodash/get"; import { autobind } from "../../utils"; import { WorkloadKubeObject } from "../workload-kube-object"; -import { IPodContainer, Pod } from "./pods.api"; +import type { IPodContainer, Pod } from "./pods.api"; import { KubeApi } from "../kube-api"; export class ReplicaSetApi extends KubeApi { diff --git a/src/renderer/api/endpoints/resource-applier.api.ts b/src/renderer/api/endpoints/resource-applier.api.ts index 6825c6d0b0..1756977c95 100644 --- a/src/renderer/api/endpoints/resource-applier.api.ts +++ b/src/renderer/api/endpoints/resource-applier.api.ts @@ -21,7 +21,7 @@ import jsYaml from "js-yaml"; import { KubeObject } from "../kube-object"; -import { KubeJsonApiData } from "../kube-json-api"; +import type { KubeJsonApiData } from "../kube-json-api"; import { apiBase } from "../index"; import { apiManager } from "../api-manager"; diff --git a/src/renderer/api/endpoints/resource-quota.api.ts b/src/renderer/api/endpoints/resource-quota.api.ts index 173d019350..4675299a39 100644 --- a/src/renderer/api/endpoints/resource-quota.api.ts +++ b/src/renderer/api/endpoints/resource-quota.api.ts @@ -21,7 +21,7 @@ import { KubeObject } from "../kube-object"; import { KubeApi } from "../kube-api"; -import { KubeJsonApiData } from "../kube-json-api"; +import type { KubeJsonApiData } from "../kube-json-api"; export interface IResourceQuotaValues { [quota: string]: string; diff --git a/src/renderer/api/endpoints/secret.api.ts b/src/renderer/api/endpoints/secret.api.ts index 62fffbe611..b51f467430 100644 --- a/src/renderer/api/endpoints/secret.api.ts +++ b/src/renderer/api/endpoints/secret.api.ts @@ -20,7 +20,7 @@ */ import { KubeObject } from "../kube-object"; -import { KubeJsonApiData } from "../kube-json-api"; +import type { KubeJsonApiData } from "../kube-json-api"; import { autobind } from "../../utils"; import { KubeApi } from "../kube-api"; diff --git a/src/renderer/api/endpoints/stateful-set.api.ts b/src/renderer/api/endpoints/stateful-set.api.ts index 41c3c11f5c..cdbeb5a01a 100644 --- a/src/renderer/api/endpoints/stateful-set.api.ts +++ b/src/renderer/api/endpoints/stateful-set.api.ts @@ -20,7 +20,7 @@ */ import get from "lodash/get"; -import { IPodContainer } from "./pods.api"; +import type { IPodContainer } from "./pods.api"; import { IAffinity, WorkloadKubeObject } from "../workload-kube-object"; import { autobind } from "../../utils"; import { KubeApi } from "../kube-api"; diff --git a/src/renderer/api/kube-api.ts b/src/renderer/api/kube-api.ts index 990b0d3a7b..21e370a207 100644 --- a/src/renderer/api/kube-api.ts +++ b/src/renderer/api/kube-api.ts @@ -30,7 +30,7 @@ import { apiKube } from "./index"; import { createKubeApiURL, parseKubeApi } from "./kube-api-parse"; import { IKubeObjectConstructor, KubeObject, KubeStatus } from "./kube-object"; import byline from "byline"; -import { IKubeWatchEvent } from "./kube-watch-api"; +import type { IKubeWatchEvent } from "./kube-watch-api"; import { ReadableWebToNodeStream } from "../utils/readableStream"; import { KubeJsonApi, KubeJsonApiData } from "./kube-json-api"; import { noop } from "../utils"; @@ -306,7 +306,7 @@ export class KubeApi { } protected parseResponse(data: unknown, namespace?: string): T | T[] | null { - if (!data) return; + if (!data) return null; const KubeObjectConstructor = this.objectConstructor; // process items list response, check before single item since there is overlap diff --git a/src/renderer/api/kube-object.ts b/src/renderer/api/kube-object.ts index 1bfd1a21d1..06c431851c 100644 --- a/src/renderer/api/kube-object.ts +++ b/src/renderer/api/kube-object.ts @@ -22,11 +22,11 @@ // Base class for all kubernetes objects import moment from "moment"; -import { KubeJsonApiData, KubeJsonApiDataList, KubeJsonApiListMetadata, KubeJsonApiMetadata } from "./kube-json-api"; +import type { KubeJsonApiData, KubeJsonApiDataList, KubeJsonApiListMetadata, KubeJsonApiMetadata } from "./kube-json-api"; import { autobind, formatDuration } from "../utils"; -import { ItemObject } from "../item.store"; +import type { ItemObject } from "../item.store"; import { apiKube } from "./index"; -import { JsonApiParams } from "./json-api"; +import type { JsonApiParams } from "./json-api"; import { resourceApplierApi } from "./endpoints/resource-applier.api"; import { hasOptionalProperty, hasTypedProperty, isObject, isString, bindPredicate, isTypedArray, isRecord } from "../../common/utils/type-narrowing"; diff --git a/src/renderer/api/kube-watch-api.ts b/src/renderer/api/kube-watch-api.ts index 33d6d44290..4c68e0fdfa 100644 --- a/src/renderer/api/kube-watch-api.ts +++ b/src/renderer/api/kube-watch-api.ts @@ -28,8 +28,8 @@ import type { ClusterContext } from "../components/context"; import plimit from "p-limit"; import { comparer, IReactionDisposer, observable, reaction, when } from "mobx"; import { autobind, noop } from "../utils"; -import { KubeApi } from "./kube-api"; -import { KubeJsonApiData } from "./kube-json-api"; +import type { KubeApi } from "./kube-api"; +import type { KubeJsonApiData } from "./kube-json-api"; import { isDebugging, isProduction } from "../../common/vars"; export interface IKubeWatchEvent { diff --git a/src/renderer/api/terminal-api.ts b/src/renderer/api/terminal-api.ts index 1b9f7d7989..2720fddf51 100644 --- a/src/renderer/api/terminal-api.ts +++ b/src/renderer/api/terminal-api.ts @@ -108,7 +108,7 @@ export class TerminalApi extends WebSocketApi { @autobind() protected _onReady(data: string) { - if (!data) return; + if (!data) return true; this.isReady = true; this.onReady.emit(); this.onData.removeListener(this._onReady); diff --git a/src/renderer/components/+apps-helm-charts/helm-charts.tsx b/src/renderer/components/+apps-helm-charts/helm-charts.tsx index 34ef8aaf23..5e451e33e5 100644 --- a/src/renderer/components/+apps-helm-charts/helm-charts.tsx +++ b/src/renderer/components/+apps-helm-charts/helm-charts.tsx @@ -22,11 +22,11 @@ import "./helm-charts.scss"; import React, { Component } from "react"; -import { RouteComponentProps } from "react-router"; +import type { RouteComponentProps } from "react-router"; import { observer } from "mobx-react"; import { helmChartsURL, IHelmChartsRouteParams } from "./helm-charts.route"; import { helmChartStore } from "./helm-chart.store"; -import { HelmChart } from "../../api/endpoints/helm-charts.api"; +import type { HelmChart } from "../../api/endpoints/helm-charts.api"; import { HelmChartDetails } from "./helm-chart-details"; import { navigation } from "../../navigation"; import { ItemListLayout } from "../item-object-list/item-list-layout"; diff --git a/src/renderer/components/+apps-releases/release-menu.tsx b/src/renderer/components/+apps-releases/release-menu.tsx index 9e29c112e4..78e4c8e94b 100644 --- a/src/renderer/components/+apps-releases/release-menu.tsx +++ b/src/renderer/components/+apps-releases/release-menu.tsx @@ -20,7 +20,7 @@ */ import React from "react"; -import { HelmRelease } from "../../api/endpoints/helm-releases.api"; +import type { HelmRelease } from "../../api/endpoints/helm-releases.api"; import { autobind, cssNames } from "../../utils"; import { releaseStore } from "./release.store"; import { MenuActions, MenuActionsProps } from "../menu/menu-actions"; @@ -56,7 +56,7 @@ export class HelmReleaseMenu extends React.Component { renderContent() { const { release, toolbar } = this.props; - if (!release) return; + if (!release) return null; const hasRollback = release && release.getRevision() > 1; return ( diff --git a/src/renderer/components/+apps-releases/release.store.ts b/src/renderer/components/+apps-releases/release.store.ts index 6a4d8e6a68..7ed2ac42c7 100644 --- a/src/renderer/components/+apps-releases/release.store.ts +++ b/src/renderer/components/+apps-releases/release.store.ts @@ -24,7 +24,7 @@ import { action, observable, reaction, when } from "mobx"; import { autobind } from "../../utils"; import { createRelease, deleteRelease, HelmRelease, IReleaseCreatePayload, IReleaseUpdatePayload, listReleases, rollbackRelease, updateRelease } from "../../api/endpoints/helm-releases.api"; import { ItemStore } from "../../item.store"; -import { Secret } from "../../api/endpoints"; +import type { Secret } from "../../api/endpoints"; import { secretsStore } from "../+config-secrets/secrets.store"; import { namespaceStore } from "../+namespaces/namespace.store"; import { Notifications } from "../notifications"; @@ -146,8 +146,6 @@ export class ReleaseStore extends ItemStore { } async removeSelectedItems() { - if (!this.selectedItems.length) return; - return Promise.all(this.selectedItems.map(this.remove)); } } diff --git a/src/renderer/components/+apps-releases/releases.tsx b/src/renderer/components/+apps-releases/releases.tsx index 716d5c8a64..bbf3944554 100644 --- a/src/renderer/components/+apps-releases/releases.tsx +++ b/src/renderer/components/+apps-releases/releases.tsx @@ -24,10 +24,10 @@ import "./releases.scss"; import React, { Component } from "react"; import kebabCase from "lodash/kebabCase"; import { disposeOnUnmount, observer } from "mobx-react"; -import { RouteComponentProps } from "react-router"; +import type { RouteComponentProps } from "react-router"; import { releaseStore } from "./release.store"; import { IReleaseRouteParams, releaseURL } from "./release.route"; -import { HelmRelease } from "../../api/endpoints/helm-releases.api"; +import type { HelmRelease } from "../../api/endpoints/helm-releases.api"; import { ReleaseDetails } from "./release-details"; import { ReleaseRollbackDialog } from "./release-rollback-dialog"; import { navigation } from "../../navigation"; diff --git a/src/renderer/components/+catalog/catalog-add-button.tsx b/src/renderer/components/+catalog/catalog-add-button.tsx index 5329702832..af6b3ebbbb 100644 --- a/src/renderer/components/+catalog/catalog-add-button.tsx +++ b/src/renderer/components/+catalog/catalog-add-button.tsx @@ -26,7 +26,7 @@ import { Icon } from "../icon"; import { disposeOnUnmount, observer } from "mobx-react"; import { observable, reaction } from "mobx"; import { autobind } from "../../../common/utils"; -import { CatalogCategory, CatalogEntityAddMenuContext, CatalogEntityAddMenu } from "../../api/catalog-entity"; +import type { CatalogCategory, CatalogEntityAddMenuContext, CatalogEntityAddMenu } from "../../api/catalog-entity"; import { EventEmitter } from "events"; import { navigate } from "../../navigation"; diff --git a/src/renderer/components/+catalog/catalog-entity.store.ts b/src/renderer/components/+catalog/catalog-entity.store.ts index f53515efca..3bd3dbacfa 100644 --- a/src/renderer/components/+catalog/catalog-entity.store.ts +++ b/src/renderer/components/+catalog/catalog-entity.store.ts @@ -21,7 +21,7 @@ import { action, computed, IReactionDisposer, observable, reaction } from "mobx"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; -import { CatalogEntity, CatalogEntityActionContext } from "../../api/catalog-entity"; +import type { CatalogEntity, CatalogEntityActionContext } from "../../api/catalog-entity"; import { ItemObject, ItemStore } from "../../item.store"; import { autobind } from "../../utils"; import { CatalogCategory } from "../../../common/catalog"; diff --git a/src/renderer/components/+cluster/cluster-issues.tsx b/src/renderer/components/+cluster/cluster-issues.tsx index e02ce958a8..ce6496f490 100644 --- a/src/renderer/components/+cluster/cluster-issues.tsx +++ b/src/renderer/components/+cluster/cluster-issues.tsx @@ -30,7 +30,7 @@ import { Table, TableCell, TableHead, TableRow } from "../table"; import { nodesStore } from "../+nodes/nodes.store"; import { eventStore } from "../+events/event.store"; import { autobind, cssNames, prevDefault } from "../../utils"; -import { ItemObject } from "../../item.store"; +import type { ItemObject } from "../../item.store"; import { Spinner } from "../spinner"; import { ThemeStore } from "../../theme.store"; import { lookupApiLink } from "../../api/kube-api"; diff --git a/src/renderer/components/+cluster/cluster-metrics.tsx b/src/renderer/components/+cluster/cluster-metrics.tsx index c247dc3ef8..0c4910e7e5 100644 --- a/src/renderer/components/+cluster/cluster-metrics.tsx +++ b/src/renderer/components/+cluster/cluster-metrics.tsx @@ -23,7 +23,7 @@ import "./cluster-metrics.scss"; import React from "react"; import { observer } from "mobx-react"; -import { ChartOptions, ChartPoint } from "chart.js"; +import type { ChartOptions, ChartPoint } from "chart.js"; import { clusterOverviewStore, MetricType } from "./cluster-overview.store"; import { BarChart } from "../chart"; import { bytesToUnits } from "../../utils"; diff --git a/src/renderer/components/+config-autoscalers/hpa-details.tsx b/src/renderer/components/+config-autoscalers/hpa-details.tsx index 4e832426e4..5b9cf76f97 100644 --- a/src/renderer/components/+config-autoscalers/hpa-details.tsx +++ b/src/renderer/components/+config-autoscalers/hpa-details.tsx @@ -100,7 +100,7 @@ export class HpaDetails extends React.Component { render() { const { object: hpa } = this.props; - if (!hpa) return; + if (!hpa) return null; const { scaleTargetRef } = hpa.spec; return ( diff --git a/src/renderer/components/+config-autoscalers/hpa.tsx b/src/renderer/components/+config-autoscalers/hpa.tsx index 663d1fd5b1..54eb0b67a8 100644 --- a/src/renderer/components/+config-autoscalers/hpa.tsx +++ b/src/renderer/components/+config-autoscalers/hpa.tsx @@ -23,10 +23,10 @@ import "./hpa.scss"; import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router"; +import type { RouteComponentProps } from "react-router"; import { KubeObjectListLayout } from "../kube-object"; -import { IHpaRouteParams } from "./hpa.route"; -import { HorizontalPodAutoscaler } from "../../api/endpoints/hpa.api"; +import type { IHpaRouteParams } from "./hpa.route"; +import type { HorizontalPodAutoscaler } from "../../api/endpoints/hpa.api"; import { hpaStore } from "./hpa.store"; import { Badge } from "../badge"; import { cssNames } from "../../utils"; diff --git a/src/renderer/components/+config-limit-ranges/limit-range-details.tsx b/src/renderer/components/+config-limit-ranges/limit-range-details.tsx index 859f8272ba..d4c9d18f28 100644 --- a/src/renderer/components/+config-limit-ranges/limit-range-details.tsx +++ b/src/renderer/components/+config-limit-ranges/limit-range-details.tsx @@ -23,7 +23,7 @@ import "./limit-range-details.scss"; import React from "react"; import { observer } from "mobx-react"; -import { KubeObjectDetailsProps } from "../kube-object"; +import type { KubeObjectDetailsProps } from "../kube-object"; import { LimitPart, LimitRange, LimitRangeItem, Resource } from "../../api/endpoints/limit-range.api"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; diff --git a/src/renderer/components/+config-limit-ranges/limit-ranges.tsx b/src/renderer/components/+config-limit-ranges/limit-ranges.tsx index 73e51bd0bf..6784e6f7d6 100644 --- a/src/renderer/components/+config-limit-ranges/limit-ranges.tsx +++ b/src/renderer/components/+config-limit-ranges/limit-ranges.tsx @@ -21,14 +21,14 @@ import "./limit-ranges.scss"; -import { RouteComponentProps } from "react-router"; +import type { RouteComponentProps } from "react-router"; import { observer } from "mobx-react"; import { KubeObjectListLayout } from "../kube-object/kube-object-list-layout"; import { limitRangeStore } from "./limit-ranges.store"; -import { LimitRangeRouteParams } from "./limit-ranges.route"; +import type { LimitRangeRouteParams } from "./limit-ranges.route"; import React from "react"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; -import { LimitRange } from "../../api/endpoints/limit-range.api"; +import type { LimitRange } from "../../api/endpoints/limit-range.api"; enum columnId { name = "name", diff --git a/src/renderer/components/+config-maps/config-map-details.tsx b/src/renderer/components/+config-maps/config-map-details.tsx index 62a0534fba..b9dd05cfaa 100644 --- a/src/renderer/components/+config-maps/config-map-details.tsx +++ b/src/renderer/components/+config-maps/config-map-details.tsx @@ -30,8 +30,8 @@ import { Input } from "../input"; import { Button } from "../button"; import { KubeEventDetails } from "../+events/kube-event-details"; import { configMapsStore } from "./config-maps.store"; -import { KubeObjectDetailsProps } from "../kube-object"; -import { ConfigMap } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object"; +import type { ConfigMap } from "../../api/endpoints"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; @@ -132,5 +132,3 @@ kubeObjectDetailRegistry.add({ Details: (props) => } }); - - diff --git a/src/renderer/components/+config-maps/config-maps.tsx b/src/renderer/components/+config-maps/config-maps.tsx index dbc78f13a0..b1997fa792 100644 --- a/src/renderer/components/+config-maps/config-maps.tsx +++ b/src/renderer/components/+config-maps/config-maps.tsx @@ -23,11 +23,11 @@ import "./config-maps.scss"; import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router"; +import type { RouteComponentProps } from "react-router"; import { configMapsStore } from "./config-maps.store"; -import { ConfigMap } from "../../api/endpoints/configmap.api"; +import type { ConfigMap } from "../../api/endpoints/configmap.api"; import { KubeObjectListLayout } from "../kube-object"; -import { IConfigMapsRouteParams } from "./config-maps.route"; +import type { IConfigMapsRouteParams } from "./config-maps.route"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; enum columnId { diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx index 8ccaa814b2..ddb95aa628 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx @@ -25,8 +25,8 @@ import React from "react"; import { observer } from "mobx-react"; import { DrawerItem } from "../drawer"; import { Badge } from "../badge"; -import { KubeObjectDetailsProps } from "../kube-object"; -import { PodDisruptionBudget } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object"; +import type { PodDisruptionBudget } from "../../api/endpoints"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx index 07bf10f96f..abc87a6a4d 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx @@ -24,7 +24,7 @@ import "./pod-disruption-budgets.scss"; import * as React from "react"; import { observer } from "mobx-react"; import { podDisruptionBudgetsStore } from "./pod-disruption-budgets.store"; -import { PodDisruptionBudget } from "../../api/endpoints/poddisruptionbudget.api"; +import type { PodDisruptionBudget } from "../../api/endpoints/poddisruptionbudget.api"; import { KubeObjectDetailsProps, KubeObjectListLayout } from "../kube-object"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; diff --git a/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx b/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx index 79b7209adf..662a8e26ec 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx @@ -25,8 +25,8 @@ import kebabCase from "lodash/kebabCase"; import { observer } from "mobx-react"; import { DrawerItem, DrawerTitle } from "../drawer"; import { cpuUnitsToNumber, cssNames, unitsToBytes, metricUnitsToNumber } from "../../utils"; -import { KubeObjectDetailsProps } from "../kube-object"; -import { ResourceQuota } from "../../api/endpoints/resource-quota.api"; +import type { KubeObjectDetailsProps } from "../kube-object"; +import type { ResourceQuota } from "../../api/endpoints/resource-quota.api"; import { LineProgress } from "../line-progress"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; diff --git a/src/renderer/components/+config-resource-quotas/resource-quotas.tsx b/src/renderer/components/+config-resource-quotas/resource-quotas.tsx index 90b5526c44..59be708d6f 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quotas.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quotas.tsx @@ -23,12 +23,12 @@ import "./resource-quotas.scss"; import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router"; +import type { RouteComponentProps } from "react-router"; import { KubeObjectListLayout } from "../kube-object"; -import { ResourceQuota } from "../../api/endpoints/resource-quota.api"; +import type { ResourceQuota } from "../../api/endpoints/resource-quota.api"; import { AddQuotaDialog } from "./add-quota-dialog"; import { resourceQuotaStore } from "./resource-quotas.store"; -import { IResourceQuotaRouteParams } from "./resource-quotas.route"; +import type { IResourceQuotaRouteParams } from "./resource-quotas.route"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; enum columnId { diff --git a/src/renderer/components/+config-secrets/add-secret-dialog.tsx b/src/renderer/components/+config-secrets/add-secret-dialog.tsx index bbf04ed533..f877fbe291 100644 --- a/src/renderer/components/+config-secrets/add-secret-dialog.tsx +++ b/src/renderer/components/+config-secrets/add-secret-dialog.tsx @@ -33,7 +33,7 @@ import { SubTitle } from "../layout/sub-title"; import { NamespaceSelect } from "../+namespaces/namespace-select"; import { Select, SelectOption } from "../select"; import { Icon } from "../icon"; -import { IKubeObjectMetadata } from "../../api/kube-object"; +import type { IKubeObjectMetadata } from "../../api/kube-object"; import { base64 } from "../../utils"; import { Notifications } from "../notifications"; import upperFirst from "lodash/upperFirst"; diff --git a/src/renderer/components/+config-secrets/secret-details.tsx b/src/renderer/components/+config-secrets/secret-details.tsx index bbf6cda035..5a4aaca64e 100644 --- a/src/renderer/components/+config-secrets/secret-details.tsx +++ b/src/renderer/components/+config-secrets/secret-details.tsx @@ -32,8 +32,8 @@ import { Notifications } from "../notifications"; import { base64 } from "../../utils"; import { Icon } from "../icon"; import { secretsStore } from "./secrets.store"; -import { KubeObjectDetailsProps } from "../kube-object"; -import { Secret } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object"; +import type { Secret } from "../../api/endpoints"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; diff --git a/src/renderer/components/+config-secrets/secrets.tsx b/src/renderer/components/+config-secrets/secrets.tsx index 41ce4cdf42..b87c6a51ed 100644 --- a/src/renderer/components/+config-secrets/secrets.tsx +++ b/src/renderer/components/+config-secrets/secrets.tsx @@ -23,10 +23,10 @@ import "./secrets.scss"; import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router"; -import { Secret } from "../../api/endpoints"; +import type { RouteComponentProps } from "react-router"; +import type { Secret } from "../../api/endpoints"; import { AddSecretDialog } from "./add-secret-dialog"; -import { ISecretsRouteParams } from "./secrets.route"; +import type { ISecretsRouteParams } from "./secrets.route"; import { KubeObjectListLayout } from "../kube-object"; import { Badge } from "../badge"; import { secretsStore } from "./secrets.store"; diff --git a/src/renderer/components/+config/config.route.ts b/src/renderer/components/+config/config.route.ts index eab91880a5..6e3cd5696e 100644 --- a/src/renderer/components/+config/config.route.ts +++ b/src/renderer/components/+config/config.route.ts @@ -19,8 +19,8 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { RouteProps } from "react-router"; -import { IURLParams } from "../../../common/utils/buildUrl"; +import type { RouteProps } from "react-router"; +import type { IURLParams } from "../../../common/utils/buildUrl"; import { configMapsRoute, configMapsURL } from "../+config-maps/config-maps.route"; import { hpaRoute } from "../+config-autoscalers"; import { limitRangesRoute } from "../+config-limit-ranges"; diff --git a/src/renderer/components/+custom-resources/crd-details.tsx b/src/renderer/components/+custom-resources/crd-details.tsx index 0561679dda..757f389702 100644 --- a/src/renderer/components/+custom-resources/crd-details.tsx +++ b/src/renderer/components/+custom-resources/crd-details.tsx @@ -24,12 +24,12 @@ import "./crd-details.scss"; import React from "react"; import { Link } from "react-router-dom"; import { observer } from "mobx-react"; -import { CustomResourceDefinition } from "../../api/endpoints/crd.api"; +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"; -import { KubeObjectDetailsProps } from "../kube-object"; +import type { KubeObjectDetailsProps } from "../kube-object"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { Input } from "../input"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; diff --git a/src/renderer/components/+custom-resources/crd-list.tsx b/src/renderer/components/+custom-resources/crd-list.tsx index 33442a5404..bb6753dce2 100644 --- a/src/renderer/components/+custom-resources/crd-list.tsx +++ b/src/renderer/components/+custom-resources/crd-list.tsx @@ -28,7 +28,7 @@ import { Link } from "react-router-dom"; import { stopPropagation } from "../../utils"; import { KubeObjectListLayout } from "../kube-object"; import { crdStore } from "./crd.store"; -import { CustomResourceDefinition } from "../../api/endpoints/crd.api"; +import type { CustomResourceDefinition } from "../../api/endpoints/crd.api"; import { Select, SelectOption } from "../select"; import { createPageParam } from "../../navigation"; import { Icon } from "../icon"; diff --git a/src/renderer/components/+custom-resources/crd-resource-details.tsx b/src/renderer/components/+custom-resources/crd-resource-details.tsx index cbd558c334..b681b23c9a 100644 --- a/src/renderer/components/+custom-resources/crd-resource-details.tsx +++ b/src/renderer/components/+custom-resources/crd-resource-details.tsx @@ -28,11 +28,11 @@ import { computed } from "mobx"; import { cssNames } from "../../utils"; import { Badge } from "../badge"; import { DrawerItem } from "../drawer"; -import { KubeObjectDetailsProps } from "../kube-object"; +import type { KubeObjectDetailsProps } from "../kube-object"; import { crdStore } from "./crd.store"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { Input } from "../input"; -import { AdditionalPrinterColumnsV1, CustomResourceDefinition } from "../../api/endpoints/crd.api"; +import type { AdditionalPrinterColumnsV1, CustomResourceDefinition } from "../../api/endpoints/crd.api"; import { parseJsonPath } from "../../utils/jsonPath"; interface Props extends KubeObjectDetailsProps { diff --git a/src/renderer/components/+custom-resources/crd-resource.store.ts b/src/renderer/components/+custom-resources/crd-resource.store.ts index 485eaccd64..b980f30890 100644 --- a/src/renderer/components/+custom-resources/crd-resource.store.ts +++ b/src/renderer/components/+custom-resources/crd-resource.store.ts @@ -22,7 +22,7 @@ import { autobind } from "../../utils"; import { KubeApi } from "../../api/kube-api"; import { KubeObjectStore } from "../../kube-object.store"; -import { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../api/kube-object"; @autobind() export class CRDResourceStore extends KubeObjectStore { diff --git a/src/renderer/components/+custom-resources/crd-resources.tsx b/src/renderer/components/+custom-resources/crd-resources.tsx index 3b280baa66..a8128f42e1 100644 --- a/src/renderer/components/+custom-resources/crd-resources.tsx +++ b/src/renderer/components/+custom-resources/crd-resources.tsx @@ -24,13 +24,13 @@ import "./crd-resources.scss"; import React from "react"; import jsonPath from "jsonpath"; import { disposeOnUnmount, observer } from "mobx-react"; -import { RouteComponentProps } from "react-router"; +import type { RouteComponentProps } from "react-router"; import { KubeObjectListLayout } from "../kube-object"; -import { KubeObject } from "../../api/kube-object"; -import { ICRDRouteParams } from "./crd.route"; +import type { KubeObject } from "../../api/kube-object"; +import type { ICRDRouteParams } from "./crd.route"; import { autorun, computed } from "mobx"; import { crdStore } from "./crd.store"; -import { TableSortCallback } from "../table"; +import type { TableSortCallback } from "../table"; import { apiManager } from "../../api/api-manager"; import { parseJsonPath } from "../../utils/jsonPath"; diff --git a/src/renderer/components/+custom-resources/crd.store.ts b/src/renderer/components/+custom-resources/crd.store.ts index 14af6d9726..9813175b8a 100644 --- a/src/renderer/components/+custom-resources/crd.store.ts +++ b/src/renderer/components/+custom-resources/crd.store.ts @@ -26,14 +26,14 @@ import { crdApi, CustomResourceDefinition } from "../../api/endpoints/crd.api"; import { apiManager } from "../../api/api-manager"; import { KubeApi } from "../../api/kube-api"; import { CRDResourceStore } from "./crd-resource.store"; -import { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../api/kube-object"; function initStore(crd: CustomResourceDefinition) { const apiBase = crd.getResourceApiBase(); const kind = crd.getResourceKind(); const isNamespaced = crd.isNamespaced(); const api = apiManager.getApi(apiBase) || new KubeApi({ apiBase, kind, isNamespaced }); - + if (!apiManager.getStore(api)) { apiManager.registerStore(new CRDResourceStore(api)); } @@ -81,7 +81,7 @@ export class CRDStore extends KubeObjectStore { getByObject(obj: KubeObject) { if (!obj) return null; const { kind, apiVersion } = obj; - + return this.items.find(crd => ( kind === crd.getResourceKind() && apiVersion === `${crd.getGroup()}/${crd.getVersion()}` )); diff --git a/src/renderer/components/+entity-settings/entity-settings.tsx b/src/renderer/components/+entity-settings/entity-settings.tsx index 779cce45d6..18eee4ffaa 100644 --- a/src/renderer/components/+entity-settings/entity-settings.tsx +++ b/src/renderer/components/+entity-settings/entity-settings.tsx @@ -23,15 +23,15 @@ import "./entity-settings.scss"; import React from "react"; import { observable } from "mobx"; -import { RouteComponentProps } from "react-router"; +import type { RouteComponentProps } from "react-router"; import { observer } from "mobx-react"; import { PageLayout } from "../layout/page-layout"; import { navigation } from "../../navigation"; import { Tabs, Tab } from "../tabs"; -import { CatalogEntity } from "../../api/catalog-entity"; +import type { CatalogEntity } from "../../api/catalog-entity"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; import { entitySettingRegistry } from "../../../extensions/registries"; -import { EntitySettingsRouteParams } from "./entity-settings.route"; +import type { EntitySettingsRouteParams } from "./entity-settings.route"; import { groupBy } from "lodash"; interface Props extends RouteComponentProps { diff --git a/src/renderer/components/+events/event-details.tsx b/src/renderer/components/+events/event-details.tsx index d10f36002d..ec50373964 100644 --- a/src/renderer/components/+events/event-details.tsx +++ b/src/renderer/components/+events/event-details.tsx @@ -27,7 +27,7 @@ import { DrawerItem, DrawerTitle } from "../drawer"; import { Link } from "react-router-dom"; import { observer } from "mobx-react"; import { KubeObjectDetailsProps, getDetailsUrl } from "../kube-object"; -import { KubeEvent } from "../../api/endpoints/events.api"; +import type { KubeEvent } from "../../api/endpoints/events.api"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { lookupApiLink } from "../../api/kube-api"; @@ -42,7 +42,7 @@ export class EventDetails extends React.Component { render() { const { object: event } = this.props; - if (!event) return; + if (!event) return null; const { message, reason, count, type, involvedObject } = event; const { kind, name, namespace, fieldPath } = involvedObject; diff --git a/src/renderer/components/+events/event.store.ts b/src/renderer/components/+events/event.store.ts index 65dd71c2ed..7f51104802 100644 --- a/src/renderer/components/+events/event.store.ts +++ b/src/renderer/components/+events/event.store.ts @@ -24,7 +24,7 @@ import compact from "lodash/compact"; import { KubeObjectStore } from "../../kube-object.store"; import { autobind } from "../../utils"; import { eventApi, KubeEvent } from "../../api/endpoints/events.api"; -import { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../api/kube-object"; import { Pod } from "../../api/endpoints/pods.api"; import { podsStore } from "../+workloads-pods/pods.store"; import { apiManager } from "../../api/api-manager"; @@ -65,7 +65,7 @@ export class EventStore extends KubeObjectStore { if (kind == Pod.kind) { // Wipe out running pods const pod = podsStore.items.find(pod => pod.getId() == uid); - if (!pod || (!pod.hasIssues() && pod.spec.priority < 500000)) return; + if (!pod || (!pod.hasIssues() && pod.spec.priority < 500000)) return undefined; } return recent; diff --git a/src/renderer/components/+events/events.tsx b/src/renderer/components/+events/events.tsx index a9bebc1a01..15aafdbf43 100644 --- a/src/renderer/components/+events/events.tsx +++ b/src/renderer/components/+events/events.tsx @@ -28,9 +28,9 @@ import { orderBy } from "lodash"; import { TabLayout } from "../layout/tab-layout"; import { EventStore, eventStore } from "./event.store"; import { getDetailsUrl, KubeObjectListLayout, KubeObjectListLayoutProps } from "../kube-object"; -import { KubeEvent } from "../../api/endpoints/events.api"; -import { TableSortCallbacks, TableSortParams, TableProps } from "../table"; -import { IHeaderPlaceholders } from "../item-object-list"; +import type { KubeEvent } from "../../api/endpoints/events.api"; +import type { TableSortCallbacks, TableSortParams, TableProps } from "../table"; +import type { IHeaderPlaceholders } from "../item-object-list"; import { Tooltip } from "../tooltip"; import { Link } from "react-router-dom"; import { cssNames, IClassName, stopPropagation } from "../../utils"; diff --git a/src/renderer/components/+events/kube-event-details.tsx b/src/renderer/components/+events/kube-event-details.tsx index 474e21abfb..4ac3e63a84 100644 --- a/src/renderer/components/+events/kube-event-details.tsx +++ b/src/renderer/components/+events/kube-event-details.tsx @@ -23,7 +23,7 @@ import "./kube-event-details.scss"; import React from "react"; import { observer } from "mobx-react"; -import { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../api/kube-object"; import { DrawerItem, DrawerTitle } from "../drawer"; import { cssNames } from "../../utils"; import { eventStore } from "./event.store"; diff --git a/src/renderer/components/+events/kube-event-icon.tsx b/src/renderer/components/+events/kube-event-icon.tsx index b93997ab4b..03bfa92a07 100644 --- a/src/renderer/components/+events/kube-event-icon.tsx +++ b/src/renderer/components/+events/kube-event-icon.tsx @@ -23,10 +23,10 @@ import "./kube-event-icon.scss"; import React from "react"; import { Icon } from "../icon"; -import { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../api/kube-object"; import { eventStore } from "./event.store"; import { cssNames } from "../../utils"; -import { KubeEvent } from "../../api/endpoints/events.api"; +import type { KubeEvent } from "../../api/endpoints/events.api"; interface Props { object: KubeObject; diff --git a/src/renderer/components/+extensions/extension-install.store.ts b/src/renderer/components/+extensions/extension-install.store.ts index fc556c068a..79ba16fa01 100644 --- a/src/renderer/components/+extensions/extension-install.store.ts +++ b/src/renderer/components/+extensions/extension-install.store.ts @@ -21,7 +21,8 @@ import { action, computed, observable } from "mobx"; import logger from "../../../main/logger"; -import { disposer, ExtendableDisposer } from "../../utils"; +import { disposer } from "../../utils"; +import type { ExtendableDisposer } from "../../utils"; import * as uuid from "uuid"; import { broadcastMessage } from "../../../common/ipc"; import { ipcRenderer } from "electron"; diff --git a/src/renderer/components/+extensions/extensions.route.ts b/src/renderer/components/+extensions/extensions.route.ts index 1bc555fd53..e8552eac10 100644 --- a/src/renderer/components/+extensions/extensions.route.ts +++ b/src/renderer/components/+extensions/extensions.route.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { RouteProps } from "react-router"; +import type { RouteProps } from "react-router"; import { buildURL } from "../../../common/utils/buildUrl"; export const extensionsRoute: RouteProps = { diff --git a/src/renderer/components/+extensions/extensions.tsx b/src/renderer/components/+extensions/extensions.tsx index cec1f5db20..93923d3093 100644 --- a/src/renderer/components/+extensions/extensions.tsx +++ b/src/renderer/components/+extensions/extensions.tsx @@ -199,7 +199,7 @@ async function createTempFilesAndValidate({ fileName, dataP }: InstallRequest): const data = await dataP; if (!data) { - return; + return null; } await fse.writeFile(tempFile, data); diff --git a/src/renderer/components/+namespaces/add-namespace-dialog.tsx b/src/renderer/components/+namespaces/add-namespace-dialog.tsx index 9970acccab..50b4d207c3 100644 --- a/src/renderer/components/+namespaces/add-namespace-dialog.tsx +++ b/src/renderer/components/+namespaces/add-namespace-dialog.tsx @@ -27,7 +27,7 @@ import { observer } from "mobx-react"; import { Dialog, DialogProps } from "../dialog"; import { Wizard, WizardStep } from "../wizard"; import { namespaceStore } from "./namespace.store"; -import { Namespace } from "../../api/endpoints"; +import type { Namespace } from "../../api/endpoints"; import { Input } from "../input"; import { systemName } from "../input/input_validators"; import { Notifications } from "../notifications"; diff --git a/src/renderer/components/+namespaces/namespace-details.tsx b/src/renderer/components/+namespaces/namespace-details.tsx index 0208a6001a..d8e5e90f7b 100644 --- a/src/renderer/components/+namespaces/namespace-details.tsx +++ b/src/renderer/components/+namespaces/namespace-details.tsx @@ -26,7 +26,7 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; import { DrawerItem } from "../drawer"; import { cssNames } from "../../utils"; -import { Namespace } from "../../api/endpoints"; +import type { Namespace } from "../../api/endpoints"; import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object"; import { Link } from "react-router-dom"; import { Spinner } from "../spinner"; @@ -60,7 +60,7 @@ export class NamespaceDetails extends React.Component { render() { const { object: namespace } = this.props; - if (!namespace) return; + if (!namespace) return null; const status = namespace.getStatus(); return ( diff --git a/src/renderer/components/+namespaces/namespace-select-filter.tsx b/src/renderer/components/+namespaces/namespace-select-filter.tsx index 0bdb4fbb8e..8f4e9df6da 100644 --- a/src/renderer/components/+namespaces/namespace-select-filter.tsx +++ b/src/renderer/components/+namespaces/namespace-select-filter.tsx @@ -28,7 +28,7 @@ import { components, PlaceholderProps } from "react-select"; import { Icon } from "../icon"; import { FilterIcon } from "../item-object-list/filter-icon"; import { FilterType } from "../item-object-list/page-filters.store"; -import { SelectOption } from "../select"; +import type { SelectOption } from "../select"; import { NamespaceSelect } from "./namespace-select"; import { namespaceStore } from "./namespace.store"; diff --git a/src/renderer/components/+namespaces/namespaces.tsx b/src/renderer/components/+namespaces/namespaces.tsx index 4de61ef7c2..2c9a778777 100644 --- a/src/renderer/components/+namespaces/namespaces.tsx +++ b/src/renderer/components/+namespaces/namespaces.tsx @@ -26,9 +26,9 @@ import { Namespace, NamespaceStatus } from "../../api/endpoints"; import { AddNamespaceDialog } from "./add-namespace-dialog"; import { TabLayout } from "../layout/tab-layout"; import { Badge } from "../badge"; -import { RouteComponentProps } from "react-router"; +import type { RouteComponentProps } from "react-router"; import { KubeObjectListLayout } from "../kube-object"; -import { INamespacesRouteParams } from "./namespaces.route"; +import type { INamespacesRouteParams } from "./namespaces.route"; import { namespaceStore } from "./namespace.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; diff --git a/src/renderer/components/+network-endpoints/endpoint-details.tsx b/src/renderer/components/+network-endpoints/endpoint-details.tsx index eebaa4dd4a..d8cc20f529 100644 --- a/src/renderer/components/+network-endpoints/endpoint-details.tsx +++ b/src/renderer/components/+network-endpoints/endpoint-details.tsx @@ -25,8 +25,8 @@ import React from "react"; import { observer } from "mobx-react"; import { DrawerTitle } from "../drawer"; import { KubeEventDetails } from "../+events/kube-event-details"; -import { KubeObjectDetailsProps } from "../kube-object"; -import { Endpoint } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object"; +import type { Endpoint } from "../../api/endpoints"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { EndpointSubsetList } from "./endpoint-subset-list"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; @@ -39,7 +39,7 @@ export class EndpointDetails extends React.Component { render() { const { object: endpoint } = this.props; - if (!endpoint) return; + if (!endpoint) return null; return (
diff --git a/src/renderer/components/+network-endpoints/endpoints.tsx b/src/renderer/components/+network-endpoints/endpoints.tsx index 666fde15c8..7cc74427fa 100644 --- a/src/renderer/components/+network-endpoints/endpoints.tsx +++ b/src/renderer/components/+network-endpoints/endpoints.tsx @@ -23,9 +23,9 @@ import "./endpoints.scss"; import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router-dom"; -import { EndpointRouteParams } from "./endpoints.route"; -import { Endpoint } from "../../api/endpoints/endpoint.api"; +import type { RouteComponentProps } from "react-router-dom"; +import type { EndpointRouteParams } from "./endpoints.route"; +import type { Endpoint } from "../../api/endpoints/endpoint.api"; import { endpointStore } from "./endpoints.store"; import { KubeObjectListLayout } from "../kube-object"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; diff --git a/src/renderer/components/+network-ingresses/ingress-charts.tsx b/src/renderer/components/+network-ingresses/ingress-charts.tsx index 4ebb7d4a9e..178d61652c 100644 --- a/src/renderer/components/+network-ingresses/ingress-charts.tsx +++ b/src/renderer/components/+network-ingresses/ingress-charts.tsx @@ -21,8 +21,8 @@ import React, { useContext } from "react"; import { observer } from "mobx-react"; -import { ChartOptions, ChartPoint } from "chart.js"; -import { IIngressMetrics, Ingress } from "../../api/endpoints"; +import type { ChartOptions, ChartPoint } from "chart.js"; +import type { IIngressMetrics, Ingress } from "../../api/endpoints"; import { BarChart, memoryOptions } from "../chart"; import { normalizeMetrics, isMetricsEmpty } from "../../api/endpoints/metrics.api"; import { NoMetrics } from "../resource-metrics/no-metrics"; diff --git a/src/renderer/components/+network-ingresses/ingress-details.tsx b/src/renderer/components/+network-ingresses/ingress-details.tsx index 896ed1ea92..8e9ddf7bb4 100644 --- a/src/renderer/components/+network-ingresses/ingress-details.tsx +++ b/src/renderer/components/+network-ingresses/ingress-details.tsx @@ -25,12 +25,12 @@ import React from "react"; import { disposeOnUnmount, observer } from "mobx-react"; import { reaction } from "mobx"; import { DrawerItem, DrawerTitle } from "../drawer"; -import { ILoadBalancerIngress, Ingress } from "../../api/endpoints"; +import type { ILoadBalancerIngress, Ingress } from "../../api/endpoints"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { KubeEventDetails } from "../+events/kube-event-details"; import { ingressStore } from "./ingress.store"; import { ResourceMetrics } from "../resource-metrics"; -import { KubeObjectDetailsProps } from "../kube-object"; +import type { KubeObjectDetailsProps } from "../kube-object"; import { IngressCharts } from "./ingress-charts"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; diff --git a/src/renderer/components/+network-ingresses/ingresses.tsx b/src/renderer/components/+network-ingresses/ingresses.tsx index 9005aaeedf..1ee39d4010 100644 --- a/src/renderer/components/+network-ingresses/ingresses.tsx +++ b/src/renderer/components/+network-ingresses/ingresses.tsx @@ -23,9 +23,9 @@ import "./ingresses.scss"; import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router-dom"; -import { IngressRouteParams } from "./ingresses.route"; -import { Ingress } from "../../api/endpoints/ingress.api"; +import type { RouteComponentProps } from "react-router-dom"; +import type { IngressRouteParams } from "./ingresses.route"; +import type { Ingress } from "../../api/endpoints/ingress.api"; import { ingressStore } from "./ingress.store"; import { KubeObjectListLayout } from "../kube-object"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; diff --git a/src/renderer/components/+network-policies/network-policies.tsx b/src/renderer/components/+network-policies/network-policies.tsx index 558973a0ad..1010c07175 100644 --- a/src/renderer/components/+network-policies/network-policies.tsx +++ b/src/renderer/components/+network-policies/network-policies.tsx @@ -23,10 +23,10 @@ import "./network-policies.scss"; import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router-dom"; -import { NetworkPolicy } from "../../api/endpoints/network-policy.api"; +import type { RouteComponentProps } from "react-router-dom"; +import type { NetworkPolicy } from "../../api/endpoints/network-policy.api"; import { KubeObjectListLayout } from "../kube-object"; -import { INetworkPoliciesRouteParams } from "./network-policies.route"; +import type { INetworkPoliciesRouteParams } from "./network-policies.route"; import { networkPolicyStore } from "./network-policy.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; diff --git a/src/renderer/components/+network-policies/network-policy-details.tsx b/src/renderer/components/+network-policies/network-policy-details.tsx index 54a0e8e93a..289d139fb5 100644 --- a/src/renderer/components/+network-policies/network-policy-details.tsx +++ b/src/renderer/components/+network-policies/network-policy-details.tsx @@ -24,12 +24,12 @@ import "./network-policy-details.scss"; import get from "lodash/get"; import React, { Fragment } from "react"; import { DrawerItem, DrawerTitle } from "../drawer"; -import { IPolicyEgress, IPolicyIngress, IPolicyIpBlock, IPolicySelector, NetworkPolicy } from "../../api/endpoints/network-policy.api"; +import type { IPolicyEgress, IPolicyIngress, IPolicyIpBlock, IPolicySelector, NetworkPolicy } from "../../api/endpoints/network-policy.api"; import { Badge } from "../badge"; import { SubTitle } from "../layout/sub-title"; import { KubeEventDetails } from "../+events/kube-event-details"; import { observer } from "mobx-react"; -import { KubeObjectDetailsProps } from "../kube-object"; +import type { KubeObjectDetailsProps } from "../kube-object"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; @@ -53,7 +53,7 @@ export class NetworkPolicyDetails extends React.Component { if (key === "ipBlock") { const { cidr, except } = data as IPolicyIpBlock; - if (!cidr) return; + if (!cidr) return null; return ( @@ -96,12 +96,9 @@ export class NetworkPolicyDetails extends React.Component { <> {to.map(item => { - const { ipBlock } = item; + const { ipBlock: { cidr, except } = {} } = item; - if (!ipBlock) return; - const { cidr, except } = ipBlock; - - if (!cidr) return; + if (!cidr) return null; return ( diff --git a/src/renderer/components/+network-services/service-details-endpoint.tsx b/src/renderer/components/+network-services/service-details-endpoint.tsx index 9ba114c90c..2e04c78f1a 100644 --- a/src/renderer/components/+network-services/service-details-endpoint.tsx +++ b/src/renderer/components/+network-services/service-details-endpoint.tsx @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../api/kube-object"; import { observer } from "mobx-react"; import React from "react"; import { Table, TableHead, TableCell, TableRow } from "../table"; diff --git a/src/renderer/components/+network-services/service-details.tsx b/src/renderer/components/+network-services/service-details.tsx index 804519ae18..f04b5687af 100644 --- a/src/renderer/components/+network-services/service-details.tsx +++ b/src/renderer/components/+network-services/service-details.tsx @@ -26,8 +26,8 @@ import { disposeOnUnmount, observer } from "mobx-react"; import { DrawerItem, DrawerTitle } from "../drawer"; import { Badge } from "../badge"; import { KubeEventDetails } from "../+events/kube-event-details"; -import { KubeObjectDetailsProps } from "../kube-object"; -import { Service } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object"; +import type { Service } from "../../api/endpoints"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { ServicePortComponent } from "./service-port-component"; import { endpointStore } from "../+network-endpoints/endpoints.store"; @@ -51,7 +51,7 @@ export class ServiceDetails extends React.Component { render() { const { object: service } = this.props; - if (!service) return; + if (!service) return null; const { spec } = service; const endpoint = endpointStore.getByName(service.getName(), service.getNs()); diff --git a/src/renderer/components/+network-services/service-port-component.tsx b/src/renderer/components/+network-services/service-port-component.tsx index 1b297ed26a..c83ea9eb17 100644 --- a/src/renderer/components/+network-services/service-port-component.tsx +++ b/src/renderer/components/+network-services/service-port-component.tsx @@ -23,7 +23,7 @@ import "./service-port-component.scss"; import React from "react"; import { observer } from "mobx-react"; -import { Service, ServicePort } from "../../api/endpoints"; +import type { Service, ServicePort } from "../../api/endpoints"; import { apiBase } from "../../api"; import { observable } from "mobx"; import { cssNames } from "../../utils"; diff --git a/src/renderer/components/+network-services/services.tsx b/src/renderer/components/+network-services/services.tsx index 739b9c30c9..33f9b73e08 100644 --- a/src/renderer/components/+network-services/services.tsx +++ b/src/renderer/components/+network-services/services.tsx @@ -23,9 +23,9 @@ import "./services.scss"; import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router"; -import { IServicesRouteParams } from "./services.route"; -import { Service } from "../../api/endpoints/service.api"; +import type { RouteComponentProps } from "react-router"; +import type { IServicesRouteParams } from "./services.route"; +import type { Service } from "../../api/endpoints/service.api"; import { KubeObjectListLayout } from "../kube-object"; import { Badge } from "../badge"; import { serviceStore } from "./services.store"; diff --git a/src/renderer/components/+network/network.route.ts b/src/renderer/components/+network/network.route.ts index 7647ddeca6..a827461f8f 100644 --- a/src/renderer/components/+network/network.route.ts +++ b/src/renderer/components/+network/network.route.ts @@ -19,12 +19,12 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { RouteProps } from "react-router"; +import type { RouteProps } from "react-router"; import { endpointRoute } from "../+network-endpoints"; import { ingressRoute } from "../+network-ingresses"; import { networkPoliciesRoute } from "../+network-policies"; import { servicesRoute, servicesURL } from "../+network-services"; -import { IURLParams } from "../../../common/utils/buildUrl"; +import type { IURLParams } from "../../../common/utils/buildUrl"; export const networkRoute: RouteProps = { path: [ diff --git a/src/renderer/components/+nodes/node-charts.tsx b/src/renderer/components/+nodes/node-charts.tsx index 9a1b1c7e1a..664da5a19b 100644 --- a/src/renderer/components/+nodes/node-charts.tsx +++ b/src/renderer/components/+nodes/node-charts.tsx @@ -20,13 +20,13 @@ */ import React, { useContext } from "react"; -import { IClusterMetrics, Node } from "../../api/endpoints"; +import type { IClusterMetrics, Node } from "../../api/endpoints"; import { BarChart, cpuOptions, memoryOptions } from "../chart"; import { isMetricsEmpty, normalizeMetrics } from "../../api/endpoints/metrics.api"; import { NoMetrics } from "../resource-metrics/no-metrics"; import { IResourceMetricsValue, ResourceMetricsContext } from "../resource-metrics"; import { observer } from "mobx-react"; -import { ChartOptions, ChartPoint } from "chart.js"; +import type { ChartOptions, ChartPoint } from "chart.js"; import { ThemeStore } from "../../theme.store"; import { mapValues } from "lodash"; diff --git a/src/renderer/components/+nodes/node-details.tsx b/src/renderer/components/+nodes/node-details.tsx index e0b93364af..df98312d17 100644 --- a/src/renderer/components/+nodes/node-details.tsx +++ b/src/renderer/components/+nodes/node-details.tsx @@ -30,8 +30,8 @@ import { Badge } from "../badge"; import { nodesStore } from "./nodes.store"; import { ResourceMetrics } from "../resource-metrics"; import { podsStore } from "../+workloads-pods/pods.store"; -import { KubeObjectDetailsProps } from "../kube-object"; -import { Node } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object"; +import type { Node } from "../../api/endpoints"; import { NodeCharts } from "./node-charts"; import { reaction } from "mobx"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; @@ -62,7 +62,7 @@ export class NodeDetails extends React.Component { render() { const { object: node } = this.props; - if (!node) return; + if (!node) return null; const { status } = node; const { nodeInfo, addresses, capacity, allocatable } = status; const conditions = node.getActiveConditions(); diff --git a/src/renderer/components/+nodes/nodes.store.ts b/src/renderer/components/+nodes/nodes.store.ts index eb7c94cc25..cd7bb12123 100644 --- a/src/renderer/components/+nodes/nodes.store.ts +++ b/src/renderer/components/+nodes/nodes.store.ts @@ -62,7 +62,7 @@ export class NodesStore extends KubeObjectStore { getLastMetricValues(node: Node, metricNames: string[]): number[] { if (!this.metricsLoaded) { - return; + return []; } const nodeName = node.getName(); diff --git a/src/renderer/components/+nodes/nodes.tsx b/src/renderer/components/+nodes/nodes.tsx index 72ef7e07a4..953562b06b 100644 --- a/src/renderer/components/+nodes/nodes.tsx +++ b/src/renderer/components/+nodes/nodes.tsx @@ -22,14 +22,14 @@ import "./nodes.scss"; import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router"; +import type { RouteComponentProps } from "react-router"; import { cssNames, interval } from "../../utils"; import { TabLayout } from "../layout/tab-layout"; import { nodesStore } from "./nodes.store"; import { podsStore } from "../+workloads-pods/pods.store"; import { KubeObjectListLayout } from "../kube-object"; -import { INodesRouteParams } from "./nodes.route"; -import { Node } from "../../api/endpoints/nodes.api"; +import type { INodesRouteParams } from "./nodes.route"; +import type { Node } from "../../api/endpoints/nodes.api"; import { LineProgress } from "../line-progress"; import { bytesToUnits } from "../../utils/convertMemory"; import { Tooltip, TooltipPosition } from "../tooltip"; @@ -73,8 +73,8 @@ export class Nodes extends React.Component { const usage = metrics[0]; const cores = metrics[1]; const cpuUsagePercent = Math.ceil(usage * 100) / cores; - const cpuUsagePercentLabel: String = cpuUsagePercent % 1 === 0 - ? cpuUsagePercent.toString() + const cpuUsagePercentLabel: String = cpuUsagePercent % 1 === 0 + ? cpuUsagePercent.toString() : cpuUsagePercent.toFixed(2); return ( diff --git a/src/renderer/components/+pod-security-policies/pod-security-policies.tsx b/src/renderer/components/+pod-security-policies/pod-security-policies.tsx index 3cefe234e9..addae6322e 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policies.tsx +++ b/src/renderer/components/+pod-security-policies/pod-security-policies.tsx @@ -25,7 +25,7 @@ import React from "react"; import { observer } from "mobx-react"; import { KubeObjectListLayout } from "../kube-object"; import { podSecurityPoliciesStore } from "./pod-security-policies.store"; -import { PodSecurityPolicy } from "../../api/endpoints"; +import type { PodSecurityPolicy } from "../../api/endpoints"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; enum columnId { diff --git a/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx b/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx index 615e87a7fd..eacc4f7696 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx +++ b/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx @@ -24,8 +24,8 @@ import "./pod-security-policy-details.scss"; import React from "react"; import { observer } from "mobx-react"; import { DrawerItem, DrawerTitle } from "../drawer"; -import { KubeObjectDetailsProps } from "../kube-object"; -import { PodSecurityPolicy } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object"; +import type { PodSecurityPolicy } from "../../api/endpoints"; import { Badge } from "../badge"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; @@ -42,7 +42,7 @@ export class PodSecurityPolicyDetails extends React.Component { rule: string; ranges?: { max: number; min: number }[]; }) { - if (!group) return; + if (!group) return null; const { rule, ranges } = group; return ( diff --git a/src/renderer/components/+storage-classes/storage-class-details.tsx b/src/renderer/components/+storage-classes/storage-class-details.tsx index 1db217ac83..e99501b963 100644 --- a/src/renderer/components/+storage-classes/storage-class-details.tsx +++ b/src/renderer/components/+storage-classes/storage-class-details.tsx @@ -27,8 +27,8 @@ import { DrawerItem, DrawerTitle } from "../drawer"; import { Badge } from "../badge"; import { KubeEventDetails } from "../+events/kube-event-details"; import { observer } from "mobx-react"; -import { KubeObjectDetailsProps } from "../kube-object"; -import { StorageClass } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object"; +import type { StorageClass } from "../../api/endpoints"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; import { storageClassStore } from "./storage-class.store"; diff --git a/src/renderer/components/+storage-classes/storage-classes.tsx b/src/renderer/components/+storage-classes/storage-classes.tsx index 725230afe0..39182abb46 100644 --- a/src/renderer/components/+storage-classes/storage-classes.tsx +++ b/src/renderer/components/+storage-classes/storage-classes.tsx @@ -22,11 +22,11 @@ import "./storage-classes.scss"; import React from "react"; -import { RouteComponentProps } from "react-router-dom"; +import type { RouteComponentProps } from "react-router-dom"; import { observer } from "mobx-react"; -import { StorageClass } from "../../api/endpoints/storage-class.api"; +import type { StorageClass } from "../../api/endpoints/storage-class.api"; import { KubeObjectListLayout } from "../kube-object"; -import { IStorageClassesRouteParams } from "./storage-classes.route"; +import type { IStorageClassesRouteParams } from "./storage-classes.route"; import { storageClassStore } from "./storage-class.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; diff --git a/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx b/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx index f7ad7ff65c..c2ae2f672f 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx @@ -33,7 +33,7 @@ import { volumeClaimStore } from "./volume-claim.store"; import { ResourceMetrics } from "../resource-metrics"; import { VolumeClaimDiskChart } from "./volume-claim-disk-chart"; import { getDetailsUrl, KubeObjectDetailsProps, KubeObjectMeta } from "../kube-object"; -import { PersistentVolumeClaim } from "../../api/endpoints"; +import type { PersistentVolumeClaim } from "../../api/endpoints"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting"; import { ClusterStore } from "../../../common/cluster-store"; diff --git a/src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx b/src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx index cf09c4caa5..cd1c6f7024 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx @@ -21,7 +21,7 @@ import React, { useContext } from "react"; import { observer } from "mobx-react"; -import { IPvcMetrics, PersistentVolumeClaim } from "../../api/endpoints"; +import type { IPvcMetrics, PersistentVolumeClaim } from "../../api/endpoints"; import { BarChart, ChartDataSets, memoryOptions } from "../chart"; import { isMetricsEmpty, normalizeMetrics } from "../../api/endpoints/metrics.api"; import { NoMetrics } from "../resource-metrics/no-metrics"; diff --git a/src/renderer/components/+storage-volume-claims/volume-claims.tsx b/src/renderer/components/+storage-volume-claims/volume-claims.tsx index 404dcf5da5..34309b43ec 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claims.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claims.tsx @@ -25,10 +25,10 @@ import React from "react"; import { observer } from "mobx-react"; import { Link, RouteComponentProps } from "react-router-dom"; import { volumeClaimStore } from "./volume-claim.store"; -import { PersistentVolumeClaim } from "../../api/endpoints/persistent-volume-claims.api"; +import type { PersistentVolumeClaim } from "../../api/endpoints/persistent-volume-claims.api"; import { podsStore } from "../+workloads-pods/pods.store"; import { getDetailsUrl, KubeObjectListLayout } from "../kube-object"; -import { IVolumeClaimsRouteParams } from "./volume-claims.route"; +import type { IVolumeClaimsRouteParams } from "./volume-claims.route"; import { unitsToBytes } from "../../utils/convertMemory"; import { stopPropagation } from "../../utils"; import { storageClassApi } from "../../api/endpoints"; diff --git a/src/renderer/components/+storage-volumes/volume-details-list.tsx b/src/renderer/components/+storage-volumes/volume-details-list.tsx index c69d470c8c..6cb3eec3d1 100644 --- a/src/renderer/components/+storage-volumes/volume-details-list.tsx +++ b/src/renderer/components/+storage-volumes/volume-details-list.tsx @@ -23,7 +23,7 @@ import "./volume-details-list.scss"; import React from "react"; import { observer } from "mobx-react"; -import { PersistentVolume } from "../../api/endpoints/persistent-volume.api"; +import type { PersistentVolume } from "../../api/endpoints/persistent-volume.api"; import { autobind } from "../../../common/utils/autobind"; import { TableRow } from "../table/table-row"; import { cssNames, prevDefault } from "../../utils"; diff --git a/src/renderer/components/+storage-volumes/volumes.store.ts b/src/renderer/components/+storage-volumes/volumes.store.ts index 97fa2b18f2..f6c1012dd8 100644 --- a/src/renderer/components/+storage-volumes/volumes.store.ts +++ b/src/renderer/components/+storage-volumes/volumes.store.ts @@ -23,7 +23,7 @@ import { KubeObjectStore } from "../../kube-object.store"; import { autobind } from "../../utils"; import { PersistentVolume, persistentVolumeApi } from "../../api/endpoints/persistent-volume.api"; import { apiManager } from "../../api/api-manager"; -import { StorageClass } from "../../api/endpoints/storage-class.api"; +import type { StorageClass } from "../../api/endpoints/storage-class.api"; @autobind() export class PersistentVolumesStore extends KubeObjectStore { diff --git a/src/renderer/components/+storage-volumes/volumes.tsx b/src/renderer/components/+storage-volumes/volumes.tsx index 590fe11a38..858d362bb2 100644 --- a/src/renderer/components/+storage-volumes/volumes.tsx +++ b/src/renderer/components/+storage-volumes/volumes.tsx @@ -24,9 +24,9 @@ import "./volumes.scss"; import React from "react"; import { observer } from "mobx-react"; import { Link, RouteComponentProps } from "react-router-dom"; -import { PersistentVolume } from "../../api/endpoints/persistent-volume.api"; +import type { PersistentVolume } from "../../api/endpoints/persistent-volume.api"; import { getDetailsUrl, KubeObjectListLayout } from "../kube-object"; -import { IVolumesRouteParams } from "./volumes.route"; +import type { IVolumesRouteParams } from "./volumes.route"; import { stopPropagation } from "../../utils"; import { volumesStore } from "./volumes.store"; import { pvcApi, storageClassApi } from "../../api/endpoints"; diff --git a/src/renderer/components/+storage/storage.route.ts b/src/renderer/components/+storage/storage.route.ts index 3162e18b8e..6903a76375 100644 --- a/src/renderer/components/+storage/storage.route.ts +++ b/src/renderer/components/+storage/storage.route.ts @@ -19,11 +19,11 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { RouteProps } from "react-router"; +import type { RouteProps } from "react-router"; import { storageClassesRoute } from "../+storage-classes"; import { volumeClaimsRoute, volumeClaimsURL } from "../+storage-volume-claims"; import { volumesRoute } from "../+storage-volumes"; -import { IURLParams } from "../../../common/utils/buildUrl"; +import type { IURLParams } from "../../../common/utils/buildUrl"; export const storageRoute: RouteProps = { path: [ diff --git a/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx b/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx index 71c0b25406..83ae0b9abd 100644 --- a/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx +++ b/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx @@ -40,7 +40,7 @@ import { namespaceStore } from "../+namespaces/namespace.store"; import { serviceAccountsStore } from "../+user-management-service-accounts/service-accounts.store"; import { roleBindingsStore } from "./role-bindings.store"; import { showDetails } from "../kube-object"; -import { KubeObjectStore } from "../../kube-object.store"; +import type { KubeObjectStore } from "../../kube-object.store"; interface BindingSelectOption extends SelectOption { value: string; // binding name diff --git a/src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx b/src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx index 2d5ff1a30f..c42cdbebed 100644 --- a/src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx +++ b/src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx @@ -23,7 +23,7 @@ import "./role-binding-details.scss"; import React from "react"; import { AddRemoveButtons } from "../add-remove-buttons"; -import { IRoleBindingSubject, RoleBinding } from "../../api/endpoints"; +import type { IRoleBindingSubject, RoleBinding } from "../../api/endpoints"; import { autobind, prevDefault } from "../../utils"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { ConfirmDialog } from "../confirm-dialog"; @@ -33,7 +33,7 @@ import { disposeOnUnmount, observer } from "mobx-react"; import { observable, reaction } from "mobx"; import { roleBindingsStore } from "./role-bindings.store"; import { AddRoleBindingDialog } from "./add-role-binding-dialog"; -import { KubeObjectDetailsProps } from "../kube-object"; +import type { KubeObjectDetailsProps } from "../kube-object"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; diff --git a/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx b/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx index d406141d16..db86d37cd6 100644 --- a/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx +++ b/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx @@ -23,9 +23,9 @@ import "./role-bindings.scss"; import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router"; -import { IRoleBindingsRouteParams } from "../+user-management/user-management.route"; -import { RoleBinding } from "../../api/endpoints"; +import type { RouteComponentProps } from "react-router"; +import type { IRoleBindingsRouteParams } from "../+user-management/user-management.route"; +import type { RoleBinding } from "../../api/endpoints"; import { roleBindingsStore } from "./role-bindings.store"; import { KubeObjectListLayout } from "../kube-object"; import { AddRoleBindingDialog } from "./add-role-binding-dialog"; diff --git a/src/renderer/components/+user-management-roles/role-details.tsx b/src/renderer/components/+user-management-roles/role-details.tsx index 1d6344c561..34fb92f816 100644 --- a/src/renderer/components/+user-management-roles/role-details.tsx +++ b/src/renderer/components/+user-management-roles/role-details.tsx @@ -25,8 +25,8 @@ import React from "react"; import { DrawerTitle } from "../drawer"; import { KubeEventDetails } from "../+events/kube-event-details"; import { observer } from "mobx-react"; -import { KubeObjectDetailsProps } from "../kube-object"; -import { Role } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object"; +import type { Role } from "../../api/endpoints"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; @@ -38,7 +38,7 @@ export class RoleDetails extends React.Component { render() { const { object: role } = this.props; - if (!role) return; + if (!role) return null; const rules = role.getRules(); return ( diff --git a/src/renderer/components/+user-management-roles/roles.tsx b/src/renderer/components/+user-management-roles/roles.tsx index 028edeb926..ac7385cb2c 100644 --- a/src/renderer/components/+user-management-roles/roles.tsx +++ b/src/renderer/components/+user-management-roles/roles.tsx @@ -23,10 +23,10 @@ import "./roles.scss"; import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router"; -import { IRolesRouteParams } from "../+user-management/user-management.route"; +import type { RouteComponentProps } from "react-router"; +import type { IRolesRouteParams } from "../+user-management/user-management.route"; import { rolesStore } from "./roles.store"; -import { Role } from "../../api/endpoints"; +import type { Role } from "../../api/endpoints"; import { KubeObjectListLayout } from "../kube-object"; import { AddRoleDialog } from "./add-role-dialog"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; diff --git a/src/renderer/components/+user-management-service-accounts/service-accounts-secret.tsx b/src/renderer/components/+user-management-service-accounts/service-accounts-secret.tsx index 060fdffe1b..d57bb8cc05 100644 --- a/src/renderer/components/+user-management-service-accounts/service-accounts-secret.tsx +++ b/src/renderer/components/+user-management-service-accounts/service-accounts-secret.tsx @@ -24,7 +24,7 @@ import "./service-accounts-secret.scss"; import React from "react"; import moment from "moment"; import { Icon } from "../icon"; -import { Secret } from "../../api/endpoints/secret.api"; +import type { Secret } from "../../api/endpoints/secret.api"; import { prevDefault } from "../../utils"; interface Props { diff --git a/src/renderer/components/+user-management-service-accounts/service-accounts.tsx b/src/renderer/components/+user-management-service-accounts/service-accounts.tsx index f8a77ff381..dff4d1fe58 100644 --- a/src/renderer/components/+user-management-service-accounts/service-accounts.tsx +++ b/src/renderer/components/+user-management-service-accounts/service-accounts.tsx @@ -23,14 +23,14 @@ import "./service-accounts.scss"; import React from "react"; import { observer } from "mobx-react"; -import { ServiceAccount } from "../../api/endpoints/service-accounts.api"; -import { RouteComponentProps } from "react-router"; -import { KubeObjectMenuProps } from "../kube-object/kube-object-menu"; +import type { ServiceAccount } from "../../api/endpoints/service-accounts.api"; +import type { RouteComponentProps } from "react-router"; +import type { KubeObjectMenuProps } from "../kube-object/kube-object-menu"; import { MenuItem } from "../menu"; import { openServiceAccountKubeConfig } from "../kubeconfig-dialog"; import { Icon } from "../icon"; import { KubeObjectListLayout } from "../kube-object"; -import { IServiceAccountsRouteParams } from "../+user-management"; +import type { IServiceAccountsRouteParams } from "../+user-management"; import { serviceAccountsStore } from "./service-accounts.store"; import { CreateServiceAccountDialog } from "./create-service-account-dialog"; import { kubeObjectMenuRegistry } from "../../../extensions/registries/kube-object-menu-registry"; diff --git a/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx b/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx index 2e0e88a856..e86f4f5c8e 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx @@ -31,7 +31,7 @@ import { Link } from "react-router-dom"; import { KubeEventDetails } from "../+events/kube-event-details"; import { cronJobStore } from "./cronjob.store"; import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object"; -import { CronJob, Job } from "../../api/endpoints"; +import type { CronJob, Job } from "../../api/endpoints"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; diff --git a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx index e32834ad6b..04560aa197 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx @@ -23,15 +23,15 @@ import "./cronjobs.scss"; import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router"; +import type { RouteComponentProps } from "react-router"; import { CronJob, cronJobApi } from "../../api/endpoints/cron-job.api"; import { MenuItem } from "../menu"; import { Icon } from "../icon"; import { cronJobStore } from "./cronjob.store"; import { jobStore } from "../+workloads-jobs/job.store"; import { eventStore } from "../+events/event.store"; -import { KubeObjectMenuProps } from "../kube-object/kube-object-menu"; -import { ICronJobsRouteParams } from "../+workloads"; +import type { KubeObjectMenuProps } from "../kube-object/kube-object-menu"; +import type { ICronJobsRouteParams } from "../+workloads"; import { KubeObjectListLayout } from "../kube-object"; import { CronJobTriggerDialog } from "./cronjob-trigger-dialog"; import { kubeObjectMenuRegistry } from "../../../extensions/registries/kube-object-menu-registry"; diff --git a/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx b/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx index 1c94fb4a34..96bf692e72 100644 --- a/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx +++ b/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx @@ -31,8 +31,8 @@ import { PodDetailsAffinities } from "../+workloads-pods/pod-details-affinities" import { KubeEventDetails } from "../+events/kube-event-details"; import { daemonSetStore } from "./daemonsets.store"; import { podsStore } from "../+workloads-pods/pods.store"; -import { KubeObjectDetailsProps } from "../kube-object"; -import { DaemonSet } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object"; +import type { DaemonSet } from "../../api/endpoints"; import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics"; import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; import { reaction } from "mobx"; diff --git a/src/renderer/components/+workloads-daemonsets/daemonsets.tsx b/src/renderer/components/+workloads-daemonsets/daemonsets.tsx index a9c441f1ae..b256ac1f62 100644 --- a/src/renderer/components/+workloads-daemonsets/daemonsets.tsx +++ b/src/renderer/components/+workloads-daemonsets/daemonsets.tsx @@ -23,14 +23,14 @@ import "./daemonsets.scss"; import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router"; -import { DaemonSet } from "../../api/endpoints"; +import type { RouteComponentProps } from "react-router"; +import type { DaemonSet } from "../../api/endpoints"; import { eventStore } from "../+events/event.store"; import { daemonSetStore } from "./daemonsets.store"; import { podsStore } from "../+workloads-pods/pods.store"; import { nodesStore } from "../+nodes/nodes.store"; import { KubeObjectListLayout } from "../kube-object"; -import { IDaemonSetsRouteParams } from "../+workloads"; +import type { IDaemonSetsRouteParams } from "../+workloads"; import { Badge } from "../badge"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; diff --git a/src/renderer/components/+workloads-deployments/deployment-details.tsx b/src/renderer/components/+workloads-deployments/deployment-details.tsx index 112953e63a..21bf03bdf5 100644 --- a/src/renderer/components/+workloads-deployments/deployment-details.tsx +++ b/src/renderer/components/+workloads-deployments/deployment-details.tsx @@ -26,13 +26,13 @@ import kebabCase from "lodash/kebabCase"; import { disposeOnUnmount, observer } from "mobx-react"; import { DrawerItem } from "../drawer"; import { Badge } from "../badge"; -import { Deployment } from "../../api/endpoints"; +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 { KubeEventDetails } from "../+events/kube-event-details"; import { podsStore } from "../+workloads-pods/pods.store"; -import { KubeObjectDetailsProps } from "../kube-object"; +import type { KubeObjectDetailsProps } from "../kube-object"; import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics"; import { deploymentStore } from "./deployments.store"; import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; diff --git a/src/renderer/components/+workloads-deployments/deployment-replicasets.tsx b/src/renderer/components/+workloads-deployments/deployment-replicasets.tsx index 8fbce9564d..0a556ddcfc 100644 --- a/src/renderer/components/+workloads-deployments/deployment-replicasets.tsx +++ b/src/renderer/components/+workloads-deployments/deployment-replicasets.tsx @@ -23,7 +23,7 @@ import "./deployment-replicasets.scss"; import React from "react"; import { observer } from "mobx-react"; -import { ReplicaSet } from "../../api/endpoints"; +import type { ReplicaSet } from "../../api/endpoints"; import { KubeObjectMenu, KubeObjectMenuProps } from "../kube-object/kube-object-menu"; import { Spinner } from "../spinner"; import { prevDefault, stopPropagation } from "../../utils"; diff --git a/src/renderer/components/+workloads-deployments/deployments.tsx b/src/renderer/components/+workloads-deployments/deployments.tsx index 77b6c34abe..74ddb08fcb 100644 --- a/src/renderer/components/+workloads-deployments/deployments.tsx +++ b/src/renderer/components/+workloads-deployments/deployments.tsx @@ -23,9 +23,9 @@ import "./deployments.scss"; import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router"; +import type { RouteComponentProps } from "react-router"; import { Deployment, deploymentApi } from "../../api/endpoints"; -import { KubeObjectMenuProps } from "../kube-object/kube-object-menu"; +import type { KubeObjectMenuProps } from "../kube-object/kube-object-menu"; import { MenuItem } from "../menu"; import { Icon } from "../icon"; import { DeploymentScaleDialog } from "./deployment-scale-dialog"; @@ -36,7 +36,7 @@ import { podsStore } from "../+workloads-pods/pods.store"; import { nodesStore } from "../+nodes/nodes.store"; import { eventStore } from "../+events/event.store"; import { KubeObjectListLayout } from "../kube-object"; -import { IDeploymentsRouteParams } from "../+workloads"; +import type { IDeploymentsRouteParams } from "../+workloads"; import { cssNames } from "../../utils"; import kebabCase from "lodash/kebabCase"; import orderBy from "lodash/orderBy"; diff --git a/src/renderer/components/+workloads-jobs/job-details.tsx b/src/renderer/components/+workloads-jobs/job-details.tsx index a947c918d1..6fcbff96e7 100644 --- a/src/renderer/components/+workloads-jobs/job-details.tsx +++ b/src/renderer/components/+workloads-jobs/job-details.tsx @@ -34,7 +34,7 @@ import { KubeEventDetails } from "../+events/kube-event-details"; import { podsStore } from "../+workloads-pods/pods.store"; import { jobStore } from "./job.store"; import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object"; -import { Job } from "../../api/endpoints"; +import type { Job } from "../../api/endpoints"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; import { lookupApiLink } from "../../api/kube-api"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; diff --git a/src/renderer/components/+workloads-jobs/jobs.tsx b/src/renderer/components/+workloads-jobs/jobs.tsx index 6a131638f4..bcc9b85efe 100644 --- a/src/renderer/components/+workloads-jobs/jobs.tsx +++ b/src/renderer/components/+workloads-jobs/jobs.tsx @@ -23,13 +23,13 @@ import "./jobs.scss"; import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router"; +import type { RouteComponentProps } from "react-router"; import { podsStore } from "../+workloads-pods/pods.store"; import { jobStore } from "./job.store"; import { eventStore } from "../+events/event.store"; -import { Job } from "../../api/endpoints/job.api"; +import type { Job } from "../../api/endpoints/job.api"; import { KubeObjectListLayout } from "../kube-object"; -import { IJobsRouteParams } from "../+workloads"; +import type { IJobsRouteParams } from "../+workloads"; import kebabCase from "lodash/kebabCase"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; diff --git a/src/renderer/components/+workloads-overview/overview-workload-status.tsx b/src/renderer/components/+workloads-overview/overview-workload-status.tsx index ec3c9878b4..65729ad255 100644 --- a/src/renderer/components/+workloads-overview/overview-workload-status.tsx +++ b/src/renderer/components/+workloads-overview/overview-workload-status.tsx @@ -28,7 +28,7 @@ import { observable } from "mobx"; import { observer } from "mobx-react"; import { PieChart } from "../chart"; import { cssVar } from "../../utils"; -import { ChartData, ChartDataSets } from "chart.js"; +import type { ChartData, ChartDataSets } from "chart.js"; import { ThemeStore } from "../../theme.store"; interface SimpleChartDataSets extends ChartDataSets { diff --git a/src/renderer/components/+workloads-overview/overview.tsx b/src/renderer/components/+workloads-overview/overview.tsx index 63e5881763..82c3549fb1 100644 --- a/src/renderer/components/+workloads-overview/overview.tsx +++ b/src/renderer/components/+workloads-overview/overview.tsx @@ -24,8 +24,8 @@ import "./overview.scss"; import React from "react"; import { disposeOnUnmount, observer } from "mobx-react"; import { OverviewStatuses } from "./overview-statuses"; -import { RouteComponentProps } from "react-router"; -import { IWorkloadsOverviewRouteParams } from "../+workloads"; +import type { RouteComponentProps } from "react-router"; +import type { IWorkloadsOverviewRouteParams } from "../+workloads"; import { eventStore } from "../+events/event.store"; import { podsStore } from "../+workloads-pods/pods.store"; import { deploymentStore } from "../+workloads-deployments/deployments.store"; diff --git a/src/renderer/components/+workloads-pods/__tests__/pod-tolerations.test.tsx b/src/renderer/components/+workloads-pods/__tests__/pod-tolerations.test.tsx index c41a32bd27..30ef2e98e9 100644 --- a/src/renderer/components/+workloads-pods/__tests__/pod-tolerations.test.tsx +++ b/src/renderer/components/+workloads-pods/__tests__/pod-tolerations.test.tsx @@ -22,9 +22,15 @@ import React from "react"; import "@testing-library/jest-dom/extend-expect"; import { fireEvent, render } from "@testing-library/react"; -import { IToleration } from "../../../api/workload-kube-object"; +import type { IToleration } from "../../../api/workload-kube-object"; import { PodTolerations } from "../pod-tolerations"; +jest.mock("electron", () => ({ + app: { + getPath: () => "/foo", + }, +})); + const tolerations: IToleration[] =[ { key: "CriticalAddonsOnly", diff --git a/src/renderer/components/+workloads-pods/container-charts.tsx b/src/renderer/components/+workloads-pods/container-charts.tsx index 558fb4c859..df55fc9b59 100644 --- a/src/renderer/components/+workloads-pods/container-charts.tsx +++ b/src/renderer/components/+workloads-pods/container-charts.tsx @@ -21,7 +21,7 @@ import React, { useContext } from "react"; import { observer } from "mobx-react"; -import { IPodMetrics } from "../../api/endpoints"; +import type { IPodMetrics } from "../../api/endpoints"; import { BarChart, cpuOptions, memoryOptions } from "../chart"; import { isMetricsEmpty, normalizeMetrics } from "../../api/endpoints/metrics.api"; import { NoMetrics } from "../resource-metrics/no-metrics"; diff --git a/src/renderer/components/+workloads-pods/pod-charts.tsx b/src/renderer/components/+workloads-pods/pod-charts.tsx index a83b96384f..d3aafa0214 100644 --- a/src/renderer/components/+workloads-pods/pod-charts.tsx +++ b/src/renderer/components/+workloads-pods/pod-charts.tsx @@ -21,12 +21,12 @@ import React, { useContext } from "react"; import { observer } from "mobx-react"; -import { IPodMetrics } from "../../api/endpoints"; +import type { IPodMetrics } from "../../api/endpoints"; import { BarChart, cpuOptions, memoryOptions } from "../chart"; import { isMetricsEmpty, normalizeMetrics } from "../../api/endpoints/metrics.api"; import { NoMetrics } from "../resource-metrics/no-metrics"; import { IResourceMetricsValue, ResourceMetricsContext } from "../resource-metrics"; -import { WorkloadKubeObject } from "../../api/workload-kube-object"; +import type { WorkloadKubeObject } from "../../api/workload-kube-object"; import { ThemeStore } from "../../theme.store"; export const podMetricTabs = [ diff --git a/src/renderer/components/+workloads-pods/pod-container-env.tsx b/src/renderer/components/+workloads-pods/pod-container-env.tsx index 4623a7fe32..3d3eb33474 100644 --- a/src/renderer/components/+workloads-pods/pod-container-env.tsx +++ b/src/renderer/components/+workloads-pods/pod-container-env.tsx @@ -23,13 +23,13 @@ import "./pod-container-env.scss"; import React, { useEffect, useState } from "react"; import { observer } from "mobx-react"; -import { IPodContainer, Secret } from "../../api/endpoints"; +import type { IPodContainer, Secret } from "../../api/endpoints"; import { DrawerItem } from "../drawer"; import { autorun } from "mobx"; import { secretsStore } from "../+config-secrets/secrets.store"; import { configMapsStore } from "../+config-maps/config-maps.store"; import { Icon } from "../icon"; -import { base64, cssNames } from "../../utils"; +import { base64, cssNames, iter } from "../../utils"; import _ from "lodash"; interface Props { @@ -113,21 +113,23 @@ export const ContainerEnvironment = observer((props: Props) => { }; const renderEnvFrom = () => { - const envVars = envFrom.map(vars => { + return Array.from(iter.filterFlatMap(envFrom, vars => { if (vars.configMapRef?.name) { return renderEnvFromConfigMap(vars.configMapRef.name); - } else if (vars.secretRef?.name ) { + } + + if (vars.secretRef?.name) { return renderEnvFromSecret(vars.secretRef.name); } - }); - return _.flatten(envVars); + return null; + })); }; const renderEnvFromConfigMap = (configMapName: string) => { const configMap = configMapsStore.getByName(configMapName, namespace); - if (!configMap) return; + if (!configMap) return null; return Object.entries(configMap.data).map(([name, value]) => (
@@ -139,7 +141,7 @@ export const ContainerEnvironment = observer((props: Props) => { const renderEnvFromSecret = (secretName: string) => { const secret = secretsStore.getByName(secretName, namespace); - if (!secret) return; + if (!secret) return null; return Object.keys(secret.data).map(key => { const secretKeyRef = { diff --git a/src/renderer/components/+workloads-pods/pod-container-port.tsx b/src/renderer/components/+workloads-pods/pod-container-port.tsx index 93b982a568..38d05adbc9 100644 --- a/src/renderer/components/+workloads-pods/pod-container-port.tsx +++ b/src/renderer/components/+workloads-pods/pod-container-port.tsx @@ -23,7 +23,7 @@ import "./pod-container-port.scss"; import React from "react"; import { observer } from "mobx-react"; -import { Pod } from "../../api/endpoints"; +import type { Pod } from "../../api/endpoints"; import { apiBase } from "../../api"; import { observable } from "mobx"; import { cssNames } from "../../utils"; diff --git a/src/renderer/components/+workloads-pods/pod-details-affinities.tsx b/src/renderer/components/+workloads-pods/pod-details-affinities.tsx index e2dc3246a1..7be1722286 100644 --- a/src/renderer/components/+workloads-pods/pod-details-affinities.tsx +++ b/src/renderer/components/+workloads-pods/pod-details-affinities.tsx @@ -24,7 +24,7 @@ import React from "react"; import jsYaml from "js-yaml"; import { AceEditor } from "../ace-editor"; import { DrawerParamToggler, DrawerItem } from "../drawer"; -import { Pod, Deployment, DaemonSet, StatefulSet, ReplicaSet, Job } from "../../api/endpoints"; +import type { Pod, Deployment, DaemonSet, StatefulSet, ReplicaSet, Job } from "../../api/endpoints"; interface Props { workload: Pod | Deployment | DaemonSet | StatefulSet | ReplicaSet | Job; diff --git a/src/renderer/components/+workloads-pods/pod-details-container.tsx b/src/renderer/components/+workloads-pods/pod-details-container.tsx index fe6d12c45f..1596a6cad7 100644 --- a/src/renderer/components/+workloads-pods/pod-details-container.tsx +++ b/src/renderer/components/+workloads-pods/pod-details-container.tsx @@ -22,7 +22,7 @@ import "./pod-details-container.scss"; import React from "react"; -import { IPodContainer, IPodContainerStatus, Pod } from "../../api/endpoints"; +import type { IPodContainer, IPodContainerStatus, Pod } from "../../api/endpoints"; import { DrawerItem } from "../drawer"; import { cssNames } from "../../utils"; import { StatusBrick } from "../status-brick"; @@ -30,7 +30,7 @@ import { Badge } from "../badge"; import { ContainerEnvironment } from "./pod-container-env"; import { PodContainerPort } from "./pod-container-port"; import { ResourceMetrics } from "../resource-metrics"; -import { IMetrics } from "../../api/endpoints/metrics.api"; +import type { IMetrics } from "../../api/endpoints/metrics.api"; import { ContainerCharts } from "./container-charts"; import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting"; import { LocaleDate } from "../locale-date"; @@ -66,6 +66,8 @@ export class PodDetailsContainer extends React.Component { ); } + + return null; } render() { diff --git a/src/renderer/components/+workloads-pods/pod-details-list.tsx b/src/renderer/components/+workloads-pods/pod-details-list.tsx index 696f28aa79..a9e21d1a5c 100644 --- a/src/renderer/components/+workloads-pods/pod-details-list.tsx +++ b/src/renderer/components/+workloads-pods/pod-details-list.tsx @@ -26,10 +26,10 @@ import kebabCase from "lodash/kebabCase"; import { reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { podsStore } from "./pods.store"; -import { Pod } from "../../api/endpoints"; +import type { Pod } from "../../api/endpoints"; import { autobind, bytesToUnits, cssNames, interval, prevDefault } from "../../utils"; import { LineProgress } from "../line-progress"; -import { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../api/kube-object"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { Spinner } from "../spinner"; import { DrawerTitle } from "../drawer"; diff --git a/src/renderer/components/+workloads-pods/pod-details-statuses.tsx b/src/renderer/components/+workloads-pods/pod-details-statuses.tsx index 4ab44dbe3d..90c59ef778 100644 --- a/src/renderer/components/+workloads-pods/pod-details-statuses.tsx +++ b/src/renderer/components/+workloads-pods/pod-details-statuses.tsx @@ -23,7 +23,7 @@ import "./pod-details-statuses.scss"; import React from "react"; import countBy from "lodash/countBy"; import kebabCase from "lodash/kebabCase"; -import { Pod } from "../../api/endpoints"; +import type { Pod } from "../../api/endpoints"; interface Props { pods: Pod[]; diff --git a/src/renderer/components/+workloads-pods/pod-details-tolerations.tsx b/src/renderer/components/+workloads-pods/pod-details-tolerations.tsx index 970a27eaf5..124192d549 100644 --- a/src/renderer/components/+workloads-pods/pod-details-tolerations.tsx +++ b/src/renderer/components/+workloads-pods/pod-details-tolerations.tsx @@ -22,7 +22,7 @@ import "./pod-details-tolerations.scss"; import React from "react"; import { DrawerParamToggler, DrawerItem } from "../drawer"; -import { WorkloadKubeObject } from "../../api/workload-kube-object"; +import type { WorkloadKubeObject } from "../../api/workload-kube-object"; import { PodTolerations } from "./pod-tolerations"; interface Props { diff --git a/src/renderer/components/+workloads-pods/pod-details.tsx b/src/renderer/components/+workloads-pods/pod-details.tsx index 1315c68238..4a67fe76d7 100644 --- a/src/renderer/components/+workloads-pods/pod-details.tsx +++ b/src/renderer/components/+workloads-pods/pod-details.tsx @@ -176,7 +176,7 @@ export class PodDetails extends React.Component { key={name} pod={pod} container={container} - metrics={metrics} + metrics={metrics || null} /> ); }) diff --git a/src/renderer/components/+workloads-pods/pod-tolerations.tsx b/src/renderer/components/+workloads-pods/pod-tolerations.tsx index 39d13aa081..5ca65cc2b3 100644 --- a/src/renderer/components/+workloads-pods/pod-tolerations.tsx +++ b/src/renderer/components/+workloads-pods/pod-tolerations.tsx @@ -23,7 +23,7 @@ import "./pod-tolerations.scss"; import React from "react"; import uniqueId from "lodash/uniqueId"; -import { IToleration } from "../../api/workload-kube-object"; +import type { IToleration } from "../../api/workload-kube-object"; import { Table, TableCell, TableHead, TableRow } from "../table"; interface Props { diff --git a/src/renderer/components/+workloads-pods/pods.store.ts b/src/renderer/components/+workloads-pods/pods.store.ts index 4343c4b50f..7bdba606e4 100644 --- a/src/renderer/components/+workloads-pods/pods.store.ts +++ b/src/renderer/components/+workloads-pods/pods.store.ts @@ -25,7 +25,7 @@ import { KubeObjectStore } from "../../kube-object.store"; import { autobind, cpuUnitsToNumber, unitsToBytes } from "../../utils"; import { IPodMetrics, Pod, PodMetrics, podMetricsApi, podsApi } from "../../api/endpoints"; import { apiManager } from "../../api/api-manager"; -import { WorkloadKubeObject } from "../../api/workload-kube-object"; +import type { WorkloadKubeObject } from "../../api/workload-kube-object"; @autobind() export class PodsStore extends KubeObjectStore { @@ -59,8 +59,6 @@ export class PodsStore extends KubeObjectStore { return this.items.filter(pod => { const owners = pod.getOwnerRefs(); - if (!owners.length) return; - return owners.find(owner => owner.uid === workload.getId()); }); } diff --git a/src/renderer/components/+workloads-pods/pods.tsx b/src/renderer/components/+workloads-pods/pods.tsx index 7c2b4e79f7..be5cbf8852 100644 --- a/src/renderer/components/+workloads-pods/pods.tsx +++ b/src/renderer/components/+workloads-pods/pods.tsx @@ -25,9 +25,9 @@ import React, { Fragment } from "react"; import { observer } from "mobx-react"; import { Link } from "react-router-dom"; import { podsStore } from "./pods.store"; -import { RouteComponentProps } from "react-router"; +import type { RouteComponentProps } from "react-router"; import { volumeClaimStore } from "../+storage-volume-claims/volume-claim.store"; -import { IPodsRouteParams } from "../+workloads"; +import type { IPodsRouteParams } from "../+workloads"; import { eventStore } from "../+events/event.store"; import { getDetailsUrl, KubeObjectListLayout } from "../kube-object"; import { nodesApi, Pod } from "../../api/endpoints"; diff --git a/src/renderer/components/+workloads-replicasets/replicaset-details.tsx b/src/renderer/components/+workloads-replicasets/replicaset-details.tsx index 1c67a86e88..e02d23a3d5 100644 --- a/src/renderer/components/+workloads-replicasets/replicaset-details.tsx +++ b/src/renderer/components/+workloads-replicasets/replicaset-details.tsx @@ -31,8 +31,8 @@ import { PodDetailsAffinities } from "../+workloads-pods/pod-details-affinities" import { KubeEventDetails } from "../+events/kube-event-details"; import { disposeOnUnmount, observer } from "mobx-react"; import { podsStore } from "../+workloads-pods/pods.store"; -import { KubeObjectDetailsProps } from "../kube-object"; -import { ReplicaSet } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object"; +import type { ReplicaSet } from "../../api/endpoints"; import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics"; import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; diff --git a/src/renderer/components/+workloads-replicasets/replicasets.tsx b/src/renderer/components/+workloads-replicasets/replicasets.tsx index d7e6dd9493..ffc75ead0e 100644 --- a/src/renderer/components/+workloads-replicasets/replicasets.tsx +++ b/src/renderer/components/+workloads-replicasets/replicasets.tsx @@ -23,12 +23,12 @@ import "./replicasets.scss"; import React from "react"; import { observer } from "mobx-react"; -import { ReplicaSet } from "../../api/endpoints"; -import { KubeObjectMenuProps } from "../kube-object/kube-object-menu"; +import type { ReplicaSet } from "../../api/endpoints"; +import type { KubeObjectMenuProps } from "../kube-object/kube-object-menu"; import { replicaSetStore } from "./replicasets.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; -import { RouteComponentProps } from "react-router"; -import { IReplicaSetsRouteParams } from "../+workloads/workloads.route"; +import type { RouteComponentProps } from "react-router"; +import type { IReplicaSetsRouteParams } from "../+workloads/workloads.route"; import { KubeObjectListLayout } from "../kube-object/kube-object-list-layout"; import { MenuItem } from "../menu/menu"; import { Icon } from "../icon/icon"; diff --git a/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx b/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx index 75f78af3be..0342d424e9 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx +++ b/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx @@ -32,8 +32,8 @@ import { PodDetailsAffinities } from "../+workloads-pods/pod-details-affinities" import { KubeEventDetails } from "../+events/kube-event-details"; import { podsStore } from "../+workloads-pods/pods.store"; import { statefulSetStore } from "./statefulset.store"; -import { KubeObjectDetailsProps } from "../kube-object"; -import { StatefulSet } from "../../api/endpoints"; +import type { KubeObjectDetailsProps } from "../kube-object"; +import type { StatefulSet } from "../../api/endpoints"; import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics"; import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; diff --git a/src/renderer/components/+workloads-statefulsets/statefulsets.tsx b/src/renderer/components/+workloads-statefulsets/statefulsets.tsx index ff359b73df..59b208cccf 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulsets.tsx +++ b/src/renderer/components/+workloads-statefulsets/statefulsets.tsx @@ -23,15 +23,15 @@ import "./statefulsets.scss"; import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router"; -import { StatefulSet } from "../../api/endpoints"; +import type { RouteComponentProps } from "react-router"; +import type { StatefulSet } from "../../api/endpoints"; import { podsStore } from "../+workloads-pods/pods.store"; import { statefulSetStore } from "./statefulset.store"; import { nodesStore } from "../+nodes/nodes.store"; import { eventStore } from "../+events/event.store"; -import { KubeObjectMenuProps } from "../kube-object/kube-object-menu"; +import type { KubeObjectMenuProps } from "../kube-object/kube-object-menu"; import { KubeObjectListLayout } from "../kube-object"; -import { IStatefulSetsRouteParams } from "../+workloads"; +import type { IStatefulSetsRouteParams } from "../+workloads"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { StatefulSetScaleDialog } from "./statefulset-scale-dialog"; import { MenuItem } from "../menu/menu"; diff --git a/src/renderer/components/+workloads/workloads.route.ts b/src/renderer/components/+workloads/workloads.route.ts index 7fec45f9ca..baef1928b7 100644 --- a/src/renderer/components/+workloads/workloads.route.ts +++ b/src/renderer/components/+workloads/workloads.route.ts @@ -21,7 +21,7 @@ import type { RouteProps } from "react-router"; import { buildURL, IURLParams } from "../../../common/utils/buildUrl"; -import { KubeResource } from "../../../common/rbac"; +import type { KubeResource } from "../../../common/rbac"; // Routes export const overviewRoute: RouteProps = { diff --git a/src/renderer/components/+workloads/workloads.stores.ts b/src/renderer/components/+workloads/workloads.stores.ts index 979e99bfc7..a06c17200d 100644 --- a/src/renderer/components/+workloads/workloads.stores.ts +++ b/src/renderer/components/+workloads/workloads.stores.ts @@ -19,14 +19,14 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { KubeObjectStore } from "../../kube-object.store"; +import type { KubeObjectStore } from "../../kube-object.store"; import { podsStore } from "../+workloads-pods/pods.store"; import { deploymentStore } from "../+workloads-deployments/deployments.store"; import { daemonSetStore } from "../+workloads-daemonsets/daemonsets.store"; import { statefulSetStore } from "../+workloads-statefulsets/statefulset.store"; import { jobStore } from "../+workloads-jobs/job.store"; import { cronJobStore } from "../+workloads-cronjobs/cronjob.store"; -import { KubeResource } from "../../../common/rbac"; +import type { KubeResource } from "../../../common/rbac"; import { replicaSetStore } from "../+workloads-replicasets/replicasets.store"; export const workloadStores: Partial> = { diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index 7242b23128..f04fb46c5c 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -151,6 +151,8 @@ export class App extends React.Component { return ; } } + + return null; }); } @@ -161,6 +163,8 @@ export class App extends React.Component { if (!menu) { return ; } + + return null; }); } diff --git a/src/renderer/components/button/button.tsx b/src/renderer/components/button/button.tsx index f35e7b6c50..83d4cc18bf 100644 --- a/src/renderer/components/button/button.tsx +++ b/src/renderer/components/button/button.tsx @@ -42,9 +42,6 @@ export interface ButtonProps extends ButtonHTMLAttributes, TooltipDecorator @withTooltip export class Button extends React.PureComponent { - private link: HTMLAnchorElement; - private button: HTMLButtonElement; - render() { const { waiting, label, primary, accent, plain, hidden, active, big, @@ -60,7 +57,7 @@ export class Button extends React.PureComponent { // render as link if (this.props.href) { return ( - this.link = e}> + {label} {children} @@ -69,7 +66,7 @@ export class Button extends React.PureComponent { // render as button return ( - diff --git a/src/renderer/components/chart/bar-chart.tsx b/src/renderer/components/chart/bar-chart.tsx index 46e25e10f7..b5946b6330 100644 --- a/src/renderer/components/chart/bar-chart.tsx +++ b/src/renderer/components/chart/bar-chart.tsx @@ -24,7 +24,7 @@ import merge from "lodash/merge"; import moment from "moment"; import Color from "color"; import { observer } from "mobx-react"; -import { ChartData, ChartOptions, ChartPoint, ChartTooltipItem, Scriptable } from "chart.js"; +import type { ChartData, ChartOptions, ChartPoint, ChartTooltipItem, Scriptable } from "chart.js"; import { Chart, ChartKind, ChartProps } from "./chart"; import { bytesToUnits, cssNames } from "../../utils"; import { ZebraStripes } from "./zebra-stripes.plugin"; diff --git a/src/renderer/components/chart/zebra-stripes.plugin.ts b/src/renderer/components/chart/zebra-stripes.plugin.ts index f1f78ee5f4..8980546763 100644 --- a/src/renderer/components/chart/zebra-stripes.plugin.ts +++ b/src/renderer/components/chart/zebra-stripes.plugin.ts @@ -22,7 +22,7 @@ // Plugin for drawing stripe bars on top of any timeseries barchart // Based on cover DIV element with repeating-linear-gradient style -import ChartJS, { ChartPoint } from "chart.js"; +import type ChartJS from "chart.js"; import moment, { Moment } from "moment"; import get from "lodash/get"; @@ -39,7 +39,7 @@ export const ZebraStripes = { }, getLastUpdate(chart: ChartJS) { - const data = chart.data.datasets[0].data[0] as ChartPoint; + const data = chart.data.datasets[0].data[0] as ChartJS.ChartPoint; return moment.unix(parseInt(data.x as string)); }, diff --git a/src/renderer/components/cluster-manager/bottom-bar.test.tsx b/src/renderer/components/cluster-manager/bottom-bar.test.tsx index 590e9534f5..eceb02697a 100644 --- a/src/renderer/components/cluster-manager/bottom-bar.test.tsx +++ b/src/renderer/components/cluster-manager/bottom-bar.test.tsx @@ -23,6 +23,12 @@ import React from "react"; import { render } from "@testing-library/react"; import "@testing-library/jest-dom/extend-expect"; +jest.mock("electron", () => ({ + app: { + getPath: () => "/foo", + }, +})); + import { BottomBar } from "./bottom-bar"; jest.mock("../../../extensions/registries"); import { statusBarRegistry } from "../../../extensions/registries"; diff --git a/src/renderer/components/cluster-manager/bottom-bar.tsx b/src/renderer/components/cluster-manager/bottom-bar.tsx index c36a75dd90..32f56d0f78 100644 --- a/src/renderer/components/cluster-manager/bottom-bar.tsx +++ b/src/renderer/components/cluster-manager/bottom-bar.tsx @@ -44,14 +44,14 @@ export class BottomBar extends React.Component { const items = statusBarRegistry.getItems(); if (!Array.isArray(items)) { - return; + return null; } return (
{items.map((registration, index) => { if (!registration?.item && !registration?.components?.Item) { - return; + return null; } return ( diff --git a/src/renderer/components/cluster-manager/cluster-status.tsx b/src/renderer/components/cluster-manager/cluster-status.tsx index 9f8b999e8c..565fee6107 100644 --- a/src/renderer/components/cluster-manager/cluster-status.tsx +++ b/src/renderer/components/cluster-manager/cluster-status.tsx @@ -30,7 +30,7 @@ import { requestMain, subscribeToBroadcast } from "../../../common/ipc"; import { Icon } from "../icon"; import { Button } from "../button"; import { cssNames, IClassName } from "../../utils"; -import { Cluster } from "../../../main/cluster"; +import type { Cluster } from "../../../main/cluster"; import { ClusterId, ClusterStore } from "../../../common/cluster-store"; import { CubeSpinner } from "../spinner"; import { clusterActivateHandler } from "../../../common/cluster-ipc"; diff --git a/src/renderer/components/cluster-manager/cluster-view.tsx b/src/renderer/components/cluster-manager/cluster-view.tsx index 2e3622944b..b1ab7c9366 100644 --- a/src/renderer/components/cluster-manager/cluster-view.tsx +++ b/src/renderer/components/cluster-manager/cluster-view.tsx @@ -23,11 +23,11 @@ import "./cluster-view.scss"; import React from "react"; import { reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; -import { RouteComponentProps } from "react-router"; -import { IClusterViewRouteParams } from "./cluster-view.route"; +import type { RouteComponentProps } from "react-router"; +import type { IClusterViewRouteParams } from "./cluster-view.route"; import { ClusterStatus } from "./cluster-status"; import { hasLoadedView, initView, lensViews, refreshViews } from "./lens-views"; -import { Cluster } from "../../../main/cluster"; +import type { Cluster } from "../../../main/cluster"; import { ClusterStore } from "../../../common/cluster-store"; import { requestMain } from "../../../common/ipc"; import { clusterActivateHandler } from "../../../common/cluster-ipc"; diff --git a/src/renderer/components/cluster-settings/cluster-settings.tsx b/src/renderer/components/cluster-settings/cluster-settings.tsx index d0aaf18e5c..d8fd374136 100644 --- a/src/renderer/components/cluster-settings/cluster-settings.tsx +++ b/src/renderer/components/cluster-settings/cluster-settings.tsx @@ -30,7 +30,7 @@ import { ShowMetricsSetting } from "./components/show-metrics"; import { ClusterPrometheusSetting } from "./components/cluster-prometheus-setting"; import { ClusterKubeconfig } from "./components/cluster-kubeconfig"; import { entitySettingRegistry } from "../../../extensions/registries"; -import { CatalogEntity } from "../../api/catalog-entity"; +import type { CatalogEntity } from "../../api/catalog-entity"; function getClusterForEntity(entity: CatalogEntity) { 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 5f02a92edd..61b576bb97 100644 --- a/src/renderer/components/cluster-settings/components/cluster-accessible-namespaces.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-accessible-namespaces.tsx @@ -21,7 +21,7 @@ import React from "react"; import { observer } from "mobx-react"; -import { Cluster } from "../../../../main/cluster"; +import type { Cluster } from "../../../../main/cluster"; import { SubTitle } from "../../layout/sub-title"; import { EditableList } from "../../editable-list"; import { observable } from "mobx"; diff --git a/src/renderer/components/cluster-settings/components/cluster-home-dir-setting.tsx b/src/renderer/components/cluster-settings/components/cluster-home-dir-setting.tsx index e2448d6520..0603bea967 100644 --- a/src/renderer/components/cluster-settings/components/cluster-home-dir-setting.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-home-dir-setting.tsx @@ -22,7 +22,7 @@ import React from "react"; import { observable, autorun } from "mobx"; import { observer, disposeOnUnmount } from "mobx-react"; -import { Cluster } from "../../../../main/cluster"; +import type { Cluster } from "../../../../main/cluster"; import { Input } from "../../input"; import { SubTitle } from "../../layout/sub-title"; diff --git a/src/renderer/components/cluster-settings/components/cluster-kubeconfig.tsx b/src/renderer/components/cluster-settings/components/cluster-kubeconfig.tsx index 489398f59c..6c7aec50f3 100644 --- a/src/renderer/components/cluster-settings/components/cluster-kubeconfig.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-kubeconfig.tsx @@ -20,7 +20,7 @@ */ import React from "react"; -import { Cluster } from "../../../../main/cluster"; +import type { Cluster } from "../../../../main/cluster"; import { observer } from "mobx-react"; import { SubTitle } from "../../layout/sub-title"; import { autobind } from "../../../../common/utils"; diff --git a/src/renderer/components/cluster-settings/components/cluster-metrics-setting.tsx b/src/renderer/components/cluster-settings/components/cluster-metrics-setting.tsx index bfa4630032..21bbf7b07a 100644 --- a/src/renderer/components/cluster-settings/components/cluster-metrics-setting.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-metrics-setting.tsx @@ -25,7 +25,7 @@ import { Select, SelectOption } from "../../select/select"; import { Icon } from "../../icon/icon"; import { Button } from "../../button/button"; import { SubTitle } from "../../layout/sub-title"; -import { Cluster } from "../../../../main/cluster"; +import type { Cluster } from "../../../../main/cluster"; import { observable, reaction } from "mobx"; interface Props { diff --git a/src/renderer/components/cluster-settings/components/cluster-name-setting.tsx b/src/renderer/components/cluster-settings/components/cluster-name-setting.tsx index 52a4383d12..cca3d8ac3d 100644 --- a/src/renderer/components/cluster-settings/components/cluster-name-setting.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-name-setting.tsx @@ -20,7 +20,7 @@ */ import React from "react"; -import { Cluster } from "../../../../main/cluster"; +import type { Cluster } from "../../../../main/cluster"; import { Input } from "../../input"; import { observable, autorun } from "mobx"; import { observer, disposeOnUnmount } from "mobx-react"; diff --git a/src/renderer/components/cluster-settings/components/cluster-prometheus-setting.tsx b/src/renderer/components/cluster-settings/components/cluster-prometheus-setting.tsx index 36395f1bdb..00d2056b3e 100644 --- a/src/renderer/components/cluster-settings/components/cluster-prometheus-setting.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-prometheus-setting.tsx @@ -22,7 +22,7 @@ import React from "react"; import { observer, disposeOnUnmount } from "mobx-react"; import { prometheusProviders } from "../../../../common/prometheus-providers"; -import { Cluster } from "../../../../main/cluster"; +import type { Cluster } from "../../../../main/cluster"; import { SubTitle } from "../../layout/sub-title"; import { Select, SelectOption } from "../../select"; import { Input } from "../../input"; diff --git a/src/renderer/components/cluster-settings/components/cluster-proxy-setting.tsx b/src/renderer/components/cluster-settings/components/cluster-proxy-setting.tsx index 52a54be547..d4c307226c 100644 --- a/src/renderer/components/cluster-settings/components/cluster-proxy-setting.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-proxy-setting.tsx @@ -22,7 +22,7 @@ import React from "react"; import { observable, autorun } from "mobx"; import { observer, disposeOnUnmount } from "mobx-react"; -import { Cluster } from "../../../../main/cluster"; +import type { Cluster } from "../../../../main/cluster"; import { Input, InputValidators } from "../../input"; import { SubTitle } from "../../layout/sub-title"; diff --git a/src/renderer/components/cluster-settings/components/show-metrics.tsx b/src/renderer/components/cluster-settings/components/show-metrics.tsx index e744875810..8d4ba2a7c7 100644 --- a/src/renderer/components/cluster-settings/components/show-metrics.tsx +++ b/src/renderer/components/cluster-settings/components/show-metrics.tsx @@ -21,7 +21,7 @@ import React from "react"; import { disposeOnUnmount, observer } from "mobx-react"; -import { Cluster } from "../../../../main/cluster"; +import type { Cluster } from "../../../../main/cluster"; import { observable, reaction } from "mobx"; import { Badge } from "../../badge/badge"; import { Icon } from "../../icon/icon"; diff --git a/src/renderer/components/dock/__test__/dock-tabs.test.tsx b/src/renderer/components/dock/__test__/dock-tabs.test.tsx index 37cb7fdc8a..0c5ae7defd 100644 --- a/src/renderer/components/dock/__test__/dock-tabs.test.tsx +++ b/src/renderer/components/dock/__test__/dock-tabs.test.tsx @@ -26,6 +26,12 @@ import "@testing-library/jest-dom/extend-expect"; import { DockTabs } from "../dock-tabs"; import { dockStore, IDockTab, TabKind } from "../dock.store"; +jest.mock("electron", () => ({ + app: { + getPath: () => "/foo", + }, +})); + const onChangeTab = jest.fn(); const getComponent = () => ( diff --git a/src/renderer/components/dock/__test__/log-resource-selector.test.tsx b/src/renderer/components/dock/__test__/log-resource-selector.test.tsx index 62c67247e0..62566b868a 100644 --- a/src/renderer/components/dock/__test__/log-resource-selector.test.tsx +++ b/src/renderer/components/dock/__test__/log-resource-selector.test.tsx @@ -26,11 +26,17 @@ import selectEvent from "react-select-event"; import { Pod } from "../../../api/endpoints"; import { LogResourceSelector } from "../log-resource-selector"; -import { LogTabData } from "../log-tab.store"; +import type { LogTabData } from "../log-tab.store"; import { dockerPod, deploymentPod1 } from "./pod.mock"; import { ThemeStore } from "../../../theme.store"; import { UserStore } from "../../../../common/user-store"; +jest.mock("electron", () => ({ + app: { + getPath: () => "/foo", + }, +})); + const getComponent = (tabData: LogTabData) => { return ( ({ + app: { + getPath: () => "/foo", + }, +})); podsStore.items.push(new Pod(dockerPod)); podsStore.items.push(new Pod(deploymentPod1)); diff --git a/src/renderer/components/dock/create-resource.store.ts b/src/renderer/components/dock/create-resource.store.ts index 573ff1cffd..7ff01286b3 100644 --- a/src/renderer/components/dock/create-resource.store.ts +++ b/src/renderer/components/dock/create-resource.store.ts @@ -89,7 +89,3 @@ export function createResourceTab(tabParams: Partial = {}) { ...tabParams }); } - -export function isCreateResourceTab(tab: IDockTab) { - return tab && tab.kind === TabKind.CREATE_RESOURCE; -} diff --git a/src/renderer/components/dock/create-resource.tsx b/src/renderer/components/dock/create-resource.tsx index 36058cabbd..44becbb52b 100644 --- a/src/renderer/components/dock/create-resource.tsx +++ b/src/renderer/components/dock/create-resource.tsx @@ -30,11 +30,11 @@ import { observable } from "mobx"; import { observer } from "mobx-react"; import { cssNames } from "../../utils"; import { createResourceStore } from "./create-resource.store"; -import { IDockTab } from "./dock.store"; +import type { IDockTab } from "./dock.store"; import { EditorPanel } from "./editor-panel"; import { InfoPanel } from "./info-panel"; import { resourceApplierApi } from "../../api/endpoints/resource-applier.api"; -import { JsonApiErrorParsed } from "../../api/json-api"; +import type { JsonApiErrorParsed } from "../../api/json-api"; import { Notifications } from "../notifications"; interface Props { @@ -87,10 +87,13 @@ export class CreateResource extends React.Component { }; create = async () => { - if (this.error) return; - if (!this.data.trim()) return; // do not save when field is empty - const resources = jsYaml.safeLoadAll(this.data) - .filter(v => !!v); // skip empty documents if "---" pasted at the beginning or end + if (this.error || !this.data.trim()) { + // do not save when field is empty or there is an error + return null; + } + + // skip empty documents if "---" pasted at the beginning or end + const resources = jsYaml.safeLoadAll(this.data).filter(Boolean); const createdResources: string[] = []; const errors: string[] = []; diff --git a/src/renderer/components/dock/dock-tabs.tsx b/src/renderer/components/dock/dock-tabs.tsx index 6bb0606574..6064259cbc 100644 --- a/src/renderer/components/dock/dock-tabs.tsx +++ b/src/renderer/components/dock/dock-tabs.tsx @@ -23,15 +23,10 @@ import React, { Fragment } from "react"; import { Icon } from "../icon"; import { Tabs } from "../tabs/tabs"; -import { isCreateResourceTab } from "./create-resource.store"; import { DockTab } from "./dock-tab"; -import { IDockTab } from "./dock.store"; -import { isEditResourceTab } from "./edit-resource.store"; -import { isInstallChartTab } from "./install-chart.store"; -import { isLogsTab } from "./log-tab.store"; +import type { IDockTab } from "./dock.store"; +import { TabKind } from "./dock.store"; import { TerminalTab } from "./terminal-tab"; -import { isTerminalTab } from "./terminal.store"; -import { isUpgradeChartTab } from "./upgrade-chart.store"; interface Props { tabs: IDockTab[] @@ -41,21 +36,22 @@ interface Props { } export const DockTabs = ({ tabs, autoFocus, selectedTab, onChangeTab }: Props) => { - const renderTab = (tab: IDockTab) => { - if (isTerminalTab(tab)) { - return ; + const renderTab = (tab?: IDockTab) => { + if (!tab) { + return null; } - if (isCreateResourceTab(tab) || isEditResourceTab(tab)) { - return ; - } - - if (isInstallChartTab(tab) || isUpgradeChartTab(tab)) { - return } />; - } - - if (isLogsTab(tab)) { - return ; + switch (tab.kind) { + case TabKind.CREATE_RESOURCE: + case TabKind.EDIT_RESOURCE: + return ; + case TabKind.INSTALL_CHART: + case TabKind.UPGRADE_CHART: + return } />; + case TabKind.POD_LOGS: + return ; + case TabKind.TERMINAL: + return ; } }; diff --git a/src/renderer/components/dock/dock.store.ts b/src/renderer/components/dock/dock.store.ts index 99617563f0..2edbbce75c 100644 --- a/src/renderer/components/dock/dock.store.ts +++ b/src/renderer/components/dock/dock.store.ts @@ -215,7 +215,7 @@ export class DockStore implements DockStorageState { if (this.tabs.length) { const newTab = this.tabs.slice(-1)[0]; // last - if (newTab.kind === TabKind.TERMINAL) { + if (newTab?.kind === TabKind.TERMINAL) { // close the dock when selected sibling inactive terminal tab const { terminalStore } = await import("./terminal.store"); diff --git a/src/renderer/components/dock/dock.tsx b/src/renderer/components/dock/dock.tsx index 6f7dbe6956..21e167ac8c 100644 --- a/src/renderer/components/dock/dock.tsx +++ b/src/renderer/components/dock/dock.tsx @@ -30,19 +30,15 @@ import { MenuItem } from "../menu"; import { MenuActions } from "../menu/menu-actions"; import { ResizeDirection, ResizingAnchor } from "../resizing-anchor"; import { CreateResource } from "./create-resource"; -import { createResourceTab, isCreateResourceTab } from "./create-resource.store"; +import { createResourceTab } from "./create-resource.store"; import { DockTabs } from "./dock-tabs"; -import { dockStore, IDockTab } from "./dock.store"; +import { dockStore, IDockTab, TabKind } from "./dock.store"; import { EditResource } from "./edit-resource"; -import { isEditResourceTab } from "./edit-resource.store"; import { InstallChart } from "./install-chart"; -import { isInstallChartTab } from "./install-chart.store"; import { Logs } from "./logs"; -import { isLogsTab } from "./log-tab.store"; import { TerminalWindow } from "./terminal-window"; -import { createTerminalTab, isTerminalTab } from "./terminal.store"; +import { createTerminalTab } from "./terminal.store"; import { UpgradeChart } from "./upgrade-chart"; -import { isUpgradeChartTab } from "./upgrade-chart.store"; import { commandRegistry } from "../../../extensions/registries/command-registry"; interface Props { @@ -74,19 +70,31 @@ export class Dock extends React.Component { selectTab(tab.id); }; - renderTabContent() { - const { isOpen, height, selectedTab: tab } = dockStore; + renderTab(tab: IDockTab) { + switch (tab.kind) { + case TabKind.CREATE_RESOURCE: + return ; + case TabKind.EDIT_RESOURCE: + return ; + case TabKind.INSTALL_CHART: + return ; + case TabKind.UPGRADE_CHART: + return ; + case TabKind.POD_LOGS: + return ; + case TabKind.TERMINAL: + return ; + } + } - if (!isOpen || !tab) return; + renderTabContent() { + const { isOpen, height, selectedTab } = dockStore; + + if (!isOpen || !selectedTab) return null; return (
- {isCreateResourceTab(tab) && } - {isEditResourceTab(tab) && } - {isInstallChartTab(tab) && } - {isUpgradeChartTab(tab) && } - {isTerminalTab(tab) && } - {isLogsTab(tab) && } + {this.renderTab(selectedTab)}
); } diff --git a/src/renderer/components/dock/edit-resource.store.ts b/src/renderer/components/dock/edit-resource.store.ts index 48d64ffbbf..b73ad9785f 100644 --- a/src/renderer/components/dock/edit-resource.store.ts +++ b/src/renderer/components/dock/edit-resource.store.ts @@ -23,9 +23,9 @@ 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 { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../api/kube-object"; import { apiManager } from "../../api/api-manager"; -import { KubeObjectStore } from "../../kube-object.store"; +import type { KubeObjectStore } from "../../kube-object.store"; export interface EditingResource { resource: string; // resource path, e.g. /api/v1/namespaces/default @@ -138,7 +138,3 @@ export function editResourceTab(object: KubeObject, tabParams: Partial return tab; } - -export function isEditResourceTab(tab: IDockTab) { - return tab && tab.kind === TabKind.EDIT_RESOURCE; -} diff --git a/src/renderer/components/dock/edit-resource.tsx b/src/renderer/components/dock/edit-resource.tsx index eafb6a7396..010e130513 100644 --- a/src/renderer/components/dock/edit-resource.tsx +++ b/src/renderer/components/dock/edit-resource.tsx @@ -25,14 +25,14 @@ import React from "react"; import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import jsYaml from "js-yaml"; -import { IDockTab } from "./dock.store"; +import type { IDockTab } from "./dock.store"; import { cssNames } from "../../utils"; import { editResourceStore } from "./edit-resource.store"; import { InfoPanel } from "./info-panel"; import { Badge } from "../badge"; import { EditorPanel } from "./editor-panel"; import { Spinner } from "../spinner"; -import { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../api/kube-object"; interface Props { className?: string; @@ -88,7 +88,7 @@ export class EditResource extends React.Component { save = async () => { if (this.error) { - return; + return null; } const store = editResourceStore.getStore(this.tabId); const updatedResource = await store.update(this.resource, jsYaml.safeLoad(this.draft)); diff --git a/src/renderer/components/dock/editor-panel.tsx b/src/renderer/components/dock/editor-panel.tsx index cca59c9b28..64e37e1f0e 100644 --- a/src/renderer/components/dock/editor-panel.tsx +++ b/src/renderer/components/dock/editor-panel.tsx @@ -27,7 +27,7 @@ import { cssNames } from "../../utils"; import { AceEditor } from "../ace-editor"; import { dockStore, TabId } from "./dock.store"; import { DockTabStore } from "./dock-tab.store"; -import { Ace } from "ace-builds"; +import type { Ace } from "ace-builds"; interface Props { className?: string; diff --git a/src/renderer/components/dock/info-panel.tsx b/src/renderer/components/dock/info-panel.tsx index ce2286bf18..da893904eb 100644 --- a/src/renderer/components/dock/info-panel.tsx +++ b/src/renderer/components/dock/info-panel.tsx @@ -104,7 +104,7 @@ export class InfoPanel extends Component { renderErrorIcon() { if (!this.props.showInlineInfo || !this.errorInfo) { - return; + return null; } return ( diff --git a/src/renderer/components/dock/install-chart.store.ts b/src/renderer/components/dock/install-chart.store.ts index 46f8cde904..3e5f7a9d8f 100644 --- a/src/renderer/components/dock/install-chart.store.ts +++ b/src/renderer/components/dock/install-chart.store.ts @@ -23,7 +23,7 @@ import { action, autorun } from "mobx"; import { dockStore, IDockTab, TabId, TabKind } from "./dock.store"; import { DockTabStore } from "./dock-tab.store"; import { getChartDetails, getChartValues, HelmChart } from "../../api/endpoints/helm-charts.api"; -import { IReleaseUpdateDetails } from "../../api/endpoints/helm-releases.api"; +import type { IReleaseUpdateDetails } from "../../api/endpoints/helm-releases.api"; import { Notifications } from "../notifications"; export interface IChartInstallData { @@ -48,15 +48,15 @@ export class InstallChartStore extends DockTabStore { autorun(() => { const { selectedTab, isOpen } = dockStore; - if (isInstallChartTab(selectedTab) && isOpen) { - this.loadData() + if (selectedTab?.kind === TabKind.INSTALL_CHART && isOpen) { + this.loadData(selectedTab.id) .catch(err => Notifications.error(String(err))); } }, { delay: 250 }); } @action - async loadData(tabId = dockStore.selectedTabId) { + async loadData(tabId: string) { const promises = []; if (!this.getData(tabId).values) { @@ -116,7 +116,3 @@ export function createInstallChartTab(chart: HelmChart, tabParams: Partial { } export const logTabStore = new LogTabStore(); - -export function isLogsTab(tab: IDockTab) { - return tab && tab.kind === TabKind.POD_LOGS; -} diff --git a/src/renderer/components/dock/log.store.ts b/src/renderer/components/dock/log.store.ts index 22fae5eac5..111fe9b018 100644 --- a/src/renderer/components/dock/log.store.ts +++ b/src/renderer/components/dock/log.store.ts @@ -23,8 +23,8 @@ import { autorun, computed, observable } from "mobx"; import { IPodLogsQuery, Pod, podsApi } from "../../api/endpoints"; import { autobind, interval } from "../../utils"; -import { dockStore, TabId } from "./dock.store"; -import { isLogsTab, logTabStore } from "./log-tab.store"; +import { dockStore, TabId, TabKind } from "./dock.store"; +import { logTabStore } from "./log-tab.store"; type PodLogLine = string; @@ -45,7 +45,7 @@ export class LogStore { autorun(() => { const { selectedTab, isOpen } = dockStore; - if (isLogsTab(selectedTab) && isOpen) { + if (selectedTab?.kind === TabKind.POD_LOGS && isOpen) { this.refresher.start(); } else { this.refresher.stop(); diff --git a/src/renderer/components/dock/logs.tsx b/src/renderer/components/dock/logs.tsx index 2f5c6c9ac8..0d7696f513 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 { autobind } from "../../utils"; -import { IDockTab } from "./dock.store"; +import type { IDockTab } from "./dock.store"; import { InfoPanel } from "./info-panel"; import { LogResourceSelector } from "./log-resource-selector"; import { LogList } from "./log-list"; diff --git a/src/renderer/components/dock/terminal-window.tsx b/src/renderer/components/dock/terminal-window.tsx index 7c0be046dd..d5b4d4a53b 100644 --- a/src/renderer/components/dock/terminal-window.tsx +++ b/src/renderer/components/dock/terminal-window.tsx @@ -25,8 +25,8 @@ import React from "react"; import { reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { cssNames } from "../../utils"; -import { IDockTab } from "./dock.store"; -import { Terminal } from "./terminal"; +import type { IDockTab } from "./dock.store"; +import type { Terminal } from "./terminal"; import { terminalStore } from "./terminal.store"; import { ThemeStore } from "../../theme.store"; diff --git a/src/renderer/components/dock/terminal.store.ts b/src/renderer/components/dock/terminal.store.ts index 4ede78c681..ba57c9bef7 100644 --- a/src/renderer/components/dock/terminal.store.ts +++ b/src/renderer/components/dock/terminal.store.ts @@ -30,10 +30,6 @@ export interface ITerminalTab extends IDockTab { node?: string; // activate node shell mode } -export function isTerminalTab(tab: IDockTab) { - return tab && tab.kind === TabKind.TERMINAL; -} - export function createTerminalTab(tabParams: Partial = {}) { return dockStore.createTab({ kind: TabKind.TERMINAL, @@ -52,9 +48,7 @@ export class TerminalStore { autorun(() => { const { selectedTab, isOpen } = dockStore; - if (!isTerminalTab(selectedTab)) return; - - if (isOpen) { + if (selectedTab?.kind === TabKind.TERMINAL && isOpen) { this.connect(selectedTab.id); } }); @@ -97,21 +91,15 @@ export class TerminalStore { } reconnect(tabId: TabId) { - const terminalApi = this.connections.get(tabId); - - if (terminalApi) terminalApi.connect(); + this.connections.get(tabId)?.connect(); } isConnected(tabId: TabId) { - return !!this.connections.get(tabId); + return Boolean(this.connections.get(tabId)); } isDisconnected(tabId: TabId) { - const terminalApi = this.connections.get(tabId); - - if (terminalApi) { - return terminalApi.readyState === WebSocketApiState.CLOSED; - } + return this.connections.get(tabId)?.readyState === WebSocketApiState.CLOSED; } sendCommand(command: string, options: { enter?: boolean; newTab?: boolean; tabId?: TabId } = {}) { diff --git a/src/renderer/components/dock/terminal.ts b/src/renderer/components/dock/terminal.ts index d3fd029259..7ce5412dab 100644 --- a/src/renderer/components/dock/terminal.ts +++ b/src/renderer/components/dock/terminal.ts @@ -24,7 +24,7 @@ import { reaction, toJS } from "mobx"; import { Terminal as XTerm } from "xterm"; import { FitAddon } from "xterm-addon-fit"; import { dockStore, TabId } from "./dock.store"; -import { TerminalApi } from "../../api/terminal-api"; +import type { TerminalApi } from "../../api/terminal-api"; import { ThemeStore } from "../../theme.store"; import { autobind } from "../../utils"; import { isMac } from "../../../common/vars"; diff --git a/src/renderer/components/dock/upgrade-chart.store.ts b/src/renderer/components/dock/upgrade-chart.store.ts index 97d8bd722e..a9b09e50d0 100644 --- a/src/renderer/components/dock/upgrade-chart.store.ts +++ b/src/renderer/components/dock/upgrade-chart.store.ts @@ -19,11 +19,12 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { action, autorun, IReactionDisposer, reaction } from "mobx"; +import { action, autorun, computed, IReactionDisposer, reaction } from "mobx"; import { dockStore, IDockTab, 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"; +import { iter } from "../../utils"; export interface IChartUpgradeData { releaseName: string; @@ -35,6 +36,10 @@ export class UpgradeChartStore extends DockTabStore { values = new DockTabStore(); + @computed private get releaseNameReverseLookup(): Map { + return new Map(iter.map(this.data, ([id, { releaseName }]) => [releaseName, id])); + } + constructor() { super({ storageKey: "chart_releases" @@ -43,9 +48,7 @@ export class UpgradeChartStore extends DockTabStore { autorun(() => { const { selectedTab, isOpen } = dockStore; - if (!isUpgradeChartTab(selectedTab)) return; - - if (isOpen) { + if (selectedTab?.kind === TabKind.UPGRADE_CHART && isOpen) { this.loadData(selectedTab.id); } }, { delay: 250 }); @@ -64,7 +67,7 @@ export class UpgradeChartStore extends DockTabStore { const dispose = reaction(() => { const release = releaseStore.getByName(releaseName); - if (release) return release.getRevision(); // watch changes only by revision + return release?.getRevision(); // watch changes only by revision }, release => { const releaseTab = this.getTabByRelease(releaseName); @@ -116,13 +119,7 @@ export class UpgradeChartStore extends DockTabStore { } getTabByRelease(releaseName: string): IDockTab { - const item = [...this.data].find(item => item[1].releaseName === releaseName); - - if (item) { - const [tabId] = item; - - return dockStore.getTabById(tabId); - } + return dockStore.getTabById(this.releaseNameReverseLookup.get(releaseName)); } } @@ -151,7 +148,3 @@ export function createUpgradeChartTab(release: HelmRelease, tabParams: Partial { get release(): HelmRelease { const tabData = upgradeChartStore.getData(this.tabId); - if (!tabData) return; + if (!tabData) return null; return releaseStore.getByName(tabData.releaseName); } @@ -87,7 +87,7 @@ export class UpgradeChart extends React.Component { }; upgrade = async () => { - if (this.error) return; + if (this.error) return null; const { version, repo } = this.version; const releaseName = this.release.getName(); const releaseNs = this.release.getNs(); diff --git a/src/renderer/components/hotbar/hotbar-entity-icon.tsx b/src/renderer/components/hotbar/hotbar-entity-icon.tsx index 41b0a69da0..93cfb28da7 100644 --- a/src/renderer/components/hotbar/hotbar-entity-icon.tsx +++ b/src/renderer/components/hotbar/hotbar-entity-icon.tsx @@ -23,7 +23,7 @@ import React, { DOMAttributes } from "react"; import { observable } from "mobx"; import { observer } from "mobx-react"; -import { CatalogEntity, CatalogEntityContextMenuContext } from "../../../common/catalog"; +import type { CatalogEntity, CatalogEntityContextMenuContext } from "../../../common/catalog"; import { catalogCategoryRegistry } from "../../api/catalog-category-registry"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; import { navigate } from "../../navigation"; diff --git a/src/renderer/components/hotbar/hotbar-icon.tsx b/src/renderer/components/hotbar/hotbar-icon.tsx index ddfa512dcd..bdd00859c2 100644 --- a/src/renderer/components/hotbar/hotbar-icon.tsx +++ b/src/renderer/components/hotbar/hotbar-icon.tsx @@ -26,7 +26,7 @@ import { Avatar } from "@material-ui/core"; import randomColor from "randomcolor"; import GraphemeSplitter from "grapheme-splitter"; -import { CatalogEntityContextMenu } from "../../../common/catalog"; +import type { CatalogEntityContextMenu } from "../../../common/catalog"; import { cssNames, IClassName, iter } from "../../utils"; import { ConfirmDialog } from "../confirm-dialog"; import { Menu, MenuItem } from "../menu"; diff --git a/src/renderer/components/icon/icon.tsx b/src/renderer/components/icon/icon.tsx index 6de4b6c39d..2e13273ab4 100644 --- a/src/renderer/components/icon/icon.tsx +++ b/src/renderer/components/icon/icon.tsx @@ -24,7 +24,7 @@ import "./icon.scss"; import React, { ReactNode } from "react"; import { findDOMNode } from "react-dom"; import { NavLink } from "react-router-dom"; -import { LocationDescriptor } from "history"; +import type { LocationDescriptor } from "history"; import { autobind, cssNames } from "../../utils"; import { TooltipDecoratorProps, withTooltip } from "../tooltip"; import isNumber from "lodash/isNumber"; diff --git a/src/renderer/components/input/drop-file-input.tsx b/src/renderer/components/input/drop-file-input.tsx index 276fb8d839..1062e1ce06 100644 --- a/src/renderer/components/input/drop-file-input.tsx +++ b/src/renderer/components/input/drop-file-input.tsx @@ -82,9 +82,8 @@ export class DropFileInput extends React.Component< if (disabled) { return contentElem; } - const isValidContentElem = React.isValidElement(contentElem); - if (isValidContentElem) { + if (React.isValidElement(contentElem)) { const contentElemProps: React.HTMLProps = { className: cssNames("DropFileInput", contentElem.props.className, className, { droppable: this.dropAreaActive, @@ -97,6 +96,8 @@ export class DropFileInput extends React.Component< return React.cloneElement(contentElem, contentElemProps); } + + return null; } catch (err) { logger.error(`Error: must contain only single child element`); diff --git a/src/renderer/components/input/input.tsx b/src/renderer/components/input/input.tsx index d4d9b9f577..324afdefb1 100644 --- a/src/renderer/components/input/input.tsx +++ b/src/renderer/components/input/input.tsx @@ -26,7 +26,7 @@ import { autobind, cssNames, debouncePromise, getRandId } from "../../utils"; import { Icon } from "../icon"; import { Tooltip, TooltipProps } from "../tooltip"; import * as Validators from "./input_validators"; -import { InputValidator } from "./input_validators"; +import type { InputValidator } from "./input_validators"; import isString from "lodash/isString"; import isFunction from "lodash/isFunction"; import isBoolean from "lodash/isBoolean"; @@ -34,7 +34,8 @@ import uniqueId from "lodash/uniqueId"; const { conditionalValidators, ...InputValidators } = Validators; -export { InputValidators, InputValidator }; +export { InputValidators }; +export type { InputValidator }; type InputElement = HTMLInputElement | HTMLTextAreaElement; type InputElementProps = InputHTMLAttributes & TextareaHTMLAttributes & DOMAttributes; diff --git a/src/renderer/components/input/input_validators.ts b/src/renderer/components/input/input_validators.ts index 46042300bc..7022527f74 100644 --- a/src/renderer/components/input/input_validators.ts +++ b/src/renderer/components/input/input_validators.ts @@ -20,7 +20,7 @@ */ import type { InputProps } from "./input"; -import { ReactNode } from "react"; +import type { ReactNode } from "react"; import fse from "fs-extra"; export interface InputValidator { diff --git a/src/renderer/components/input/search-input-url.tsx b/src/renderer/components/input/search-input-url.tsx index 44474ba5a7..cf9bb267b2 100644 --- a/src/renderer/components/input/search-input-url.tsx +++ b/src/renderer/components/input/search-input-url.tsx @@ -23,7 +23,7 @@ import React from "react"; import debounce from "lodash/debounce"; import { autorun, observable } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; -import { InputProps } from "./input"; +import type { InputProps } from "./input"; import { SearchInput } from "./search-input"; import { createPageParam } from "../../navigation"; diff --git a/src/renderer/components/item-object-list/item-list-layout.tsx b/src/renderer/components/item-object-list/item-list-layout.tsx index de1d7f9fac..527e43652c 100644 --- a/src/renderer/components/item-object-list/item-list-layout.tsx +++ b/src/renderer/components/item-object-list/item-list-layout.tsx @@ -31,7 +31,7 @@ import { autobind, createStorage, cssNames, IClassName, isReactNode, noop, Obser import { AddRemoveButtons, AddRemoveButtonsProps } from "../add-remove-buttons"; import { NoItems } from "../no-items"; import { Spinner } from "../spinner"; -import { ItemObject, ItemStore } from "../../item.store"; +import type { ItemObject, ItemStore } from "../../item.store"; import { SearchInputUrl } from "../input"; import { Filter, FilterType, pageFilters } from "./page-filters.store"; import { PageFiltersList } from "./page-filters-list"; @@ -247,7 +247,7 @@ export class ItemListLayout extends React.Component { const { isSelected } = store; const item = this.items.find(item => item.getId() == uid); - if (!item) return; + if (!item) return null; const itemId = item.getId(); return ( @@ -279,6 +279,8 @@ export class ItemListLayout extends React.Component { if (!headCell || this.showColumn(headCell)) { return ; } + + return null; }) } {renderItemMenu && ( @@ -320,7 +322,7 @@ export class ItemListLayout extends React.Component { const { isReady, filters } = this; if (!isReady || !filters.length || hideFilters || !this.showFilters) { - return; + return null; } return ; @@ -392,7 +394,7 @@ export class ItemListLayout extends React.Component { renderHeader() { const { showHeader, customizeHeader, renderHeaderTitle, headerClassName, isClusterScoped } = this.props; - if (!showHeader) return; + if (!showHeader) return null; const title = typeof renderHeaderTitle === "function" ? renderHeaderTitle(this) : renderHeaderTitle; const placeholders: IHeaderPlaceholders = { title:
{title}
, @@ -431,7 +433,7 @@ export class ItemListLayout extends React.Component { const { customizeTableRowProps, renderTableHeader, isSelectable, isConfigurable, store } = this.props; if (!renderTableHeader) { - return; + return null; } const enabledItems = this.items.filter(item => !customizeTableRowProps(item).disabled); @@ -520,9 +522,7 @@ export class ItemListLayout extends React.Component { } renderFooter() { - if (this.props.renderFooter) { - return this.props.renderFooter(this); - } + return this.props.renderFooter?.(this); } render() { 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 db08bffff8..bf700b871c 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 @@ -27,7 +27,7 @@ import { cssNames, formatDuration } from "../../utils"; import { KubeObject, KubeObjectStatus, KubeObjectStatusLevel } from "../../..//extensions/renderer-api/k8s-api"; import { kubeObjectStatusRegistry } from "../../../extensions/registries"; -function statusClassName(level: number): string { +function statusClassName(level: KubeObjectStatusLevel): string { switch (level) { case KubeObjectStatusLevel.INFO: return "info"; diff --git a/src/renderer/components/kube-object/kube-object-details.tsx b/src/renderer/components/kube-object/kube-object-details.tsx index 23e4e0c863..b4cc81824c 100644 --- a/src/renderer/components/kube-object/kube-object-details.tsx +++ b/src/renderer/components/kube-object/kube-object-details.tsx @@ -26,7 +26,7 @@ import { disposeOnUnmount, observer } from "mobx-react"; import { computed, observable, reaction } from "mobx"; import { createPageParam, navigation } from "../../navigation"; import { Drawer } from "../drawer"; -import { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../api/kube-object"; import { Spinner } from "../spinner"; import { apiManager } from "../../api/api-manager"; import { crdStore } from "../+custom-resources/crd.store"; diff --git a/src/renderer/components/kube-object/kube-object-list-layout.tsx b/src/renderer/components/kube-object/kube-object-list-layout.tsx index bb455dc4cb..44cb536429 100644 --- a/src/renderer/components/kube-object/kube-object-list-layout.tsx +++ b/src/renderer/components/kube-object/kube-object-list-layout.tsx @@ -23,9 +23,9 @@ import React from "react"; import { computed } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { cssNames } from "../../utils"; -import { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../api/kube-object"; import { ItemListLayout, ItemListLayoutProps } from "../item-object-list/item-list-layout"; -import { KubeObjectStore } from "../../kube-object.store"; +import type { KubeObjectStore } from "../../kube-object.store"; import { KubeObjectMenu } from "./kube-object-menu"; import { kubeSelectedUrlParam, showDetails } from "./kube-object-details"; import { kubeWatchApi } from "../../api/kube-watch-api"; diff --git a/src/renderer/components/kube-object/kube-object-menu.tsx b/src/renderer/components/kube-object/kube-object-menu.tsx index 88ed9ba53c..b2c26ef9ff 100644 --- a/src/renderer/components/kube-object/kube-object-menu.tsx +++ b/src/renderer/components/kube-object/kube-object-menu.tsx @@ -21,7 +21,7 @@ import React from "react"; import { autobind, cssNames } from "../../utils"; -import { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../api/kube-object"; import { editResourceTab } from "../dock/edit-resource.store"; import { MenuActions, MenuActionsProps } from "../menu/menu-actions"; import { hideDetails } from "./kube-object-details"; @@ -38,7 +38,7 @@ export class KubeObjectMenu extends React.Component { const { isExpandable, expanded, isActive } = this; if (!isExpandable || !expanded) { - return; + return null; } return ( diff --git a/src/renderer/components/layout/sidebar.tsx b/src/renderer/components/layout/sidebar.tsx index fdb950a02c..5149ebb4d6 100644 --- a/src/renderer/components/layout/sidebar.tsx +++ b/src/renderer/components/layout/sidebar.tsx @@ -155,7 +155,7 @@ export class Sidebar extends React.Component { pageUrl = tabRoutes[0].url; isActive = isActiveRoute(tabRoutes.map((tab) => tab.routePath)); } else { - return; + return null; } return ( diff --git a/src/renderer/components/menu/menu-actions.tsx b/src/renderer/components/menu/menu-actions.tsx index b1eaa6f9e0..c6c36482ab 100644 --- a/src/renderer/components/menu/menu-actions.tsx +++ b/src/renderer/components/menu/menu-actions.tsx @@ -75,7 +75,7 @@ export class MenuActions extends React.Component { } renderTriggerIcon() { - if (this.props.toolbar) return; + if (this.props.toolbar) return null; const { triggerIcon = "more_vert" } = this.props; let className: string; diff --git a/src/renderer/components/notifications/notifications.store.tsx b/src/renderer/components/notifications/notifications.store.tsx index 43b11cefa0..5e22e1b01e 100644 --- a/src/renderer/components/notifications/notifications.store.tsx +++ b/src/renderer/components/notifications/notifications.store.tsx @@ -19,11 +19,11 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import React from "react"; +import type React from "react"; import { action, observable } from "mobx"; import { autobind } from "../../utils"; import uniqueId from "lodash/uniqueId"; -import { JsonApiErrorParsed } from "../../api/json-api"; +import type { JsonApiErrorParsed } from "../../api/json-api"; export type NotificationId = string | number; export type NotificationMessage = React.ReactNode | React.ReactNode[] | JsonApiErrorParsed; diff --git a/src/renderer/components/resource-metrics/resource-metrics-text.tsx b/src/renderer/components/resource-metrics/resource-metrics-text.tsx index 0a971c5a1a..a83ef8118c 100644 --- a/src/renderer/components/resource-metrics/resource-metrics-text.tsx +++ b/src/renderer/components/resource-metrics/resource-metrics-text.tsx @@ -20,7 +20,7 @@ */ import React from "react"; -import { IPodMetrics } from "../../api/endpoints"; +import type { IPodMetrics } from "../../api/endpoints"; import { getMetricLastPoints, IMetrics } from "../../api/endpoints/metrics.api"; import { bytesToUnits } from "../../utils"; import { Badge } from "../badge"; diff --git a/src/renderer/components/resource-metrics/resource-metrics.tsx b/src/renderer/components/resource-metrics/resource-metrics.tsx index 90a180a3c2..aaf111a8cb 100644 --- a/src/renderer/components/resource-metrics/resource-metrics.tsx +++ b/src/renderer/components/resource-metrics/resource-metrics.tsx @@ -24,7 +24,7 @@ import "./resource-metrics.scss"; import React, { createContext, useEffect, useState } from "react"; import { Radio, RadioGroup } from "../radio"; import { useInterval } from "../../hooks"; -import { KubeObject } from "../../api/kube-object"; +import type { KubeObject } from "../../api/kube-object"; import { cssNames } from "../../utils"; import { Spinner } from "../spinner"; diff --git a/src/renderer/components/scroll-spy/scroll-spy.tsx b/src/renderer/components/scroll-spy/scroll-spy.tsx index 208ad326bb..672f7dee5d 100644 --- a/src/renderer/components/scroll-spy/scroll-spy.tsx +++ b/src/renderer/components/scroll-spy/scroll-spy.tsx @@ -22,7 +22,7 @@ import { observer } from "mobx-react"; import React, { useEffect, useRef, useState } from "react"; import { useMutationObserver } from "../../hooks"; -import { NavigationTree } from "../tree-view"; +import type { NavigationTree } from "../tree-view"; interface Props extends React.DOMAttributes { render: (data: NavigationTree[]) => JSX.Element diff --git a/src/renderer/components/table/table-cell.tsx b/src/renderer/components/table/table-cell.tsx index e7d88c8e67..0f9fdd8aa0 100644 --- a/src/renderer/components/table/table-cell.tsx +++ b/src/renderer/components/table/table-cell.tsx @@ -64,7 +64,7 @@ export class TableCell extends React.Component { renderSortIcon() { const { sortBy, _sorting } = this.props; - if (!this.isSortable) return; + if (!this.isSortable) return null; const sortActive = _sorting.sortBy === sortBy; const sortIconName = (!sortActive || _sorting.orderBy === "desc") ? "arrow_drop_down" : "arrow_drop_up"; @@ -83,6 +83,8 @@ export class TableCell extends React.Component { if (checkbox && showCheckbox) { return ; } + + return null; } render() { diff --git a/src/renderer/components/table/table-row.tsx b/src/renderer/components/table/table-row.tsx index 4a1acebe5f..9b3ce613e1 100644 --- a/src/renderer/components/table/table-row.tsx +++ b/src/renderer/components/table/table-row.tsx @@ -23,7 +23,7 @@ import "./table-row.scss"; import React, { CSSProperties } from "react"; import { cssNames } from "../../utils"; -import { ItemObject } from "../../item.store"; +import type { ItemObject } from "../../item.store"; export type TableRowElem = React.ReactElement; diff --git a/src/renderer/components/table/table.storage.ts b/src/renderer/components/table/table.storage.ts index 3a9b6af789..94db9eda32 100644 --- a/src/renderer/components/table/table.storage.ts +++ b/src/renderer/components/table/table.storage.ts @@ -20,7 +20,7 @@ */ import { createStorage } from "../../utils"; -import { TableSortParams } from "./table"; +import type { TableSortParams } from "./table"; export interface TableStorageModel { sortParams: { diff --git a/src/renderer/components/table/table.tsx b/src/renderer/components/table/table.tsx index 6884923f8a..9672a9d1ff 100644 --- a/src/renderer/components/table/table.tsx +++ b/src/renderer/components/table/table.tsx @@ -27,10 +27,10 @@ import { observer } from "mobx-react"; import { autobind, cssNames, noop } from "../../utils"; import { TableRow, TableRowElem, TableRowProps } from "./table-row"; import { TableHead, TableHeadElem, TableHeadProps } from "./table-head"; -import { TableCellElem } from "./table-cell"; +import type { TableCellElem } from "./table-cell"; import { VirtualList } from "../virtual-list"; import { createPageParam } from "../../navigation"; -import { ItemObject } from "../../item.store"; +import type { ItemObject } from "../../item.store"; import { getSortParams, setSortParams } from "./table.storage"; import { computed } from "mobx"; @@ -102,33 +102,35 @@ export class Table extends React.Component { const content = React.Children.toArray(children) as (TableRowElem | TableHeadElem)[]; const headElem: React.ReactElement = content.find(elem => elem.type === TableHead); - if (headElem) { - if (sortable) { - const columns = React.Children.toArray(headElem.props.children) as TableCellElem[]; - - return React.cloneElement(headElem, { - children: columns.map(elem => { - if (elem.props.checkbox) { - return elem; - } - const title = elem.props.title || ( - // copy cell content to title if it's a string - // usable if part of TableCell's content is hidden when there is not enough space - typeof elem.props.children === "string" ? elem.props.children : undefined - ); - - return React.cloneElement(elem, { - title, - _sort: this.sort, - _sorting: this.sortParams, - _nowrap: headElem.props.nowrap, - }); - }) - }); - } - - return headElem; + if (!headElem) { + return null; } + + if (sortable) { + const columns = React.Children.toArray(headElem.props.children) as TableCellElem[]; + + return React.cloneElement(headElem, { + children: columns.map(elem => { + if (elem.props.checkbox) { + return elem; + } + const title = elem.props.title || ( + // copy cell content to title if it's a string + // usable if part of TableCell's content is hidden when there is not enough space + typeof elem.props.children === "string" ? elem.props.children : undefined + ); + + return React.cloneElement(elem, { + title, + _sort: this.sort, + _sorting: this.sortParams, + _nowrap: headElem.props.nowrap, + }); + }) + }); + } + + return headElem; } getSorted(items: any[]) { diff --git a/src/renderer/components/virtual-list/virtual-list.tsx b/src/renderer/components/virtual-list/virtual-list.tsx index fd9f91db0d..86f0c7e44d 100644 --- a/src/renderer/components/virtual-list/virtual-list.tsx +++ b/src/renderer/components/virtual-list/virtual-list.tsx @@ -27,8 +27,8 @@ import React, { Component } from "react"; import { observer } from "mobx-react"; import { Align, ListChildComponentProps, ListOnScrollProps, VariableSizeList } from "react-window"; import { cssNames, noop } from "../../utils"; -import { TableRowProps } from "../table/table-row"; -import { ItemObject } from "../../item.store"; +import type { TableRowProps } from "../table/table-row"; +import type { ItemObject } from "../../item.store"; import throttle from "lodash/throttle"; import debounce from "lodash/debounce"; import isEqual from "lodash/isEqual"; diff --git a/src/renderer/components/wizard/wizard.tsx b/src/renderer/components/wizard/wizard.tsx index 8ade6d9210..654db47ef6 100755 --- a/src/renderer/components/wizard/wizard.tsx +++ b/src/renderer/components/wizard/wizard.tsx @@ -221,7 +221,7 @@ export class WizardStep extends React.Component(key: string, initialValue: T, options?: CreateObservableOptions) { const storage = createStorage(key, initialValue, options); diff --git a/src/renderer/kube-object.store.ts b/src/renderer/kube-object.store.ts index 0c82bbeb56..fb60bd0330 100644 --- a/src/renderer/kube-object.store.ts +++ b/src/renderer/kube-object.store.ts @@ -24,11 +24,11 @@ import type { ClusterContext } from "./components/context"; import { action, computed, observable, reaction, when } from "mobx"; import { autobind, bifurcateArray, noop, rejectPromiseBy } from "./utils"; import { KubeObject, KubeStatus } from "./api/kube-object"; -import { IKubeWatchEvent } from "./api/kube-watch-api"; +import type { IKubeWatchEvent } from "./api/kube-watch-api"; import { ItemStore } from "./item.store"; import { apiManager } from "./api/api-manager"; import { IKubeApiQueryParams, KubeApi, parseKubeApi } from "./api/kube-api"; -import { KubeJsonApiData } from "./api/kube-json-api"; +import type { KubeJsonApiData } from "./api/kube-json-api"; import { Notifications } from "./components/notifications"; export interface KubeObjectStoreLoadingParams { @@ -89,9 +89,13 @@ export abstract class KubeObjectStore extends ItemSt if (namespaces.length) { return this.items.filter(item => namespaces.includes(item.getNs())); - } else if (!strict) { + } + + if (!strict) { return this.items; } + + return []; } getById(id: string) { @@ -194,7 +198,7 @@ export abstract class KubeObjectStore extends ItemSt } @action - reloadAll(opts: { force?: boolean, namespaces?: string[], merge?: boolean } = {}) { + async reloadAll(opts: { force?: boolean, namespaces?: string[], merge?: boolean } = {}) { const { force = false, ...loadingOptions } = opts; if (this.isLoading || (this.isLoaded && !force)) { diff --git a/src/renderer/navigation/page-param.ts b/src/renderer/navigation/page-param.ts index 2908993a0c..1d20e0de48 100644 --- a/src/renderer/navigation/page-param.ts +++ b/src/renderer/navigation/page-param.ts @@ -20,7 +20,7 @@ */ // Manage observable URL-param from document.location.search -import { IObservableHistory } from "mobx-observable-history"; +import type { IObservableHistory } from "mobx-observable-history"; export interface PageParamInit { name: string; diff --git a/src/renderer/utils/display-booleans.ts b/src/renderer/utils/display-booleans.ts index cb47b43351..262e032ca7 100644 --- a/src/renderer/utils/display-booleans.ts +++ b/src/renderer/utils/display-booleans.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import React from "react"; +import type React from "react"; export function displayBooleans(shouldShow: boolean, from: React.ReactNode): React.ReactNode { if (shouldShow) { diff --git a/src/renderer/utils/prevDefault.ts b/src/renderer/utils/prevDefault.ts index 77d5ef6f89..4479cbcf93 100644 --- a/src/renderer/utils/prevDefault.ts +++ b/src/renderer/utils/prevDefault.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import React from "react"; +import type React from "react"; // Helper for preventing default event action and performing custom callback // 1) diff --git a/src/renderer/utils/rbac.ts b/src/renderer/utils/rbac.ts index d2740f1f12..ca264f050c 100644 --- a/src/renderer/utils/rbac.ts +++ b/src/renderer/utils/rbac.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { KubeResource } from "../../common/rbac"; +import type { KubeResource } from "../../common/rbac"; export const ResourceNames: Record = { "namespaces": "Namespaces", diff --git a/tsconfig.json b/tsconfig.json index b2cb7376ef..2d72839134 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,14 +13,16 @@ "sourceMap": true, "strict": false, "noImplicitAny": true, - "noUnusedLocals": false, - "noImplicitReturns": false, + "noUnusedLocals": true, + "noImplicitReturns": true, "experimentalDecorators": true, "emitDecoratorMetadata": true, + "isolatedModules": true, "skipLibCheck": true, "allowJs": false, "esModuleInterop": true, "allowSyntheticDefaultImports": true, + "importsNotUsedAsValues": "error", "traceResolution": false, "resolveJsonModule": true, "paths": { diff --git a/webpack.extensions.ts b/webpack.extensions.ts index fb79c55675..e5a95660aa 100644 --- a/webpack.extensions.ts +++ b/webpack.extensions.ts @@ -21,7 +21,7 @@ import path from "path"; -import webpack from "webpack"; +import type webpack from "webpack"; import { sassCommonVars, isDevelopment, isProduction } from "./src/common/vars"; export default function generateExtensionTypes(): webpack.Configuration { diff --git a/webpack.main.ts b/webpack.main.ts index 45c74a85c7..26550de14f 100755 --- a/webpack.main.ts +++ b/webpack.main.ts @@ -20,7 +20,7 @@ */ import path from "path"; -import webpack from "webpack"; +import type webpack from "webpack"; import ForkTsCheckerPlugin from "fork-ts-checker-webpack-plugin"; import { isProduction, mainDir, buildDir, isDevelopment } from "./src/common/vars"; import nodeExternals from "webpack-node-externals"; From b61ba7ef719f89fbbf3070dc0b70cdd37af09978 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 20 May 2021 01:50:51 -0400 Subject: [PATCH 21/21] Filter out unknown catalog entities (#2816) * Filter out unknown catelog entities - Keep raw data - But filter unknown types until a category is registered Signed-off-by: Sebastian Malton * fix unit tests Signed-off-by: Sebastian Malton * simplify tests Signed-off-by: Sebastian Malton * Remove getOrDefault, consolodate ExtendedMap Signed-off-by: Sebastian Malton --- .../catalog/catalog-category-registry.ts | 40 +++++++++-------- src/common/utils/extended-map.ts | 43 +++++++++++++------ .../__tests__/catalog-entity-registry.test.ts | 12 +++--- src/renderer/api/catalog-entity-registry.ts | 25 +++++------ 4 files changed, 71 insertions(+), 49 deletions(-) diff --git a/src/common/catalog/catalog-category-registry.ts b/src/common/catalog/catalog-category-registry.ts index 886db3e90a..a0319d773b 100644 --- a/src/common/catalog/catalog-category-registry.ts +++ b/src/common/catalog/catalog-category-registry.ts @@ -19,26 +19,38 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { action, computed, observable, toJS } from "mobx"; +import { action, computed, observable } from "mobx"; +import { Disposer, ExtendedMap } from "../utils"; import { CatalogCategory, CatalogEntityData, CatalogEntityKindData } from "./catalog-entity"; export class CatalogCategoryRegistry { - @observable protected categories: CatalogCategory[] = []; + protected categories = observable.set(); - @action add(category: CatalogCategory) { - this.categories.push(category); + @action add(category: CatalogCategory): Disposer { + this.categories.add(category); + + return () => this.categories.delete(category); } - @action remove(category: CatalogCategory) { - this.categories = this.categories.filter((cat) => cat.apiVersion !== category.apiVersion && cat.kind !== category.kind); + @computed private get groupKindLookup(): Map> { + // ExtendedMap has the convenience methods `getOrInsert` and `strictSet` + const res = new ExtendedMap>(); + + for (const category of this.categories) { + res + .getOrInsert(category.spec.group, ExtendedMap.new) + .strictSet(category.spec.names.kind, category); + } + + return res; } @computed get items() { - return toJS(this.categories); + return Array.from(this.categories); } - getForGroupKind(group: string, kind: string) { - return this.categories.find((c) => c.spec.group === group && c.spec.names.kind === kind) as T; + getForGroupKind(group: string, kind: string): T | undefined { + return this.groupKindLookup.get(group)?.get(kind) as T; } getEntityForData(data: CatalogEntityData & CatalogEntityKindData) { @@ -60,17 +72,11 @@ export class CatalogCategoryRegistry { return new specVersion.entityClass(data); } - getCategoryForEntity(data: CatalogEntityData & CatalogEntityKindData) { + getCategoryForEntity(data: CatalogEntityData & CatalogEntityKindData): T | undefined { const splitApiVersion = data.apiVersion.split("/"); const group = splitApiVersion[0]; - const category = this.categories.find((category) => { - return category.spec.group === group && category.spec.names.kind === data.kind; - }); - - if (!category) return null; - - return category as T; + return this.getForGroupKind(group, data.kind); } } diff --git a/src/common/utils/extended-map.ts b/src/common/utils/extended-map.ts index 9d3a0dc7b3..c8b7ff4c65 100644 --- a/src/common/utils/extended-map.ts +++ b/src/common/utils/extended-map.ts @@ -22,19 +22,17 @@ import { action, IEnhancer, IObservableMapInitialValues, ObservableMap } from "mobx"; export class ExtendedMap extends Map { - constructor(protected getDefault: () => V, entries?: readonly (readonly [K, V])[] | null) { - super(entries); + static new(entries?: readonly (readonly [K, V])[] | null): ExtendedMap { + return new ExtendedMap(entries); } - getOrInsert(key: K, val: V): V { - if (this.has(key)) { - return this.get(key); - } - - return this.set(key, val).get(key); - } - - getOrInsertWith(key: K, getVal: () => V): V { + /** + * Get the value behind `key`. If it was not pressent, 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 + */ + getOrInsert(key: K, getVal: () => V): V { if (this.has(key)) { return this.get(key); } @@ -42,12 +40,29 @@ export class ExtendedMap extends Map { return this.set(key, getVal()).get(key); } - getOrDefault(key: K): V { + /** + * Set the value associated with `key` iff there was not a previous value + * @throws if `key` already in map + * @returns `this` so that `strictSet` can be chained + */ + strictSet(key: K, val: V): this { if (this.has(key)) { - return this.get(key); + throw new TypeError("Duplicate key in map"); } - return this.set(key, this.getDefault()).get(key); + return this.set(key, val); + } + + /** + * Get the value associated with `key` + * @throws if `key` did not a value associated with it + */ + strictGet(key: K): V { + if (!this.has(key)) { + throw new TypeError("key not in map"); + } + + return this.get(key); } } diff --git a/src/renderer/api/__tests__/catalog-entity-registry.test.ts b/src/renderer/api/__tests__/catalog-entity-registry.test.ts index 7cc208ad55..359b293993 100644 --- a/src/renderer/api/__tests__/catalog-entity-registry.test.ts +++ b/src/renderer/api/__tests__/catalog-entity-registry.test.ts @@ -42,7 +42,7 @@ describe("CatalogEntityRegistry", () => { spec: {} }]; - catalog.updateItems(items); + (catalog as any).rawItems.replace(items); expect(catalog.items.length).toEqual(1); items.push({ @@ -60,7 +60,7 @@ describe("CatalogEntityRegistry", () => { spec: {} }); - catalog.updateItems(items); + (catalog as any).rawItems.replace(items); expect(catalog.items.length).toEqual(2); }); @@ -81,13 +81,13 @@ describe("CatalogEntityRegistry", () => { spec: {} }]; - catalog.updateItems(items); + (catalog as any).rawItems.replace(items); expect(catalog.items.length).toEqual(1); expect(catalog.items[0].status.phase).toEqual("disconnected"); items[0].status.phase = "connected"; - catalog.updateItems(items); + (catalog as any).rawItems.replace(items); expect(catalog.items.length).toEqual(1); expect(catalog.items[0].status.phase).toEqual("connected"); }); @@ -125,9 +125,9 @@ describe("CatalogEntityRegistry", () => { } ]; - catalog.updateItems(items); + (catalog as any).rawItems.replace(items); items.splice(0, 1); - catalog.updateItems(items); + (catalog as any).rawItems.replace(items); expect(catalog.items.length).toEqual(1); expect(catalog.items[0].metadata.uid).toEqual("456"); }); diff --git a/src/renderer/api/catalog-entity-registry.ts b/src/renderer/api/catalog-entity-registry.ts index 42c9b6f224..ac4e6748dc 100644 --- a/src/renderer/api/catalog-entity-registry.ts +++ b/src/renderer/api/catalog-entity-registry.ts @@ -19,28 +19,25 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { action, observable } from "mobx"; +import { computed, observable } from "mobx"; import { broadcastMessage, subscribeToBroadcast } from "../../common/ipc"; import { CatalogCategory, CatalogEntity, CatalogEntityData, catalogCategoryRegistry, CatalogCategoryRegistry, CatalogEntityKindData } from "../../common/catalog"; import "../../common/catalog-entities"; +import { iter } from "../utils"; export class CatalogEntityRegistry { - @observable protected _items: CatalogEntity[] = observable.array([], { deep: true }); + protected rawItems = observable.array([], { deep: true }); @observable protected _activeEntity: CatalogEntity; constructor(private categoryRegistry: CatalogCategoryRegistry) {} init() { subscribeToBroadcast("catalog:items", (ev, items: (CatalogEntityData & CatalogEntityKindData)[]) => { - this.updateItems(items); + this.rawItems.replace(items); }); broadcastMessage("catalog:broadcast"); } - @action updateItems(items: (CatalogEntityData & CatalogEntityKindData)[]) { - this._items = items.map(data => this.categoryRegistry.getEntityForData(data)); - } - set activeEntity(entity: CatalogEntity) { this._activeEntity = entity; } @@ -49,23 +46,27 @@ export class CatalogEntityRegistry { return this._activeEntity; } - get items() { - return this._items; + @computed get items() { + return Array.from(iter.filterMap(this.rawItems, rawItem => this.categoryRegistry.getEntityForData(rawItem))); + } + + @computed get entities(): Map { + return new Map(this.items.map(item => [item.metadata.uid, item])); } getById(id: string) { - return this._items.find((entity) => entity.metadata.uid === id); + return this.entities.get(id); } getItemsForApiKind(apiVersion: string, kind: string): T[] { - const items = this._items.filter((item) => item.apiVersion === apiVersion && item.kind === kind); + const items = this.items.filter((item) => item.apiVersion === apiVersion && item.kind === kind); return items as T[]; } getItemsForCategory(category: CatalogCategory): T[] { const supportedVersions = category.spec.versions.map((v) => `${category.spec.group}/${v.name}`); - const items = this._items.filter((item) => supportedVersions.includes(item.apiVersion) && item.kind === category.spec.names.kind); + const items = this.items.filter((item) => supportedVersions.includes(item.apiVersion) && item.kind === category.spec.names.kind); return items as T[]; }