From 5a878ccffb9cb1b0fd111ba9ce8ba9e462607fc9 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 9 Jul 2021 17:21:34 -0400 Subject: [PATCH] Provide better typing for dock tabs - Change name from IDockTab to DockTabDescriptor - Make all fields required - Add new types for the createTab() and the create(Type)Tab() functions Signed-off-by: Sebastian Malton --- .../dock/__test__/dock-tabs.test.tsx | 20 +++---- .../components/dock/create-resource.store.ts | 8 +-- .../components/dock/create-resource.tsx | 4 +- src/renderer/components/dock/dock-tab.tsx | 4 +- src/renderer/components/dock/dock-tabs.tsx | 10 ++-- src/renderer/components/dock/dock.store.ts | 54 +++++++++++++------ src/renderer/components/dock/dock.tsx | 6 +-- .../components/dock/edit-resource.store.ts | 8 +-- .../components/dock/edit-resource.tsx | 4 +- .../components/dock/install-chart.store.ts | 8 +-- .../components/dock/install-chart.tsx | 4 +- src/renderer/components/dock/log-tab.store.ts | 6 +-- src/renderer/components/dock/logs.tsx | 4 +- .../components/dock/terminal-window.tsx | 4 +- .../components/dock/terminal.store.ts | 10 ++-- .../components/dock/upgrade-chart.store.ts | 10 ++-- .../components/dock/upgrade-chart.tsx | 4 +- 17 files changed, 96 insertions(+), 72 deletions(-) diff --git a/src/renderer/components/dock/__test__/dock-tabs.test.tsx b/src/renderer/components/dock/__test__/dock-tabs.test.tsx index ad27853900..1a99f43056 100644 --- a/src/renderer/components/dock/__test__/dock-tabs.test.tsx +++ b/src/renderer/components/dock/__test__/dock-tabs.test.tsx @@ -24,7 +24,7 @@ import { fireEvent, render } from "@testing-library/react"; import "@testing-library/jest-dom/extend-expect"; import { DockTabs } from "../dock-tabs"; -import { dockStore, IDockTab, TabKind } from "../dock.store"; +import { dockStore, DockTabDescriptor, TabKind } from "../dock.store"; import { noop } from "../../../utils"; jest.mock("electron", () => ({ @@ -33,12 +33,12 @@ jest.mock("electron", () => ({ }, })); -const initialTabs: IDockTab[] = [ - { id: "terminal", kind: TabKind.TERMINAL, title: "Terminal" }, - { id: "create", kind: TabKind.CREATE_RESOURCE, title: "Create resource" }, - { id: "edit", kind: TabKind.EDIT_RESOURCE, title: "Edit resource" }, - { id: "install", kind: TabKind.INSTALL_CHART, title: "Install chart" }, - { id: "logs", kind: TabKind.POD_LOGS, title: "Logs" }, +const initialTabs: DockTabDescriptor[] = [ + { id: "terminal", kind: TabKind.TERMINAL, title: "Terminal", pinned: false, }, + { id: "create", kind: TabKind.CREATE_RESOURCE, title: "Create resource", pinned: false, }, + { id: "edit", kind: TabKind.EDIT_RESOURCE, title: "Edit resource", pinned: false, }, + { id: "install", kind: TabKind.INSTALL_CHART, title: "Install chart", pinned: false, }, + { id: "logs", kind: TabKind.POD_LOGS, title: "Logs", pinned: false, }, ]; const getComponent = () => ( @@ -142,7 +142,7 @@ describe("", () => { it("disables 'Close All' & 'Close Other' items if only 1 tab available", () => { dockStore.tabs = [{ - id: "terminal", kind: TabKind.TERMINAL, title: "Terminal" + id: "terminal", kind: TabKind.TERMINAL, title: "Terminal", pinned: false, }]; const { container, getByText } = renderTabs(); const tab = container.querySelector(".Tab"); @@ -157,8 +157,8 @@ describe("", () => { it("disables 'Close To The Right' item if last tab clicked", () => { dockStore.tabs = [ - { id: "terminal", kind: TabKind.TERMINAL, title: "Terminal" }, - { id: "logs", kind: TabKind.POD_LOGS, title: "Pod Logs" }, + { id: "terminal", kind: TabKind.TERMINAL, title: "Terminal", pinned: false, }, + { id: "logs", kind: TabKind.POD_LOGS, title: "Pod Logs", pinned: false, }, ]; const { container, getByText } = renderTabs(); const tab = container.querySelectorAll(".Tab")[1]; diff --git a/src/renderer/components/dock/create-resource.store.ts b/src/renderer/components/dock/create-resource.store.ts index 2e049deacf..55c5f14cfa 100644 --- a/src/renderer/components/dock/create-resource.store.ts +++ b/src/renderer/components/dock/create-resource.store.ts @@ -27,7 +27,7 @@ import filehound from "filehound"; import { watch } from "chokidar"; import { autoBind } from "../../utils"; import { DockTabStore } from "./dock-tab.store"; -import { dockStore, IDockTab, TabKind } from "./dock.store"; +import { dockStore, SpecializedCreateDockTabDescriptor, TabKind } from "./dock.store"; export class CreateResourceStore extends DockTabStore { constructor() { @@ -81,10 +81,10 @@ export class CreateResourceStore extends DockTabStore { export const createResourceStore = new CreateResourceStore(); -export function createResourceTab(tabParams: Partial = {}) { +export function createResourceTab(tabParams: SpecializedCreateDockTabDescriptor = {}) { return dockStore.createTab({ - kind: TabKind.CREATE_RESOURCE, title: "Create resource", - ...tabParams + ...tabParams, + kind: TabKind.CREATE_RESOURCE, }); } diff --git a/src/renderer/components/dock/create-resource.tsx b/src/renderer/components/dock/create-resource.tsx index 413cbebc6d..510b291d34 100644 --- a/src/renderer/components/dock/create-resource.tsx +++ b/src/renderer/components/dock/create-resource.tsx @@ -30,7 +30,7 @@ import { observable, makeObservable } from "mobx"; import { observer } from "mobx-react"; import { cssNames } from "../../utils"; import { createResourceStore } from "./create-resource.store"; -import type { IDockTab } from "./dock.store"; +import type { DockTabDescriptor } from "./dock.store"; import { EditorPanel } from "./editor-panel"; import { InfoPanel } from "./info-panel"; import { resourceApplierApi } from "../../api/endpoints/resource-applier.api"; @@ -39,7 +39,7 @@ import { Notifications } from "../notifications"; interface Props { className?: string; - tab: IDockTab; + tab: DockTabDescriptor; } @observer diff --git a/src/renderer/components/dock/dock-tab.tsx b/src/renderer/components/dock/dock-tab.tsx index dd4ff63824..5da99ba230 100644 --- a/src/renderer/components/dock/dock-tab.tsx +++ b/src/renderer/components/dock/dock-tab.tsx @@ -24,13 +24,13 @@ import "./dock-tab.scss"; import React from "react"; import { observer } from "mobx-react"; import { boundMethod, cssNames, prevDefault, isMiddleClick } from "../../utils"; -import { dockStore, IDockTab } from "./dock.store"; +import { dockStore, DockTabDescriptor } from "./dock.store"; import { Tab, TabProps } from "../tabs"; import { Icon } from "../icon"; import { Menu, MenuItem } from "../menu"; import { observable, makeObservable } from "mobx"; -export interface DockTabProps extends TabProps { +export interface DockTabProps extends TabProps { moreActions?: React.ReactNode; } diff --git a/src/renderer/components/dock/dock-tabs.tsx b/src/renderer/components/dock/dock-tabs.tsx index 6064259cbc..68aa4646a7 100644 --- a/src/renderer/components/dock/dock-tabs.tsx +++ b/src/renderer/components/dock/dock-tabs.tsx @@ -24,19 +24,19 @@ import React, { Fragment } from "react"; import { Icon } from "../icon"; import { Tabs } from "../tabs/tabs"; import { DockTab } from "./dock-tab"; -import type { IDockTab } from "./dock.store"; +import type { DockTabDescriptor } from "./dock.store"; import { TabKind } from "./dock.store"; import { TerminalTab } from "./terminal-tab"; interface Props { - tabs: IDockTab[] + tabs: DockTabDescriptor[] autoFocus: boolean - selectedTab: IDockTab - onChangeTab: (tab: IDockTab) => void + selectedTab: DockTabDescriptor + onChangeTab: (tab: DockTabDescriptor) => void } export const DockTabs = ({ tabs, autoFocus, selectedTab, onChangeTab }: Props) => { - const renderTab = (tab?: IDockTab) => { + const renderTab = (tab?: DockTabDescriptor) => { if (!tab) { return null; } diff --git a/src/renderer/components/dock/dock.store.ts b/src/renderer/components/dock/dock.store.ts index 2c9789ce41..871775d0de 100644 --- a/src/renderer/components/dock/dock.store.ts +++ b/src/renderer/components/dock/dock.store.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import MD5 from "crypto-js/md5"; +import * as uuid from "uuid"; import { action, computed, IReactionOptions, makeObservable, observable, reaction } from "mobx"; import { autoBind, createStorage } from "../../utils"; import throttle from "lodash/throttle"; @@ -35,16 +35,24 @@ export enum TabKind { POD_LOGS = "pod-logs", } -export interface IDockTab { - id?: TabId; +export interface DockTabDescriptor { + id: TabId; kind: TabKind; - title?: string; - pinned?: boolean; // not closable + title: string; + pinned: boolean; // not closable + + /** + * DockTabData may contain extra data + */ + [key: string]: any; } +export type CreateDockTabDescriptor = Partial> & Pick; +export type SpecializedCreateDockTabDescriptor = Omit; + export interface DockStorageState { height: number; - tabs: IDockTab[]; + tabs: DockTabDescriptor[]; selectedTabId?: TabId; isOpen?: boolean; } @@ -62,7 +70,7 @@ export class DockStore implements DockStorageState { private storage = createStorage("dock", { height: 300, tabs: [ - { id: "terminal", kind: TabKind.TERMINAL, title: "Terminal" }, + { id: "terminal", kind: TabKind.TERMINAL, title: "Terminal", pinned: false }, ], }); @@ -88,11 +96,11 @@ export class DockStore implements DockStorageState { }); } - get tabs(): IDockTab[] { + get tabs(): DockTabDescriptor[] { return this.storage.get().tabs; } - set tabs(tabs: IDockTab[]) { + set tabs(tabs: DockTabDescriptor[]) { this.storage.merge({ tabs }); } @@ -191,15 +199,31 @@ export class DockStore implements DockStorageState { } @action - createTab(anonTab: IDockTab, addNumber = true): IDockTab { - const tabId = MD5(Math.random().toString() + Date.now()).toString(); - const tab: IDockTab = { id: tabId, ...anonTab }; + createTab(rawTabDesc: CreateDockTabDescriptor, addNumber = true): DockTabDescriptor { + const { + id = uuid.v4(), + kind, + pinned = false, + ...restOfTabFields + } = rawTabDesc; + let { title = kind } = rawTabDesc; if (addNumber) { - const tabNumber = this.getNewTabNumber(tab.kind); + const tabNumber = this.getNewTabNumber(kind); - if (tabNumber > 1) tab.title += ` (${tabNumber})`; + if (tabNumber > 1) { + title += ` (${tabNumber})`; + } } + + const tab: DockTabDescriptor = { + ...restOfTabFields, + id, + kind, + pinned, + title + }; + this.tabs.push(tab); this.selectTab(tab.id); this.open(); @@ -234,7 +258,7 @@ export class DockStore implements DockStorageState { } } - closeTabs(tabs: IDockTab[]) { + closeTabs(tabs: DockTabDescriptor[]) { tabs.forEach(tab => this.closeTab(tab.id)); } diff --git a/src/renderer/components/dock/dock.tsx b/src/renderer/components/dock/dock.tsx index c3c4ca520b..17331ad375 100644 --- a/src/renderer/components/dock/dock.tsx +++ b/src/renderer/components/dock/dock.tsx @@ -32,7 +32,7 @@ import { ResizeDirection, ResizingAnchor } from "../resizing-anchor"; import { CreateResource } from "./create-resource"; import { createResourceTab } from "./create-resource.store"; import { DockTabs } from "./dock-tabs"; -import { dockStore, IDockTab, TabKind } from "./dock.store"; +import { dockStore, DockTabDescriptor, TabKind } from "./dock.store"; import { EditResource } from "./edit-resource"; import { InstallChart } from "./install-chart"; import { Logs } from "./logs"; @@ -62,14 +62,14 @@ export class Dock extends React.Component { } }; - onChangeTab = (tab: IDockTab) => { + onChangeTab = (tab: DockTabDescriptor) => { const { open, selectTab } = dockStore; open(); selectTab(tab.id); }; - renderTab(tab: IDockTab) { + renderTab(tab: DockTabDescriptor) { switch (tab.kind) { case TabKind.CREATE_RESOURCE: return ; diff --git a/src/renderer/components/dock/edit-resource.store.ts b/src/renderer/components/dock/edit-resource.store.ts index 9b10491901..a37ffb05d7 100644 --- a/src/renderer/components/dock/edit-resource.store.ts +++ b/src/renderer/components/dock/edit-resource.store.ts @@ -22,7 +22,7 @@ import { autoBind, noop } from "../../utils"; import { DockTabStore } from "./dock-tab.store"; import { autorun, IReactionDisposer } from "mobx"; -import { dockStore, IDockTab, TabId, TabKind } from "./dock.store"; +import { dockStore, DockTabDescriptor, SpecializedCreateDockTabDescriptor, TabId, TabKind } from "./dock.store"; import type { KubeObject } from "../../api/kube-object"; import { apiManager } from "../../api/api-manager"; import type { KubeObjectStore } from "../../kube-object.store"; @@ -96,7 +96,7 @@ export class EditResourceStore extends DockTabStore { return this.getData(tabId)?.resource; } - getTabByResource(object: KubeObject): IDockTab { + getTabByResource(object: KubeObject): DockTabDescriptor { const [tabId] = Array.from(this.data).find(([, { resource }]) => { return object.selfLink === resource; }) || []; @@ -115,7 +115,7 @@ export class EditResourceStore extends DockTabStore { export const editResourceStore = new EditResourceStore(); -export function editResourceTab(object: KubeObject, tabParams: Partial = {}) { +export function editResourceTab(object: KubeObject, tabParams: SpecializedCreateDockTabDescriptor = {}) { // use existing tab if already opened let tab = editResourceStore.getTabByResource(object); @@ -128,8 +128,8 @@ export function editResourceTab(object: KubeObject, tabParams: Partial if (!tab) { tab = dockStore.createTab({ title: `${object.kind}: ${object.getName()}`, + ...tabParams, kind: TabKind.EDIT_RESOURCE, - ...tabParams }, false); editResourceStore.setData(tab.id, { resource: object.selfLink, diff --git a/src/renderer/components/dock/edit-resource.tsx b/src/renderer/components/dock/edit-resource.tsx index 455bbda61a..41ff3f4659 100644 --- a/src/renderer/components/dock/edit-resource.tsx +++ b/src/renderer/components/dock/edit-resource.tsx @@ -25,7 +25,7 @@ import React from "react"; import { action, computed, makeObservable, observable } from "mobx"; import { observer } from "mobx-react"; import jsYaml from "js-yaml"; -import type { IDockTab } from "./dock.store"; +import type { DockTabDescriptor } from "./dock.store"; import { cssNames } from "../../utils"; import { editResourceStore } from "./edit-resource.store"; import { InfoPanel } from "./info-panel"; @@ -36,7 +36,7 @@ import type { KubeObject } from "../../api/kube-object"; interface Props { className?: string; - tab: IDockTab; + tab: DockTabDescriptor; } @observer diff --git a/src/renderer/components/dock/install-chart.store.ts b/src/renderer/components/dock/install-chart.store.ts index 20e0a7a0ac..88fe5c8169 100644 --- a/src/renderer/components/dock/install-chart.store.ts +++ b/src/renderer/components/dock/install-chart.store.ts @@ -20,7 +20,7 @@ */ import { action, autorun, makeObservable } from "mobx"; -import { dockStore, IDockTab, TabId, TabKind } from "./dock.store"; +import { dockStore, SpecializedCreateDockTabDescriptor, TabId, TabKind } from "./dock.store"; import { DockTabStore } from "./dock-tab.store"; import { getChartDetails, getChartValues, HelmChart } from "../../api/endpoints/helm-charts.api"; import type { IReleaseUpdateDetails } from "../../api/endpoints/helm-releases.api"; @@ -98,12 +98,12 @@ export class InstallChartStore extends DockTabStore { export const installChartStore = new InstallChartStore(); -export function createInstallChartTab(chart: HelmChart, tabParams: Partial = {}) { +export function createInstallChartTab(chart: HelmChart, tabParams: SpecializedCreateDockTabDescriptor = {}) { const { name, repo, version } = chart; const tab = dockStore.createTab({ - kind: TabKind.INSTALL_CHART, title: `Helm Install: ${repo}/${name}`, - ...tabParams + ...tabParams, + kind: TabKind.INSTALL_CHART, }, false); installChartStore.setData(tab.id, { diff --git a/src/renderer/components/dock/install-chart.tsx b/src/renderer/components/dock/install-chart.tsx index 69e0313eec..cc85f478a1 100644 --- a/src/renderer/components/dock/install-chart.tsx +++ b/src/renderer/components/dock/install-chart.tsx @@ -24,7 +24,7 @@ import "./install-chart.scss"; import React, { Component } from "react"; import { observable, makeObservable } from "mobx"; import { observer } from "mobx-react"; -import { dockStore, IDockTab } from "./dock.store"; +import { dockStore, DockTabDescriptor } from "./dock.store"; import { InfoPanel } from "./info-panel"; import { Badge } from "../badge"; import { NamespaceSelect } from "../+namespaces/namespace-select"; @@ -42,7 +42,7 @@ import { navigate } from "../../navigation"; import { releaseURL } from "../../../common/routes"; interface Props { - tab: IDockTab; + tab: DockTabDescriptor; } @observer diff --git a/src/renderer/components/dock/log-tab.store.ts b/src/renderer/components/dock/log-tab.store.ts index 560cea5cff..332d88af1f 100644 --- a/src/renderer/components/dock/log-tab.store.ts +++ b/src/renderer/components/dock/log-tab.store.ts @@ -26,7 +26,7 @@ import { podsStore } from "../+workloads-pods/pods.store"; import { IPodContainer, Pod } from "../../api/endpoints"; import type { WorkloadKubeObject } from "../../api/workload-kube-object"; import { DockTabStore } from "./dock-tab.store"; -import { dockStore, IDockTab, TabKind } from "./dock.store"; +import { dockStore, SpecializedCreateDockTabDescriptor, TabKind } from "./dock.store"; export interface LogTabData { pods: Pod[]; @@ -90,10 +90,10 @@ export class LogTabStore extends DockTabStore { dockStore.renameTab(tabId, `Pod ${selectedPod.metadata.name}`); } - private createDockTab(tabParams: Partial) { + private createDockTab(tabParams: SpecializedCreateDockTabDescriptor) { dockStore.createTab({ + ...tabParams, kind: TabKind.POD_LOGS, - ...tabParams }, false); } diff --git a/src/renderer/components/dock/logs.tsx b/src/renderer/components/dock/logs.tsx index 4649d28eeb..fe074c01db 100644 --- a/src/renderer/components/dock/logs.tsx +++ b/src/renderer/components/dock/logs.tsx @@ -25,7 +25,7 @@ import { disposeOnUnmount, observer } from "mobx-react"; import { searchStore } from "../../../common/search-store"; import { boundMethod } from "../../utils"; -import type { IDockTab } from "./dock.store"; +import type { DockTabDescriptor } from "./dock.store"; import { InfoPanel } from "./info-panel"; import { LogResourceSelector } from "./log-resource-selector"; import { LogList } from "./log-list"; @@ -36,7 +36,7 @@ import { LogTabData, logTabStore } from "./log-tab.store"; interface Props { className?: string - tab: IDockTab + tab: DockTabDescriptor } @observer diff --git a/src/renderer/components/dock/terminal-window.tsx b/src/renderer/components/dock/terminal-window.tsx index d5b4d4a53b..cb89c91a30 100644 --- a/src/renderer/components/dock/terminal-window.tsx +++ b/src/renderer/components/dock/terminal-window.tsx @@ -25,14 +25,14 @@ import React from "react"; import { reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { cssNames } from "../../utils"; -import type { IDockTab } from "./dock.store"; +import type { DockTabDescriptor } from "./dock.store"; import type { Terminal } from "./terminal"; import { terminalStore } from "./terminal.store"; import { ThemeStore } from "../../theme.store"; interface Props { className?: string; - tab: IDockTab; + tab: DockTabDescriptor; } @observer diff --git a/src/renderer/components/dock/terminal.store.ts b/src/renderer/components/dock/terminal.store.ts index 7f0396336e..45fd2d1a13 100644 --- a/src/renderer/components/dock/terminal.store.ts +++ b/src/renderer/components/dock/terminal.store.ts @@ -23,18 +23,18 @@ import { autorun, observable } from "mobx"; import { autoBind } from "../../utils"; import { Terminal } from "./terminal"; import { TerminalApi } from "../../api/terminal-api"; -import { dockStore, IDockTab, TabId, TabKind } from "./dock.store"; +import { dockStore, DockTabDescriptor, SpecializedCreateDockTabDescriptor, TabId, TabKind } from "./dock.store"; import { WebSocketApiState } from "../../api/websocket-api"; -export interface ITerminalTab extends IDockTab { +export interface ITerminalTab extends DockTabDescriptor { node?: string; // activate node shell mode } -export function createTerminalTab(tabParams: Partial = {}) { +export function createTerminalTab(tabParams: SpecializedCreateDockTabDescriptor = {}) { return dockStore.createTab({ - kind: TabKind.TERMINAL, title: `Terminal`, - ...tabParams + ...tabParams, + kind: TabKind.TERMINAL, }); } diff --git a/src/renderer/components/dock/upgrade-chart.store.ts b/src/renderer/components/dock/upgrade-chart.store.ts index 5aafdfb0ea..061f231286 100644 --- a/src/renderer/components/dock/upgrade-chart.store.ts +++ b/src/renderer/components/dock/upgrade-chart.store.ts @@ -20,7 +20,7 @@ */ import { action, autorun, computed, IReactionDisposer, reaction, makeObservable } from "mobx"; -import { dockStore, IDockTab, TabId, TabKind } from "./dock.store"; +import { dockStore, DockTabDescriptor, SpecializedCreateDockTabDescriptor, TabId, TabKind } from "./dock.store"; import { DockTabStore } from "./dock-tab.store"; import { getReleaseValues, HelmRelease } from "../../api/endpoints/helm-releases.api"; import { releaseStore } from "../+apps-releases/release.store"; @@ -120,14 +120,14 @@ export class UpgradeChartStore extends DockTabStore { this.values.setData(tabId, values); } - getTabByRelease(releaseName: string): IDockTab { + getTabByRelease(releaseName: string): DockTabDescriptor { return dockStore.getTabById(this.releaseNameReverseLookup.get(releaseName)); } } export const upgradeChartStore = new UpgradeChartStore(); -export function createUpgradeChartTab(release: HelmRelease, tabParams: Partial = {}) { +export function createUpgradeChartTab(release: HelmRelease, tabParams: SpecializedCreateDockTabDescriptor = {}) { let tab = upgradeChartStore.getTabByRelease(release.getName()); if (tab) { @@ -137,9 +137,9 @@ export function createUpgradeChartTab(release: HelmRelease, tabParams: Partial