From e8babbbf4ab53ff7aeab6a1b47744c52984d3ffa Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 14 May 2021 13:34:13 -0400 Subject: [PATCH 1/5] Move all RouteParam's and URL builders to src/common - Prevents some circular dependencies - Allowed main to use them as needed Signed-off-by: Sebastian Malton --- .../__tests__/command-palette.tests.ts | 2 +- .../catalog-entities/kubernetes-cluster.ts | 4 +- .../routes/add-cluster.ts} | 2 +- .../apps.route.ts => common/routes/apps.ts} | 2 +- .../routes/catalog.ts} | 2 +- .../routes/cluster-view.ts} | 6 +- .../routes/cluster.ts} | 2 +- .../routes/config-maps.ts} | 6 +- .../routes/config.ts} | 16 ++--- .../crd.route.ts => common/routes/crd.ts} | 10 ++-- .../routes/endpoints.ts} | 2 +- .../routes/entity-settings.ts} | 2 +- .../routes/events.ts} | 2 +- .../routes/extensions.ts} | 2 +- .../routes/helm-charts.ts} | 4 +- .../hpa.route.ts => common/routes/hpa.ts} | 2 +- .../+cluster => common/routes}/index.ts | 35 ++++++++++- .../routes/ingresses.ts} | 2 +- .../routes/limit-ranges.ts} | 2 +- .../routes/namespaces.ts} | 6 +- .../routes/network-policies.ts} | 6 +- .../routes/network.ts} | 14 ++--- .../nodes.route.ts => common/routes/nodes.ts} | 6 +- .../routes/pod-disruption-budgets.ts} | 6 +- src/common/routes/preferences.ts | 29 +++++++++ .../routes/releases.ts} | 8 +-- .../routes/resource-quotas.ts} | 6 +- .../routes/secrets.ts} | 4 +- .../routes/services.ts} | 6 +- .../routes/storage-classes.ts} | 7 +-- .../routes/storage.ts} | 10 ++-- .../routes/user-management.ts} | 16 ++--- .../routes/volume-claims.ts} | 6 +- .../routes/volumes.ts} | 6 +- .../routes/welcome.ts} | 2 +- .../routes/workloads.ts} | 38 ++++++------ src/common/utils/buildUrl.ts | 4 +- src/extensions/npm/extensions/package.json | 2 +- src/extensions/renderer-api/navigation.ts | 2 +- src/main/menu.ts | 6 +- src/main/tray.ts | 2 +- src/renderer/api/endpoints/crd.api.ts | 2 +- .../components/+add-cluster/add-cluster.tsx | 4 +- src/renderer/components/+add-cluster/index.ts | 1 - .../+apps-helm-charts/helm-charts.tsx | 2 +- .../components/+apps-helm-charts/index.ts | 1 - .../components/+apps-releases/index.ts | 1 - .../components/+apps-releases/releases.tsx | 4 +- src/renderer/components/+apps/apps.command.ts | 3 +- src/renderer/components/+apps/apps.tsx | 5 +- src/renderer/components/+apps/index.ts | 1 - src/renderer/components/+catalog/catalog.tsx | 2 +- src/renderer/components/+catalog/index.tsx | 1 - .../components/+config-autoscalers/hpa.tsx | 2 +- .../components/+config-autoscalers/index.ts | 1 - .../components/+config-limit-ranges/index.ts | 1 - .../+config-limit-ranges/limit-ranges.tsx | 2 +- .../components/+config-maps/config-maps.tsx | 4 +- src/renderer/components/+config-maps/index.ts | 1 - .../+config-pod-disruption-budgets/index.ts | 1 - .../+config-resource-quotas/index.ts | 1 - .../resource-quotas.tsx | 4 +- .../components/+config-secrets/index.ts | 2 - .../components/+config-secrets/secrets.tsx | 4 +- .../components/+config/config.command.ts | 19 +++--- src/renderer/components/+config/config.tsx | 53 ++++++++-------- src/renderer/components/+config/index.ts | 1 - .../+custom-resources/crd-resources.tsx | 4 +- .../+custom-resources/custom-resources.tsx | 2 +- .../components/+custom-resources/index.ts | 1 - .../+entity-settings/entity-settings.tsx | 2 +- .../components/+entity-settings/index.ts | 1 - src/renderer/components/+events/events.tsx | 2 +- src/renderer/components/+events/index.ts | 1 - src/renderer/components/+extensions/index.ts | 1 - src/renderer/components/+namespaces/index.ts | 1 - .../components/+namespaces/namespaces.tsx | 4 +- .../+network-endpoints/endpoints.tsx | 2 +- .../components/+network-endpoints/index.ts | 1 - .../components/+network-ingresses/index.ts | 1 - .../+network-ingresses/ingresses.tsx | 2 +- .../components/+network-policies/index.ts | 1 - .../+network-policies/network-policies.tsx | 4 +- .../components/+network-services/index.ts | 1 - .../components/+network-services/services.tsx | 4 +- src/renderer/components/+network/index.ts | 1 - .../components/+network/network.command.ts | 13 ++-- src/renderer/components/+network/network.tsx | 37 ++++++------ src/renderer/components/+nodes/index.ts | 1 - .../components/+nodes/node.command.ts | 2 +- src/renderer/components/+nodes/nodes.tsx | 4 +- .../components/+preferences/index.tsx | 1 - .../+preferences/preferences.route.ts | 38 ------------ .../components/+storage-classes/index.ts | 2 - .../+storage-classes/storage-classes.tsx | 4 +- .../+storage-volume-claims/index.ts | 2 - .../+storage-volume-claims/volume-claims.tsx | 4 +- .../components/+storage-volumes/index.ts | 1 - .../components/+storage-volumes/volumes.tsx | 4 +- src/renderer/components/+storage/index.ts | 1 - src/renderer/components/+storage/storage.tsx | 19 +++--- .../role-bindings.tsx | 4 +- .../+user-management-roles/roles.tsx | 4 +- .../service-accounts.tsx | 4 +- .../components/+user-management/index.ts | 1 - .../+user-management/user-management.tsx | 18 +++--- src/renderer/components/+welcome/index.ts | 1 - src/renderer/components/+welcome/welcome.tsx | 3 +- .../+workloads-cronjobs/cronjobs.tsx | 4 +- .../+workloads-daemonsets/daemonsets.tsx | 4 +- .../+workloads-deployments/deployments.tsx | 4 +- .../components/+workloads-jobs/jobs.tsx | 4 +- .../+workloads-overview/overview-statuses.tsx | 3 +- .../+workloads-overview/overview.tsx | 4 +- .../components/+workloads-pods/pods.tsx | 4 +- .../+workloads-replicasets/replicasets.tsx | 4 +- .../+workloads-statefulsets/statefulsets.tsx | 4 +- src/renderer/components/+workloads/index.ts | 1 - .../+workloads/workloads.command.ts | 14 ++--- .../components/+workloads/workloads.tsx | 52 ++++++++-------- src/renderer/components/app.tsx | 43 +++++++------ .../components/cluster-manager/bottom-bar.tsx | 2 +- .../cluster-manager/cluster-manager.tsx | 30 +++++----- .../cluster-manager/cluster-view.tsx | 5 +- .../cluster-settings.command.ts | 2 +- .../command-palette/command-dialog.tsx | 2 +- .../components/dock/install-chart.tsx | 2 +- src/renderer/components/layout/sidebar.tsx | 60 ++++++++----------- src/renderer/ipc/index.tsx | 2 +- src/renderer/navigation/helpers.ts | 4 +- src/renderer/protocol-handler/app-handlers.ts | 28 ++++----- 131 files changed, 434 insertions(+), 472 deletions(-) rename src/{renderer/components/+add-cluster/add-cluster.route.ts => common/routes/add-cluster.ts} (95%) rename src/{renderer/components/+apps/apps.route.ts => common/routes/apps.ts} (95%) rename src/{renderer/components/+catalog/catalog.route.ts => common/routes/catalog.ts} (95%) rename src/{renderer/components/cluster-manager/cluster-view.route.ts => common/routes/cluster-view.ts} (87%) rename src/{renderer/components/+cluster/cluster.route.ts => common/routes/cluster.ts} (95%) rename src/{renderer/components/+config-maps/config-maps.route.ts => common/routes/config-maps.ts} (86%) rename src/{renderer/components/+config/config.route.ts => common/routes/config.ts} (72%) rename src/{renderer/components/+custom-resources/crd.route.ts => common/routes/crd.ts} (83%) rename src/{renderer/components/+network-endpoints/endpoints.route.ts => common/routes/endpoints.ts} (95%) rename src/{renderer/components/+entity-settings/entity-settings.route.ts => common/routes/entity-settings.ts} (96%) rename src/{renderer/components/+events/events.route.ts => common/routes/events.ts} (95%) rename src/{renderer/components/+extensions/extensions.route.ts => common/routes/extensions.ts} (95%) rename src/{renderer/components/+apps-helm-charts/helm-charts.route.ts => common/routes/helm-charts.ts} (93%) rename src/{renderer/components/+config-autoscalers/hpa.route.ts => common/routes/hpa.ts} (95%) rename src/{renderer/components/+cluster => common/routes}/index.ts (53%) rename src/{renderer/components/+network-ingresses/ingresses.route.ts => common/routes/ingresses.ts} (95%) rename src/{renderer/components/+config-limit-ranges/limit-ranges.route.ts => common/routes/limit-ranges.ts} (95%) rename src/{renderer/components/+namespaces/namespaces.route.ts => common/routes/namespaces.ts} (86%) rename src/{renderer/components/+network-policies/network-policies.route.ts => common/routes/network-policies.ts} (85%) rename src/{renderer/components/+network/network.route.ts => common/routes/network.ts} (76%) rename src/{renderer/components/+nodes/nodes.route.ts => common/routes/nodes.ts} (88%) rename src/{renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.route.ts => common/routes/pod-disruption-budgets.ts} (86%) create mode 100644 src/common/routes/preferences.ts rename src/{renderer/components/+apps-releases/release.route.ts => common/routes/releases.ts} (85%) rename src/{renderer/components/+config-resource-quotas/resource-quotas.route.ts => common/routes/resource-quotas.ts} (86%) rename src/{renderer/components/+config-secrets/secrets.route.ts => common/routes/secrets.ts} (92%) rename src/{renderer/components/+network-services/services.route.ts => common/routes/services.ts} (87%) rename src/{renderer/components/+storage-classes/storage-classes.route.ts => common/routes/storage-classes.ts} (86%) rename src/{renderer/components/+storage/storage.route.ts => common/routes/storage.ts} (79%) rename src/{renderer/components/+user-management/user-management.route.ts => common/routes/user-management.ts} (76%) rename src/{renderer/components/+storage-volume-claims/volume-claims.route.ts => common/routes/volume-claims.ts} (86%) rename src/{renderer/components/+storage-volumes/volumes.route.ts => common/routes/volumes.ts} (87%) rename src/{renderer/components/+welcome/welcome.route.ts => common/routes/welcome.ts} (95%) rename src/{renderer/components/+workloads/workloads.route.ts => common/routes/workloads.ts} (66%) delete mode 100644 src/renderer/components/+preferences/preferences.route.ts diff --git a/integration/__tests__/command-palette.tests.ts b/integration/__tests__/command-palette.tests.ts index 03ef6e23ae81..14e95d12646e 100644 --- a/integration/__tests__/command-palette.tests.ts +++ b/integration/__tests__/command-palette.tests.ts @@ -40,7 +40,7 @@ describe("Lens command palette", () => { it("opens command dialog from menu", async () => { await app.electron.ipcRenderer.send("test-menu-item-click", "View", "Command Palette..."); - await app.client.waitUntilTextExists(".Select__option", "Preferences: Open"); + await app.client.waitUntilTextExists(".Select__option", "Hotbar: Switch"); await app.client.keys("Escape"); }); }); diff --git a/src/common/catalog-entities/kubernetes-cluster.ts b/src/common/catalog-entities/kubernetes-cluster.ts index 43fee50eaf12..ca78cba92c43 100644 --- a/src/common/catalog-entities/kubernetes-cluster.ts +++ b/src/common/catalog-entities/kubernetes-cluster.ts @@ -26,9 +26,9 @@ import { ClusterStore } from "../cluster-store"; import { requestMain } from "../ipc"; import { productName } from "../vars"; import { CatalogCategory, CatalogCategorySpec } from "../catalog"; +import { addClusterURL } from "../routes"; import { app } from "electron"; - export type KubernetesClusterPrometheusMetrics = { address?: { namespace: string; @@ -171,7 +171,7 @@ export class KubernetesClusterCategory extends CatalogCategory { icon: "text_snippet", title: "Add from kubeconfig", onClick: () => { - ctx.navigate("/add-cluster"); + ctx.navigate(addClusterURL()); } }); }); diff --git a/src/renderer/components/+add-cluster/add-cluster.route.ts b/src/common/routes/add-cluster.ts similarity index 95% rename from src/renderer/components/+add-cluster/add-cluster.route.ts rename to src/common/routes/add-cluster.ts index 88e4b2ab0155..93ac41f0bf9e 100644 --- a/src/renderer/components/+add-cluster/add-cluster.route.ts +++ b/src/common/routes/add-cluster.ts @@ -20,7 +20,7 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const addClusterRoute: RouteProps = { path: "/add-cluster" diff --git a/src/renderer/components/+apps/apps.route.ts b/src/common/routes/apps.ts similarity index 95% rename from src/renderer/components/+apps/apps.route.ts rename to src/common/routes/apps.ts index 9babe0ca455b..72a92616dcfc 100644 --- a/src/renderer/components/+apps/apps.route.ts +++ b/src/common/routes/apps.ts @@ -20,7 +20,7 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const appsRoute: RouteProps = { path: "/apps", diff --git a/src/renderer/components/+catalog/catalog.route.ts b/src/common/routes/catalog.ts similarity index 95% rename from src/renderer/components/+catalog/catalog.route.ts rename to src/common/routes/catalog.ts index b7bbe8c99323..2dee4b4e0773 100644 --- a/src/renderer/components/+catalog/catalog.route.ts +++ b/src/common/routes/catalog.ts @@ -20,7 +20,7 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export interface ICatalogViewRouteParam { group?: string; diff --git a/src/renderer/components/cluster-manager/cluster-view.route.ts b/src/common/routes/cluster-view.ts similarity index 87% rename from src/renderer/components/cluster-manager/cluster-view.route.ts rename to src/common/routes/cluster-view.ts index 5f7fde56d7fd..66b9c63d60d3 100644 --- a/src/renderer/components/cluster-manager/cluster-view.route.ts +++ b/src/common/routes/cluster-view.ts @@ -20,9 +20,9 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; -export interface IClusterViewRouteParams { +export interface ClusterViewRouteParams { clusterId: string; } @@ -31,4 +31,4 @@ export const clusterViewRoute: RouteProps = { path: "/cluster/:clusterId", }; -export const clusterViewURL = buildURL(clusterViewRoute.path); +export const clusterViewURL = buildURL(clusterViewRoute.path); diff --git a/src/renderer/components/+cluster/cluster.route.ts b/src/common/routes/cluster.ts similarity index 95% rename from src/renderer/components/+cluster/cluster.route.ts rename to src/common/routes/cluster.ts index 01ce68a4956b..3a39ccd22ac8 100644 --- a/src/renderer/components/+cluster/cluster.route.ts +++ b/src/common/routes/cluster.ts @@ -20,7 +20,7 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const clusterRoute: RouteProps = { path: "/cluster" diff --git a/src/renderer/components/+config-maps/config-maps.route.ts b/src/common/routes/config-maps.ts similarity index 86% rename from src/renderer/components/+config-maps/config-maps.route.ts rename to src/common/routes/config-maps.ts index fa9293d4b0b5..99aeaaf553c9 100644 --- a/src/renderer/components/+config-maps/config-maps.route.ts +++ b/src/common/routes/config-maps.ts @@ -20,13 +20,13 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const configMapsRoute: RouteProps = { path: "/configmaps" }; -export interface IConfigMapsRouteParams { +export interface ConfigMapsRouteParams { } -export const configMapsURL = buildURL(configMapsRoute.path); +export const configMapsURL = buildURL(configMapsRoute.path); diff --git a/src/renderer/components/+config/config.route.ts b/src/common/routes/config.ts similarity index 72% rename from src/renderer/components/+config/config.route.ts rename to src/common/routes/config.ts index 6e3cd5696e4f..7dca2906729d 100644 --- a/src/renderer/components/+config/config.route.ts +++ b/src/common/routes/config.ts @@ -20,13 +20,13 @@ */ 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"; -import { pdbRoute } from "../+config-pod-disruption-budgets"; -import { resourceQuotaRoute } from "../+config-resource-quotas"; -import { secretsRoute } from "../+config-secrets"; +import type { URLParams } from "../utils/buildUrl"; +import { configMapsRoute, configMapsURL } from "./config-maps"; +import { hpaRoute } from "./hpa"; +import { limitRangesRoute } from "./limit-ranges"; +import { pdbRoute } from "./pod-disruption-budgets"; +import { resourceQuotaRoute } from "./resource-quotas"; +import { secretsRoute } from "./secrets"; export const configRoute: RouteProps = { path: [ @@ -39,4 +39,4 @@ export const configRoute: RouteProps = { ].map(route => route.path.toString()) }; -export const configURL = (params?: IURLParams) => configMapsURL(params); +export const configURL = (params?: URLParams) => configMapsURL(params); diff --git a/src/renderer/components/+custom-resources/crd.route.ts b/src/common/routes/crd.ts similarity index 83% rename from src/renderer/components/+custom-resources/crd.route.ts rename to src/common/routes/crd.ts index 91042649e300..1a70fac8750d 100644 --- a/src/renderer/components/+custom-resources/crd.route.ts +++ b/src/common/routes/crd.ts @@ -20,7 +20,7 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const crdRoute: RouteProps = { path: "/crd" @@ -34,14 +34,14 @@ export const crdResourcesRoute: RouteProps = { path: `${crdRoute.path}/:group/:name` }; -export interface ICRDListQuery { +export interface CRDListQuery { groups?: string; } -export interface ICRDRouteParams { +export interface CRDRouteParams { group: string; name: string; } -export const crdURL = buildURL<{}, ICRDListQuery>(crdDefinitionsRoute.path); -export const crdResourcesURL = buildURL(crdResourcesRoute.path); +export const crdURL = buildURL<{}, CRDListQuery>(crdDefinitionsRoute.path); +export const crdResourcesURL = buildURL(crdResourcesRoute.path); diff --git a/src/renderer/components/+network-endpoints/endpoints.route.ts b/src/common/routes/endpoints.ts similarity index 95% rename from src/renderer/components/+network-endpoints/endpoints.route.ts rename to src/common/routes/endpoints.ts index 18aaf10c74c5..db09de66a04f 100644 --- a/src/renderer/components/+network-endpoints/endpoints.route.ts +++ b/src/common/routes/endpoints.ts @@ -20,7 +20,7 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const endpointRoute: RouteProps = { path: "/endpoints" diff --git a/src/renderer/components/+entity-settings/entity-settings.route.ts b/src/common/routes/entity-settings.ts similarity index 96% rename from src/renderer/components/+entity-settings/entity-settings.route.ts rename to src/common/routes/entity-settings.ts index 20091c85e061..8368d81b7ed2 100644 --- a/src/renderer/components/+entity-settings/entity-settings.route.ts +++ b/src/common/routes/entity-settings.ts @@ -20,7 +20,7 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export interface EntitySettingsRouteParams { entityId: string; diff --git a/src/renderer/components/+events/events.route.ts b/src/common/routes/events.ts similarity index 95% rename from src/renderer/components/+events/events.route.ts rename to src/common/routes/events.ts index 2760b7ef0b94..73995ce6b031 100644 --- a/src/renderer/components/+events/events.route.ts +++ b/src/common/routes/events.ts @@ -20,7 +20,7 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const eventRoute: RouteProps = { path: "/events" diff --git a/src/renderer/components/+extensions/extensions.route.ts b/src/common/routes/extensions.ts similarity index 95% rename from src/renderer/components/+extensions/extensions.route.ts rename to src/common/routes/extensions.ts index e8552eac105e..6ef25d11c687 100644 --- a/src/renderer/components/+extensions/extensions.route.ts +++ b/src/common/routes/extensions.ts @@ -20,7 +20,7 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const extensionsRoute: RouteProps = { path: "/extensions" diff --git a/src/renderer/components/+apps-helm-charts/helm-charts.route.ts b/src/common/routes/helm-charts.ts similarity index 93% rename from src/renderer/components/+apps-helm-charts/helm-charts.route.ts rename to src/common/routes/helm-charts.ts index 55a19eb826a2..7689a50a17b9 100644 --- a/src/renderer/components/+apps-helm-charts/helm-charts.route.ts +++ b/src/common/routes/helm-charts.ts @@ -20,8 +20,8 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; -import { appsRoute } from "../+apps/apps.route"; +import { buildURL } from "../utils/buildUrl"; +import { appsRoute } from "./apps"; export const helmChartsRoute: RouteProps = { path: `${appsRoute.path}/charts/:repo?/:chartName?` diff --git a/src/renderer/components/+config-autoscalers/hpa.route.ts b/src/common/routes/hpa.ts similarity index 95% rename from src/renderer/components/+config-autoscalers/hpa.route.ts rename to src/common/routes/hpa.ts index 59a6945f894e..977aebb657b5 100644 --- a/src/renderer/components/+config-autoscalers/hpa.route.ts +++ b/src/common/routes/hpa.ts @@ -20,7 +20,7 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const hpaRoute: RouteProps = { path: "/hpa" diff --git a/src/renderer/components/+cluster/index.ts b/src/common/routes/index.ts similarity index 53% rename from src/renderer/components/+cluster/index.ts rename to src/common/routes/index.ts index 34cc79e0f6a0..6cdd81e2b4c8 100644 --- a/src/renderer/components/+cluster/index.ts +++ b/src/common/routes/index.ts @@ -19,5 +19,36 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./cluster.route"; - +export * from "./add-cluster"; +export * from "./apps"; +export * from "./catalog"; +export * from "./cluster-view"; +export * from "./cluster"; +export * from "./config-maps"; +export * from "./config"; +export * from "./crd"; +export * from "./endpoints"; +export * from "./entity-settings"; +export * from "./events"; +export * from "./extensions"; +export * from "./helm-charts"; +export * from "./hpa"; +export * from "./ingresses"; +export * from "./limit-ranges"; +export * from "./namespaces"; +export * from "./network-policies"; +export * from "./network"; +export * from "./nodes"; +export * from "./pod-disruption-budgets"; +export * from "./preferences"; +export * from "./releases"; +export * from "./resource-quotas"; +export * from "./secrets"; +export * from "./services"; +export * from "./storage-classes"; +export * from "./storage"; +export * from "./user-management"; +export * from "./volume-claims"; +export * from "./volumes"; +export * from "./welcome"; +export * from "./workloads"; diff --git a/src/renderer/components/+network-ingresses/ingresses.route.ts b/src/common/routes/ingresses.ts similarity index 95% rename from src/renderer/components/+network-ingresses/ingresses.route.ts rename to src/common/routes/ingresses.ts index 29a8ed6ada5a..66c37774d5a1 100644 --- a/src/renderer/components/+network-ingresses/ingresses.route.ts +++ b/src/common/routes/ingresses.ts @@ -20,7 +20,7 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const ingressRoute: RouteProps = { path: "/ingresses" diff --git a/src/renderer/components/+config-limit-ranges/limit-ranges.route.ts b/src/common/routes/limit-ranges.ts similarity index 95% rename from src/renderer/components/+config-limit-ranges/limit-ranges.route.ts rename to src/common/routes/limit-ranges.ts index af3bf2708971..02b9258c6780 100644 --- a/src/renderer/components/+config-limit-ranges/limit-ranges.route.ts +++ b/src/common/routes/limit-ranges.ts @@ -20,7 +20,7 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const limitRangesRoute: RouteProps = { path: "/limitranges" diff --git a/src/renderer/components/+namespaces/namespaces.route.ts b/src/common/routes/namespaces.ts similarity index 86% rename from src/renderer/components/+namespaces/namespaces.route.ts rename to src/common/routes/namespaces.ts index 6419f2f72c22..4a2395064862 100644 --- a/src/renderer/components/+namespaces/namespaces.route.ts +++ b/src/common/routes/namespaces.ts @@ -20,13 +20,13 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const namespacesRoute: RouteProps = { path: "/namespaces" }; -export interface INamespacesRouteParams { +export interface NamespacesRouteParams { } -export const namespacesURL = buildURL(namespacesRoute.path); +export const namespacesURL = buildURL(namespacesRoute.path); diff --git a/src/renderer/components/+network-policies/network-policies.route.ts b/src/common/routes/network-policies.ts similarity index 85% rename from src/renderer/components/+network-policies/network-policies.route.ts rename to src/common/routes/network-policies.ts index 3f905939badd..b49094a4184c 100644 --- a/src/renderer/components/+network-policies/network-policies.route.ts +++ b/src/common/routes/network-policies.ts @@ -20,13 +20,13 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const networkPoliciesRoute: RouteProps = { path: "/network-policies" }; -export interface INetworkPoliciesRouteParams { +export interface NetworkPoliciesRouteParams { } -export const networkPoliciesURL = buildURL(networkPoliciesRoute.path); +export const networkPoliciesURL = buildURL(networkPoliciesRoute.path); diff --git a/src/renderer/components/+network/network.route.ts b/src/common/routes/network.ts similarity index 76% rename from src/renderer/components/+network/network.route.ts rename to src/common/routes/network.ts index a827461f8f64..17b51e200a81 100644 --- a/src/renderer/components/+network/network.route.ts +++ b/src/common/routes/network.ts @@ -20,19 +20,19 @@ */ 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 type { IURLParams } from "../../../common/utils/buildUrl"; +import type { URLParams } from "../utils/buildUrl"; +import { endpointRoute } from "./endpoints"; +import { ingressRoute } from "./ingresses"; +import { networkPoliciesRoute } from "./network-policies"; +import { servicesRoute, servicesURL } from "./services"; export const networkRoute: RouteProps = { path: [ servicesRoute, endpointRoute, ingressRoute, - networkPoliciesRoute + networkPoliciesRoute, ].map(route => route.path.toString()) }; -export const networkURL = (params?: IURLParams) => servicesURL(params); +export const networkURL = (params?: URLParams) => servicesURL(params); diff --git a/src/renderer/components/+nodes/nodes.route.ts b/src/common/routes/nodes.ts similarity index 88% rename from src/renderer/components/+nodes/nodes.route.ts rename to src/common/routes/nodes.ts index dd9fc5a1d4db..bfb6d8ea003f 100644 --- a/src/renderer/components/+nodes/nodes.route.ts +++ b/src/common/routes/nodes.ts @@ -20,13 +20,13 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const nodesRoute: RouteProps = { path: "/nodes" }; -export interface INodesRouteParams { +export interface NodesRouteParams { } -export const nodesURL = buildURL(nodesRoute.path); +export const nodesURL = buildURL(nodesRoute.path); diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.route.ts b/src/common/routes/pod-disruption-budgets.ts similarity index 86% rename from src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.route.ts rename to src/common/routes/pod-disruption-budgets.ts index a8b8efb65fc6..985752746adc 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.route.ts +++ b/src/common/routes/pod-disruption-budgets.ts @@ -20,13 +20,13 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const pdbRoute: RouteProps = { path: "/poddisruptionbudgets" }; -export interface IPodDisruptionBudgetsRouteParams { +export interface PodDisruptionBudgetsRouteParams { } -export const pdbURL = buildURL(pdbRoute.path); +export const pdbURL = buildURL(pdbRoute.path); diff --git a/src/common/routes/preferences.ts b/src/common/routes/preferences.ts new file mode 100644 index 000000000000..45fd3074c8a1 --- /dev/null +++ b/src/common/routes/preferences.ts @@ -0,0 +1,29 @@ +/** + * 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 { RouteProps } from "react-router"; +import { buildURL } from "../utils/buildUrl"; + +export const preferencesRoute: RouteProps = { + path: "/preferences" +}; + +export const preferencesURL = buildURL(preferencesRoute.path); diff --git a/src/renderer/components/+apps-releases/release.route.ts b/src/common/routes/releases.ts similarity index 85% rename from src/renderer/components/+apps-releases/release.route.ts rename to src/common/routes/releases.ts index 6a2c5d38506b..2984bfd24587 100644 --- a/src/renderer/components/+apps-releases/release.route.ts +++ b/src/common/routes/releases.ts @@ -20,16 +20,16 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; -import { appsRoute } from "../+apps/apps.route"; +import { buildURL } from "../utils/buildUrl"; +import { appsRoute } from "./apps"; export const releaseRoute: RouteProps = { path: `${appsRoute.path}/releases/:namespace?/:name?` }; -export interface IReleaseRouteParams { +export interface ReleaseRouteParams { name?: string; namespace?: string; } -export const releaseURL = buildURL(releaseRoute.path); +export const releaseURL = buildURL(releaseRoute.path); diff --git a/src/renderer/components/+config-resource-quotas/resource-quotas.route.ts b/src/common/routes/resource-quotas.ts similarity index 86% rename from src/renderer/components/+config-resource-quotas/resource-quotas.route.ts rename to src/common/routes/resource-quotas.ts index dfbdab001dd7..7d8a5163a2ba 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quotas.route.ts +++ b/src/common/routes/resource-quotas.ts @@ -20,13 +20,13 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const resourceQuotaRoute: RouteProps = { path: "/resourcequotas" }; -export interface IResourceQuotaRouteParams { +export interface ResourceQuotaRouteParams { } -export const resourceQuotaURL = buildURL(resourceQuotaRoute.path); +export const resourceQuotaURL = buildURL(resourceQuotaRoute.path); diff --git a/src/renderer/components/+config-secrets/secrets.route.ts b/src/common/routes/secrets.ts similarity index 92% rename from src/renderer/components/+config-secrets/secrets.route.ts rename to src/common/routes/secrets.ts index 487b0198b040..10ee187f64b0 100644 --- a/src/renderer/components/+config-secrets/secrets.route.ts +++ b/src/common/routes/secrets.ts @@ -20,13 +20,13 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const secretsRoute: RouteProps = { path: "/secrets" }; -export interface ISecretsRouteParams { +export interface SecretsRouteParams { } export const secretsURL = buildURL(secretsRoute.path); diff --git a/src/renderer/components/+network-services/services.route.ts b/src/common/routes/services.ts similarity index 87% rename from src/renderer/components/+network-services/services.route.ts rename to src/common/routes/services.ts index a145e4b93cd4..b4e3acdad9d0 100644 --- a/src/renderer/components/+network-services/services.route.ts +++ b/src/common/routes/services.ts @@ -20,13 +20,13 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const servicesRoute: RouteProps = { path: "/services" }; -export interface IServicesRouteParams { +export interface ServicesRouteParams { } -export const servicesURL = buildURL(servicesRoute.path); +export const servicesURL = buildURL(servicesRoute.path); diff --git a/src/renderer/components/+storage-classes/storage-classes.route.ts b/src/common/routes/storage-classes.ts similarity index 86% rename from src/renderer/components/+storage-classes/storage-classes.route.ts rename to src/common/routes/storage-classes.ts index 75f25c2b5f3d..1a0128cbf8de 100644 --- a/src/renderer/components/+storage-classes/storage-classes.route.ts +++ b/src/common/routes/storage-classes.ts @@ -20,14 +20,13 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const storageClassesRoute: RouteProps = { path: "/storage-classes" }; -export interface IStorageClassesRouteParams { +export interface StorageClassesRouteParams { } -export const storageClassesURL = buildURL(storageClassesRoute.path); - +export const storageClassesURL = buildURL(storageClassesRoute.path); diff --git a/src/renderer/components/+storage/storage.route.ts b/src/common/routes/storage.ts similarity index 79% rename from src/renderer/components/+storage/storage.route.ts rename to src/common/routes/storage.ts index 6903a7637580..5de524795d4f 100644 --- a/src/renderer/components/+storage/storage.route.ts +++ b/src/common/routes/storage.ts @@ -20,10 +20,10 @@ */ import type { RouteProps } from "react-router"; -import { storageClassesRoute } from "../+storage-classes"; -import { volumeClaimsRoute, volumeClaimsURL } from "../+storage-volume-claims"; -import { volumesRoute } from "../+storage-volumes"; -import type { IURLParams } from "../../../common/utils/buildUrl"; +import type { URLParams } from "../utils/buildUrl"; +import { storageClassesRoute } from "./storage-classes"; +import { volumeClaimsRoute, volumeClaimsURL } from "./volume-claims"; +import { volumesRoute } from "./volumes"; export const storageRoute: RouteProps = { path: [ @@ -33,4 +33,4 @@ export const storageRoute: RouteProps = { ].map(route => route.path.toString()) }; -export const storageURL = (params?: IURLParams) => volumeClaimsURL(params); +export const storageURL = (params?: URLParams) => volumeClaimsURL(params); diff --git a/src/renderer/components/+user-management/user-management.route.ts b/src/common/routes/user-management.ts similarity index 76% rename from src/renderer/components/+user-management/user-management.route.ts rename to src/common/routes/user-management.ts index f6e4def1e86c..28efff026c77 100644 --- a/src/renderer/components/+user-management/user-management.route.ts +++ b/src/common/routes/user-management.ts @@ -20,7 +20,7 @@ */ import type { RouteProps } from "react-router"; -import { buildURL, IURLParams } from "../../../common/utils/buildUrl"; +import { buildURL, URLParams } from "../utils/buildUrl"; // Routes export const serviceAccountsRoute: RouteProps = { @@ -46,18 +46,18 @@ export const usersManagementRoute: RouteProps = { }; // Route params -export interface IServiceAccountsRouteParams { +export interface ServiceAccountsRouteParams { } -export interface IRoleBindingsRouteParams { +export interface RoleBindingsRouteParams { } -export interface IRolesRouteParams { +export interface RolesRouteParams { } // URL-builders -export const usersManagementURL = (params?: IURLParams) => serviceAccountsURL(params); -export const serviceAccountsURL = buildURL(serviceAccountsRoute.path); -export const roleBindingsURL = buildURL(roleBindingsRoute.path); -export const rolesURL = buildURL(rolesRoute.path); +export const usersManagementURL = (params?: URLParams) => serviceAccountsURL(params); +export const serviceAccountsURL = buildURL(serviceAccountsRoute.path); +export const roleBindingsURL = buildURL(roleBindingsRoute.path); +export const rolesURL = buildURL(rolesRoute.path); export const podSecurityPoliciesURL = buildURL(podSecurityPoliciesRoute.path); diff --git a/src/renderer/components/+storage-volume-claims/volume-claims.route.ts b/src/common/routes/volume-claims.ts similarity index 86% rename from src/renderer/components/+storage-volume-claims/volume-claims.route.ts rename to src/common/routes/volume-claims.ts index 2d22b6ed32eb..42171328df3e 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claims.route.ts +++ b/src/common/routes/volume-claims.ts @@ -20,13 +20,13 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const volumeClaimsRoute: RouteProps = { path: "/persistent-volume-claims" }; -export interface IVolumeClaimsRouteParams { +export interface VolumeClaimsRouteParams { } -export const volumeClaimsURL = buildURL(volumeClaimsRoute.path); +export const volumeClaimsURL = buildURL(volumeClaimsRoute.path); diff --git a/src/renderer/components/+storage-volumes/volumes.route.ts b/src/common/routes/volumes.ts similarity index 87% rename from src/renderer/components/+storage-volumes/volumes.route.ts rename to src/common/routes/volumes.ts index 822e2b738f2b..c5a969e98804 100644 --- a/src/renderer/components/+storage-volumes/volumes.route.ts +++ b/src/common/routes/volumes.ts @@ -20,13 +20,13 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const volumesRoute: RouteProps = { path: "/persistent-volumes" }; -export interface IVolumesRouteParams { +export interface VolumesRouteParams { } -export const volumesURL = buildURL(volumesRoute.path); +export const volumesURL = buildURL(volumesRoute.path); diff --git a/src/renderer/components/+welcome/welcome.route.ts b/src/common/routes/welcome.ts similarity index 95% rename from src/renderer/components/+welcome/welcome.route.ts rename to src/common/routes/welcome.ts index b4a1fc24e225..dd854d11a1d2 100644 --- a/src/renderer/components/+welcome/welcome.route.ts +++ b/src/common/routes/welcome.ts @@ -20,7 +20,7 @@ */ import type { RouteProps } from "react-router"; -import { buildURL } from "../../../common/utils/buildUrl"; +import { buildURL } from "../utils/buildUrl"; export const welcomeRoute: RouteProps = { path: "/welcome" diff --git a/src/renderer/components/+workloads/workloads.route.ts b/src/common/routes/workloads.ts similarity index 66% rename from src/renderer/components/+workloads/workloads.route.ts rename to src/common/routes/workloads.ts index baef1928b7f3..94a9378d024f 100644 --- a/src/renderer/components/+workloads/workloads.route.ts +++ b/src/common/routes/workloads.ts @@ -20,8 +20,8 @@ */ import type { RouteProps } from "react-router"; -import { buildURL, IURLParams } from "../../../common/utils/buildUrl"; -import type { KubeResource } from "../../../common/rbac"; +import { buildURL, URLParams } from "../utils/buildUrl"; +import type { KubeResource } from "../rbac"; // Routes export const overviewRoute: RouteProps = { @@ -63,40 +63,40 @@ export const workloadsRoute: RouteProps = { }; // Route params -export interface IWorkloadsOverviewRouteParams { +export interface WorkloadsOverviewRouteParams { } -export interface IPodsRouteParams { +export interface PodsRouteParams { } -export interface IDeploymentsRouteParams { +export interface DeploymentsRouteParams { } -export interface IDaemonSetsRouteParams { +export interface DaemonSetsRouteParams { } -export interface IStatefulSetsRouteParams { +export interface StatefulSetsRouteParams { } -export interface IReplicaSetsRouteParams { +export interface ReplicaSetsRouteParams { } -export interface IJobsRouteParams { +export interface JobsRouteParams { } -export interface ICronJobsRouteParams { +export interface CronJobsRouteParams { } // URL-builders -export const workloadsURL = (params?: IURLParams) => overviewURL(params); -export const overviewURL = buildURL(overviewRoute.path); -export const podsURL = buildURL(podsRoute.path); -export const deploymentsURL = buildURL(deploymentsRoute.path); -export const daemonSetsURL = buildURL(daemonSetsRoute.path); -export const statefulSetsURL = buildURL(statefulSetsRoute.path); -export const replicaSetsURL = buildURL(replicaSetsRoute.path); -export const jobsURL = buildURL(jobsRoute.path); -export const cronJobsURL = buildURL(cronJobsRoute.path); +export const workloadsURL = (params?: URLParams) => overviewURL(params); +export const overviewURL = buildURL(overviewRoute.path); +export const podsURL = buildURL(podsRoute.path); +export const deploymentsURL = buildURL(deploymentsRoute.path); +export const daemonSetsURL = buildURL(daemonSetsRoute.path); +export const statefulSetsURL = buildURL(statefulSetsRoute.path); +export const replicaSetsURL = buildURL(replicaSetsRoute.path); +export const jobsURL = buildURL(jobsRoute.path); +export const cronJobsURL = buildURL(cronJobsRoute.path); export const workloadURL: Partial>> = { "pods": podsURL, diff --git a/src/common/utils/buildUrl.ts b/src/common/utils/buildUrl.ts index d373aa634dad..965a0be1bafa 100644 --- a/src/common/utils/buildUrl.ts +++ b/src/common/utils/buildUrl.ts @@ -21,7 +21,7 @@ import { compile } from "path-to-regexp"; -export interface IURLParams

{ +export interface URLParams

{ params?: P; query?: Q; fragment?: string; @@ -30,7 +30,7 @@ export interface IURLParams

{ export function buildURL

(path: string | any) { const pathBuilder = compile(String(path)); - return function ({ params, query, fragment }: IURLParams = {}): string { + return function ({ params, query, fragment }: URLParams = {}): string { const queryParams = query ? new URLSearchParams(Object.entries(query)).toString() : ""; const parts = [ pathBuilder(params), diff --git a/src/extensions/npm/extensions/package.json b/src/extensions/npm/extensions/package.json index 6857b12ddae3..3833ec905e9c 100644 --- a/src/extensions/npm/extensions/package.json +++ b/src/extensions/npm/extensions/package.json @@ -2,7 +2,7 @@ "name": "@k8slens/extensions", "productName": "OpenLens extensions", "description": "OpenLens - Open Source Kubernetes IDE: extensions", - "version": "0.0.0", + "version": "5.0.0-beta.5", "copyright": "© 2021 OpenLens Authors", "license": "MIT", "main": "dist/src/extensions/extension-api.js", diff --git a/src/extensions/renderer-api/navigation.ts b/src/extensions/renderer-api/navigation.ts index f8a338ac3fdf..7fc321f620ca 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 type { IURLParams } from "../../common/utils/buildUrl"; +export type { URLParams } from "../../common/utils/buildUrl"; // exporting to extensions-api version of helper without `isSystem` flag export function createPageParam(init: PageParamInit) { diff --git a/src/main/menu.ts b/src/main/menu.ts index 707047067965..7d80ce162e1b 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -23,16 +23,12 @@ import { app, BrowserWindow, dialog, ipcMain, IpcMainEvent, Menu, MenuItem, Menu import { autorun } from "mobx"; 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"; -import { welcomeURL } from "../renderer/components/+welcome/welcome.route"; -import { extensionsURL } from "../renderer/components/+extensions/extensions.route"; -import { catalogURL } from "../renderer/components/+catalog/catalog.route"; import { menuRegistry } from "../extensions/registries/menu-registry"; import logger from "./logger"; import { exitApp } from "./exit-app"; import { broadcastMessage } from "../common/ipc"; import * as packageJson from "../../package.json"; +import { preferencesURL, extensionsURL, addClusterURL, catalogURL, welcomeURL } from "../common/routes"; export type MenuTopId = "mac" | "file" | "edit" | "view" | "help"; diff --git a/src/main/tray.ts b/src/main/tray.ts index cca309082863..24b00d122a40 100644 --- a/src/main/tray.ts +++ b/src/main/tray.ts @@ -26,10 +26,10 @@ import { autorun } from "mobx"; import { showAbout } from "./menu"; import { checkForUpdates, isAutoUpdateEnabled } from "./app-updater"; 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"; import { exitApp } from "./exit-app"; +import { preferencesURL } from "../common/routes"; const TRAY_LOG_PREFIX = "[TRAY]"; diff --git a/src/renderer/api/endpoints/crd.api.ts b/src/renderer/api/endpoints/crd.api.ts index 5d2b657ce491..c50e83020540 100644 --- a/src/renderer/api/endpoints/crd.api.ts +++ b/src/renderer/api/endpoints/crd.api.ts @@ -20,8 +20,8 @@ */ import { KubeObject } from "../kube-object"; -import { crdResourcesURL } from "../../components/+custom-resources/crd.route"; import { KubeApi } from "../kube-api"; +import { crdResourcesURL } from "../../../common/routes"; type AdditionalPrinterColumnsCommon = { name: string; diff --git a/src/renderer/components/+add-cluster/add-cluster.tsx b/src/renderer/components/+add-cluster/add-cluster.tsx index 7f706e91982a..e211c2d6f143 100644 --- a/src/renderer/components/+add-cluster/add-cluster.tsx +++ b/src/renderer/components/+add-cluster/add-cluster.tsx @@ -36,9 +36,9 @@ import { ExecValidationNotFoundError } from "../../../common/custom-errors"; import { appEventBus } from "../../../common/event-bus"; import { PageLayout } from "../layout/page-layout"; import { docsUrl } from "../../../common/vars"; -import { catalogURL } from "../+catalog"; -import { preferencesURL } from "../+preferences"; import { Input } from "../input"; +import { catalogURL, preferencesURL } from "../../../common/routes"; + @observer export class AddCluster extends React.Component { @observable.ref kubeConfigLocal: KubeConfig; diff --git a/src/renderer/components/+add-cluster/index.ts b/src/renderer/components/+add-cluster/index.ts index f04c6a4bdcee..19498760603a 100644 --- a/src/renderer/components/+add-cluster/index.ts +++ b/src/renderer/components/+add-cluster/index.ts @@ -20,4 +20,3 @@ */ export * from "./add-cluster"; -export * from "./add-cluster.route"; diff --git a/src/renderer/components/+apps-helm-charts/helm-charts.tsx b/src/renderer/components/+apps-helm-charts/helm-charts.tsx index 5e451e33e59f..e3055162b72b 100644 --- a/src/renderer/components/+apps-helm-charts/helm-charts.tsx +++ b/src/renderer/components/+apps-helm-charts/helm-charts.tsx @@ -24,13 +24,13 @@ import "./helm-charts.scss"; import React, { Component } from "react"; 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 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"; import { SearchInputUrl } from "../input"; +import { helmChartsURL, IHelmChartsRouteParams } from "../../../common/routes"; enum columnId { name = "name", diff --git a/src/renderer/components/+apps-helm-charts/index.ts b/src/renderer/components/+apps-helm-charts/index.ts index 400313ea3210..74f1f4d66a70 100644 --- a/src/renderer/components/+apps-helm-charts/index.ts +++ b/src/renderer/components/+apps-helm-charts/index.ts @@ -20,4 +20,3 @@ */ export * from "./helm-charts"; -export * from "./helm-charts.route"; diff --git a/src/renderer/components/+apps-releases/index.ts b/src/renderer/components/+apps-releases/index.ts index 01eeefb05fc8..100df69e95ed 100644 --- a/src/renderer/components/+apps-releases/index.ts +++ b/src/renderer/components/+apps-releases/index.ts @@ -20,4 +20,3 @@ */ export * from "./releases"; -export * from "./release.route"; diff --git a/src/renderer/components/+apps-releases/releases.tsx b/src/renderer/components/+apps-releases/releases.tsx index bbf394455471..32fa7ada4342 100644 --- a/src/renderer/components/+apps-releases/releases.tsx +++ b/src/renderer/components/+apps-releases/releases.tsx @@ -26,7 +26,6 @@ import kebabCase from "lodash/kebabCase"; import { disposeOnUnmount, observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; import { releaseStore } from "./release.store"; -import { IReleaseRouteParams, releaseURL } from "./release.route"; import type { HelmRelease } from "../../api/endpoints/helm-releases.api"; import { ReleaseDetails } from "./release-details"; import { ReleaseRollbackDialog } from "./release-rollback-dialog"; @@ -34,6 +33,7 @@ import { navigation } from "../../navigation"; import { ItemListLayout } from "../item-object-list/item-list-layout"; import { HelmReleaseMenu } from "./release-menu"; import { secretsStore } from "../+config-secrets/secrets.store"; +import { ReleaseRouteParams, releaseURL } from "../../../common/routes"; enum columnId { name = "name", @@ -46,7 +46,7 @@ enum columnId { updated = "update" } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+apps/apps.command.ts b/src/renderer/components/+apps/apps.command.ts index 830fad12d4c2..eca0529bc4d3 100644 --- a/src/renderer/components/+apps/apps.command.ts +++ b/src/renderer/components/+apps/apps.command.ts @@ -21,8 +21,7 @@ import { navigate } from "../../navigation"; import { commandRegistry } from "../../../extensions/registries/command-registry"; -import { helmChartsURL } from "../+apps-helm-charts"; -import { releaseURL } from "../+apps-releases"; +import { helmChartsURL, releaseURL } from "../../../common/routes"; commandRegistry.add({ id: "cluster.viewHelmCharts", diff --git a/src/renderer/components/+apps/apps.tsx b/src/renderer/components/+apps/apps.tsx index 1e9ee3623af3..346dd255a4e3 100644 --- a/src/renderer/components/+apps/apps.tsx +++ b/src/renderer/components/+apps/apps.tsx @@ -22,9 +22,10 @@ import React from "react"; import { observer } from "mobx-react"; import { TabLayout, TabLayoutRoute } from "../layout/tab-layout"; -import { HelmCharts, helmChartsRoute, helmChartsURL } from "../+apps-helm-charts"; -import { HelmReleases, releaseRoute, releaseURL } from "../+apps-releases"; +import { HelmCharts } from "../+apps-helm-charts"; +import { HelmReleases } from "../+apps-releases"; import { namespaceUrlParam } from "../+namespaces/namespace.store"; +import { helmChartsURL, helmChartsRoute, releaseURL, releaseRoute } from "../../../common/routes"; @observer export class Apps extends React.Component { diff --git a/src/renderer/components/+apps/index.ts b/src/renderer/components/+apps/index.ts index 9cec263b5b81..f0fa78df0376 100644 --- a/src/renderer/components/+apps/index.ts +++ b/src/renderer/components/+apps/index.ts @@ -20,5 +20,4 @@ */ export * from "./apps"; -export * from "./apps.route"; export * from "./apps.command"; diff --git a/src/renderer/components/+catalog/catalog.tsx b/src/renderer/components/+catalog/catalog.tsx index 5211e034c27f..6cbda649df54 100644 --- a/src/renderer/components/+catalog/catalog.tsx +++ b/src/renderer/components/+catalog/catalog.tsx @@ -38,8 +38,8 @@ import { Tab, Tabs } from "../tabs"; import { catalogCategoryRegistry } from "../../../common/catalog"; import { CatalogAddButton } from "./catalog-add-button"; import type { RouteComponentProps } from "react-router"; -import type { ICatalogViewRouteParam } from "./catalog.route"; import { Notifications } from "../notifications"; +import type { ICatalogViewRouteParam } from "../../../common/routes"; enum sortBy { name = "name", diff --git a/src/renderer/components/+catalog/index.tsx b/src/renderer/components/+catalog/index.tsx index 0efe388e11b4..b658c981b262 100644 --- a/src/renderer/components/+catalog/index.tsx +++ b/src/renderer/components/+catalog/index.tsx @@ -19,5 +19,4 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./catalog.route"; export * from "./catalog"; diff --git a/src/renderer/components/+config-autoscalers/hpa.tsx b/src/renderer/components/+config-autoscalers/hpa.tsx index 54eb0b67a85e..d5c65216bed2 100644 --- a/src/renderer/components/+config-autoscalers/hpa.tsx +++ b/src/renderer/components/+config-autoscalers/hpa.tsx @@ -25,12 +25,12 @@ import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; import { KubeObjectListLayout } from "../kube-object"; -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"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { IHpaRouteParams } from "../../../common/routes"; enum columnId { name = "name", diff --git a/src/renderer/components/+config-autoscalers/index.ts b/src/renderer/components/+config-autoscalers/index.ts index ae6379ef6d0e..d7c91afc1567 100644 --- a/src/renderer/components/+config-autoscalers/index.ts +++ b/src/renderer/components/+config-autoscalers/index.ts @@ -21,4 +21,3 @@ export * from "./hpa"; export * from "./hpa-details"; -export * from "./hpa.route"; diff --git a/src/renderer/components/+config-limit-ranges/index.ts b/src/renderer/components/+config-limit-ranges/index.ts index bb96c6a3d392..5666fc77c4cd 100644 --- a/src/renderer/components/+config-limit-ranges/index.ts +++ b/src/renderer/components/+config-limit-ranges/index.ts @@ -20,5 +20,4 @@ */ export * from "./limit-ranges"; -export * from "./limit-ranges.route"; export * from "./limit-range-details"; diff --git a/src/renderer/components/+config-limit-ranges/limit-ranges.tsx b/src/renderer/components/+config-limit-ranges/limit-ranges.tsx index 6784e6f7d6cd..664654814c34 100644 --- a/src/renderer/components/+config-limit-ranges/limit-ranges.tsx +++ b/src/renderer/components/+config-limit-ranges/limit-ranges.tsx @@ -25,10 +25,10 @@ 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 type { LimitRangeRouteParams } from "./limit-ranges.route"; import React from "react"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { LimitRange } from "../../api/endpoints/limit-range.api"; +import type { LimitRangeRouteParams } from "../../../common/routes"; enum columnId { name = "name", diff --git a/src/renderer/components/+config-maps/config-maps.tsx b/src/renderer/components/+config-maps/config-maps.tsx index b1997fa792cc..fb757a69bf9c 100644 --- a/src/renderer/components/+config-maps/config-maps.tsx +++ b/src/renderer/components/+config-maps/config-maps.tsx @@ -27,8 +27,8 @@ import type { RouteComponentProps } from "react-router"; import { configMapsStore } from "./config-maps.store"; import type { ConfigMap } from "../../api/endpoints/configmap.api"; import { KubeObjectListLayout } from "../kube-object"; -import type { IConfigMapsRouteParams } from "./config-maps.route"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { ConfigMapsRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -37,7 +37,7 @@ enum columnId { age = "age", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+config-maps/index.ts b/src/renderer/components/+config-maps/index.ts index 537b8478f0f8..b4ca786263c7 100644 --- a/src/renderer/components/+config-maps/index.ts +++ b/src/renderer/components/+config-maps/index.ts @@ -19,6 +19,5 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./config-maps.route"; export * from "./config-maps"; export * from "./config-map-details"; diff --git a/src/renderer/components/+config-pod-disruption-budgets/index.ts b/src/renderer/components/+config-pod-disruption-budgets/index.ts index af54d9ca0463..d494a1fa36cd 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/index.ts +++ b/src/renderer/components/+config-pod-disruption-budgets/index.ts @@ -19,6 +19,5 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./pod-disruption-budgets.route"; export * from "./pod-disruption-budgets"; export * from "./pod-disruption-budgets-details"; diff --git a/src/renderer/components/+config-resource-quotas/index.ts b/src/renderer/components/+config-resource-quotas/index.ts index f4c10c854d9e..e6f87451e560 100644 --- a/src/renderer/components/+config-resource-quotas/index.ts +++ b/src/renderer/components/+config-resource-quotas/index.ts @@ -19,6 +19,5 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./resource-quotas.route"; export * from "./resource-quotas"; export * from "./resource-quota-details"; diff --git a/src/renderer/components/+config-resource-quotas/resource-quotas.tsx b/src/renderer/components/+config-resource-quotas/resource-quotas.tsx index 59be708d6f64..d1ce05c0985a 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quotas.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quotas.tsx @@ -28,8 +28,8 @@ import { KubeObjectListLayout } from "../kube-object"; import type { ResourceQuota } from "../../api/endpoints/resource-quota.api"; import { AddQuotaDialog } from "./add-quota-dialog"; import { resourceQuotaStore } from "./resource-quotas.store"; -import type { IResourceQuotaRouteParams } from "./resource-quotas.route"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { ResourceQuotaRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -37,7 +37,7 @@ enum columnId { age = "age" } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+config-secrets/index.ts b/src/renderer/components/+config-secrets/index.ts index 1cfc5d40628a..783c83455dda 100644 --- a/src/renderer/components/+config-secrets/index.ts +++ b/src/renderer/components/+config-secrets/index.ts @@ -19,7 +19,5 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./secrets.route"; export * from "./secrets"; export * from "./secret-details"; - diff --git a/src/renderer/components/+config-secrets/secrets.tsx b/src/renderer/components/+config-secrets/secrets.tsx index b87c6a51ed1a..d74305a499dd 100644 --- a/src/renderer/components/+config-secrets/secrets.tsx +++ b/src/renderer/components/+config-secrets/secrets.tsx @@ -26,11 +26,11 @@ import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; import type { Secret } from "../../api/endpoints"; import { AddSecretDialog } from "./add-secret-dialog"; -import type { ISecretsRouteParams } from "./secrets.route"; import { KubeObjectListLayout } from "../kube-object"; import { Badge } from "../badge"; import { secretsStore } from "./secrets.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { SecretsRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -41,7 +41,7 @@ enum columnId { age = "age", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+config/config.command.ts b/src/renderer/components/+config/config.command.ts index 21aeb82bd2c6..4e660fadeadd 100644 --- a/src/renderer/components/+config/config.command.ts +++ b/src/renderer/components/+config/config.command.ts @@ -21,51 +21,46 @@ import { navigate } from "../../navigation"; import { commandRegistry } from "../../../extensions/registries/command-registry"; -import { configMapsURL } from "../+config-maps"; -import { secretsURL } from "../+config-secrets"; -import { resourceQuotaURL } from "../+config-resource-quotas"; -import { limitRangeURL } from "../+config-limit-ranges"; -import { hpaURL } from "../+config-autoscalers"; -import { pdbURL } from "../+config-pod-disruption-budgets"; +import * as routes from "../../../common/routes"; commandRegistry.add({ id: "cluster.viewConfigMaps", title: "Cluster: View ConfigMaps", scope: "entity", - action: () => navigate(configMapsURL()) + action: () => navigate(routes.configMapsURL()) }); commandRegistry.add({ id: "cluster.viewSecrets", title: "Cluster: View Secrets", scope: "entity", - action: () => navigate(secretsURL()) + action: () => navigate(routes.secretsURL()) }); commandRegistry.add({ id: "cluster.viewResourceQuotas", title: "Cluster: View ResourceQuotas", scope: "entity", - action: () => navigate(resourceQuotaURL()) + action: () => navigate(routes.resourceQuotaURL()) }); commandRegistry.add({ id: "cluster.viewLimitRanges", title: "Cluster: View LimitRanges", scope: "entity", - action: () => navigate(limitRangeURL()) + action: () => navigate(routes.limitRangeURL()) }); commandRegistry.add({ id: "cluster.viewHorizontalPodAutoscalers", title: "Cluster: View HorizontalPodAutoscalers (HPA)", scope: "entity", - action: () => navigate(hpaURL()) + action: () => navigate(routes.hpaURL()) }); commandRegistry.add({ id: "cluster.viewPodDisruptionBudget", title: "Cluster: View PodDisruptionBudgets", scope: "entity", - action: () => navigate(pdbURL()) + action: () => navigate(routes.pdbURL()) }); diff --git a/src/renderer/components/+config/config.tsx b/src/renderer/components/+config/config.tsx index 95c97cb21722..c5948ed37fdb 100644 --- a/src/renderer/components/+config/config.tsx +++ b/src/renderer/components/+config/config.tsx @@ -22,76 +22,77 @@ import React from "react"; import { observer } from "mobx-react"; import { TabLayout, TabLayoutRoute } from "../layout/tab-layout"; -import { ConfigMaps, configMapsRoute, configMapsURL } from "../+config-maps"; -import { Secrets, secretsRoute, secretsURL } from "../+config-secrets"; +import { ConfigMaps } from "../+config-maps"; +import { Secrets } from "../+config-secrets"; import { namespaceUrlParam } from "../+namespaces/namespace.store"; -import { resourceQuotaRoute, ResourceQuotas, resourceQuotaURL } from "../+config-resource-quotas"; -import { pdbRoute, pdbURL, PodDisruptionBudgets } from "../+config-pod-disruption-budgets"; -import { HorizontalPodAutoscalers, hpaRoute, hpaURL } from "../+config-autoscalers"; +import { ResourceQuotas } from "../+config-resource-quotas"; +import { PodDisruptionBudgets } from "../+config-pod-disruption-budgets"; +import { HorizontalPodAutoscalers } from "../+config-autoscalers"; import { isAllowedResource } from "../../../common/rbac"; -import { LimitRanges, limitRangesRoute, limitRangeURL } from "../+config-limit-ranges"; +import { LimitRanges } from "../+config-limit-ranges"; +import * as routes from "../../../common/routes"; @observer export class Config extends React.Component { static get tabRoutes(): TabLayoutRoute[] { const query = namespaceUrlParam.toObjectParam(); - const routes: TabLayoutRoute[] = []; + const tabs: TabLayoutRoute[] = []; if (isAllowedResource("configmaps")) { - routes.push({ + tabs.push({ title: "ConfigMaps", component: ConfigMaps, - url: configMapsURL({ query }), - routePath: configMapsRoute.path.toString(), + url: routes.configMapsURL({ query }), + routePath: routes.configMapsRoute.path.toString(), }); } if (isAllowedResource("secrets")) { - routes.push({ + tabs.push({ title: "Secrets", component: Secrets, - url: secretsURL({ query }), - routePath: secretsRoute.path.toString(), + url: routes.secretsURL({ query }), + routePath: routes.secretsRoute.path.toString(), }); } if (isAllowedResource("resourcequotas")) { - routes.push({ + tabs.push({ title: "Resource Quotas", component: ResourceQuotas, - url: resourceQuotaURL({ query }), - routePath: resourceQuotaRoute.path.toString(), + url: routes.resourceQuotaURL({ query }), + routePath: routes.resourceQuotaRoute.path.toString(), }); } if (isAllowedResource("limitranges")) { - routes.push({ + tabs.push({ title: "Limit Ranges", component: LimitRanges, - url: limitRangeURL({ query }), - routePath: limitRangesRoute.path.toString(), + url: routes.limitRangeURL({ query }), + routePath: routes.limitRangesRoute.path.toString(), }); } if (isAllowedResource("horizontalpodautoscalers")) { - routes.push({ + tabs.push({ title: "HPA", component: HorizontalPodAutoscalers, - url: hpaURL({ query }), - routePath: hpaRoute.path.toString(), + url: routes.hpaURL({ query }), + routePath: routes.hpaRoute.path.toString(), }); } if (isAllowedResource("poddisruptionbudgets")) { - routes.push({ + tabs.push({ title: "Pod Disruption Budgets", component: PodDisruptionBudgets, - url: pdbURL({ query }), - routePath: pdbRoute.path.toString(), + url: routes.pdbURL({ query }), + routePath: routes.pdbRoute.path.toString(), }); } - return routes; + return tabs; } render() { diff --git a/src/renderer/components/+config/index.ts b/src/renderer/components/+config/index.ts index e8be23f1bc94..0d30c3f64a65 100644 --- a/src/renderer/components/+config/index.ts +++ b/src/renderer/components/+config/index.ts @@ -19,6 +19,5 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./config.route"; export * from "./config"; export * from "./config.command"; diff --git a/src/renderer/components/+custom-resources/crd-resources.tsx b/src/renderer/components/+custom-resources/crd-resources.tsx index a8128f42e1e3..b1de0c47753f 100644 --- a/src/renderer/components/+custom-resources/crd-resources.tsx +++ b/src/renderer/components/+custom-resources/crd-resources.tsx @@ -27,14 +27,14 @@ import { disposeOnUnmount, observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; import { KubeObjectListLayout } from "../kube-object"; import type { KubeObject } from "../../api/kube-object"; -import type { ICRDRouteParams } from "./crd.route"; import { autorun, computed } from "mobx"; import { crdStore } from "./crd.store"; import type { TableSortCallback } from "../table"; import { apiManager } from "../../api/api-manager"; import { parseJsonPath } from "../../utils/jsonPath"; +import type { CRDRouteParams } from "../../../common/routes"; -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } enum columnId { diff --git a/src/renderer/components/+custom-resources/custom-resources.tsx b/src/renderer/components/+custom-resources/custom-resources.tsx index 30d996985743..2d1a09aac95c 100644 --- a/src/renderer/components/+custom-resources/custom-resources.tsx +++ b/src/renderer/components/+custom-resources/custom-resources.tsx @@ -23,9 +23,9 @@ import React from "react"; import { observer } from "mobx-react"; import { Redirect, Route, Switch } from "react-router"; import { TabLayout, TabLayoutRoute } from "../layout/tab-layout"; -import { crdDefinitionsRoute, crdResourcesRoute, crdURL } from "./crd.route"; import { CrdList } from "./crd-list"; import { CrdResources } from "./crd-resources"; +import { crdURL, crdDefinitionsRoute, crdResourcesRoute } from "../../../common/routes"; @observer export class CustomResources extends React.Component { diff --git a/src/renderer/components/+custom-resources/index.ts b/src/renderer/components/+custom-resources/index.ts index e17eee852fb1..b045590b14c3 100644 --- a/src/renderer/components/+custom-resources/index.ts +++ b/src/renderer/components/+custom-resources/index.ts @@ -19,7 +19,6 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./crd.route"; export * from "./crd-list"; export * from "./crd-details"; export * from "./crd-resources"; diff --git a/src/renderer/components/+entity-settings/entity-settings.tsx b/src/renderer/components/+entity-settings/entity-settings.tsx index 18eee4ffaa1a..a1aacbc7d539 100644 --- a/src/renderer/components/+entity-settings/entity-settings.tsx +++ b/src/renderer/components/+entity-settings/entity-settings.tsx @@ -31,7 +31,7 @@ import { Tabs, Tab } from "../tabs"; import type { CatalogEntity } from "../../api/catalog-entity"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; import { entitySettingRegistry } from "../../../extensions/registries"; -import type { EntitySettingsRouteParams } from "./entity-settings.route"; +import type { EntitySettingsRouteParams } from "../../../common/routes"; import { groupBy } from "lodash"; interface Props extends RouteComponentProps { diff --git a/src/renderer/components/+entity-settings/index.ts b/src/renderer/components/+entity-settings/index.ts index c0acc3661710..051b607dccb4 100644 --- a/src/renderer/components/+entity-settings/index.ts +++ b/src/renderer/components/+entity-settings/index.ts @@ -21,5 +21,4 @@ import "../cluster-settings"; -export * from "./entity-settings.route"; export * from "./entity-settings"; diff --git a/src/renderer/components/+events/events.tsx b/src/renderer/components/+events/events.tsx index 15aafdbf4389..38df27502722 100644 --- a/src/renderer/components/+events/events.tsx +++ b/src/renderer/components/+events/events.tsx @@ -36,7 +36,7 @@ import { Link } from "react-router-dom"; import { cssNames, IClassName, stopPropagation } from "../../utils"; import { Icon } from "../icon"; import { lookupApiLink } from "../../api/kube-api"; -import { eventsURL } from "./events.route"; +import { eventsURL } from "../../../common/routes"; enum columnId { message = "message", diff --git a/src/renderer/components/+events/index.ts b/src/renderer/components/+events/index.ts index d14ee810d894..587e822adc94 100644 --- a/src/renderer/components/+events/index.ts +++ b/src/renderer/components/+events/index.ts @@ -20,5 +20,4 @@ */ export * from "./events"; -export * from "./events.route"; export * from "./event-details"; diff --git a/src/renderer/components/+extensions/index.ts b/src/renderer/components/+extensions/index.ts index 359c1eb73fdb..8452ee5a3bb5 100644 --- a/src/renderer/components/+extensions/index.ts +++ b/src/renderer/components/+extensions/index.ts @@ -19,5 +19,4 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./extensions.route"; export * from "./extensions"; diff --git a/src/renderer/components/+namespaces/index.ts b/src/renderer/components/+namespaces/index.ts index 4d4ce14643fa..90f61353031d 100644 --- a/src/renderer/components/+namespaces/index.ts +++ b/src/renderer/components/+namespaces/index.ts @@ -19,7 +19,6 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./namespaces.route"; export * from "./namespaces"; export * from "./namespace-details"; export * from "./add-namespace-dialog"; diff --git a/src/renderer/components/+namespaces/namespaces.tsx b/src/renderer/components/+namespaces/namespaces.tsx index 2c9a77877701..bb657ef9a3a4 100644 --- a/src/renderer/components/+namespaces/namespaces.tsx +++ b/src/renderer/components/+namespaces/namespaces.tsx @@ -28,9 +28,9 @@ import { TabLayout } from "../layout/tab-layout"; import { Badge } from "../badge"; import type { RouteComponentProps } from "react-router"; import { KubeObjectListLayout } from "../kube-object"; -import type { INamespacesRouteParams } from "./namespaces.route"; import { namespaceStore } from "./namespace.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { NamespacesRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -39,7 +39,7 @@ enum columnId { status = "status", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } export class Namespaces extends React.Component { diff --git a/src/renderer/components/+network-endpoints/endpoints.tsx b/src/renderer/components/+network-endpoints/endpoints.tsx index 7cc74427fa59..3ae66884fa16 100644 --- a/src/renderer/components/+network-endpoints/endpoints.tsx +++ b/src/renderer/components/+network-endpoints/endpoints.tsx @@ -24,11 +24,11 @@ import "./endpoints.scss"; import React from "react"; import { observer } from "mobx-react"; 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"; +import type { EndpointRouteParams } from "../../../common/routes"; enum columnId { name = "name", diff --git a/src/renderer/components/+network-endpoints/index.ts b/src/renderer/components/+network-endpoints/index.ts index 6295e6341f80..a6c1f07e4582 100644 --- a/src/renderer/components/+network-endpoints/index.ts +++ b/src/renderer/components/+network-endpoints/index.ts @@ -19,6 +19,5 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./endpoints.route"; export * from "./endpoints"; export * from "./endpoint-details"; diff --git a/src/renderer/components/+network-ingresses/index.ts b/src/renderer/components/+network-ingresses/index.ts index 855e2a0bcfe4..c950d57d0168 100644 --- a/src/renderer/components/+network-ingresses/index.ts +++ b/src/renderer/components/+network-ingresses/index.ts @@ -19,6 +19,5 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./ingresses.route"; export * from "./ingresses"; export * from "./ingress-details"; diff --git a/src/renderer/components/+network-ingresses/ingresses.tsx b/src/renderer/components/+network-ingresses/ingresses.tsx index 1ee39d40105f..2a15bf5cb859 100644 --- a/src/renderer/components/+network-ingresses/ingresses.tsx +++ b/src/renderer/components/+network-ingresses/ingresses.tsx @@ -24,11 +24,11 @@ import "./ingresses.scss"; import React from "react"; import { observer } from "mobx-react"; 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"; +import type { IngressRouteParams } from "../../../common/routes"; enum columnId { name = "name", diff --git a/src/renderer/components/+network-policies/index.ts b/src/renderer/components/+network-policies/index.ts index f12802e0685e..fa2d9fd1af4e 100644 --- a/src/renderer/components/+network-policies/index.ts +++ b/src/renderer/components/+network-policies/index.ts @@ -19,6 +19,5 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./network-policies.route"; export * from "./network-policies"; export * from "./network-policy-details"; diff --git a/src/renderer/components/+network-policies/network-policies.tsx b/src/renderer/components/+network-policies/network-policies.tsx index 1010c07175b9..6aa63eff2300 100644 --- a/src/renderer/components/+network-policies/network-policies.tsx +++ b/src/renderer/components/+network-policies/network-policies.tsx @@ -26,9 +26,9 @@ import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router-dom"; import type { NetworkPolicy } from "../../api/endpoints/network-policy.api"; import { KubeObjectListLayout } from "../kube-object"; -import type { INetworkPoliciesRouteParams } from "./network-policies.route"; import { networkPolicyStore } from "./network-policy.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { NetworkPoliciesRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -37,7 +37,7 @@ enum columnId { age = "age", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+network-services/index.ts b/src/renderer/components/+network-services/index.ts index 5a75b46ee2c2..9c3666a24cd4 100644 --- a/src/renderer/components/+network-services/index.ts +++ b/src/renderer/components/+network-services/index.ts @@ -19,6 +19,5 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./services.route"; export * from "./services"; export * from "./service-details"; diff --git a/src/renderer/components/+network-services/services.tsx b/src/renderer/components/+network-services/services.tsx index 33f9b73e08f5..502955b630e0 100644 --- a/src/renderer/components/+network-services/services.tsx +++ b/src/renderer/components/+network-services/services.tsx @@ -24,12 +24,12 @@ import "./services.scss"; import React from "react"; import { observer } from "mobx-react"; 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"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { ServicesRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -43,7 +43,7 @@ enum columnId { status = "status", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+network/index.ts b/src/renderer/components/+network/index.ts index 92bb989bc263..bfb7c13b58cf 100644 --- a/src/renderer/components/+network/index.ts +++ b/src/renderer/components/+network/index.ts @@ -19,6 +19,5 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./network.route"; export * from "./network"; export * from "./network.command"; diff --git a/src/renderer/components/+network/network.command.ts b/src/renderer/components/+network/network.command.ts index ef4639a9fc7e..4171348a1bab 100644 --- a/src/renderer/components/+network/network.command.ts +++ b/src/renderer/components/+network/network.command.ts @@ -21,35 +21,32 @@ import { navigate } from "../../navigation"; import { commandRegistry } from "../../../extensions/registries/command-registry"; -import { servicesURL } from "../+network-services"; -import { endpointURL } from "../+network-endpoints"; -import { ingressURL } from "../+network-ingresses"; -import { networkPoliciesURL } from "../+network-policies"; +import * as routes from "../../../common/routes"; commandRegistry.add({ id: "cluster.viewServices", title: "Cluster: View Services", scope: "entity", - action: () => navigate(servicesURL()) + action: () => navigate(routes.servicesURL()) }); commandRegistry.add({ id: "cluster.viewEndpoints", title: "Cluster: View Endpoints", scope: "entity", - action: () => navigate(endpointURL()) + action: () => navigate(routes.endpointURL()) }); commandRegistry.add({ id: "cluster.viewIngresses", title: "Cluster: View Ingresses", scope: "entity", - action: () => navigate(ingressURL()) + action: () => navigate(routes.ingressURL()) }); commandRegistry.add({ id: "cluster.viewNetworkPolicies", title: "Cluster: View NetworkPolicies", scope: "entity", - action: () => navigate(networkPoliciesURL()) + action: () => navigate(routes.networkPoliciesURL()) }); diff --git a/src/renderer/components/+network/network.tsx b/src/renderer/components/+network/network.tsx index 55ff6b6e964d..b9458b31e82e 100644 --- a/src/renderer/components/+network/network.tsx +++ b/src/renderer/components/+network/network.tsx @@ -24,56 +24,57 @@ import "./network.scss"; import React from "react"; import { observer } from "mobx-react"; import { TabLayout, TabLayoutRoute } from "../layout/tab-layout"; -import { Services, servicesRoute, servicesURL } from "../+network-services"; -import { endpointRoute, Endpoints, endpointURL } from "../+network-endpoints"; -import { Ingresses, ingressRoute, ingressURL } from "../+network-ingresses"; -import { NetworkPolicies, networkPoliciesRoute, networkPoliciesURL } from "../+network-policies"; +import { Services } from "../+network-services"; +import { Endpoints } from "../+network-endpoints"; +import { Ingresses } from "../+network-ingresses"; +import { NetworkPolicies } from "../+network-policies"; import { namespaceUrlParam } from "../+namespaces/namespace.store"; import { isAllowedResource } from "../../../common/rbac"; +import * as routes from "../../../common/routes"; @observer export class Network extends React.Component { static get tabRoutes(): TabLayoutRoute[] { const query = namespaceUrlParam.toObjectParam(); - const routes: TabLayoutRoute[] = []; + const tabs: TabLayoutRoute[] = []; if (isAllowedResource("services")) { - routes.push({ + tabs.push({ title: "Services", component: Services, - url: servicesURL({ query }), - routePath: servicesRoute.path.toString(), + url: routes.servicesURL({ query }), + routePath: routes.servicesRoute.path.toString(), }); } if (isAllowedResource("endpoints")) { - routes.push({ + tabs.push({ title: "Endpoints", component: Endpoints, - url: endpointURL({ query }), - routePath: endpointRoute.path.toString(), + url: routes.endpointURL({ query }), + routePath: routes.endpointRoute.path.toString(), }); } if (isAllowedResource("ingresses")) { - routes.push({ + tabs.push({ title: "Ingresses", component: Ingresses, - url: ingressURL({ query }), - routePath: ingressRoute.path.toString(), + url: routes.ingressURL({ query }), + routePath: routes.ingressRoute.path.toString(), }); } if (isAllowedResource("networkpolicies")) { - routes.push({ + tabs.push({ title: "Network Policies", component: NetworkPolicies, - url: networkPoliciesURL({ query }), - routePath: networkPoliciesRoute.path.toString(), + url: routes.networkPoliciesURL({ query }), + routePath: routes.networkPoliciesRoute.path.toString(), }); } - return routes; + return tabs; } render() { diff --git a/src/renderer/components/+nodes/index.ts b/src/renderer/components/+nodes/index.ts index 4c2e0a97c786..eb9f3cd2c19e 100644 --- a/src/renderer/components/+nodes/index.ts +++ b/src/renderer/components/+nodes/index.ts @@ -20,6 +20,5 @@ */ export * from "./nodes"; -export * from "./nodes.route"; export * from "./node-details"; export * from "./node.command"; diff --git a/src/renderer/components/+nodes/node.command.ts b/src/renderer/components/+nodes/node.command.ts index 34e226c52aa8..314381b5a44b 100644 --- a/src/renderer/components/+nodes/node.command.ts +++ b/src/renderer/components/+nodes/node.command.ts @@ -21,7 +21,7 @@ import { navigate } from "../../navigation"; import { commandRegistry } from "../../../extensions/registries/command-registry"; -import { nodesURL } from "./nodes.route"; +import { nodesURL } from "../../../common/routes"; commandRegistry.add({ id: "cluster.viewNodes", diff --git a/src/renderer/components/+nodes/nodes.tsx b/src/renderer/components/+nodes/nodes.tsx index 953562b06bad..4011a52b04fe 100644 --- a/src/renderer/components/+nodes/nodes.tsx +++ b/src/renderer/components/+nodes/nodes.tsx @@ -28,7 +28,6 @@ import { TabLayout } from "../layout/tab-layout"; import { nodesStore } from "./nodes.store"; import { podsStore } from "../+workloads-pods/pods.store"; import { KubeObjectListLayout } from "../kube-object"; -import type { INodesRouteParams } from "./nodes.route"; import type { Node } from "../../api/endpoints/nodes.api"; import { LineProgress } from "../line-progress"; import { bytesToUnits } from "../../utils/convertMemory"; @@ -37,6 +36,7 @@ import kebabCase from "lodash/kebabCase"; import upperFirst from "lodash/upperFirst"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { Badge } from "../badge/badge"; +import type { NodesRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -51,7 +51,7 @@ enum columnId { status = "status", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+preferences/index.tsx b/src/renderer/components/+preferences/index.tsx index 182af1e6b8f0..11ee65ea7892 100644 --- a/src/renderer/components/+preferences/index.tsx +++ b/src/renderer/components/+preferences/index.tsx @@ -19,5 +19,4 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./preferences.route"; export * from "./preferences"; diff --git a/src/renderer/components/+preferences/preferences.route.ts b/src/renderer/components/+preferences/preferences.route.ts deleted file mode 100644 index 1ae181a30069..000000000000 --- a/src/renderer/components/+preferences/preferences.route.ts +++ /dev/null @@ -1,38 +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 type { RouteProps } from "react-router"; -import { commandRegistry } from "../../../extensions/registries/command-registry"; -import { buildURL } from "../../../common/utils/buildUrl"; -import { navigate } from "../../navigation"; - -export const preferencesRoute: RouteProps = { - path: "/preferences" -}; - -export const preferencesURL = buildURL(preferencesRoute.path); - -commandRegistry.add({ - id: "app.showPreferences", - title: "Preferences: Open", - scope: "global", - action: () => navigate(preferencesURL()) -}); diff --git a/src/renderer/components/+storage-classes/index.ts b/src/renderer/components/+storage-classes/index.ts index 20cc9c1bd837..d4e62fa31bc2 100644 --- a/src/renderer/components/+storage-classes/index.ts +++ b/src/renderer/components/+storage-classes/index.ts @@ -19,7 +19,5 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./storage-classes.route"; export * from "./storage-classes"; export * from "./storage-class-details"; - diff --git a/src/renderer/components/+storage-classes/storage-classes.tsx b/src/renderer/components/+storage-classes/storage-classes.tsx index 39182abb46f7..554772178639 100644 --- a/src/renderer/components/+storage-classes/storage-classes.tsx +++ b/src/renderer/components/+storage-classes/storage-classes.tsx @@ -26,9 +26,9 @@ import type { RouteComponentProps } from "react-router-dom"; import { observer } from "mobx-react"; import type { StorageClass } from "../../api/endpoints/storage-class.api"; import { KubeObjectListLayout } from "../kube-object"; -import type { IStorageClassesRouteParams } from "./storage-classes.route"; import { storageClassStore } from "./storage-class.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { StorageClassesRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -38,7 +38,7 @@ enum columnId { reclaimPolicy = "reclaim", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+storage-volume-claims/index.ts b/src/renderer/components/+storage-volume-claims/index.ts index c5bf0dc16bec..270126d49ad4 100644 --- a/src/renderer/components/+storage-volume-claims/index.ts +++ b/src/renderer/components/+storage-volume-claims/index.ts @@ -19,7 +19,5 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./volume-claims.route"; export * from "./volume-claims"; export * from "./volume-claim-details"; - diff --git a/src/renderer/components/+storage-volume-claims/volume-claims.tsx b/src/renderer/components/+storage-volume-claims/volume-claims.tsx index 34309b43ec93..c222405756ba 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claims.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claims.tsx @@ -28,11 +28,11 @@ import { volumeClaimStore } from "./volume-claim.store"; import type { PersistentVolumeClaim } from "../../api/endpoints/persistent-volume-claims.api"; import { podsStore } from "../+workloads-pods/pods.store"; import { getDetailsUrl, KubeObjectListLayout } from "../kube-object"; -import type { IVolumeClaimsRouteParams } from "./volume-claims.route"; import { unitsToBytes } from "../../utils/convertMemory"; import { stopPropagation } from "../../utils"; import { storageClassApi } from "../../api/endpoints"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { VolumeClaimsRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -44,7 +44,7 @@ enum columnId { age = "age", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+storage-volumes/index.ts b/src/renderer/components/+storage-volumes/index.ts index 73a697d7a0d5..5495c73c2790 100644 --- a/src/renderer/components/+storage-volumes/index.ts +++ b/src/renderer/components/+storage-volumes/index.ts @@ -19,6 +19,5 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./volumes.route"; export * from "./volumes"; export * from "./volume-details"; diff --git a/src/renderer/components/+storage-volumes/volumes.tsx b/src/renderer/components/+storage-volumes/volumes.tsx index 858d362bb22a..1300dc98384d 100644 --- a/src/renderer/components/+storage-volumes/volumes.tsx +++ b/src/renderer/components/+storage-volumes/volumes.tsx @@ -26,11 +26,11 @@ import { observer } from "mobx-react"; import { Link, RouteComponentProps } from "react-router-dom"; import type { PersistentVolume } from "../../api/endpoints/persistent-volume.api"; import { getDetailsUrl, KubeObjectListLayout } from "../kube-object"; -import type { IVolumesRouteParams } from "./volumes.route"; import { stopPropagation } from "../../utils"; import { volumesStore } from "./volumes.store"; import { pvcApi, storageClassApi } from "../../api/endpoints"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { VolumesRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -41,7 +41,7 @@ enum columnId { age = "age", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+storage/index.ts b/src/renderer/components/+storage/index.ts index 042fea4785ca..60e8c1b9cd50 100644 --- a/src/renderer/components/+storage/index.ts +++ b/src/renderer/components/+storage/index.ts @@ -19,5 +19,4 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./storage.route"; export * from "./storage"; diff --git a/src/renderer/components/+storage/storage.tsx b/src/renderer/components/+storage/storage.tsx index b8147f677a2d..732c1f4ea3fd 100644 --- a/src/renderer/components/+storage/storage.tsx +++ b/src/renderer/components/+storage/storage.tsx @@ -24,11 +24,12 @@ import "./storage.scss"; import React from "react"; import { observer } from "mobx-react"; import { TabLayout, TabLayoutRoute } from "../layout/tab-layout"; -import { PersistentVolumes, volumesRoute, volumesURL } from "../+storage-volumes"; -import { StorageClasses, storageClassesRoute, storageClassesURL } from "../+storage-classes"; -import { PersistentVolumeClaims, volumeClaimsRoute, volumeClaimsURL } from "../+storage-volume-claims"; +import { PersistentVolumes } from "../+storage-volumes"; +import { StorageClasses } from "../+storage-classes"; +import { PersistentVolumeClaims } from "../+storage-volume-claims"; import { namespaceUrlParam } from "../+namespaces/namespace.store"; import { isAllowedResource } from "../../../common/rbac"; +import * as routes from "../../../common/routes"; @observer export class Storage extends React.Component { @@ -40,8 +41,8 @@ export class Storage extends React.Component { tabRoutes.push({ title: "Persistent Volume Claims", component: PersistentVolumeClaims, - url: volumeClaimsURL({ query }), - routePath: volumeClaimsRoute.path.toString(), + url: routes.volumeClaimsURL({ query }), + routePath: routes.volumeClaimsRoute.path.toString(), }); } @@ -49,8 +50,8 @@ export class Storage extends React.Component { tabRoutes.push({ title: "Persistent Volumes", component: PersistentVolumes, - url: volumesURL(), - routePath: volumesRoute.path.toString(), + url: routes.volumesURL(), + routePath: routes.volumesRoute.path.toString(), }); } @@ -58,8 +59,8 @@ export class Storage extends React.Component { tabRoutes.push({ title: "Storage Classes", component: StorageClasses, - url: storageClassesURL(), - routePath: storageClassesRoute.path.toString(), + url: routes.storageClassesURL(), + routePath: routes.storageClassesRoute.path.toString(), }); } 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 db86d37cd66f..f33e51128fcd 100644 --- a/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx +++ b/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx @@ -24,12 +24,12 @@ import "./role-bindings.scss"; import React from "react"; import { observer } from "mobx-react"; 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"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { RoleBindingsRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -38,7 +38,7 @@ enum columnId { age = "age", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+user-management-roles/roles.tsx b/src/renderer/components/+user-management-roles/roles.tsx index ac7385cb2cbb..2eeef76b6997 100644 --- a/src/renderer/components/+user-management-roles/roles.tsx +++ b/src/renderer/components/+user-management-roles/roles.tsx @@ -24,12 +24,12 @@ import "./roles.scss"; import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; -import type { IRolesRouteParams } from "../+user-management/user-management.route"; import { rolesStore } from "./roles.store"; import type { Role } from "../../api/endpoints"; import { KubeObjectListLayout } from "../kube-object"; import { AddRoleDialog } from "./add-role-dialog"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { RolesRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -37,7 +37,7 @@ enum columnId { age = "age", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer 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 dff4d1fe58fe..0299e0f7f9de 100644 --- a/src/renderer/components/+user-management-service-accounts/service-accounts.tsx +++ b/src/renderer/components/+user-management-service-accounts/service-accounts.tsx @@ -30,11 +30,11 @@ import { MenuItem } from "../menu"; import { openServiceAccountKubeConfig } from "../kubeconfig-dialog"; import { Icon } from "../icon"; import { KubeObjectListLayout } from "../kube-object"; -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"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { ServiceAccountsRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -42,7 +42,7 @@ enum columnId { age = "age", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+user-management/index.ts b/src/renderer/components/+user-management/index.ts index 0bdffbed1fd8..06afee0efab7 100644 --- a/src/renderer/components/+user-management/index.ts +++ b/src/renderer/components/+user-management/index.ts @@ -20,4 +20,3 @@ */ export * from "./user-management"; -export * from "./user-management.route"; diff --git a/src/renderer/components/+user-management/user-management.tsx b/src/renderer/components/+user-management/user-management.tsx index 85d55c03f6c1..e5bc629d0b78 100644 --- a/src/renderer/components/+user-management/user-management.tsx +++ b/src/renderer/components/+user-management/user-management.tsx @@ -26,10 +26,10 @@ import { TabLayout, TabLayoutRoute } from "../layout/tab-layout"; import { Roles } from "../+user-management-roles"; import { RoleBindings } from "../+user-management-roles-bindings"; import { ServiceAccounts } from "../+user-management-service-accounts"; -import { podSecurityPoliciesRoute, podSecurityPoliciesURL, roleBindingsRoute, roleBindingsURL, rolesRoute, rolesURL, serviceAccountsRoute, serviceAccountsURL } from "./user-management.route"; import { namespaceUrlParam } from "../+namespaces/namespace.store"; import { PodSecurityPolicies } from "../+pod-security-policies"; import { isAllowedResource } from "../../../common/rbac"; +import * as routes from "../../../common/routes"; @observer export class UserManagement extends React.Component { @@ -41,8 +41,8 @@ export class UserManagement extends React.Component { tabRoutes.push({ title: "Service Accounts", component: ServiceAccounts, - url: serviceAccountsURL({ query }), - routePath: serviceAccountsRoute.path.toString(), + url: routes.serviceAccountsURL({ query }), + routePath: routes.serviceAccountsRoute.path.toString(), }); } @@ -51,8 +51,8 @@ export class UserManagement extends React.Component { tabRoutes.push({ title: "Role Bindings", component: RoleBindings, - url: roleBindingsURL({ query }), - routePath: roleBindingsRoute.path.toString(), + url: routes.roleBindingsURL({ query }), + routePath: routes.roleBindingsRoute.path.toString(), }); } @@ -61,8 +61,8 @@ export class UserManagement extends React.Component { tabRoutes.push({ title: "Roles", component: Roles, - url: rolesURL({ query }), - routePath: rolesRoute.path.toString(), + url: routes.rolesURL({ query }), + routePath: routes.rolesRoute.path.toString(), }); } @@ -70,8 +70,8 @@ export class UserManagement extends React.Component { tabRoutes.push({ title: "Pod Security Policies", component: PodSecurityPolicies, - url: podSecurityPoliciesURL(), - routePath: podSecurityPoliciesRoute.path.toString(), + url: routes.podSecurityPoliciesURL(), + routePath: routes.podSecurityPoliciesRoute.path.toString(), }); } diff --git a/src/renderer/components/+welcome/index.ts b/src/renderer/components/+welcome/index.ts index b905153b6803..8465266d6e7b 100644 --- a/src/renderer/components/+welcome/index.ts +++ b/src/renderer/components/+welcome/index.ts @@ -20,4 +20,3 @@ */ export * from "./welcome"; -export * from "./welcome.route"; diff --git a/src/renderer/components/+welcome/welcome.tsx b/src/renderer/components/+welcome/welcome.tsx index 071d7bbaba5b..61577989423b 100644 --- a/src/renderer/components/+welcome/welcome.tsx +++ b/src/renderer/components/+welcome/welcome.tsx @@ -26,8 +26,7 @@ import { Icon } from "../icon"; import { productName, slackUrl } from "../../../common/vars"; import { welcomeMenuRegistry } from "../../../extensions/registries"; import { navigate } from "../../navigation"; -import { catalogURL } from "../+catalog"; -import { preferencesURL } from "../+preferences"; +import { catalogURL, preferencesURL } from "../../../common/routes"; @observer export class Welcome extends React.Component { diff --git a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx index 04560aa197fe..64690422d06d 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx @@ -31,13 +31,13 @@ import { cronJobStore } from "./cronjob.store"; import { jobStore } from "../+workloads-jobs/job.store"; import { eventStore } from "../+events/event.store"; 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"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { ConfirmDialog } from "../confirm-dialog/confirm-dialog"; import { Notifications } from "../notifications/notifications"; +import type { CronJobsRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -49,7 +49,7 @@ enum columnId { age = "age", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+workloads-daemonsets/daemonsets.tsx b/src/renderer/components/+workloads-daemonsets/daemonsets.tsx index b256ac1f62f7..e22c310e3dfe 100644 --- a/src/renderer/components/+workloads-daemonsets/daemonsets.tsx +++ b/src/renderer/components/+workloads-daemonsets/daemonsets.tsx @@ -30,9 +30,9 @@ import { daemonSetStore } from "./daemonsets.store"; import { podsStore } from "../+workloads-pods/pods.store"; import { nodesStore } from "../+nodes/nodes.store"; import { KubeObjectListLayout } from "../kube-object"; -import type { IDaemonSetsRouteParams } from "../+workloads"; import { Badge } from "../badge"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { DaemonSetsRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -42,7 +42,7 @@ enum columnId { age = "age", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+workloads-deployments/deployments.tsx b/src/renderer/components/+workloads-deployments/deployments.tsx index 74ddb08fcbbc..6bca45c864ee 100644 --- a/src/renderer/components/+workloads-deployments/deployments.tsx +++ b/src/renderer/components/+workloads-deployments/deployments.tsx @@ -36,13 +36,13 @@ 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 type { IDeploymentsRouteParams } from "../+workloads"; import { cssNames } from "../../utils"; import kebabCase from "lodash/kebabCase"; import orderBy from "lodash/orderBy"; import { kubeObjectMenuRegistry } from "../../../extensions/registries/kube-object-menu-registry"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { Notifications } from "../notifications"; +import type { DeploymentsRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -53,7 +53,7 @@ enum columnId { condition = "condition", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+workloads-jobs/jobs.tsx b/src/renderer/components/+workloads-jobs/jobs.tsx index bcc9b85efeec..9d0c46764fc8 100644 --- a/src/renderer/components/+workloads-jobs/jobs.tsx +++ b/src/renderer/components/+workloads-jobs/jobs.tsx @@ -29,9 +29,9 @@ import { jobStore } from "./job.store"; import { eventStore } from "../+events/event.store"; import type { Job } from "../../api/endpoints/job.api"; import { KubeObjectListLayout } from "../kube-object"; -import type { IJobsRouteParams } from "../+workloads"; import kebabCase from "lodash/kebabCase"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { JobsRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -41,7 +41,7 @@ enum columnId { age = "age", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+workloads-overview/overview-statuses.tsx b/src/renderer/components/+workloads-overview/overview-statuses.tsx index 2384a6433014..e475a49cf55e 100644 --- a/src/renderer/components/+workloads-overview/overview-statuses.tsx +++ b/src/renderer/components/+workloads-overview/overview-statuses.tsx @@ -25,12 +25,13 @@ import React from "react"; import { observer } from "mobx-react"; import { OverviewWorkloadStatus } from "./overview-workload-status"; import { Link } from "react-router-dom"; -import { workloadURL, workloadStores } from "../+workloads"; +import { workloadStores } from "../+workloads"; import { namespaceStore } from "../+namespaces/namespace.store"; import { NamespaceSelectFilter } from "../+namespaces/namespace-select-filter"; import { isAllowedResource, KubeResource } from "../../../common/rbac"; import { ResourceNames } from "../../utils/rbac"; import { autobind } from "../../utils"; +import { workloadURL } from "../../../common/routes"; const resources: KubeResource[] = [ "pods", diff --git a/src/renderer/components/+workloads-overview/overview.tsx b/src/renderer/components/+workloads-overview/overview.tsx index 82c3549fb14a..d0afd396b760 100644 --- a/src/renderer/components/+workloads-overview/overview.tsx +++ b/src/renderer/components/+workloads-overview/overview.tsx @@ -25,7 +25,6 @@ import React from "react"; import { disposeOnUnmount, observer } from "mobx-react"; import { OverviewStatuses } from "./overview-statuses"; 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"; @@ -38,8 +37,9 @@ import { Events } from "../+events"; import { isAllowedResource } from "../../../common/rbac"; import { kubeWatchApi } from "../../api/kube-watch-api"; import { clusterContext } from "../context"; +import type { WorkloadsOverviewRouteParams } from "../../../common/routes"; -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+workloads-pods/pods.tsx b/src/renderer/components/+workloads-pods/pods.tsx index be5cbf885200..807d531b201a 100644 --- a/src/renderer/components/+workloads-pods/pods.tsx +++ b/src/renderer/components/+workloads-pods/pods.tsx @@ -27,7 +27,6 @@ import { Link } from "react-router-dom"; import { podsStore } from "./pods.store"; import type { RouteComponentProps } from "react-router"; import { volumeClaimStore } from "../+storage-volume-claims/volume-claim.store"; -import type { IPodsRouteParams } from "../+workloads"; import { eventStore } from "../+events/event.store"; import { getDetailsUrl, KubeObjectListLayout } from "../kube-object"; import { nodesApi, Pod } from "../../api/endpoints"; @@ -39,6 +38,7 @@ import kebabCase from "lodash/kebabCase"; import { lookupApiLink } from "../../api/kube-api"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { Badge } from "../badge"; +import type { PodsRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -52,7 +52,7 @@ enum columnId { status = "status", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+workloads-replicasets/replicasets.tsx b/src/renderer/components/+workloads-replicasets/replicasets.tsx index ffc75ead0ef7..30aebb6efaee 100644 --- a/src/renderer/components/+workloads-replicasets/replicasets.tsx +++ b/src/renderer/components/+workloads-replicasets/replicasets.tsx @@ -28,12 +28,12 @@ import type { KubeObjectMenuProps } from "../kube-object/kube-object-menu"; import { replicaSetStore } from "./replicasets.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; 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"; import { kubeObjectMenuRegistry } from "../../../extensions/registries/kube-object-menu-registry"; import { ReplicaSetScaleDialog } from "./replicaset-scale-dialog"; +import type { ReplicaSetsRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -44,7 +44,7 @@ enum columnId { age = "age", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+workloads-statefulsets/statefulsets.tsx b/src/renderer/components/+workloads-statefulsets/statefulsets.tsx index 59b208cccfaf..3340c30381b2 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulsets.tsx +++ b/src/renderer/components/+workloads-statefulsets/statefulsets.tsx @@ -31,12 +31,12 @@ import { nodesStore } from "../+nodes/nodes.store"; import { eventStore } from "../+events/event.store"; import type { KubeObjectMenuProps } from "../kube-object/kube-object-menu"; import { KubeObjectListLayout } from "../kube-object"; -import type { IStatefulSetsRouteParams } from "../+workloads"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { StatefulSetScaleDialog } from "./statefulset-scale-dialog"; import { MenuItem } from "../menu/menu"; import { Icon } from "../icon/icon"; import { kubeObjectMenuRegistry } from "../../../extensions/registries/kube-object-menu-registry"; +import type { StatefulSetsRouteParams } from "../../../common/routes"; enum columnId { name = "name", @@ -46,7 +46,7 @@ enum columnId { replicas = "replicas", } -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/+workloads/index.ts b/src/renderer/components/+workloads/index.ts index f094bb5ff3bd..4e0e932a5169 100644 --- a/src/renderer/components/+workloads/index.ts +++ b/src/renderer/components/+workloads/index.ts @@ -19,7 +19,6 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export * from "./workloads.route"; export * from "./workloads"; export * from "./workloads.stores"; export * from "./workloads.command"; diff --git a/src/renderer/components/+workloads/workloads.command.ts b/src/renderer/components/+workloads/workloads.command.ts index b09308d11355..2cc8895714d2 100644 --- a/src/renderer/components/+workloads/workloads.command.ts +++ b/src/renderer/components/+workloads/workloads.command.ts @@ -21,46 +21,46 @@ import { navigate } from "../../navigation"; import { commandRegistry } from "../../../extensions/registries/command-registry"; -import { cronJobsURL, daemonSetsURL, deploymentsURL, jobsURL, podsURL, statefulSetsURL } from "./workloads.route"; +import * as routes from "../../../common/routes"; commandRegistry.add({ id: "cluster.viewPods", title: "Cluster: View Pods", scope: "entity", - action: () => navigate(podsURL()) + action: () => navigate(routes.podsURL()) }); commandRegistry.add({ id: "cluster.viewDeployments", title: "Cluster: View Deployments", scope: "entity", - action: () => navigate(deploymentsURL()) + action: () => navigate(routes.deploymentsURL()) }); commandRegistry.add({ id: "cluster.viewDaemonSets", title: "Cluster: View DaemonSets", scope: "entity", - action: () => navigate(daemonSetsURL()) + action: () => navigate(routes.daemonSetsURL()) }); commandRegistry.add({ id: "cluster.viewStatefulSets", title: "Cluster: View StatefulSets", scope: "entity", - action: () => navigate(statefulSetsURL()) + action: () => navigate(routes.statefulSetsURL()) }); commandRegistry.add({ id: "cluster.viewJobs", title: "Cluster: View Jobs", scope: "entity", - action: () => navigate(jobsURL()) + action: () => navigate(routes.jobsURL()) }); commandRegistry.add({ id: "cluster.viewCronJobs", title: "Cluster: View CronJobs", scope: "entity", - action: () => navigate(cronJobsURL()) + action: () => navigate(routes.cronJobsURL()) }); diff --git a/src/renderer/components/+workloads/workloads.tsx b/src/renderer/components/+workloads/workloads.tsx index 3b3c294b776f..2923f962a48a 100644 --- a/src/renderer/components/+workloads/workloads.tsx +++ b/src/renderer/components/+workloads/workloads.tsx @@ -25,7 +25,6 @@ import React from "react"; import { observer } from "mobx-react"; import { TabLayout, TabLayoutRoute } from "../layout/tab-layout"; import { WorkloadsOverview } from "../+workloads-overview/overview"; -import { cronJobsRoute, cronJobsURL, daemonSetsRoute, daemonSetsURL, deploymentsRoute, deploymentsURL, jobsRoute, jobsURL, overviewRoute, overviewURL, podsRoute, podsURL, replicaSetsRoute, replicaSetsURL, statefulSetsRoute, statefulSetsURL } from "./workloads.route"; import { namespaceUrlParam } from "../+namespaces/namespace.store"; import { Pods } from "../+workloads-pods"; import { Deployments } from "../+workloads-deployments"; @@ -35,84 +34,85 @@ import { Jobs } from "../+workloads-jobs"; import { CronJobs } from "../+workloads-cronjobs"; import { isAllowedResource } from "../../../common/rbac"; import { ReplicaSets } from "../+workloads-replicasets"; +import * as routes from "../../../common/routes"; @observer export class Workloads extends React.Component { static get tabRoutes(): TabLayoutRoute[] { const query = namespaceUrlParam.toObjectParam(); - const routes: TabLayoutRoute[] = [ + const tabs: TabLayoutRoute[] = [ { title: "Overview", component: WorkloadsOverview, - url: overviewURL({ query }), - routePath: overviewRoute.path.toString() + url: routes.overviewURL({ query }), + routePath: routes.overviewRoute.path.toString() } ]; if (isAllowedResource("pods")) { - routes.push({ + tabs.push({ title: "Pods", component: Pods, - url: podsURL({ query }), - routePath: podsRoute.path.toString() + url: routes.podsURL({ query }), + routePath: routes.podsRoute.path.toString() }); } if (isAllowedResource("deployments")) { - routes.push({ + tabs.push({ title: "Deployments", component: Deployments, - url: deploymentsURL({ query }), - routePath: deploymentsRoute.path.toString(), + url: routes.deploymentsURL({ query }), + routePath: routes.deploymentsRoute.path.toString(), }); } if (isAllowedResource("daemonsets")) { - routes.push({ + tabs.push({ title: "DaemonSets", component: DaemonSets, - url: daemonSetsURL({ query }), - routePath: daemonSetsRoute.path.toString(), + url: routes.daemonSetsURL({ query }), + routePath: routes.daemonSetsRoute.path.toString(), }); } if (isAllowedResource("statefulsets")) { - routes.push({ + tabs.push({ title: "StatefulSets", component: StatefulSets, - url: statefulSetsURL({ query }), - routePath: statefulSetsRoute.path.toString(), + url: routes.statefulSetsURL({ query }), + routePath: routes.statefulSetsRoute.path.toString(), }); } if (isAllowedResource("replicasets")) { - routes.push({ + tabs.push({ title: "ReplicaSets", component: ReplicaSets, - url: replicaSetsURL({ query }), - routePath: replicaSetsRoute.path.toString(), + url: routes.replicaSetsURL({ query }), + routePath: routes.replicaSetsRoute.path.toString(), }); } if (isAllowedResource("jobs")) { - routes.push({ + tabs.push({ title: "Jobs", component: Jobs, - url: jobsURL({ query }), - routePath: jobsRoute.path.toString(), + url: routes.jobsURL({ query }), + routePath: routes.jobsRoute.path.toString(), }); } if (isAllowedResource("cronjobs")) { - routes.push({ + tabs.push({ title: "CronJobs", component: CronJobs, - url: cronJobsURL({ query }), - routePath: cronJobsRoute.path.toString(), + url: routes.cronJobsURL({ query }), + routePath: routes.cronJobsRoute.path.toString(), }); } - return routes; + return tabs; } render() { diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index f04fb46c5c80..27c5f3e7f4bd 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -28,25 +28,21 @@ import { Notifications } from "./notifications"; import { NotFound } from "./+404"; import { UserManagement } from "./+user-management/user-management"; import { ConfirmDialog } from "./confirm-dialog"; -import { usersManagementRoute } from "./+user-management/user-management.route"; -import { clusterRoute, clusterURL } from "./+cluster"; import { KubeConfigDialog } from "./kubeconfig-dialog/kubeconfig-dialog"; -import { Nodes, nodesRoute } from "./+nodes"; -import { Workloads, workloadsRoute, workloadsURL } from "./+workloads"; -import { Namespaces, namespacesRoute } from "./+namespaces"; -import { Network, networkRoute } from "./+network"; -import { Storage, storageRoute } from "./+storage"; +import { Nodes } from "./+nodes"; +import { Workloads } from "./+workloads"; +import { Namespaces } from "./+namespaces"; +import { Network } from "./+network"; +import { Storage } from "./+storage"; import { ClusterOverview } from "./+cluster/cluster-overview"; -import { Config, configRoute } from "./+config"; +import { Config } from "./+config"; import { Events } from "./+events/events"; -import { eventRoute } from "./+events"; -import { Apps, appsRoute } from "./+apps"; +import { Apps } from "./+apps"; import { KubeObjectDetails } from "./kube-object/kube-object-details"; import { AddRoleBindingDialog } from "./+user-management-roles-bindings"; import { DeploymentScaleDialog } from "./+workloads-deployments/deployment-scale-dialog"; import { CronJobTriggerDialog } from "./+workloads-cronjobs/cronjob-trigger-dialog"; import { CustomResources } from "./+custom-resources/custom-resources"; -import { crdRoute } from "./+custom-resources"; import { isAllowedResource } from "../../common/rbac"; import { MainLayout } from "./layout/main-layout"; import { ErrorBoundary } from "./error-boundary"; @@ -72,6 +68,7 @@ import { CommandContainer } from "./command-palette/command-container"; import { KubeObjectStore } from "../kube-object.store"; import { clusterContext } from "./context"; import { namespaceStore } from "./+namespaces/namespace.store"; +import * as routes from "../../common/routes"; @observer export class App extends React.Component { @@ -112,7 +109,7 @@ export class App extends React.Component { ]); } - @observable startUrl = isAllowedResource(["events", "nodes", "pods"]) ? clusterURL() : workloadsURL(); + @observable startUrl = isAllowedResource(["events", "nodes", "pods"]) ? routes.clusterURL() : routes.workloadsURL(); getTabLayoutRoutes(menuItem: ClusterPageMenuRegistration) { const routes: TabLayoutRoute[] = []; @@ -174,17 +171,17 @@ export class App extends React.Component { - - - - - - - - - - - + + + + + + + + + + + {this.renderExtensionTabLayoutRoutes()} {this.renderExtensionRoutes()} diff --git a/src/renderer/components/cluster-manager/bottom-bar.tsx b/src/renderer/components/cluster-manager/bottom-bar.tsx index 32f56d0f78ea..19c237982485 100644 --- a/src/renderer/components/cluster-manager/bottom-bar.tsx +++ b/src/renderer/components/cluster-manager/bottom-bar.tsx @@ -25,8 +25,8 @@ import React from "react"; import { observer } from "mobx-react"; import { StatusBarRegistration, statusBarRegistry } from "../../../extensions/registries"; import { navigate } from "../../navigation"; -import { catalogURL } from "../+catalog"; import { Icon } from "../icon"; +import { catalogURL } from "../../../common/routes"; @observer export class BottomBar extends React.Component { diff --git a/src/renderer/components/cluster-manager/cluster-manager.tsx b/src/renderer/components/cluster-manager/cluster-manager.tsx index a43ccb527a2a..2fc4d1d2a911 100644 --- a/src/renderer/components/cluster-manager/cluster-manager.tsx +++ b/src/renderer/components/cluster-manager/cluster-manager.tsx @@ -25,16 +25,16 @@ import React from "react"; import { Redirect, Route, Switch } from "react-router"; import { observer } from "mobx-react"; import { BottomBar } from "./bottom-bar"; -import { Catalog, catalogRoute } from "../+catalog"; -import { Preferences, preferencesRoute } from "../+preferences"; -import { AddCluster, addClusterRoute } from "../+add-cluster"; +import { Catalog } from "../+catalog"; +import { Preferences } from "../+preferences"; +import { AddCluster } from "../+add-cluster"; import { ClusterView } from "./cluster-view"; -import { clusterViewRoute } from "./cluster-view.route"; import { globalPageRegistry } from "../../../extensions/registries/page-registry"; -import { Extensions, extensionsRoute } from "../+extensions"; +import { Extensions } from "../+extensions"; import { HotbarMenu } from "../hotbar/hotbar-menu"; -import { EntitySettings, entitySettingsRoute } from "../+entity-settings"; -import { Welcome, welcomeRoute, welcomeURL } from "../+welcome"; +import { EntitySettings } from "../+entity-settings"; +import { Welcome } from "../+welcome"; +import * as routes from "../../../common/routes"; @observer export class ClusterManager extends React.Component { @@ -44,20 +44,20 @@ export class ClusterManager extends React.Component {

- - - - - - - + + + + + + + { globalPageRegistry.getItems() .map(({ url, components: { Page } }) => ( )) } - +
diff --git a/src/renderer/components/cluster-manager/cluster-view.tsx b/src/renderer/components/cluster-manager/cluster-view.tsx index b1ab7c936640..08d67a53122a 100644 --- a/src/renderer/components/cluster-manager/cluster-view.tsx +++ b/src/renderer/components/cluster-manager/cluster-view.tsx @@ -24,7 +24,6 @@ import React from "react"; import { reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; 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 type { Cluster } from "../../../main/cluster"; @@ -32,10 +31,10 @@ import { ClusterStore } from "../../../common/cluster-store"; import { requestMain } from "../../../common/ipc"; import { clusterActivateHandler } from "../../../common/cluster-ipc"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; -import { catalogURL } from "../+catalog"; import { navigate } from "../../navigation"; +import { catalogURL, ClusterViewRouteParams } from "../../../common/routes"; -interface Props extends RouteComponentProps { +interface Props extends RouteComponentProps { } @observer diff --git a/src/renderer/components/cluster-settings/cluster-settings.command.ts b/src/renderer/components/cluster-settings/cluster-settings.command.ts index 80d49ae39fb9..e0325d534072 100644 --- a/src/renderer/components/cluster-settings/cluster-settings.command.ts +++ b/src/renderer/components/cluster-settings/cluster-settings.command.ts @@ -21,8 +21,8 @@ import { navigate } from "../../navigation"; import { commandRegistry } from "../../../extensions/registries/command-registry"; -import { entitySettingsURL } from "../+entity-settings"; import { ClusterStore } from "../../../common/cluster-store"; +import { entitySettingsURL } from "../../../common/routes"; commandRegistry.add({ id: "cluster.viewCurrentClusterSettings", diff --git a/src/renderer/components/command-palette/command-dialog.tsx b/src/renderer/components/command-palette/command-dialog.tsx index 73bfc889fd34..bfd401ea0c58 100644 --- a/src/renderer/components/command-palette/command-dialog.tsx +++ b/src/renderer/components/command-palette/command-dialog.tsx @@ -29,7 +29,7 @@ import { ClusterStore } from "../../../common/cluster-store"; import { CommandOverlay } from "./command-container"; import { broadcastMessage } from "../../../common/ipc"; import { navigate } from "../../navigation"; -import { clusterViewURL } from "../cluster-manager/cluster-view.route"; +import { clusterViewURL } from "../../../common/routes"; @observer export class CommandDialog extends React.Component { diff --git a/src/renderer/components/dock/install-chart.tsx b/src/renderer/components/dock/install-chart.tsx index c3015e7bfe1c..743b76e0e501 100644 --- a/src/renderer/components/dock/install-chart.tsx +++ b/src/renderer/components/dock/install-chart.tsx @@ -33,13 +33,13 @@ import { IChartInstallData, installChartStore } from "./install-chart.store"; import { Spinner } from "../spinner"; import { Icon } from "../icon"; import { Button } from "../button"; -import { releaseURL } from "../+apps-releases"; import { releaseStore } from "../+apps-releases/release.store"; import { LogsDialog } from "../dialog/logs-dialog"; import { Select, SelectOption } from "../select"; import { Input } from "../input"; import { EditorPanel } from "./editor-panel"; import { navigate } from "../../navigation"; +import { releaseURL } from "../../../common/routes"; interface Props { tab: IDockTab; diff --git a/src/renderer/components/layout/sidebar.tsx b/src/renderer/components/layout/sidebar.tsx index 5149ebb4d6a2..c4c56d34e119 100644 --- a/src/renderer/components/layout/sidebar.tsx +++ b/src/renderer/components/layout/sidebar.tsx @@ -27,29 +27,21 @@ import { observer } from "mobx-react"; import { NavLink } from "react-router-dom"; import { cssNames } from "../../utils"; import { Icon } from "../icon"; -import { workloadsRoute, workloadsURL } from "../+workloads/workloads.route"; -import { namespacesRoute, namespacesURL } from "../+namespaces/namespaces.route"; -import { nodesRoute, nodesURL } from "../+nodes/nodes.route"; -import { usersManagementRoute, usersManagementURL } from "../+user-management/user-management.route"; -import { networkRoute, networkURL } from "../+network/network.route"; -import { storageRoute, storageURL } from "../+storage/storage.route"; -import { clusterRoute, clusterURL } from "../+cluster"; -import { Config, configRoute, configURL } from "../+config"; -import { eventRoute, eventsURL } from "../+events"; -import { Apps, appsRoute, appsURL } from "../+apps"; import { namespaceUrlParam } from "../+namespaces/namespace.store"; import { Workloads } from "../+workloads"; import { UserManagement } from "../+user-management"; import { Storage } from "../+storage"; import { Network } from "../+network"; import { crdStore } from "../+custom-resources/crd.store"; -import { crdRoute, crdURL } from "../+custom-resources"; import { CustomResources } from "../+custom-resources/custom-resources"; import { isActiveRoute } from "../../navigation"; import { isAllowedResource } from "../../../common/rbac"; import { Spinner } from "../spinner"; import { ClusterPageMenuRegistration, clusterPageMenuRegistry, clusterPageRegistry, getExtensionPageUrl } from "../../../extensions/registries"; import { SidebarItem } from "./sidebar-item"; +import { Apps } from "../+apps"; +import * as routes from "../../../common/routes"; +import { Config } from "../+config"; interface Props { className?: string; @@ -76,7 +68,7 @@ export class Sidebar extends React.Component { return Object.entries(crdStore.groups).map(([group, crds]) => { const id = `crd-group:${group}`; - const crdGroupsPageUrl = crdURL({ query: { groups: group } }); + const crdGroupsPageUrl = routes.crdURL({ query: { groups: group } }); return ( @@ -196,25 +188,25 @@ export class Sidebar extends React.Component { } /> } /> } > {this.renderTreeFromTabRoutes(Workloads.tabRoutes)} @@ -222,9 +214,9 @@ export class Sidebar extends React.Component { } > {this.renderTreeFromTabRoutes(Config.tabRoutes)} @@ -232,9 +224,9 @@ export class Sidebar extends React.Component { } > {this.renderTreeFromTabRoutes(Network.tabRoutes)} @@ -242,9 +234,9 @@ export class Sidebar extends React.Component { } > {this.renderTreeFromTabRoutes(Storage.tabRoutes)} @@ -252,24 +244,24 @@ export class Sidebar extends React.Component { } /> } /> } > {this.renderTreeFromTabRoutes(Apps.tabRoutes)} @@ -277,9 +269,9 @@ export class Sidebar extends React.Component { } > {this.renderTreeFromTabRoutes(UserManagement.tabRoutes)} @@ -287,8 +279,8 @@ export class Sidebar extends React.Component { } > diff --git a/src/renderer/ipc/index.tsx b/src/renderer/ipc/index.tsx index 5ae4b48aad8f..3f1f7508cfaf 100644 --- a/src/renderer/ipc/index.tsx +++ b/src/renderer/ipc/index.tsx @@ -28,7 +28,7 @@ import { isMac } from "../../common/vars"; import { invalidKubeconfigHandler } from "./invalid-kubeconfig-handler"; import { ClusterStore } from "../../common/cluster-store"; import { navigate } from "../navigation"; -import { entitySettingsURL } from "../components/+entity-settings"; +import { entitySettingsURL } from "../../common/routes"; function sendToBackchannel(backchannel: string, notificationId: string, data: BackchannelArg): void { notificationsStore.remove(notificationId); diff --git a/src/renderer/navigation/helpers.ts b/src/renderer/navigation/helpers.ts index a6d4c3a07bb5..d2b6553109c3 100644 --- a/src/renderer/navigation/helpers.ts +++ b/src/renderer/navigation/helpers.ts @@ -22,8 +22,8 @@ import type { LocationDescriptor } from "history"; import { matchPath, RouteProps } from "react-router"; import { PageParam, PageSystemParamInit } from "./page-param"; -import { clusterViewRoute, IClusterViewRouteParams } from "../components/cluster-manager/cluster-view.route"; import { navigation } from "./history"; +import { ClusterViewRouteParams, clusterViewRoute } from "../../common/routes"; export function navigate(location: LocationDescriptor) { const currentLocation = navigation.location.pathname; @@ -48,7 +48,7 @@ export function isActiveRoute(route: string | string[] | RouteProps): boolean { } export function getMatchedClusterId(): string { - const matched = matchPath(navigation.location.pathname, { + const matched = matchPath(navigation.location.pathname, { exact: true, path: clusterViewRoute.path }); diff --git a/src/renderer/protocol-handler/app-handlers.ts b/src/renderer/protocol-handler/app-handlers.ts index bbd91ab19b19..ae4d5cf88435 100644 --- a/src/renderer/protocol-handler/app-handlers.ts +++ b/src/renderer/protocol-handler/app-handlers.ts @@ -19,45 +19,41 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { addClusterURL } from "../components/+add-cluster"; -import { catalogURL } from "../components/+catalog"; -import { attemptInstallByInfo, extensionsURL } from "../components/+extensions"; -import { preferencesURL } from "../components/+preferences"; -import { clusterViewURL } from "../components/cluster-manager/cluster-view.route"; +import { attemptInstallByInfo } from "../components/+extensions"; import { LensProtocolRouterRenderer } from "./router"; import { navigate } from "../navigation/helpers"; -import { entitySettingsURL } from "../components/+entity-settings"; import { catalogEntityRegistry } from "../api/catalog-entity-registry"; import { ClusterStore } from "../../common/cluster-store"; import { EXTENSION_NAME_MATCH, EXTENSION_PUBLISHER_MATCH, LensProtocolRouter } from "../../common/protocol-handler"; +import * as routes from "../../common/routes"; export function bindProtocolAddRouteHandlers() { LensProtocolRouterRenderer .getInstance() .addInternalHandler("/preferences", ({ search: { highlight }}) => { - navigate(preferencesURL({ fragment: highlight })); + navigate(routes.preferencesURL({ fragment: highlight })); }) .addInternalHandler("/", () => { - navigate(catalogURL()); + navigate(routes.catalogURL()); }) .addInternalHandler("/landing", () => { - navigate(catalogURL()); + navigate(routes.catalogURL()); }) .addInternalHandler("/landing/view/:group/:kind", ({ pathname: { group, kind } }) => { - navigate(catalogURL({ + navigate(routes.catalogURL({ params: { group, kind } })); }) .addInternalHandler("/cluster", () => { - navigate(addClusterURL()); + navigate(routes.addClusterURL()); }) .addInternalHandler("/entity/:entityId/settings", ({ pathname: { entityId } }) => { const entity = catalogEntityRegistry.getById(entityId); if (entity) { - navigate(entitySettingsURL({ params: { entityId } })); + navigate(routes.entitySettingsURL({ params: { entityId } })); } else { console.log("[APP-HANDLER]: catalog entity with given ID does not exist", { entityId }); } @@ -67,7 +63,7 @@ export function bindProtocolAddRouteHandlers() { const cluster = ClusterStore.getInstance().getById(clusterId); if (cluster) { - navigate(clusterViewURL({ params: { clusterId } })); + navigate(routes.clusterViewURL({ params: { clusterId } })); } else { console.log("[APP-HANDLER]: cluster with given ID does not exist", { clusterId }); } @@ -76,13 +72,13 @@ export function bindProtocolAddRouteHandlers() { const cluster = ClusterStore.getInstance().getById(clusterId); if (cluster) { - navigate(entitySettingsURL({ params: { entityId: clusterId } })); + navigate(routes.entitySettingsURL({ params: { entityId: clusterId } })); } else { console.log("[APP-HANDLER]: cluster with given ID does not exist", { clusterId }); } }) .addInternalHandler("/extensions", () => { - navigate(extensionsURL()); + navigate(routes.extensionsURL()); }) .addInternalHandler(`/extensions/install${LensProtocolRouter.ExtensionUrlSchema}`, ({ pathname, search: { version } }) => { const name = [ @@ -91,7 +87,7 @@ export function bindProtocolAddRouteHandlers() { ].filter(Boolean) .join("/"); - navigate(extensionsURL()); + navigate(routes.extensionsURL()); attemptInstallByInfo({ name, version, requireConfirmation: true }); }); } From 034fc4a33cb25041c654df29007987d9a586c04b Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 14 May 2021 17:24:22 -0400 Subject: [PATCH 2/5] Explicitly initialize registries - Helps moves towards turning on banning CyclicImports Signed-off-by: Sebastian Malton --- src/common/protocol-handler/router.ts | 2 +- src/extensions/extension-loader.ts | 28 +- src/extensions/interfaces/registrations.ts | 2 +- .../__tests__/page-registry.test.ts | 24 +- .../registries/app-preference-registry.ts | 2 - src/extensions/registries/base-registry.ts | 3 +- src/extensions/registries/command-registry.ts | 2 - .../registries/entity-setting-registry.ts | 2 - src/extensions/registries/index.ts | 2 +- .../registries/kube-object-detail-registry.ts | 6 +- .../registries/kube-object-menu-registry.ts | 2 - .../registries/kube-object-status-registry.ts | 2 - src/extensions/registries/menu-registry.ts | 2 - .../registries/page-menu-registry.ts | 2 - src/extensions/registries/page-registry.ts | 8 +- ...andler-registry.ts => protocol-handler.ts} | 0 .../registries/status-bar-registry.ts | 2 - .../registries/welcome-menu-registry.ts | 2 - src/main/index.ts | 2 + .../initializers/index.ts} | 18 +- .../initializers/registries.ts} | 13 +- src/main/menu.ts | 4 +- src/renderer/api/catalog-entity.ts | 4 +- .../api/kube-object-detail-registry.ts | 2 +- src/renderer/bootstrap.tsx | 8 + src/renderer/components/+apps/index.ts | 1 - .../+config-autoscalers/hpa-details.tsx | 19 - .../limit-range-details.tsx | 9 - .../+config-maps/config-map-details.tsx | 19 - .../pod-disruption-budgets-details.tsx | 9 - .../resource-quota-details.tsx | 9 - .../+config-secrets/secret-details.tsx | 9 - .../components/+config/config.command.ts | 66 --- src/renderer/components/+config/index.ts | 1 - .../+custom-resources/crd-details.tsx | 9 - .../+entity-settings/entity-settings.tsx | 4 +- .../components/+events/event-details.tsx | 9 - .../+namespaces/namespace-details.tsx | 9 - .../+network-endpoints/endpoint-details.tsx | 18 - .../+network-ingresses/ingress-details.tsx | 18 - .../network-policy-details.tsx | 19 - .../+network-services/service-details.tsx | 19 - src/renderer/components/+network/index.ts | 1 - src/renderer/components/+nodes/index.ts | 1 - .../components/+nodes/node-details.tsx | 19 - .../pod-security-policy-details.tsx | 9 - .../components/+preferences/preferences.tsx | 6 +- .../storage-class-details.tsx | 19 - .../volume-claim-details.tsx | 19 - .../+storage-volumes/volume-details.tsx | 19 - .../role-binding-details.tsx | 35 -- .../+user-management-roles/role-details.tsx | 34 -- .../service-accounts-details.tsx | 18 - .../service-accounts.tsx | 22 +- src/renderer/components/+welcome/welcome.tsx | 27 +- .../+workloads-cronjobs/cronjob-details.tsx | 18 - .../+workloads-cronjobs/cronjobs.tsx | 9 - .../daemonset-details.tsx | 18 - .../deployment-details.tsx | 18 - .../+workloads-deployments/deployments.tsx | 9 - .../+workloads-jobs/job-details.tsx | 18 - .../+workloads-pods/pod-details.tsx | 19 - .../replicaset-details.tsx | 18 - .../+workloads-replicasets/replicasets.tsx | 9 - .../statefulset-details.tsx | 20 - .../+workloads-statefulsets/statefulsets.tsx | 9 - src/renderer/components/+workloads/index.ts | 1 - .../+workloads/workloads.command.ts | 66 --- src/renderer/components/app.tsx | 16 +- .../cluster-manager/bottom-bar.test.tsx | 29 +- .../components/cluster-manager/bottom-bar.tsx | 4 +- .../cluster-manager/cluster-manager.tsx | 4 +- .../cluster-settings/cluster-settings.tsx | 213 ++++----- ...w-metrics.tsx => cluster-show-metrics.tsx} | 0 .../cluster-settings/components/index.ts | 29 ++ .../components/cluster-settings/index.ts | 1 - .../command-palette/command-container.tsx | 6 +- .../command-palette/command-dialog.tsx | 53 ++- src/renderer/components/dock/dock.tsx | 9 - .../components/hotbar/hotbar-cell.tsx | 1 - .../components/hotbar/hotbar-menu.tsx | 1 - .../components/hotbar/hotbar.commands.tsx | 48 -- .../kube-object-status-icon.tsx | 4 +- .../kube-object/kube-object-details.tsx | 4 +- .../kube-object/kube-object-menu.tsx | 5 +- src/renderer/components/layout/sidebar.tsx | 10 +- .../initializers/command-registry.tsx | 193 ++++++++ .../initializers/entity-settings-registry.ts | 70 +++ src/renderer/initializers/index.ts | 27 ++ .../kube-object-detail-registry.ts | 443 ++++++++++++++++++ .../initializers/kube-object-menu-registry.ts | 68 +++ .../registries.ts} | 45 +- .../welcome-menu-registry.ts} | 33 +- src/renderer/lens-app.tsx | 10 +- webpack.extensions.ts | 1 + 95 files changed, 1104 insertions(+), 1075 deletions(-) rename src/extensions/registries/{protocol-handler-registry.ts => protocol-handler.ts} (100%) rename src/{renderer/components/+apps/apps.command.ts => main/initializers/index.ts} (68%) rename src/{renderer/components/+nodes/node.command.ts => main/initializers/registries.ts} (77%) delete mode 100644 src/renderer/components/+config/config.command.ts delete mode 100644 src/renderer/components/+workloads/workloads.command.ts rename src/renderer/components/cluster-settings/components/{show-metrics.tsx => cluster-show-metrics.tsx} (100%) create mode 100644 src/renderer/components/cluster-settings/components/index.ts delete mode 100644 src/renderer/components/hotbar/hotbar.commands.tsx create mode 100644 src/renderer/initializers/command-registry.tsx create mode 100644 src/renderer/initializers/entity-settings-registry.ts create mode 100644 src/renderer/initializers/index.ts create mode 100644 src/renderer/initializers/kube-object-detail-registry.ts create mode 100644 src/renderer/initializers/kube-object-menu-registry.ts rename src/renderer/{components/+network/network.command.ts => initializers/registries.ts} (57%) rename src/renderer/{components/cluster-settings/cluster-settings.command.ts => initializers/welcome-menu-registry.ts} (67%) diff --git a/src/common/protocol-handler/router.ts b/src/common/protocol-handler/router.ts index 59101b5aa70c..0fd264db60a8 100644 --- a/src/common/protocol-handler/router.ts +++ b/src/common/protocol-handler/router.ts @@ -29,7 +29,7 @@ import { RoutingError, RoutingErrorType } from "./error"; import { ExtensionsStore } from "../../extensions/extensions-store"; import { ExtensionLoader } from "../../extensions/extension-loader"; import type { LensExtension } from "../../extensions/lens-extension"; -import type { RouteHandler, RouteParams } from "../../extensions/registries/protocol-handler-registry"; +import type { RouteHandler, RouteParams } from "../../extensions/registries/protocol-handler"; // IPC channel for protocol actions. Main broadcasts the open-url events to this channel. export const ProtocolHandlerIpcPrefix = "protocol-handler"; diff --git a/src/extensions/extension-loader.ts b/src/extensions/extension-loader.ts index b024ddd761dc..df230601cb81 100644 --- a/src/extensions/extension-loader.ts +++ b/src/extensions/extension-loader.ts @@ -207,11 +207,13 @@ export class ExtensionLoader extends Singleton { } loadOnMain() { + registries.MenuRegistry.createInstance(); + logger.debug(`${logModule}: load on main`); this.autoInitExtensions(async (extension: LensMainExtension) => { // Each .add returns a function to remove the item const removeItems = [ - registries.menuRegistry.add(extension.appMenus) + registries.MenuRegistry.getInstance().add(extension.appMenus) ]; this.events.on("remove", (removedExtension: LensRendererExtension) => { @@ -230,12 +232,12 @@ export class ExtensionLoader extends Singleton { logger.debug(`${logModule}: load on main renderer (cluster manager)`); this.autoInitExtensions(async (extension: LensRendererExtension) => { const removeItems = [ - registries.globalPageRegistry.add(extension.globalPages, extension), - registries.appPreferenceRegistry.add(extension.appPreferences), - registries.entitySettingRegistry.add(extension.entitySettings), - registries.statusBarRegistry.add(extension.statusBarItems), - registries.commandRegistry.add(extension.commands), - registries.welcomeMenuRegistry.add(extension.welcomeMenus), + registries.GlobalPageRegistry.getInstance().add(extension.globalPages, extension), + registries.AppPreferenceRegistry.getInstance().add(extension.appPreferences), + registries.EntitySettingRegistry.getInstance().add(extension.entitySettings), + registries.StatusBarRegistry.getInstance().add(extension.statusBarItems), + registries.CommandRegistry.getInstance().add(extension.commands), + registries.WelcomeMenuRegistry.getInstance().add(extension.welcomeMenus), ]; this.events.on("remove", (removedExtension: LensRendererExtension) => { @@ -260,12 +262,12 @@ export class ExtensionLoader extends Singleton { } const removeItems = [ - registries.clusterPageRegistry.add(extension.clusterPages, extension), - registries.clusterPageMenuRegistry.add(extension.clusterPageMenus, extension), - registries.kubeObjectMenuRegistry.add(extension.kubeObjectMenuItems), - registries.kubeObjectDetailRegistry.add(extension.kubeObjectDetailItems), - registries.kubeObjectStatusRegistry.add(extension.kubeObjectStatusTexts), - registries.commandRegistry.add(extension.commands), + registries.ClusterPageRegistry.getInstance().add(extension.clusterPages, extension), + registries.ClusterPageMenuRegistry.getInstance().add(extension.clusterPageMenus, extension), + registries.KubeObjectMenuRegistry.getInstance().add(extension.kubeObjectMenuItems), + registries.KubeObjectDetailRegistry.getInstance().add(extension.kubeObjectDetailItems), + registries.KubeObjectStatusRegistry.getInstance().add(extension.kubeObjectStatusTexts), + registries.CommandRegistry.getInstance().add(extension.commands), ]; this.events.on("remove", (removedExtension: LensRendererExtension) => { diff --git a/src/extensions/interfaces/registrations.ts b/src/extensions/interfaces/registrations.ts index e2e8d1ed1170..dadde70ceb20 100644 --- a/src/extensions/interfaces/registrations.ts +++ b/src/extensions/interfaces/registrations.ts @@ -26,4 +26,4 @@ export type { KubeObjectStatusRegistration } from "../registries/kube-object-sta export type { PageRegistration, RegisteredPage, PageParams, PageComponentProps, PageComponents, PageTarget } from "../registries/page-registry"; export type { PageMenuRegistration, ClusterPageMenuRegistration, PageMenuComponents } from "../registries/page-menu-registry"; export type { StatusBarRegistration } from "../registries/status-bar-registry"; -export type { ProtocolHandlerRegistration, RouteParams as ProtocolRouteParams, RouteHandler as ProtocolRouteHandler } from "../registries/protocol-handler-registry"; +export type { ProtocolHandlerRegistration, RouteParams as ProtocolRouteParams, RouteHandler as ProtocolRouteHandler } from "../registries/protocol-handler"; diff --git a/src/extensions/registries/__tests__/page-registry.test.ts b/src/extensions/registries/__tests__/page-registry.test.ts index fc40b1bacaa5..9b73c3c1daa1 100644 --- a/src/extensions/registries/__tests__/page-registry.test.ts +++ b/src/extensions/registries/__tests__/page-registry.test.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { getExtensionPageUrl, globalPageRegistry, PageParams } from "../page-registry"; +import { ClusterPageRegistry, getExtensionPageUrl, GlobalPageRegistry, PageParams } from "../page-registry"; import { LensExtension } from "../../lens-extension"; import React from "react"; import { Console } from "console"; @@ -42,7 +42,8 @@ describe("getPageUrl", () => { isBundled: false, isEnabled: true }); - globalPageRegistry.add({ + ClusterPageRegistry.createInstance(); + GlobalPageRegistry.createInstance().add({ id: "page-with-params", components: { Page: () => React.createElement("Page with params") @@ -54,6 +55,11 @@ describe("getPageUrl", () => { }, ext); }); + afterEach(() => { + GlobalPageRegistry.resetInstance(); + ClusterPageRegistry.resetInstance(); + }); + it("returns a page url for extension", () => { expect(getExtensionPageUrl({ extensionId: ext.name })).toBe("/extension/foo-bar"); }); @@ -102,7 +108,8 @@ describe("globalPageRegistry", () => { isBundled: false, isEnabled: true }); - globalPageRegistry.add([ + ClusterPageRegistry.createInstance(); + GlobalPageRegistry.createInstance().add([ { id: "test-page", components: { @@ -123,9 +130,14 @@ describe("globalPageRegistry", () => { ], ext); }); + afterEach(() => { + GlobalPageRegistry.resetInstance(); + ClusterPageRegistry.resetInstance(); + }); + describe("getByPageTarget", () => { it("matching to first registered page without id", () => { - const page = globalPageRegistry.getByPageTarget({ extensionId: ext.name }); + const page = GlobalPageRegistry.getInstance().getByPageTarget({ extensionId: ext.name }); expect(page.id).toEqual(undefined); expect(page.extensionId).toEqual(ext.name); @@ -133,7 +145,7 @@ describe("globalPageRegistry", () => { }); it("returns matching page", () => { - const page = globalPageRegistry.getByPageTarget({ + const page = GlobalPageRegistry.getInstance().getByPageTarget({ pageId: "test-page", extensionId: ext.name }); @@ -142,7 +154,7 @@ describe("globalPageRegistry", () => { }); it("returns null if target not found", () => { - const page = globalPageRegistry.getByPageTarget({ + const page = GlobalPageRegistry.getInstance().getByPageTarget({ pageId: "wrong-page", extensionId: ext.name }); diff --git a/src/extensions/registries/app-preference-registry.ts b/src/extensions/registries/app-preference-registry.ts index 4df13edc6369..fb20034d5220 100644 --- a/src/extensions/registries/app-preference-registry.ts +++ b/src/extensions/registries/app-preference-registry.ts @@ -46,5 +46,3 @@ export class AppPreferenceRegistry extends BaseRegistry { +export class BaseRegistry extends Singleton { private items = observable.map(); getItems(): I[] { diff --git a/src/extensions/registries/command-registry.ts b/src/extensions/registries/command-registry.ts index ba88f623dd31..967fbd12710d 100644 --- a/src/extensions/registries/command-registry.ts +++ b/src/extensions/registries/command-registry.ts @@ -54,5 +54,3 @@ export class CommandRegistry extends BaseRegistry { return super.add(filteredItems, extension); } } - -export const commandRegistry = new CommandRegistry(); diff --git a/src/extensions/registries/entity-setting-registry.ts b/src/extensions/registries/entity-setting-registry.ts index 80b20196c321..54d85ef57f4c 100644 --- a/src/extensions/registries/entity-setting-registry.ts +++ b/src/extensions/registries/entity-setting-registry.ts @@ -68,5 +68,3 @@ export class EntitySettingRegistry extends BaseRegistry (b.priority ?? 50) - (a.priority ?? 50)); } } - -export const entitySettingRegistry = new EntitySettingRegistry(); diff --git a/src/extensions/registries/index.ts b/src/extensions/registries/index.ts index 7056206dafef..5f9bd64aa4a4 100644 --- a/src/extensions/registries/index.ts +++ b/src/extensions/registries/index.ts @@ -32,4 +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"; +export * from "./protocol-handler"; diff --git a/src/extensions/registries/kube-object-detail-registry.ts b/src/extensions/registries/kube-object-detail-registry.ts index 7cc17bbc7ec9..844f5fc0eeec 100644 --- a/src/extensions/registries/kube-object-detail-registry.ts +++ b/src/extensions/registries/kube-object-detail-registry.ts @@ -20,10 +20,12 @@ */ import type React from "react"; +import type { KubeObjectDetailsProps } from "../renderer-api/components"; +import type { KubeObject } from "../renderer-api/k8s-api"; import { BaseRegistry } from "./base-registry"; export interface KubeObjectDetailComponents { - Details: React.ComponentType; + Details: React.ComponentType>; } export interface KubeObjectDetailRegistration { @@ -42,5 +44,3 @@ export class KubeObjectDetailRegistry extends BaseRegistry (b.priority ?? 50) - (a.priority ?? 50)); } } - -export const kubeObjectDetailRegistry = new KubeObjectDetailRegistry(); diff --git a/src/extensions/registries/kube-object-menu-registry.ts b/src/extensions/registries/kube-object-menu-registry.ts index 414d55db5994..fbbc872d2baa 100644 --- a/src/extensions/registries/kube-object-menu-registry.ts +++ b/src/extensions/registries/kube-object-menu-registry.ts @@ -39,5 +39,3 @@ export class KubeObjectMenuRegistry extends BaseRegistry { } - -export const menuRegistry = new MenuRegistry(); diff --git a/src/extensions/registries/page-menu-registry.ts b/src/extensions/registries/page-menu-registry.ts index 08df7b1c7946..53dc7431719a 100644 --- a/src/extensions/registries/page-menu-registry.ts +++ b/src/extensions/registries/page-menu-registry.ts @@ -77,5 +77,3 @@ export class ClusterPageMenuRegistry extends PageMenuRegistry { @@ -96,7 +96,7 @@ export function getExtensionPageUrl(target: PageTarget): string { return pageUrl.href.replace(pageUrl.origin, ""); } -export class PageRegistry extends BaseRegistry { +class PageRegistry extends BaseRegistry { protected getRegisteredItem(page: PageRegistration, ext: LensExtension): RegisteredPage { const { id: pageId } = page; const extensionId = ext.name; @@ -139,5 +139,5 @@ export class PageRegistry extends BaseRegistry } } -export const globalPageRegistry = new PageRegistry(); -export const clusterPageRegistry = new PageRegistry(); +export class ClusterPageRegistry extends PageRegistry {} +export class GlobalPageRegistry extends PageRegistry {} diff --git a/src/extensions/registries/protocol-handler-registry.ts b/src/extensions/registries/protocol-handler.ts similarity index 100% rename from src/extensions/registries/protocol-handler-registry.ts rename to src/extensions/registries/protocol-handler.ts diff --git a/src/extensions/registries/status-bar-registry.ts b/src/extensions/registries/status-bar-registry.ts index 0814f9cc7afd..2afdee76a61b 100644 --- a/src/extensions/registries/status-bar-registry.ts +++ b/src/extensions/registries/status-bar-registry.ts @@ -41,5 +41,3 @@ export interface StatusBarRegistration extends StatusBarRegistrationV2 { export class StatusBarRegistry extends BaseRegistry { } - -export const statusBarRegistry = new StatusBarRegistry(); diff --git a/src/extensions/registries/welcome-menu-registry.ts b/src/extensions/registries/welcome-menu-registry.ts index 077f1d3aea80..709202845975 100644 --- a/src/extensions/registries/welcome-menu-registry.ts +++ b/src/extensions/registries/welcome-menu-registry.ts @@ -28,5 +28,3 @@ export interface WelcomeMenuRegistration { } export class WelcomeMenuRegistry extends BaseRegistry {} - -export const welcomeMenuRegistry = new WelcomeMenuRegistry(); diff --git a/src/main/index.ts b/src/main/index.ts index 2585b0740ece..7ded3e220973 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -55,6 +55,7 @@ import { HotbarStore } from "../common/hotbar-store"; import { HelmRepoManager } from "./helm/helm-repo-manager"; import { KubeconfigSyncManager } from "./catalog-sources"; import { handleWsUpgrade } from "./proxy/ws-upgrade"; +import { initRegistries } from "./initializers"; const workingDir = path.join(app.getPath("appData"), appName); const cleanup = disposer(); @@ -169,6 +170,7 @@ app.on("ready", async () => { app.exit(); } + initRegistries(); const extensionDiscovery = ExtensionDiscovery.createInstance(); ExtensionLoader.createInstance().init(); diff --git a/src/renderer/components/+apps/apps.command.ts b/src/main/initializers/index.ts similarity index 68% rename from src/renderer/components/+apps/apps.command.ts rename to src/main/initializers/index.ts index eca0529bc4d3..9cf15b3771d7 100644 --- a/src/renderer/components/+apps/apps.command.ts +++ b/src/main/initializers/index.ts @@ -19,20 +19,4 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { navigate } from "../../navigation"; -import { commandRegistry } from "../../../extensions/registries/command-registry"; -import { helmChartsURL, releaseURL } from "../../../common/routes"; - -commandRegistry.add({ - id: "cluster.viewHelmCharts", - title: "Cluster: View Helm Charts", - scope: "entity", - action: () => navigate(helmChartsURL()) -}); - -commandRegistry.add({ - id: "cluster.viewHelmReleases", - title: "Cluster: View Helm Releases", - scope: "entity", - action: () => navigate(releaseURL()) -}); +export * from "./registries"; diff --git a/src/renderer/components/+nodes/node.command.ts b/src/main/initializers/registries.ts similarity index 77% rename from src/renderer/components/+nodes/node.command.ts rename to src/main/initializers/registries.ts index 314381b5a44b..28fcdff1a1ba 100644 --- a/src/renderer/components/+nodes/node.command.ts +++ b/src/main/initializers/registries.ts @@ -19,13 +19,8 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { navigate } from "../../navigation"; -import { commandRegistry } from "../../../extensions/registries/command-registry"; -import { nodesURL } from "../../../common/routes"; +import * as registries from "../../extensions/registries"; -commandRegistry.add({ - id: "cluster.viewNodes", - title: "Cluster: View Nodes", - scope: "entity", - action: () => navigate(nodesURL()) -}); +export function initRegistries() { + registries.MenuRegistry.createInstance(); +} diff --git a/src/main/menu.ts b/src/main/menu.ts index 7d80ce162e1b..5b60541baa2f 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -23,7 +23,7 @@ import { app, BrowserWindow, dialog, ipcMain, IpcMainEvent, Menu, MenuItem, Menu import { autorun } from "mobx"; import type { WindowManager } from "./window-manager"; import { appName, isMac, isWindows, isTestEnv, docsUrl, supportUrl, productName } from "../common/vars"; -import { menuRegistry } from "../extensions/registries/menu-registry"; +import { MenuRegistry } from "../extensions/registries/menu-registry"; import logger from "./logger"; import { exitApp } from "./exit-app"; import { broadcastMessage } from "../common/ipc"; @@ -255,7 +255,7 @@ export function buildMenu(windowManager: WindowManager) { }; // Modify menu from extensions-api - menuRegistry.getItems().forEach(({ parentId, ...menuItem }) => { + MenuRegistry.getInstance().getItems().forEach(({ parentId, ...menuItem }) => { try { const topMenu = appMenu[parentId as MenuTopId].submenu as MenuItemConstructorOptions[]; diff --git a/src/renderer/api/catalog-entity.ts b/src/renderer/api/catalog-entity.ts index 63a5ce62eb7c..1a0154defe03 100644 --- a/src/renderer/api/catalog-entity.ts +++ b/src/renderer/api/catalog-entity.ts @@ -20,7 +20,7 @@ */ import { navigate } from "../navigation"; -import { commandRegistry } from "../../extensions/registries"; +import { CommandRegistry } from "../../extensions/registries"; import type { CatalogEntity } from "../../common/catalog"; export { CatalogCategory, CatalogEntity } from "../../common/catalog"; @@ -37,6 +37,6 @@ export type { export const catalogEntityRunContext = { navigate: (url: string) => navigate(url), setCommandPaletteContext: (entity?: CatalogEntity) => { - commandRegistry.activeEntity = entity; + CommandRegistry.getInstance().activeEntity = entity; } }; diff --git a/src/renderer/api/kube-object-detail-registry.ts b/src/renderer/api/kube-object-detail-registry.ts index 0afc7907da78..1693fd56f17d 100644 --- a/src/renderer/api/kube-object-detail-registry.ts +++ b/src/renderer/api/kube-object-detail-registry.ts @@ -19,4 +19,4 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export { kubeObjectDetailRegistry } from "../../extensions/registries/kube-object-detail-registry"; +export { KubeObjectDetailRegistry } from "../../extensions/registries/kube-object-detail-registry"; diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx index 62430ac788c0..0a59d069282a 100644 --- a/src/renderer/bootstrap.tsx +++ b/src/renderer/bootstrap.tsx @@ -43,6 +43,7 @@ import { ThemeStore } from "./theme.store"; import { HelmRepoManager } from "../main/helm/helm-repo-manager"; import { ExtensionInstallationStateStore } from "./components/+extensions/extension-install.store"; import { DefaultProps } from "./mui-base-theme"; +import { initCommandRegistry, initEntitySettingsRegistry, initKubeObjectMenuRegistry, initRegistries, initWelcomeMenuRegistry, intiKubeObjectDetailRegistry } from "./initializers"; /** * If this is a development buid, wait a second to attach @@ -74,6 +75,13 @@ export async function bootstrap(App: AppComponent) { await attachChromeDebugger(); rootElem.classList.toggle("is-mac", isMac); + initRegistries(); + initCommandRegistry(); + initEntitySettingsRegistry(); + initKubeObjectMenuRegistry(); + intiKubeObjectDetailRegistry(); + initWelcomeMenuRegistry(); + ExtensionLoader.createInstance().init(); ExtensionDiscovery.createInstance().init(); diff --git a/src/renderer/components/+apps/index.ts b/src/renderer/components/+apps/index.ts index f0fa78df0376..4c8d6dfea053 100644 --- a/src/renderer/components/+apps/index.ts +++ b/src/renderer/components/+apps/index.ts @@ -20,4 +20,3 @@ */ export * from "./apps"; -export * from "./apps.command"; diff --git a/src/renderer/components/+config-autoscalers/hpa-details.tsx b/src/renderer/components/+config-autoscalers/hpa-details.tsx index 5b9cf76f97ba..1a6db54e78c6 100644 --- a/src/renderer/components/+config-autoscalers/hpa-details.tsx +++ b/src/renderer/components/+config-autoscalers/hpa-details.tsx @@ -29,11 +29,9 @@ import { Badge } from "../badge"; import { KubeObjectDetailsProps, getDetailsUrl } from "../kube-object"; import { cssNames } from "../../utils"; import { HorizontalPodAutoscaler, HpaMetricType, IHpaMetric } from "../../api/endpoints/hpa.api"; -import { KubeEventDetails } from "../+events/kube-event-details"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { lookupApiLink } from "../../api/kube-api"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; -import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; interface Props extends KubeObjectDetailsProps { } @@ -150,20 +148,3 @@ export class HpaDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "HorizontalPodAutoscaler", - apiVersions: ["autoscaling/v2beta1"], - components: { - Details: (props) => - } -}); - -kubeObjectDetailRegistry.add({ - kind: "HorizontalPodAutoscaler", - apiVersions: ["autoscaling/v2beta1"], - priority: 5, - components: { - Details: (props) => - } -}); 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 d4c9d18f28d5..853102931369 100644 --- a/src/renderer/components/+config-limit-ranges/limit-range-details.tsx +++ b/src/renderer/components/+config-limit-ranges/limit-range-details.tsx @@ -25,7 +25,6 @@ import React from "react"; import { observer } from "mobx-react"; 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"; import { DrawerItem } from "../drawer/drawer-item"; import { Badge } from "../badge"; @@ -108,11 +107,3 @@ export class LimitRangeDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "LimitRange", - apiVersions: ["v1"], - components: { - Details: (props) => - } -}); diff --git a/src/renderer/components/+config-maps/config-map-details.tsx b/src/renderer/components/+config-maps/config-map-details.tsx index b9dd05cfaaa3..f1af70047d7b 100644 --- a/src/renderer/components/+config-maps/config-map-details.tsx +++ b/src/renderer/components/+config-maps/config-map-details.tsx @@ -28,12 +28,10 @@ import { DrawerTitle } from "../drawer"; import { Notifications } from "../notifications"; import { Input } from "../input"; import { Button } from "../button"; -import { KubeEventDetails } from "../+events/kube-event-details"; import { configMapsStore } from "./config-maps.store"; 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"; interface Props extends KubeObjectDetailsProps { } @@ -115,20 +113,3 @@ export class ConfigMapDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "ConfigMap", - apiVersions: ["v1"], - components: { - Details: (props) => - } -}); - -kubeObjectDetailRegistry.add({ - kind: "ConfigMap", - apiVersions: ["v1"], - priority: 5, - components: { - Details: (props) => - } -}); 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 ddb95aa62890..ad4bc41dc1e5 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 @@ -28,7 +28,6 @@ import { Badge } from "../badge"; 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"; interface Props extends KubeObjectDetailsProps { } @@ -74,11 +73,3 @@ export class PodDisruptionBudgetDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "PodDisruptionBudget", - apiVersions: ["policy/v1beta1"], - components: { - Details: (props) => - } -}); 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 662a8e26ec20..cf7c505dcfb1 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx @@ -30,7 +30,6 @@ 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"; -import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; interface Props extends KubeObjectDetailsProps { } @@ -117,11 +116,3 @@ export class ResourceQuotaDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "ResourceQuota", - apiVersions: ["v1"], - components: { - Details: (props) => - } -}); diff --git a/src/renderer/components/+config-secrets/secret-details.tsx b/src/renderer/components/+config-secrets/secret-details.tsx index 5a4aaca64ef3..18ea67d5f7e9 100644 --- a/src/renderer/components/+config-secrets/secret-details.tsx +++ b/src/renderer/components/+config-secrets/secret-details.tsx @@ -35,7 +35,6 @@ import { secretsStore } from "./secrets.store"; 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"; interface Props extends KubeObjectDetailsProps { } @@ -138,11 +137,3 @@ export class SecretDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "Secret", - apiVersions: ["v1"], - components: { - Details: (props) => - } -}); diff --git a/src/renderer/components/+config/config.command.ts b/src/renderer/components/+config/config.command.ts deleted file mode 100644 index 4e660fadeadd..000000000000 --- a/src/renderer/components/+config/config.command.ts +++ /dev/null @@ -1,66 +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 { navigate } from "../../navigation"; -import { commandRegistry } from "../../../extensions/registries/command-registry"; -import * as routes from "../../../common/routes"; - -commandRegistry.add({ - id: "cluster.viewConfigMaps", - title: "Cluster: View ConfigMaps", - scope: "entity", - action: () => navigate(routes.configMapsURL()) -}); - -commandRegistry.add({ - id: "cluster.viewSecrets", - title: "Cluster: View Secrets", - scope: "entity", - action: () => navigate(routes.secretsURL()) -}); - -commandRegistry.add({ - id: "cluster.viewResourceQuotas", - title: "Cluster: View ResourceQuotas", - scope: "entity", - action: () => navigate(routes.resourceQuotaURL()) -}); - -commandRegistry.add({ - id: "cluster.viewLimitRanges", - title: "Cluster: View LimitRanges", - scope: "entity", - action: () => navigate(routes.limitRangeURL()) -}); - -commandRegistry.add({ - id: "cluster.viewHorizontalPodAutoscalers", - title: "Cluster: View HorizontalPodAutoscalers (HPA)", - scope: "entity", - action: () => navigate(routes.hpaURL()) -}); - -commandRegistry.add({ - id: "cluster.viewPodDisruptionBudget", - title: "Cluster: View PodDisruptionBudgets", - scope: "entity", - action: () => navigate(routes.pdbURL()) -}); diff --git a/src/renderer/components/+config/index.ts b/src/renderer/components/+config/index.ts index 0d30c3f64a65..521bf1d3a13e 100644 --- a/src/renderer/components/+config/index.ts +++ b/src/renderer/components/+config/index.ts @@ -20,4 +20,3 @@ */ export * from "./config"; -export * from "./config.command"; diff --git a/src/renderer/components/+custom-resources/crd-details.tsx b/src/renderer/components/+custom-resources/crd-details.tsx index 757f38970210..74fa17b4f56e 100644 --- a/src/renderer/components/+custom-resources/crd-details.tsx +++ b/src/renderer/components/+custom-resources/crd-details.tsx @@ -33,7 +33,6 @@ 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"; -import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; interface Props extends KubeObjectDetailsProps { } @@ -156,11 +155,3 @@ export class CRDDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "CustomResourceDefinition", - apiVersions: ["apiextensions.k8s.io/v1", "apiextensions.k8s.io/v1beta1"], - components: { - Details: (props) => - } -}); diff --git a/src/renderer/components/+entity-settings/entity-settings.tsx b/src/renderer/components/+entity-settings/entity-settings.tsx index a1aacbc7d539..e33c4b3d413b 100644 --- a/src/renderer/components/+entity-settings/entity-settings.tsx +++ b/src/renderer/components/+entity-settings/entity-settings.tsx @@ -30,7 +30,7 @@ import { navigation } from "../../navigation"; import { Tabs, Tab } from "../tabs"; import type { CatalogEntity } from "../../api/catalog-entity"; import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; -import { entitySettingRegistry } from "../../../extensions/registries"; +import { EntitySettingRegistry } from "../../../extensions/registries"; import type { EntitySettingsRouteParams } from "../../../common/routes"; import { groupBy } from "lodash"; @@ -52,7 +52,7 @@ export class EntitySettings extends React.Component { get menuItems() { if (!this.entity) return []; - return entitySettingRegistry.getItemsForKind(this.entity.kind, this.entity.apiVersion, this.entity.metadata.source); + return EntitySettingRegistry.getInstance().getItemsForKind(this.entity.kind, this.entity.apiVersion, this.entity.metadata.source); } async componentDidMount() { diff --git a/src/renderer/components/+events/event-details.tsx b/src/renderer/components/+events/event-details.tsx index ec503739646b..639c4b9dcf1a 100644 --- a/src/renderer/components/+events/event-details.tsx +++ b/src/renderer/components/+events/event-details.tsx @@ -31,7 +31,6 @@ 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"; -import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; import { LocaleDate } from "../locale-date"; interface Props extends KubeObjectDetailsProps { @@ -95,11 +94,3 @@ export class EventDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "Event", - apiVersions: ["v1"], - components: { - Details: (props) => - } -}); diff --git a/src/renderer/components/+namespaces/namespace-details.tsx b/src/renderer/components/+namespaces/namespace-details.tsx index d8e5e90f7bb5..28248a3ce709 100644 --- a/src/renderer/components/+namespaces/namespace-details.tsx +++ b/src/renderer/components/+namespaces/namespace-details.tsx @@ -32,7 +32,6 @@ import { Link } from "react-router-dom"; import { Spinner } from "../spinner"; import { resourceQuotaStore } from "../+config-resource-quotas/resource-quotas.store"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; -import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; import { limitRangeStore } from "../+config-limit-ranges/limit-ranges.store"; interface Props extends KubeObjectDetailsProps { @@ -95,11 +94,3 @@ export class NamespaceDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "Namespace", - apiVersions: ["v1"], - components: { - Details: (props) => - } -}); diff --git a/src/renderer/components/+network-endpoints/endpoint-details.tsx b/src/renderer/components/+network-endpoints/endpoint-details.tsx index d8cc20f52937..8554a4b2f7ab 100644 --- a/src/renderer/components/+network-endpoints/endpoint-details.tsx +++ b/src/renderer/components/+network-endpoints/endpoint-details.tsx @@ -24,12 +24,10 @@ import "./endpoint-details.scss"; import React from "react"; import { observer } from "mobx-react"; import { DrawerTitle } from "../drawer"; -import { KubeEventDetails } from "../+events/kube-event-details"; 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"; interface Props extends KubeObjectDetailsProps { } @@ -54,19 +52,3 @@ export class EndpointDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "Endpoints", - apiVersions: ["v1"], - components: { - Details: (props) => - } -}); -kubeObjectDetailRegistry.add({ - kind: "Endpoints", - apiVersions: ["v1"], - priority: 5, - components: { - Details: (props) => - } -}); diff --git a/src/renderer/components/+network-ingresses/ingress-details.tsx b/src/renderer/components/+network-ingresses/ingress-details.tsx index 8e9ddf7bb4ab..ae1e553fc21c 100644 --- a/src/renderer/components/+network-ingresses/ingress-details.tsx +++ b/src/renderer/components/+network-ingresses/ingress-details.tsx @@ -27,13 +27,11 @@ import { reaction } from "mobx"; import { DrawerItem, DrawerTitle } from "../drawer"; 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 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"; import { getBackendServiceNamePort } from "../../api/endpoints/ingress.api"; import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting"; import { ClusterStore } from "../../../common/cluster-store"; @@ -166,19 +164,3 @@ export class IngressDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "Ingress", - apiVersions: ["networking.k8s.io/v1", "extensions/v1beta1"], - components: { - Details: (props) => - } -}); -kubeObjectDetailRegistry.add({ - kind: "Ingress", - apiVersions: ["networking.k8s.io/v1", "extensions/v1beta1"], - priority: 5, - components: { - Details: (props) => - } -}); diff --git a/src/renderer/components/+network-policies/network-policy-details.tsx b/src/renderer/components/+network-policies/network-policy-details.tsx index 289d139fb559..7ac8f2f7bfa9 100644 --- a/src/renderer/components/+network-policies/network-policy-details.tsx +++ b/src/renderer/components/+network-policies/network-policy-details.tsx @@ -27,11 +27,9 @@ import { DrawerItem, DrawerTitle } from "../drawer"; 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 type { KubeObjectDetailsProps } from "../kube-object"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; -import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; interface Props extends KubeObjectDetailsProps { } @@ -172,20 +170,3 @@ export class NetworkPolicyDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "NetworkPolicy", - apiVersions: ["networking.k8s.io/v1"], - components: { - Details: (props) => - } -}); - -kubeObjectDetailRegistry.add({ - kind: "NetworkPolicy", - apiVersions: ["networking.k8s.io/v1"], - priority: 5, - components: { - Details: (props) => - } -}); diff --git a/src/renderer/components/+network-services/service-details.tsx b/src/renderer/components/+network-services/service-details.tsx index f04b5687afd5..9a90c129fc9e 100644 --- a/src/renderer/components/+network-services/service-details.tsx +++ b/src/renderer/components/+network-services/service-details.tsx @@ -25,14 +25,12 @@ import React from "react"; import { disposeOnUnmount, observer } from "mobx-react"; import { DrawerItem, DrawerTitle } from "../drawer"; import { Badge } from "../badge"; -import { KubeEventDetails } from "../+events/kube-event-details"; 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"; import { ServiceDetailsEndpoint } from "./service-details-endpoint"; -import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; import { kubeWatchApi } from "../../api/kube-watch-api"; interface Props extends KubeObjectDetailsProps { @@ -105,20 +103,3 @@ export class ServiceDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "Service", - apiVersions: ["v1"], - components: { - Details: (props) => - } -}); - -kubeObjectDetailRegistry.add({ - kind: "Service", - apiVersions: ["v1"], - priority: 5, - components: { - Details: (props) => - } -}); diff --git a/src/renderer/components/+network/index.ts b/src/renderer/components/+network/index.ts index bfb7c13b58cf..3d501faf9b93 100644 --- a/src/renderer/components/+network/index.ts +++ b/src/renderer/components/+network/index.ts @@ -20,4 +20,3 @@ */ export * from "./network"; -export * from "./network.command"; diff --git a/src/renderer/components/+nodes/index.ts b/src/renderer/components/+nodes/index.ts index eb9f3cd2c19e..dbcdba942269 100644 --- a/src/renderer/components/+nodes/index.ts +++ b/src/renderer/components/+nodes/index.ts @@ -21,4 +21,3 @@ export * from "./nodes"; export * from "./node-details"; -export * from "./node.command"; diff --git a/src/renderer/components/+nodes/node-details.tsx b/src/renderer/components/+nodes/node-details.tsx index df98312d17b6..681a4f5b87ed 100644 --- a/src/renderer/components/+nodes/node-details.tsx +++ b/src/renderer/components/+nodes/node-details.tsx @@ -36,8 +36,6 @@ import { NodeCharts } from "./node-charts"; import { reaction } from "mobx"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; -import { KubeEventDetails } from "../+events/kube-event-details"; -import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting"; import { ClusterStore } from "../../../common/cluster-store"; @@ -177,20 +175,3 @@ export class NodeDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "Node", - apiVersions: ["v1"], - components: { - Details: (props) => - } -}); - -kubeObjectDetailRegistry.add({ - kind: "Node", - apiVersions: ["v1"], - priority: 5, - components: { - Details: (props) => - } -}); 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 eacc4f769639..abdefe92288b 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 @@ -29,7 +29,6 @@ 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"; -import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; interface Props extends KubeObjectDetailsProps { } @@ -231,11 +230,3 @@ export class PodSecurityPolicyDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "PodSecurityPolicy", - apiVersions: ["policy/v1beta1"], - components: { - Details: (props) => - } -}); diff --git a/src/renderer/components/+preferences/preferences.tsx b/src/renderer/components/+preferences/preferences.tsx index f6eda62b8242..7aebeef6b2cf 100644 --- a/src/renderer/components/+preferences/preferences.tsx +++ b/src/renderer/components/+preferences/preferences.tsx @@ -27,7 +27,7 @@ import { computed, observable, reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; import { isWindows } from "../../../common/vars"; -import { appPreferenceRegistry, RegisteredAppPreference } from "../../../extensions/registries/app-preference-registry"; +import { AppPreferenceRegistry, RegisteredAppPreference } from "../../../extensions/registries/app-preference-registry"; import { UserStore } from "../../../common/user-store"; import { ThemeStore } from "../../theme.store"; import { Input } from "../input"; @@ -88,7 +88,7 @@ export class Preferences extends React.Component { }; renderNavigation() { - const extensions = appPreferenceRegistry.getItems().filter(e => !e.showInPreferencesTab); + const extensions = AppPreferenceRegistry.getInstance().getItems().filter(e => !e.showInPreferencesTab); return ( @@ -120,7 +120,7 @@ export class Preferences extends React.Component { } render() { - const extensions = appPreferenceRegistry.getItems(); + const extensions = AppPreferenceRegistry.getInstance().getItems(); const telemetryExtensions = extensions.filter(e => e.showInPreferencesTab == Pages.Telemetry); const defaultShell = process.env.SHELL || process.env.PTYSHELL diff --git a/src/renderer/components/+storage-classes/storage-class-details.tsx b/src/renderer/components/+storage-classes/storage-class-details.tsx index e99501b963e7..0d2b9e06008f 100644 --- a/src/renderer/components/+storage-classes/storage-class-details.tsx +++ b/src/renderer/components/+storage-classes/storage-class-details.tsx @@ -25,12 +25,10 @@ import React from "react"; import startCase from "lodash/startCase"; import { DrawerItem, DrawerTitle } from "../drawer"; import { Badge } from "../badge"; -import { KubeEventDetails } from "../+events/kube-event-details"; import { observer } from "mobx-react"; 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"; import { VolumeDetailsList } from "../+storage-volumes/volume-details-list"; import { volumesStore } from "../+storage-volumes/volumes.store"; @@ -89,20 +87,3 @@ export class StorageClassDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "StorageClass", - apiVersions: ["storage.k8s.io/v1"], - components: { - Details: (props) => - } -}); - -kubeObjectDetailRegistry.add({ - kind: "StorageClass", - apiVersions: ["storage.k8s.io/v1"], - priority: 5, - components: { - Details: (props) => - } -}); 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 c2ae2f672f76..271fae5eadfb 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx @@ -28,13 +28,11 @@ import { DrawerItem, DrawerTitle } from "../drawer"; import { Badge } from "../badge"; import { podsStore } from "../+workloads-pods/pods.store"; import { Link } from "react-router-dom"; -import { KubeEventDetails } from "../+events/kube-event-details"; 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 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"; @@ -116,20 +114,3 @@ export class PersistentVolumeClaimDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "PersistentVolumeClaim", - apiVersions: ["v1"], - components: { - Details: (props) => - } -}); - -kubeObjectDetailRegistry.add({ - kind: "PersistentVolumeClaim", - apiVersions: ["v1"], - priority: 5, - components: { - Details: (props) => - } -}); diff --git a/src/renderer/components/+storage-volumes/volume-details.tsx b/src/renderer/components/+storage-volumes/volume-details.tsx index ff718b4352bd..66354db988cc 100644 --- a/src/renderer/components/+storage-volumes/volume-details.tsx +++ b/src/renderer/components/+storage-volumes/volume-details.tsx @@ -27,11 +27,9 @@ import { Link } from "react-router-dom"; import { observer } from "mobx-react"; import { DrawerItem, DrawerTitle } from "../drawer"; import { Badge } from "../badge"; -import { KubeEventDetails } from "../+events/kube-event-details"; import { PersistentVolume, pvcApi } from "../../api/endpoints"; import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; -import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; interface Props extends KubeObjectDetailsProps { } @@ -121,20 +119,3 @@ export class PersistentVolumeDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "PersistentVolume", - apiVersions: ["v1"], - components: { - Details: (props) => - } -}); - -kubeObjectDetailRegistry.add({ - kind: "PersistentVolume", - apiVersions: ["v1"], - priority: 5, - components: { - Details: (props) => - } -}); 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 c42cdbebed53..5b08893f25f4 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 @@ -28,14 +28,12 @@ import { autobind, prevDefault } from "../../utils"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { ConfirmDialog } from "../confirm-dialog"; import { DrawerTitle } from "../drawer"; -import { KubeEventDetails } from "../+events/kube-event-details"; 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 type { KubeObjectDetailsProps } from "../kube-object"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; -import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; interface Props extends KubeObjectDetailsProps { } @@ -145,36 +143,3 @@ export class RoleBindingDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "RoleBinding", - apiVersions: ["rbac.authorization.k8s.io/v1"], - components: { - Details: (props) => - } -}); -kubeObjectDetailRegistry.add({ - kind: "RoleBinding", - apiVersions: ["rbac.authorization.k8s.io/v1"], - priority: 5, - components: { - Details: (props) => - } -}); - - -kubeObjectDetailRegistry.add({ - kind: "ClusterRoleBinding", - apiVersions: ["rbac.authorization.k8s.io/v1"], - components: { - Details: (props) => - } -}); -kubeObjectDetailRegistry.add({ - kind: "ClusterRoleBinding", - apiVersions: ["rbac.authorization.k8s.io/v1"], - priority: 5, - components: { - Details: (props) => - } -}); diff --git a/src/renderer/components/+user-management-roles/role-details.tsx b/src/renderer/components/+user-management-roles/role-details.tsx index 34fb92f8160e..0807944915cd 100644 --- a/src/renderer/components/+user-management-roles/role-details.tsx +++ b/src/renderer/components/+user-management-roles/role-details.tsx @@ -23,12 +23,10 @@ import "./role-details.scss"; import React from "react"; import { DrawerTitle } from "../drawer"; -import { KubeEventDetails } from "../+events/kube-event-details"; import { observer } from "mobx-react"; 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"; interface Props extends KubeObjectDetailsProps { } @@ -85,35 +83,3 @@ export class RoleDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "Role", - apiVersions: ["rbac.authorization.k8s.io/v1"], - components: { - Details: (props) => - } -}); -kubeObjectDetailRegistry.add({ - kind: "Role", - apiVersions: ["rbac.authorization.k8s.io/v1"], - priority: 5, - components: { - Details: (props) => - } -}); - -kubeObjectDetailRegistry.add({ - kind: "ClusterRole", - apiVersions: ["rbac.authorization.k8s.io/v1"], - components: { - Details: (props) => - } -}); -kubeObjectDetailRegistry.add({ - kind: "ClusterRole", - apiVersions: ["rbac.authorization.k8s.io/v1"], - priority: 5, - components: { - Details: (props) => - } -}); diff --git a/src/renderer/components/+user-management-service-accounts/service-accounts-details.tsx b/src/renderer/components/+user-management-service-accounts/service-accounts-details.tsx index d168398d760d..59628be7fac0 100644 --- a/src/renderer/components/+user-management-service-accounts/service-accounts-details.tsx +++ b/src/renderer/components/+user-management-service-accounts/service-accounts-details.tsx @@ -30,11 +30,9 @@ import { disposeOnUnmount, observer } from "mobx-react"; import { secretsStore } from "../+config-secrets/secrets.store"; import { Link } from "react-router-dom"; import { Secret, ServiceAccount } from "../../api/endpoints"; -import { KubeEventDetails } from "../+events/kube-event-details"; import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; import { Icon } from "../icon"; -import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; interface Props extends KubeObjectDetailsProps { } @@ -158,19 +156,3 @@ export class ServiceAccountsDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "ServiceAccount", - apiVersions: ["v1"], - components: { - Details: (props) => - } -}); -kubeObjectDetailRegistry.add({ - kind: "ServiceAccount", - apiVersions: ["v1"], - priority: 5, - components: { - Details: (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 0299e0f7f9de..624360c2ffb7 100644 --- a/src/renderer/components/+user-management-service-accounts/service-accounts.tsx +++ b/src/renderer/components/+user-management-service-accounts/service-accounts.tsx @@ -25,16 +25,14 @@ import React from "react"; import { observer } from "mobx-react"; 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 { KubeObjectListLayout, KubeObjectMenuProps } from "../kube-object"; import { serviceAccountsStore } from "./service-accounts.store"; import { CreateServiceAccountDialog } from "./create-service-account-dialog"; -import { kubeObjectMenuRegistry } from "../../../extensions/registries/kube-object-menu-registry"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { ServiceAccountsRouteParams } from "../../../common/routes"; +import { MenuItem } from "../menu"; +import { Icon } from "../icon"; +import { openServiceAccountKubeConfig } from "../kubeconfig-dialog"; enum columnId { name = "name", @@ -89,21 +87,13 @@ export class ServiceAccounts extends React.Component { } } -function ServiceAccountMenu(props: KubeObjectMenuProps) { +export function ServiceAccountMenu(props: KubeObjectMenuProps) { const { object, toolbar } = props; return ( openServiceAccountKubeConfig(object)}> - + Kubeconfig ); } - -kubeObjectMenuRegistry.add({ - kind: "ServiceAccount", - apiVersions: ["v1"], - components: { - MenuItem: ServiceAccountMenu - } -}); diff --git a/src/renderer/components/+welcome/welcome.tsx b/src/renderer/components/+welcome/welcome.tsx index 61577989423b..ed3d9b5dc490 100644 --- a/src/renderer/components/+welcome/welcome.tsx +++ b/src/renderer/components/+welcome/welcome.tsx @@ -24,33 +24,10 @@ import React from "react"; import { observer } from "mobx-react"; import { Icon } from "../icon"; import { productName, slackUrl } from "../../../common/vars"; -import { welcomeMenuRegistry } from "../../../extensions/registries"; -import { navigate } from "../../navigation"; -import { catalogURL, preferencesURL } from "../../../common/routes"; +import { WelcomeMenuRegistry } from "../../../extensions/registries"; @observer export class Welcome extends React.Component { - - componentDidMount() { - if (welcomeMenuRegistry.getItems().find((item) => item.title === "Browse Your Catalog")) { - return; - } - - welcomeMenuRegistry.add({ - title: "Browse Your Catalog", - icon: "view_list", - click: () => navigate(catalogURL()) - }); - - if (welcomeMenuRegistry.getItems().length === 1) { - welcomeMenuRegistry.add({ - title: "Configure Preferences", - icon: "settings", - click: () => navigate(preferencesURL()) - }); - } - } - render() { return (
@@ -65,7 +42,7 @@ export class Welcome extends React.Component {

    - { welcomeMenuRegistry.getItems().map((item, index) => ( + {WelcomeMenuRegistry.getInstance().getItems().map((item, index) => (
  • item.click()}> {typeof item.title === "string" ? item.title : item.title()}
  • diff --git a/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx b/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx index e86f4f5c8ef4..12f919b4e6db 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx @@ -28,12 +28,10 @@ import { DrawerItem, DrawerTitle } from "../drawer"; import { Badge } from "../badge/badge"; import { jobStore } from "../+workloads-jobs/job.store"; 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 type { CronJob, Job } from "../../api/endpoints"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; -import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; interface Props extends KubeObjectDetailsProps { } @@ -105,19 +103,3 @@ export class CronJobDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "CronJob", - apiVersions: ["batch/v1beta1"], - components: { - Details: (props) => - } -}); -kubeObjectDetailRegistry.add({ - kind: "CronJob", - apiVersions: ["batch/v1beta1"], - priority: 5, - components: { - Details: (props) => - } -}); diff --git a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx index 64690422d06d..df976a187bc4 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx @@ -33,7 +33,6 @@ import { eventStore } from "../+events/event.store"; import type { KubeObjectMenuProps } from "../kube-object/kube-object-menu"; import { KubeObjectListLayout } from "../kube-object"; import { CronJobTriggerDialog } from "./cronjob-trigger-dialog"; -import { kubeObjectMenuRegistry } from "../../../extensions/registries/kube-object-menu-registry"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { ConfirmDialog } from "../confirm-dialog/confirm-dialog"; import { Notifications } from "../notifications/notifications"; @@ -152,11 +151,3 @@ export function CronJobMenu(props: KubeObjectMenuProps) { ); } - -kubeObjectMenuRegistry.add({ - kind: "CronJob", - apiVersions: ["batch/v1beta1"], - components: { - MenuItem: CronJobMenu - } -}); diff --git a/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx b/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx index 96bf692e7203..0d72ee07fce2 100644 --- a/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx +++ b/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx @@ -28,7 +28,6 @@ import { Badge } from "../badge"; import { PodDetailsStatuses } from "../+workloads-pods/pod-details-statuses"; import { PodDetailsTolerations } from "../+workloads-pods/pod-details-tolerations"; 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 type { KubeObjectDetailsProps } from "../kube-object"; @@ -38,7 +37,6 @@ import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; import { reaction } from "mobx"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; 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"; @@ -118,19 +116,3 @@ export class DaemonSetDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "DaemonSet", - apiVersions: ["apps/v1"], - components: { - Details: (props: any) => - } -}); -kubeObjectDetailRegistry.add({ - kind: "DaemonSet", - apiVersions: ["apps/v1"], - priority: 5, - components: { - Details: (props: any) => - } -}); diff --git a/src/renderer/components/+workloads-deployments/deployment-details.tsx b/src/renderer/components/+workloads-deployments/deployment-details.tsx index 21bf03bdf57c..80a5362e6185 100644 --- a/src/renderer/components/+workloads-deployments/deployment-details.tsx +++ b/src/renderer/components/+workloads-deployments/deployment-details.tsx @@ -30,7 +30,6 @@ 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 type { KubeObjectDetailsProps } from "../kube-object"; import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics"; @@ -39,7 +38,6 @@ import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; import { reaction } from "mobx"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; 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"; @@ -141,19 +139,3 @@ export class DeploymentDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "Deployment", - apiVersions: ["apps/v1"], - components: { - Details: (props: any) => - } -}); -kubeObjectDetailRegistry.add({ - kind: "Deployment", - apiVersions: ["apps/v1"], - priority: 5, - components: { - Details: (props: any) => - } -}); diff --git a/src/renderer/components/+workloads-deployments/deployments.tsx b/src/renderer/components/+workloads-deployments/deployments.tsx index 6bca45c864ee..d57d5135b2d2 100644 --- a/src/renderer/components/+workloads-deployments/deployments.tsx +++ b/src/renderer/components/+workloads-deployments/deployments.tsx @@ -39,7 +39,6 @@ import { KubeObjectListLayout } from "../kube-object"; import { cssNames } from "../../utils"; import kebabCase from "lodash/kebabCase"; import orderBy from "lodash/orderBy"; -import { kubeObjectMenuRegistry } from "../../../extensions/registries/kube-object-menu-registry"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { Notifications } from "../notifications"; import type { DeploymentsRouteParams } from "../../../common/routes"; @@ -153,11 +152,3 @@ export function DeploymentMenu(props: KubeObjectMenuProps) { ); } - -kubeObjectMenuRegistry.add({ - kind: "Deployment", - apiVersions: ["apps/v1"], - components: { - MenuItem: DeploymentMenu - } -}); diff --git a/src/renderer/components/+workloads-jobs/job-details.tsx b/src/renderer/components/+workloads-jobs/job-details.tsx index 6fcbff96e76e..02cd5b41d455 100644 --- a/src/renderer/components/+workloads-jobs/job-details.tsx +++ b/src/renderer/components/+workloads-jobs/job-details.tsx @@ -30,7 +30,6 @@ import { PodDetailsStatuses } from "../+workloads-pods/pod-details-statuses"; import { Link } from "react-router-dom"; 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 { jobStore } from "./job.store"; import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object"; @@ -38,7 +37,6 @@ 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"; -import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; interface Props extends KubeObjectDetailsProps { } @@ -125,19 +123,3 @@ export class JobDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "Job", - apiVersions: ["batch/v1"], - components: { - Details: (props: any) => - } -}); -kubeObjectDetailRegistry.add({ - kind: "Job", - apiVersions: ["batch/v1"], - priority: 5, - components: { - Details: (props: any) => - } -}); diff --git a/src/renderer/components/+workloads-pods/pod-details.tsx b/src/renderer/components/+workloads-pods/pod-details.tsx index 4a67fe76d75e..883db9c73cb5 100644 --- a/src/renderer/components/+workloads-pods/pod-details.tsx +++ b/src/renderer/components/+workloads-pods/pod-details.tsx @@ -34,7 +34,6 @@ import { PodDetailsContainer } from "./pod-details-container"; import { PodDetailsAffinities } from "./pod-details-affinities"; import { PodDetailsTolerations } from "./pod-details-tolerations"; import { Icon } from "../icon"; -import { KubeEventDetails } from "../+events/kube-event-details"; import { PodDetailsSecrets } from "./pod-details-secrets"; import { ResourceMetrics } from "../resource-metrics"; import { podsStore } from "./pods.store"; @@ -42,7 +41,6 @@ import { getDetailsUrl, KubeObjectDetailsProps } from "../kube-object"; import { getItemMetrics } from "../../api/endpoints/metrics.api"; import { PodCharts, podMetricTabs } from "./pod-charts"; 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"; @@ -248,20 +246,3 @@ export class PodDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "Pod", - apiVersions: ["v1"], - components: { - Details: (props: KubeObjectDetailsProps) => - } -}); - -kubeObjectDetailRegistry.add({ - kind: "Pod", - apiVersions: ["v1"], - priority: 5, - components: { - Details: (props: KubeObjectDetailsProps) => - } -}); diff --git a/src/renderer/components/+workloads-replicasets/replicaset-details.tsx b/src/renderer/components/+workloads-replicasets/replicaset-details.tsx index e02d23a3d5c4..432b34f6eedb 100644 --- a/src/renderer/components/+workloads-replicasets/replicaset-details.tsx +++ b/src/renderer/components/+workloads-replicasets/replicaset-details.tsx @@ -28,7 +28,6 @@ import { replicaSetStore } from "./replicasets.store"; import { PodDetailsStatuses } from "../+workloads-pods/pod-details-statuses"; import { PodDetailsTolerations } from "../+workloads-pods/pod-details-tolerations"; 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 type { KubeObjectDetailsProps } from "../kube-object"; @@ -37,7 +36,6 @@ import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics"; import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; 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"; @@ -118,19 +116,3 @@ export class ReplicaSetDetails extends React.Component { ); } } - -kubeObjectDetailRegistry.add({ - kind: "ReplicaSet", - apiVersions: ["apps/v1"], - components: { - Details: (props: any) => - } -}); -kubeObjectDetailRegistry.add({ - kind: "ReplicaSet", - apiVersions: ["apps/v1"], - priority: 5, - components: { - Details: (props: any) => - } -}); diff --git a/src/renderer/components/+workloads-replicasets/replicasets.tsx b/src/renderer/components/+workloads-replicasets/replicasets.tsx index 30aebb6efaee..b14915e85f0a 100644 --- a/src/renderer/components/+workloads-replicasets/replicasets.tsx +++ b/src/renderer/components/+workloads-replicasets/replicasets.tsx @@ -31,7 +31,6 @@ import type { RouteComponentProps } from "react-router"; import { KubeObjectListLayout } from "../kube-object/kube-object-list-layout"; import { MenuItem } from "../menu/menu"; import { Icon } from "../icon/icon"; -import { kubeObjectMenuRegistry } from "../../../extensions/registries/kube-object-menu-registry"; import { ReplicaSetScaleDialog } from "./replicaset-scale-dialog"; import type { ReplicaSetsRouteParams } from "../../../common/routes"; @@ -105,11 +104,3 @@ export function ReplicaSetMenu(props: KubeObjectMenuProps) { ); } - -kubeObjectMenuRegistry.add({ - kind: "ReplicaSet", - apiVersions: ["apps/v1"], - components: { - MenuItem: ReplicaSetMenu - } -}); diff --git a/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx b/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx index 0342d424e9b2..6888962476e3 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx +++ b/src/renderer/components/+workloads-statefulsets/statefulset-details.tsx @@ -29,7 +29,6 @@ import { DrawerItem } from "../drawer"; import { PodDetailsStatuses } from "../+workloads-pods/pod-details-statuses"; 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 { statefulSetStore } from "./statefulset.store"; import type { KubeObjectDetailsProps } from "../kube-object"; @@ -38,7 +37,6 @@ import { ResourceMetrics, ResourceMetricsText } from "../resource-metrics"; import { PodCharts, podMetricTabs } from "../+workloads-pods/pod-charts"; import { PodDetailsList } from "../+workloads-pods/pod-details-list"; 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"; @@ -116,21 +114,3 @@ export class StatefulSetDetails extends React.Component { ); } } - - -kubeObjectDetailRegistry.add({ - kind: "StatefulSet", - apiVersions: ["apps/v1"], - components: { - Details: (props: any) => - } -}); - -kubeObjectDetailRegistry.add({ - kind: "StatefulSet", - apiVersions: ["apps/v1"], - priority: 5, - components: { - Details: (props: any) => - } -}); diff --git a/src/renderer/components/+workloads-statefulsets/statefulsets.tsx b/src/renderer/components/+workloads-statefulsets/statefulsets.tsx index 3340c30381b2..0431191d7ded 100644 --- a/src/renderer/components/+workloads-statefulsets/statefulsets.tsx +++ b/src/renderer/components/+workloads-statefulsets/statefulsets.tsx @@ -35,7 +35,6 @@ import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import { StatefulSetScaleDialog } from "./statefulset-scale-dialog"; import { MenuItem } from "../menu/menu"; import { Icon } from "../icon/icon"; -import { kubeObjectMenuRegistry } from "../../../extensions/registries/kube-object-menu-registry"; import type { StatefulSetsRouteParams } from "../../../common/routes"; enum columnId { @@ -110,11 +109,3 @@ export function StatefulSetMenu(props: KubeObjectMenuProps) { ); } - -kubeObjectMenuRegistry.add({ - kind: "StatefulSet", - apiVersions: ["apps/v1"], - components: { - MenuItem: StatefulSetMenu - } -}); diff --git a/src/renderer/components/+workloads/index.ts b/src/renderer/components/+workloads/index.ts index 4e0e932a5169..ab4e8fa18c21 100644 --- a/src/renderer/components/+workloads/index.ts +++ b/src/renderer/components/+workloads/index.ts @@ -21,4 +21,3 @@ export * from "./workloads"; export * from "./workloads.stores"; -export * from "./workloads.command"; diff --git a/src/renderer/components/+workloads/workloads.command.ts b/src/renderer/components/+workloads/workloads.command.ts deleted file mode 100644 index 2cc8895714d2..000000000000 --- a/src/renderer/components/+workloads/workloads.command.ts +++ /dev/null @@ -1,66 +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 { navigate } from "../../navigation"; -import { commandRegistry } from "../../../extensions/registries/command-registry"; -import * as routes from "../../../common/routes"; - -commandRegistry.add({ - id: "cluster.viewPods", - title: "Cluster: View Pods", - scope: "entity", - action: () => navigate(routes.podsURL()) -}); - -commandRegistry.add({ - id: "cluster.viewDeployments", - title: "Cluster: View Deployments", - scope: "entity", - action: () => navigate(routes.deploymentsURL()) -}); - -commandRegistry.add({ - id: "cluster.viewDaemonSets", - title: "Cluster: View DaemonSets", - scope: "entity", - action: () => navigate(routes.daemonSetsURL()) -}); - -commandRegistry.add({ - id: "cluster.viewStatefulSets", - title: "Cluster: View StatefulSets", - scope: "entity", - action: () => navigate(routes.statefulSetsURL()) -}); - -commandRegistry.add({ - id: "cluster.viewJobs", - title: "Cluster: View Jobs", - scope: "entity", - action: () => navigate(routes.jobsURL()) -}); - -commandRegistry.add({ - id: "cluster.viewCronJobs", - title: "Cluster: View CronJobs", - scope: "entity", - action: () => navigate(routes.cronJobsURL()) -}); diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index 27c5f3e7f4bd..e0dc16a47c8f 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -50,13 +50,13 @@ import { Terminal } from "./dock/terminal"; import { getHostedCluster, getHostedClusterId } from "../../common/cluster-store"; import logger from "../../main/logger"; import { webFrame } from "electron"; -import { clusterPageRegistry, getExtensionPageUrl } from "../../extensions/registries/page-registry"; +import { ClusterPageRegistry, getExtensionPageUrl } from "../../extensions/registries/page-registry"; import { ExtensionLoader } from "../../extensions/extension-loader"; import { appEventBus } from "../../common/event-bus"; import { requestMain } from "../../common/ipc"; import whatInput from "what-input"; import { clusterSetFrameIdHandler } from "../../common/cluster-ipc"; -import { ClusterPageMenuRegistration, clusterPageMenuRegistry } from "../../extensions/registries"; +import { ClusterPageMenuRegistration, ClusterPageMenuRegistry } from "../../extensions/registries"; import { TabLayout, TabLayoutRoute } from "./layout/tab-layout"; import { StatefulSetScaleDialog } from "./+workloads-statefulsets/statefulset-scale-dialog"; import { eventStore } from "./+events/event.store"; @@ -117,8 +117,8 @@ export class App extends React.Component { if (!menuItem.id) { return routes; } - clusterPageMenuRegistry.getSubItems(menuItem).forEach((subMenu) => { - const page = clusterPageRegistry.getByPageTarget(subMenu.target); + ClusterPageMenuRegistry.getInstance().getSubItems(menuItem).forEach((subMenu) => { + const page = ClusterPageRegistry.getInstance().getByPageTarget(subMenu.target); if (page) { routes.push({ @@ -134,7 +134,7 @@ export class App extends React.Component { } renderExtensionTabLayoutRoutes() { - return clusterPageMenuRegistry.getRootItems().map((menu, index) => { + return ClusterPageMenuRegistry.getInstance().getRootItems().map((menu, index) => { const tabRoutes = this.getTabLayoutRoutes(menu); if (tabRoutes.length > 0) { @@ -142,7 +142,7 @@ export class App extends React.Component { return tab.routePath)}/>; } else { - const page = clusterPageRegistry.getByPageTarget(menu.target); + const page = ClusterPageRegistry.getInstance().getByPageTarget(menu.target); if (page) { return ; @@ -154,8 +154,8 @@ export class App extends React.Component { } renderExtensionRoutes() { - return clusterPageRegistry.getItems().map((page, index) => { - const menu = clusterPageMenuRegistry.getByPage(page); + return ClusterPageRegistry.getInstance().getItems().map((page, index) => { + const menu = ClusterPageMenuRegistry.getInstance().getByPage(page); if (!menu) { return ; diff --git a/src/renderer/components/cluster-manager/bottom-bar.test.tsx b/src/renderer/components/cluster-manager/bottom-bar.test.tsx index eceb02697a5a..bf6c11245ed1 100644 --- a/src/renderer/components/cluster-manager/bottom-bar.test.tsx +++ b/src/renderer/components/cluster-manager/bottom-bar.test.tsx @@ -30,10 +30,17 @@ jest.mock("electron", () => ({ })); import { BottomBar } from "./bottom-bar"; -jest.mock("../../../extensions/registries"); -import { statusBarRegistry } from "../../../extensions/registries"; +import { StatusBarRegistry } from "../../../extensions/registries"; describe("", () => { + beforeEach(() => { + StatusBarRegistry.createInstance(); + }); + + afterEach(() => { + StatusBarRegistry.resetInstance(); + }); + it("renders w/o errors", () => { const { container } = render(); @@ -41,19 +48,19 @@ describe("", () => { }); it("renders w/o errors when .getItems() returns unexpected (not type complient) data", async () => { - statusBarRegistry.getItems = jest.fn().mockImplementationOnce(() => undefined); + StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => undefined); expect(() => render()).not.toThrow(); - statusBarRegistry.getItems = jest.fn().mockImplementationOnce(() => "hello"); + StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => "hello"); expect(() => render()).not.toThrow(); - statusBarRegistry.getItems = jest.fn().mockImplementationOnce(() => 6); + StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => 6); expect(() => render()).not.toThrow(); - statusBarRegistry.getItems = jest.fn().mockImplementationOnce(() => null); + StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => null); expect(() => render()).not.toThrow(); - statusBarRegistry.getItems = jest.fn().mockImplementationOnce(() => []); + StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => []); expect(() => render()).not.toThrow(); - statusBarRegistry.getItems = jest.fn().mockImplementationOnce(() => [{}]); + StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => [{}]); expect(() => render()).not.toThrow(); - statusBarRegistry.getItems = jest.fn().mockImplementationOnce(() => { return {};}); + StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => { return {};}); expect(() => render()).not.toThrow(); }); @@ -61,7 +68,7 @@ describe("", () => { const testId = "testId"; const text = "heee"; - statusBarRegistry.getItems = jest.fn().mockImplementationOnce(() => [ + StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => [ { item: {text} } ]); const { getByTestId } = render(); @@ -73,7 +80,7 @@ describe("", () => { const testId = "testId"; const text = "heee"; - statusBarRegistry.getItems = jest.fn().mockImplementationOnce(() => [ + StatusBarRegistry.getInstance().getItems = jest.fn().mockImplementationOnce(() => [ { item: () => {text} } ]); const { getByTestId } = render(); diff --git a/src/renderer/components/cluster-manager/bottom-bar.tsx b/src/renderer/components/cluster-manager/bottom-bar.tsx index 19c237982485..8e37128198c6 100644 --- a/src/renderer/components/cluster-manager/bottom-bar.tsx +++ b/src/renderer/components/cluster-manager/bottom-bar.tsx @@ -23,7 +23,7 @@ import "./bottom-bar.scss"; import React from "react"; import { observer } from "mobx-react"; -import { StatusBarRegistration, statusBarRegistry } from "../../../extensions/registries"; +import { StatusBarRegistration, StatusBarRegistry } from "../../../extensions/registries"; import { navigate } from "../../navigation"; import { Icon } from "../icon"; import { catalogURL } from "../../../common/routes"; @@ -41,7 +41,7 @@ export class BottomBar extends React.Component { } renderRegisteredItems() { - const items = statusBarRegistry.getItems(); + const items = StatusBarRegistry.getInstance().getItems(); if (!Array.isArray(items)) { return null; diff --git a/src/renderer/components/cluster-manager/cluster-manager.tsx b/src/renderer/components/cluster-manager/cluster-manager.tsx index 2fc4d1d2a911..4bd14e7805bc 100644 --- a/src/renderer/components/cluster-manager/cluster-manager.tsx +++ b/src/renderer/components/cluster-manager/cluster-manager.tsx @@ -29,7 +29,7 @@ import { Catalog } from "../+catalog"; import { Preferences } from "../+preferences"; import { AddCluster } from "../+add-cluster"; import { ClusterView } from "./cluster-view"; -import { globalPageRegistry } from "../../../extensions/registries/page-registry"; +import { GlobalPageRegistry } from "../../../extensions/registries/page-registry"; import { Extensions } from "../+extensions"; import { HotbarMenu } from "../hotbar/hotbar-menu"; import { EntitySettings } from "../+entity-settings"; @@ -52,7 +52,7 @@ export class ClusterManager extends React.Component { { - globalPageRegistry.getItems() + GlobalPageRegistry.getInstance().getItems() .map(({ url, components: { Page } }) => ( )) diff --git a/src/renderer/components/cluster-settings/cluster-settings.tsx b/src/renderer/components/cluster-settings/cluster-settings.tsx index d8fd374136ee..32190df9bcf2 100644 --- a/src/renderer/components/cluster-settings/cluster-settings.tsx +++ b/src/renderer/components/cluster-settings/cluster-settings.tsx @@ -21,140 +21,93 @@ import React from "react"; import { ClusterStore } from "../../../common/cluster-store"; -import { ClusterProxySetting } from "./components/cluster-proxy-setting"; -import { ClusterNameSetting } from "./components/cluster-name-setting"; -import { ClusterHomeDirSetting } from "./components/cluster-home-dir-setting"; -import { ClusterAccessibleNamespaces } from "./components/cluster-accessible-namespaces"; -import { ClusterMetricsSetting } from "./components/cluster-metrics-setting"; -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 type { EntitySettingViewProps } from "../../../extensions/registries"; import type { CatalogEntity } from "../../api/catalog-entity"; - +import * as components from "./components"; function getClusterForEntity(entity: CatalogEntity) { return ClusterStore.getInstance().getById(entity.metadata.uid); } -entitySettingRegistry.add([ - { - apiVersions: ["entity.k8slens.dev/v1alpha1"], - kind: "KubernetesCluster", - source: "local", - title: "General", - group: "Settings", - components: { - View: (props: { entity: CatalogEntity }) => { - const cluster = getClusterForEntity(props.entity); - - if (!cluster) { - return null; - } - - return ( -
    -
    - -
    -
    - -
    -
    - ); - } - } - }, - { - apiVersions: ["entity.k8slens.dev/v1alpha1"], - kind: "KubernetesCluster", - title: "Proxy", - group: "Settings", - components: { - View: (props: { entity: CatalogEntity }) => { - const cluster = getClusterForEntity(props.entity); - - if (!cluster) { - return null; - } - - return ( -
    - -
    - ); - } - } - }, - { - apiVersions: ["entity.k8slens.dev/v1alpha1"], - kind: "KubernetesCluster", - title: "Terminal", - group: "Settings", - components: { - View: (props: { entity: CatalogEntity }) => { - const cluster = getClusterForEntity(props.entity); - - if (!cluster) { - return null; - } - - return ( -
    - -
    - ); - } - } - }, - { - apiVersions: ["entity.k8slens.dev/v1alpha1"], - kind: "KubernetesCluster", - title: "Namespaces", - group: "Settings", - components: { - View: (props: { entity: CatalogEntity }) => { - const cluster = getClusterForEntity(props.entity); - - if (!cluster) { - return null; - } - - return ( -
    - -
    - ); - } - } - }, - { - apiVersions: ["entity.k8slens.dev/v1alpha1"], - kind: "KubernetesCluster", - title: "Metrics", - group: "Settings", - components: { - View: (props: { entity: CatalogEntity }) => { - const cluster = getClusterForEntity(props.entity); - - if (!cluster) { - return null; - } - - return ( -
    -
    - -
    -
    - -
    -
    - -
    -
    - ); - } - } +export function GeneralSettings({ entity }: EntitySettingViewProps) { + const cluster = getClusterForEntity(entity); + + if (!cluster) { + return null; + } + + return ( +
    +
    + +
    +
    + +
    +
    + ); +} + +export function ProxySettings({ entity }: EntitySettingViewProps) { + const cluster = getClusterForEntity(entity); + + if (!cluster) { + return null; + } + + return ( +
    + +
    + ); +} + +export function TerminalSettings({ entity }: EntitySettingViewProps) { + const cluster = getClusterForEntity(entity); + + if (!cluster) { + return null; + } + + return ( +
    + +
    + ); +} + +export function NamespacesSettings({ entity }: EntitySettingViewProps) { + const cluster = getClusterForEntity(entity); + + if (!cluster) { + return null; + } + + return ( +
    + +
    + ); +} + +export function MetricsSettings({ entity }: EntitySettingViewProps) { + const cluster = getClusterForEntity(entity); + + if (!cluster) { + return null; } -]); + + return ( +
    +
    + +
    +
    + +
    +
    + +
    +
    + ); +} diff --git a/src/renderer/components/cluster-settings/components/show-metrics.tsx b/src/renderer/components/cluster-settings/components/cluster-show-metrics.tsx similarity index 100% rename from src/renderer/components/cluster-settings/components/show-metrics.tsx rename to src/renderer/components/cluster-settings/components/cluster-show-metrics.tsx diff --git a/src/renderer/components/cluster-settings/components/index.ts b/src/renderer/components/cluster-settings/components/index.ts new file mode 100644 index 000000000000..66a64def62b2 --- /dev/null +++ b/src/renderer/components/cluster-settings/components/index.ts @@ -0,0 +1,29 @@ +/** + * 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 * from "./cluster-accessible-namespaces"; +export * from "./cluster-home-dir-setting"; +export * from "./cluster-kubeconfig"; +export * from "./cluster-metrics-setting"; +export * from "./cluster-name-setting"; +export * from "./cluster-prometheus-setting"; +export * from "./cluster-proxy-setting"; +export * from "./cluster-show-metrics"; diff --git a/src/renderer/components/cluster-settings/index.ts b/src/renderer/components/cluster-settings/index.ts index 752856c9ede6..f69a8e86f52b 100644 --- a/src/renderer/components/cluster-settings/index.ts +++ b/src/renderer/components/cluster-settings/index.ts @@ -20,4 +20,3 @@ */ export * from "./cluster-settings"; -export * from "./cluster-settings.command"; diff --git a/src/renderer/components/command-palette/command-container.tsx b/src/renderer/components/command-palette/command-container.tsx index c2e98d321872..419e4ef37088 100644 --- a/src/renderer/components/command-palette/command-container.tsx +++ b/src/renderer/components/command-palette/command-container.tsx @@ -28,7 +28,7 @@ import { Dialog } from "../dialog"; import { EventEmitter } from "../../../common/event-emitter"; import { subscribeToBroadcast } from "../../../common/ipc"; import { CommandDialog } from "./command-dialog"; -import { CommandRegistration, commandRegistry } from "../../../extensions/registries/command-registry"; +import { CommandRegistration, CommandRegistry } from "../../../extensions/registries/command-registry"; export type CommandDialogEvent = { component: React.ReactElement @@ -63,12 +63,12 @@ export class CommandContainer extends React.Component<{ clusterId?: string }> { } private findCommandById(commandId: string) { - return commandRegistry.getItems().find((command) => command.id === commandId); + return CommandRegistry.getInstance().getItems().find((command) => command.id === commandId); } private runCommand(command: CommandRegistration) { command.action({ - entity: commandRegistry.activeEntity + entity: CommandRegistry.getInstance().activeEntity }); } diff --git a/src/renderer/components/command-palette/command-dialog.tsx b/src/renderer/components/command-palette/command-dialog.tsx index bfd401ea0c58..0ed4b247167b 100644 --- a/src/renderer/components/command-palette/command-dialog.tsx +++ b/src/renderer/components/command-palette/command-dialog.tsx @@ -24,7 +24,7 @@ import { Select } from "../select"; import { computed, observable, toJS } from "mobx"; import { observer } from "mobx-react"; import React from "react"; -import { commandRegistry } from "../../../extensions/registries/command-registry"; +import { CommandRegistry } from "../../../extensions/registries/command-registry"; import { ClusterStore } from "../../../common/cluster-store"; import { CommandOverlay } from "./command-container"; import { broadcastMessage } from "../../../common/ipc"; @@ -36,33 +36,40 @@ export class CommandDialog extends React.Component { @observable menuIsOpen = true; @computed get options() { + const registry = CommandRegistry.getInstance(); + const context = { - entity: commandRegistry.activeEntity + entity: registry.activeEntity }; - return commandRegistry.getItems().filter((command) => { - if (command.scope === "entity" && !ClusterStore.getInstance().active) { - return false; - } + return registry.getItems() + .filter((command) => { + if (command.scope === "entity" && !ClusterStore.getInstance().active) { + return false; + } - if (!command.isActive) { - return true; - } + if (!command.isActive) { + return true; + } - try { - return command.isActive(context); - } catch(e) { - console.error(e); + try { + return command.isActive(context); + } catch(e) { + console.error(e); - return false; - } - }).map((command) => { - return { value: command.id, label: command.title }; - }).sort((a, b) => a.label > b.label ? 1 : -1); + return false; + } + }) + .map((command) => ({ + value: command.id, + label: command.title, + })) + .sort((a, b) => a.label > b.label ? 1 : -1); } private onChange(value: string) { - const command = commandRegistry.getItems().find((cmd) => cmd.id === value); + const registry = CommandRegistry.getInstance(); + const command = registry.getItems().find((cmd) => cmd.id === value); if (!command) { return; @@ -75,15 +82,15 @@ export class CommandDialog extends React.Component { if (command.scope === "global") { action({ - entity: commandRegistry.activeEntity + entity: registry.activeEntity }); - } else if(commandRegistry.activeEntity) { + } else if(registry.activeEntity) { navigate(clusterViewURL({ params: { - clusterId: commandRegistry.activeEntity.metadata.uid + clusterId: registry.activeEntity.metadata.uid } })); - broadcastMessage(`command-palette:run-action:${commandRegistry.activeEntity.metadata.uid}`, command.id); + broadcastMessage(`command-palette:run-action:${registry.activeEntity.metadata.uid}`, command.id); } } catch(error) { console.error("[COMMAND-DIALOG] failed to execute command", command.id, error); diff --git a/src/renderer/components/dock/dock.tsx b/src/renderer/components/dock/dock.tsx index 21e167ac8c78..c3c4ca520bcf 100644 --- a/src/renderer/components/dock/dock.tsx +++ b/src/renderer/components/dock/dock.tsx @@ -39,7 +39,6 @@ import { Logs } from "./logs"; import { TerminalWindow } from "./terminal-window"; import { createTerminalTab } from "./terminal.store"; import { UpgradeChart } from "./upgrade-chart"; -import { commandRegistry } from "../../../extensions/registries/command-registry"; interface Props { className?: string; @@ -161,11 +160,3 @@ export class Dock extends React.Component { ); } } - -commandRegistry.add({ - id: "cluster.openTerminal", - title: "Cluster: Open terminal", - scope: "entity", - action: () => createTerminalTab(), - isActive: (context) => !!context.entity -}); diff --git a/src/renderer/components/hotbar/hotbar-cell.tsx b/src/renderer/components/hotbar/hotbar-cell.tsx index e3328dcbedd4..8fd703f7a960 100644 --- a/src/renderer/components/hotbar/hotbar-cell.tsx +++ b/src/renderer/components/hotbar/hotbar-cell.tsx @@ -19,7 +19,6 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ import "./hotbar-menu.scss"; -import "./hotbar.commands"; import React, { HTMLAttributes, ReactNode, useState } from "react"; diff --git a/src/renderer/components/hotbar/hotbar-menu.tsx b/src/renderer/components/hotbar/hotbar-menu.tsx index d3bb838ac71f..bc478a5b1428 100644 --- a/src/renderer/components/hotbar/hotbar-menu.tsx +++ b/src/renderer/components/hotbar/hotbar-menu.tsx @@ -20,7 +20,6 @@ */ import "./hotbar-menu.scss"; -import "./hotbar.commands"; import React from "react"; import { observer } from "mobx-react"; diff --git a/src/renderer/components/hotbar/hotbar.commands.tsx b/src/renderer/components/hotbar/hotbar.commands.tsx deleted file mode 100644 index 399970cd6825..000000000000 --- a/src/renderer/components/hotbar/hotbar.commands.tsx +++ /dev/null @@ -1,48 +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 { commandRegistry } from "../../../extensions/registries"; -import { CommandOverlay } from "../command-palette"; -import { HotbarAddCommand } from "./hotbar-add-command"; -import { HotbarRemoveCommand } from "./hotbar-remove-command"; -import { HotbarSwitchCommand } from "./hotbar-switch-command"; - -commandRegistry.add({ - id: "hotbar.switchHotbar", - title: "Hotbar: Switch ...", - scope: "global", - action: () => CommandOverlay.open() -}); - -commandRegistry.add({ - id: "hotbar.addHotbar", - title: "Hotbar: Add Hotbar ...", - scope: "global", - action: () => CommandOverlay.open() -}); - -commandRegistry.add({ - id: "hotbar.removeHotbar", - title: "Hotbar: Remove Hotbar ...", - scope: "global", - action: () => CommandOverlay.open() -}); 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 bf700b871c2f..ebde73f89459 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 @@ -25,7 +25,7 @@ import React from "react"; import { Icon } from "../icon"; import { cssNames, formatDuration } from "../../utils"; import { KubeObject, KubeObjectStatus, KubeObjectStatusLevel } from "../../..//extensions/renderer-api/k8s-api"; -import { kubeObjectStatusRegistry } from "../../../extensions/registries"; +import { KubeObjectStatusRegistry } from "../../../extensions/registries"; function statusClassName(level: KubeObjectStatusLevel): string { switch (level) { @@ -105,7 +105,7 @@ export class KubeObjectStatusIcon extends React.Component { } render() { - const statuses = kubeObjectStatusRegistry.getItemsForObject(this.props.object); + const statuses = KubeObjectStatusRegistry.getInstance().getItemsForObject(this.props.object); if (statuses.length === 0) { return null; diff --git a/src/renderer/components/kube-object/kube-object-details.tsx b/src/renderer/components/kube-object/kube-object-details.tsx index b4cc81824cff..92a17e08e9e4 100644 --- a/src/renderer/components/kube-object/kube-object-details.tsx +++ b/src/renderer/components/kube-object/kube-object-details.tsx @@ -32,7 +32,7 @@ import { apiManager } from "../../api/api-manager"; import { crdStore } from "../+custom-resources/crd.store"; import { CrdResourceDetails } from "../+custom-resources"; import { KubeObjectMenu } from "./kube-object-menu"; -import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; +import { KubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; /** * Used to store `object.selfLink` to show more info about resource in the details panel. @@ -143,7 +143,7 @@ export class KubeObjectDetails extends React.Component { const { kind, getName } = object; title = `${kind}: ${getName()}`; - details = kubeObjectDetailRegistry.getItemsForKind(object.kind, object.apiVersion).map((item, index) => { + details = KubeObjectDetailRegistry.getInstance().getItemsForKind(object.kind, object.apiVersion).map((item, index) => { return ; }); diff --git a/src/renderer/components/kube-object/kube-object-menu.tsx b/src/renderer/components/kube-object/kube-object-menu.tsx index b2c26ef9ffc7..013c1a4ca146 100644 --- a/src/renderer/components/kube-object/kube-object-menu.tsx +++ b/src/renderer/components/kube-object/kube-object-menu.tsx @@ -26,7 +26,7 @@ import { editResourceTab } from "../dock/edit-resource.store"; import { MenuActions, MenuActionsProps } from "../menu/menu-actions"; import { hideDetails } from "./kube-object-details"; import { apiManager } from "../../api/api-manager"; -import { kubeObjectMenuRegistry } from "../../../extensions/registries/kube-object-menu-registry"; +import { KubeObjectMenuRegistry } from "../../../extensions/registries/kube-object-menu-registry"; export interface KubeObjectMenuProps extends MenuActionsProps { object: T | null | undefined; @@ -88,7 +88,8 @@ export class KubeObjectMenu extends React.Component ( { return routes; } - clusterPageMenuRegistry.getSubItems(menu).forEach((subMenu) => { - const subPage = clusterPageRegistry.getByPageTarget(subMenu.target); + ClusterPageMenuRegistry.getInstance().getSubItems(menu).forEach((subMenu) => { + const subPage = ClusterPageRegistry.getInstance().getByPageTarget(subMenu.target); if (subPage) { const { extensionId, id: pageId } = subPage; @@ -131,8 +131,8 @@ export class Sidebar extends React.Component { } renderRegisteredMenus() { - return clusterPageMenuRegistry.getRootItems().map((menuItem, index) => { - const registeredPage = clusterPageRegistry.getByPageTarget(menuItem.target); + return ClusterPageMenuRegistry.getInstance().getRootItems().map((menuItem, index) => { + const registeredPage = ClusterPageRegistry.getInstance().getByPageTarget(menuItem.target); const tabRoutes = this.getTabLayoutRoutes(menuItem); const id = `registered-item-${index}`; let pageUrl: string; diff --git a/src/renderer/initializers/command-registry.tsx b/src/renderer/initializers/command-registry.tsx new file mode 100644 index 000000000000..ab9066ad17a8 --- /dev/null +++ b/src/renderer/initializers/command-registry.tsx @@ -0,0 +1,193 @@ +/** + * 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 { ClusterStore } from "../../common/cluster-store"; +import * as routes from "../../common/routes"; +import { CommandRegistry } from "../../extensions/registries"; +import { CommandOverlay } from "../components/command-palette"; +import { createTerminalTab } from "../components/dock/terminal.store"; +import { HotbarAddCommand } from "../components/hotbar/hotbar-add-command"; +import { HotbarRemoveCommand } from "../components/hotbar/hotbar-remove-command"; +import { HotbarSwitchCommand } from "../components/hotbar/hotbar-switch-command"; +import { navigate } from "../navigation"; + +export function initCommandRegistry() { + CommandRegistry.getInstance() + .add([ + { + id: "app.showPreferences", + title: "Preferences: Open", + scope: "global", + action: () => navigate(routes.preferencesURL()) + }, + { + id: "cluster.viewHelmCharts", + title: "Cluster: View Helm Charts", + scope: "entity", + action: () => navigate(routes.helmChartsURL()) + }, + { + id: "cluster.viewHelmReleases", + title: "Cluster: View Helm Releases", + scope: "entity", + action: () => navigate(routes.releaseURL()) + }, + { + id: "cluster.viewConfigMaps", + title: "Cluster: View ConfigMaps", + scope: "entity", + action: () => navigate(routes.configMapsURL()) + }, + { + id: "cluster.viewSecrets", + title: "Cluster: View Secrets", + scope: "entity", + action: () => navigate(routes.secretsURL()) + }, + { + id: "cluster.viewResourceQuotas", + title: "Cluster: View ResourceQuotas", + scope: "entity", + action: () => navigate(routes.resourceQuotaURL()) + }, + { + id: "cluster.viewLimitRanges", + title: "Cluster: View LimitRanges", + scope: "entity", + action: () => navigate(routes.limitRangeURL()) + }, + { + id: "cluster.viewHorizontalPodAutoscalers", + title: "Cluster: View HorizontalPodAutoscalers (HPA)", + scope: "entity", + action: () => navigate(routes.hpaURL()) + }, + { + id: "cluster.viewPodDisruptionBudget", + title: "Cluster: View PodDisruptionBudgets", + scope: "entity", + action: () => navigate(routes.pdbURL()) + }, + { + id: "cluster.viewServices", + title: "Cluster: View Services", + scope: "entity", + action: () => navigate(routes.servicesURL()) + }, + { + id: "cluster.viewEndpoints", + title: "Cluster: View Endpoints", + scope: "entity", + action: () => navigate(routes.endpointURL()) + }, + { + id: "cluster.viewIngresses", + title: "Cluster: View Ingresses", + scope: "entity", + action: () => navigate(routes.ingressURL()) + }, + { + id: "cluster.viewNetworkPolicies", + title: "Cluster: View NetworkPolicies", + scope: "entity", + action: () => navigate(routes.networkPoliciesURL()) + }, + { + id: "cluster.viewNodes", + title: "Cluster: View Nodes", + scope: "entity", + action: () => navigate(routes.nodesURL()) + }, + { + id: "cluster.viewPods", + title: "Cluster: View Pods", + scope: "entity", + action: () => navigate(routes.podsURL()) + }, + { + id: "cluster.viewDeployments", + title: "Cluster: View Deployments", + scope: "entity", + action: () => navigate(routes.deploymentsURL()) + }, + { + id: "cluster.viewDaemonSets", + title: "Cluster: View DaemonSets", + scope: "entity", + action: () => navigate(routes.daemonSetsURL()) + }, + { + id: "cluster.viewStatefulSets", + title: "Cluster: View StatefulSets", + scope: "entity", + action: () => navigate(routes.statefulSetsURL()) + }, + { + id: "cluster.viewJobs", + title: "Cluster: View Jobs", + scope: "entity", + action: () => navigate(routes.jobsURL()) + }, + { + id: "cluster.viewCronJobs", + title: "Cluster: View CronJobs", + scope: "entity", + action: () => navigate(routes.cronJobsURL()) + }, + { + id: "cluster.viewCurrentClusterSettings", + title: "Cluster: View Settings", + scope: "global", + action: () => navigate(routes.entitySettingsURL({ + params: { + entityId: ClusterStore.getInstance().active.id + } + })), + isActive: (context) => !!context.entity + }, + { + id: "cluster.openTerminal", + title: "Cluster: Open terminal", + scope: "entity", + action: () => createTerminalTab(), + isActive: (context) => !!context.entity + }, + { + id: "hotbar.switchHotbar", + title: "Hotbar: Switch ...", + scope: "global", + action: () => CommandOverlay.open() + }, + { + id: "hotbar.addHotbar", + title: "Hotbar: Add Hotbar ...", + scope: "global", + action: () => CommandOverlay.open() + }, + { + id: "hotbar.removeHotbar", + title: "Hotbar: Remove Hotbar ...", + scope: "global", + action: () => CommandOverlay.open() + }, + ]); +} diff --git a/src/renderer/initializers/entity-settings-registry.ts b/src/renderer/initializers/entity-settings-registry.ts new file mode 100644 index 000000000000..e7203ca97bff --- /dev/null +++ b/src/renderer/initializers/entity-settings-registry.ts @@ -0,0 +1,70 @@ +/** + * 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 { EntitySettingRegistry } from "../../extensions/registries"; +import * as clusterSettings from "../components/cluster-settings"; + +export function initEntitySettingsRegistry() { + EntitySettingRegistry.getInstance() + .add([ + { + apiVersions: ["entity.k8slens.dev/v1alpha1"], + kind: "KubernetesCluster", + source: "local", + title: "General", + components: { + View: clusterSettings.GeneralSettings, + } + }, + { + apiVersions: ["entity.k8slens.dev/v1alpha1"], + kind: "KubernetesCluster", + title: "Proxy", + components: { + View: clusterSettings.ProxySettings, + } + }, + { + apiVersions: ["entity.k8slens.dev/v1alpha1"], + kind: "KubernetesCluster", + title: "Terminal", + components: { + View: clusterSettings.TerminalSettings, + } + }, + { + apiVersions: ["entity.k8slens.dev/v1alpha1"], + kind: "KubernetesCluster", + title: "Namespaces", + components: { + View: clusterSettings.NamespacesSettings, + } + }, + { + apiVersions: ["entity.k8slens.dev/v1alpha1"], + kind: "KubernetesCluster", + title: "Metrics", + components: { + View: clusterSettings.MetricsSettings, + } + } + ]); +} diff --git a/src/renderer/initializers/index.ts b/src/renderer/initializers/index.ts new file mode 100644 index 000000000000..5eeef311dc1f --- /dev/null +++ b/src/renderer/initializers/index.ts @@ -0,0 +1,27 @@ +/** + * 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 * from "./command-registry"; +export * from "./entity-settings-registry"; +export * from "./kube-object-detail-registry"; +export * from "./kube-object-menu-registry"; +export * from "./registries"; +export * from "./welcome-menu-registry"; diff --git a/src/renderer/initializers/kube-object-detail-registry.ts b/src/renderer/initializers/kube-object-detail-registry.ts new file mode 100644 index 000000000000..7752213858bf --- /dev/null +++ b/src/renderer/initializers/kube-object-detail-registry.ts @@ -0,0 +1,443 @@ +/** + * 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 { KubeObjectDetailRegistry } from "../api/kube-object-detail-registry"; +import { HpaDetails } from "../components/+config-autoscalers"; +import { LimitRangeDetails } from "../components/+config-limit-ranges"; +import { ConfigMapDetails } from "../components/+config-maps"; +import { PodDisruptionBudgetDetails } from "../components/+config-pod-disruption-budgets"; +import { ResourceQuotaDetails } from "../components/+config-resource-quotas"; +import { SecretDetails } from "../components/+config-secrets"; +import { CRDDetails } from "../components/+custom-resources"; +import { EventDetails } from "../components/+events"; +import { KubeEventDetails } from "../components/+events/kube-event-details"; +import { NamespaceDetails } from "../components/+namespaces"; +import { EndpointDetails } from "../components/+network-endpoints"; +import { IngressDetails } from "../components/+network-ingresses"; +import { NetworkPolicyDetails } from "../components/+network-policies"; +import { ServiceDetails } from "../components/+network-services"; +import { NodeDetails } from "../components/+nodes"; +import { PodSecurityPolicyDetails } from "../components/+pod-security-policies"; +import { StorageClassDetails } from "../components/+storage-classes"; +import { PersistentVolumeClaimDetails } from "../components/+storage-volume-claims"; +import { PersistentVolumeDetails } from "../components/+storage-volumes"; +import { RoleDetails } from "../components/+user-management-roles"; +import { RoleBindingDetails } from "../components/+user-management-roles-bindings"; +import { ServiceAccountsDetails } from "../components/+user-management-service-accounts"; +import { CronJobDetails } from "../components/+workloads-cronjobs"; +import { DaemonSetDetails } from "../components/+workloads-daemonsets"; +import { DeploymentDetails } from "../components/+workloads-deployments"; +import { JobDetails } from "../components/+workloads-jobs"; +import { PodDetails } from "../components/+workloads-pods"; +import { ReplicaSetDetails } from "../components/+workloads-replicasets"; +import { StatefulSetDetails } from "../components/+workloads-statefulsets"; + +export function intiKubeObjectDetailRegistry() { + KubeObjectDetailRegistry.getInstance() + .add([ + { + kind: "HorizontalPodAutoscaler", + apiVersions: ["autoscaling/v2beta1"], + components: { + Details: HpaDetails, + } + }, + { + kind: "HorizontalPodAutoscaler", + apiVersions: ["autoscaling/v2beta1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "LimitRange", + apiVersions: ["v1"], + components: { + Details: LimitRangeDetails, + } + }, + { + kind: "ConfigMap", + apiVersions: ["v1"], + components: { + Details: ConfigMapDetails, + } + }, + { + kind: "ConfigMap", + apiVersions: ["v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "PodDisruptionBudget", + apiVersions: ["policy/v1beta1"], + components: { + Details: PodDisruptionBudgetDetails, + } + }, + { + kind: "ResourceQuota", + apiVersions: ["v1"], + components: { + Details: ResourceQuotaDetails, + } + }, + { + kind: "Secret", + apiVersions: ["v1"], + components: { + Details: SecretDetails, + } + }, + { + kind: "CustomResourceDefinition", + apiVersions: ["apiextensions.k8s.io/v1", "apiextensions.k8s.io/v1beta1"], + components: { + Details: CRDDetails, + } + }, + { + kind: "Event", + apiVersions: ["v1"], + components: { + Details: EventDetails, + } + }, + { + kind: "Namespace", + apiVersions: ["v1"], + components: { + Details: NamespaceDetails, + } + }, + { + kind: "Endpoints", + apiVersions: ["v1"], + components: { + Details: EndpointDetails, + } + }, + { + kind: "Endpoints", + apiVersions: ["v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "Ingress", + apiVersions: ["networking.k8s.io/v1", "extensions/v1beta1"], + components: { + Details: IngressDetails, + } + }, + { + kind: "Ingress", + apiVersions: ["networking.k8s.io/v1", "extensions/v1beta1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "NetworkPolicy", + apiVersions: ["networking.k8s.io/v1"], + components: { + Details: NetworkPolicyDetails, + } + }, + { + kind: "NetworkPolicy", + apiVersions: ["networking.k8s.io/v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "Service", + apiVersions: ["v1"], + components: { + Details: ServiceDetails, + } + }, + { + kind: "Service", + apiVersions: ["v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "Node", + apiVersions: ["v1"], + components: { + Details: NodeDetails, + } + }, + { + kind: "Node", + apiVersions: ["v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "PodSecurityPolicy", + apiVersions: ["policy/v1beta1"], + components: { + Details: PodSecurityPolicyDetails, + } + }, + { + kind: "StorageClass", + apiVersions: ["storage.k8s.io/v1"], + components: { + Details: StorageClassDetails, + } + }, + { + kind: "StorageClass", + apiVersions: ["storage.k8s.io/v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "PersistentVolumeClaim", + apiVersions: ["v1"], + components: { + Details: PersistentVolumeClaimDetails, + } + }, + { + kind: "PersistentVolumeClaim", + apiVersions: ["v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "PersistentVolume", + apiVersions: ["v1"], + components: { + Details: PersistentVolumeDetails, + } + }, + { + kind: "PersistentVolume", + apiVersions: ["v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "Role", + apiVersions: ["rbac.authorization.k8s.io/v1"], + components: { + Details: RoleDetails, + } + }, + { + kind: "Role", + apiVersions: ["rbac.authorization.k8s.io/v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "ClusterRole", + apiVersions: ["rbac.authorization.k8s.io/v1"], + components: { + Details: RoleDetails, + } + }, + { + kind: "ClusterRole", + apiVersions: ["rbac.authorization.k8s.io/v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "RoleBinding", + apiVersions: ["rbac.authorization.k8s.io/v1"], + components: { + Details: RoleBindingDetails, + } + }, + { + kind: "RoleBinding", + apiVersions: ["rbac.authorization.k8s.io/v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "ClusterRoleBinding", + apiVersions: ["rbac.authorization.k8s.io/v1"], + components: { + Details: RoleBindingDetails, + } + }, + { + kind: "ClusterRoleBinding", + apiVersions: ["rbac.authorization.k8s.io/v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "ServiceAccount", + apiVersions: ["v1"], + components: { + Details: ServiceAccountsDetails, + } + }, + { + kind: "ServiceAccount", + apiVersions: ["v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "CronJob", + apiVersions: ["batch/v1beta1"], + components: { + Details: CronJobDetails, + } + }, + { + kind: "CronJob", + apiVersions: ["batch/v1beta1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "DaemonSet", + apiVersions: ["apps/v1"], + components: { + Details: DaemonSetDetails, + } + }, + { + kind: "DaemonSet", + apiVersions: ["apps/v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "Deployment", + apiVersions: ["apps/v1"], + components: { + Details: DeploymentDetails, + } + }, + { + kind: "Deployment", + apiVersions: ["apps/v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "Job", + apiVersions: ["batch/v1"], + components: { + Details: JobDetails, + } + }, + { + kind: "Job", + apiVersions: ["batch/v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "Pod", + apiVersions: ["v1"], + components: { + Details: PodDetails, + } + }, + { + kind: "Pod", + apiVersions: ["v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "ReplicaSet", + apiVersions: ["apps/v1"], + components: { + Details: ReplicaSetDetails, + } + }, + { + kind: "ReplicaSet", + apiVersions: ["apps/v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + }, + { + kind: "StatefulSet", + apiVersions: ["apps/v1"], + components: { + Details: StatefulSetDetails, + } + }, + { + kind: "StatefulSet", + apiVersions: ["apps/v1"], + priority: 5, + components: { + Details: KubeEventDetails, + } + } + ]); +} diff --git a/src/renderer/initializers/kube-object-menu-registry.ts b/src/renderer/initializers/kube-object-menu-registry.ts new file mode 100644 index 000000000000..38f895a21aa9 --- /dev/null +++ b/src/renderer/initializers/kube-object-menu-registry.ts @@ -0,0 +1,68 @@ +/** + * 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 { KubeObjectMenuRegistry } from "../../extensions/registries"; +import { ServiceAccountMenu } from "../components/+user-management-service-accounts"; +import { CronJobMenu } from "../components/+workloads-cronjobs"; +import { DeploymentMenu } from "../components/+workloads-deployments"; +import { ReplicaSetMenu } from "../components/+workloads-replicasets"; +import { StatefulSetMenu } from "../components/+workloads-statefulsets"; + +export function initKubeObjectMenuRegistry() { + KubeObjectMenuRegistry.getInstance() + .add([ + { + kind: "ServiceAccount", + apiVersions: ["v1"], + components: { + MenuItem: ServiceAccountMenu, + } + }, + { + kind: "CronJob", + apiVersions: ["batch/v1beta1"], + components: { + MenuItem: CronJobMenu + } + }, + { + kind: "Deployment", + apiVersions: ["apps/v1"], + components: { + MenuItem: DeploymentMenu + } + }, + { + kind: "ReplicaSet", + apiVersions: ["apps/v1"], + components: { + MenuItem: ReplicaSetMenu + } + }, + { + kind: "StatefulSet", + apiVersions: ["apps/v1"], + components: { + MenuItem: StatefulSetMenu + } + } + ]); +} diff --git a/src/renderer/components/+network/network.command.ts b/src/renderer/initializers/registries.ts similarity index 57% rename from src/renderer/components/+network/network.command.ts rename to src/renderer/initializers/registries.ts index 4171348a1bab..ce883728a8a7 100644 --- a/src/renderer/components/+network/network.command.ts +++ b/src/renderer/initializers/registries.ts @@ -19,34 +19,19 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { navigate } from "../../navigation"; -import { commandRegistry } from "../../../extensions/registries/command-registry"; -import * as routes from "../../../common/routes"; +import * as registries from "../../extensions/registries"; -commandRegistry.add({ - id: "cluster.viewServices", - title: "Cluster: View Services", - scope: "entity", - action: () => navigate(routes.servicesURL()) -}); - -commandRegistry.add({ - id: "cluster.viewEndpoints", - title: "Cluster: View Endpoints", - scope: "entity", - action: () => navigate(routes.endpointURL()) -}); - -commandRegistry.add({ - id: "cluster.viewIngresses", - title: "Cluster: View Ingresses", - scope: "entity", - action: () => navigate(routes.ingressURL()) -}); - -commandRegistry.add({ - id: "cluster.viewNetworkPolicies", - title: "Cluster: View NetworkPolicies", - scope: "entity", - action: () => navigate(routes.networkPoliciesURL()) -}); +export function initRegistries() { + registries.GlobalPageRegistry.createInstance(); + registries.AppPreferenceRegistry.createInstance(); + registries.EntitySettingRegistry.createInstance(); + registries.StatusBarRegistry.createInstance(); + registries.CommandRegistry.createInstance(); + registries.WelcomeMenuRegistry.createInstance(); + registries.ClusterPageRegistry.createInstance(); + registries.ClusterPageMenuRegistry.createInstance(); + registries.KubeObjectMenuRegistry.createInstance(); + registries.KubeObjectDetailRegistry.createInstance(); + registries.KubeObjectStatusRegistry.createInstance(); + registries.CommandRegistry.createInstance(); +} diff --git a/src/renderer/components/cluster-settings/cluster-settings.command.ts b/src/renderer/initializers/welcome-menu-registry.ts similarity index 67% rename from src/renderer/components/cluster-settings/cluster-settings.command.ts rename to src/renderer/initializers/welcome-menu-registry.ts index e0325d534072..887735b3577f 100644 --- a/src/renderer/components/cluster-settings/cluster-settings.command.ts +++ b/src/renderer/initializers/welcome-menu-registry.ts @@ -19,19 +19,22 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { navigate } from "../../navigation"; -import { commandRegistry } from "../../../extensions/registries/command-registry"; -import { ClusterStore } from "../../../common/cluster-store"; -import { entitySettingsURL } from "../../../common/routes"; +import { catalogURL, preferencesURL } from "../../common/routes"; +import { WelcomeMenuRegistry } from "../../extensions/registries"; +import { navigate } from "../navigation"; -commandRegistry.add({ - id: "cluster.viewCurrentClusterSettings", - title: "Cluster: View Settings", - scope: "global", - action: () => navigate(entitySettingsURL({ - params: { - entityId: ClusterStore.getInstance().active.id - } - })), - isActive: (context) => !!context.entity -}); +export function initWelcomeMenuRegistry() { + WelcomeMenuRegistry.getInstance() + .add([ + { + title: "Browse Your Catalog", + icon: "view_list", + click: () => navigate(catalogURL()) + }, + { + title: "Configure Preferences", + icon: "settings", + click: () => navigate(preferencesURL()) + } + ]); +} diff --git a/src/renderer/lens-app.tsx b/src/renderer/lens-app.tsx index 904381976138..afec8bfde687 100644 --- a/src/renderer/lens-app.tsx +++ b/src/renderer/lens-app.tsx @@ -36,7 +36,7 @@ import { registerIpcHandlers } from "./ipc"; import { ipcRenderer } from "electron"; import { IpcRendererNavigationEvents } from "./navigation/events"; import { catalogEntityRegistry } from "./api/catalog-entity-registry"; -import { commandRegistry } from "../extensions/registries"; +import { CommandRegistry } from "../extensions/registries"; import { reaction } from "mobx"; @observer @@ -56,12 +56,10 @@ export class LensApp extends React.Component { componentDidMount() { reaction(() => catalogEntityRegistry.items, (items) => { - if (!commandRegistry.activeEntity) { - return; - } + const reg = CommandRegistry.getInstance(); - if (!items.includes(commandRegistry.activeEntity)) { - commandRegistry.activeEntity = null; + if (reg.activeEntity && items.includes(reg.activeEntity)) { + reg.activeEntity = null; } }); } diff --git a/webpack.extensions.ts b/webpack.extensions.ts index e5a95660aad4..90b20c358928 100644 --- a/webpack.extensions.ts +++ b/webpack.extensions.ts @@ -47,6 +47,7 @@ export default function generateExtensionTypes(): webpack.Configuration { optimization: { minimize: false, // speed up types compilation }, + stats: "errors-warnings", module: { rules: [ { From d5bfa3a215205286603ae70c9f1c35af74a0f0d9 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 19 May 2021 12:29:20 -0400 Subject: [PATCH 3/5] Add more specific IPC helpers Signed-off-by: Sebastian Malton --- src/common/base-store.ts | 18 ++++------ src/common/cluster-ipc.ts | 13 ++++--- src/common/cluster-store.ts | 24 +++++++++---- src/common/ipc/ipc.ts | 35 +++++-------------- src/extensions/extension-discovery.ts | 8 ++--- src/extensions/extension-loader.ts | 10 +++--- src/main/window-manager.ts | 4 +-- src/renderer/api/catalog-entity-registry.ts | 4 +-- .../cluster-manager/cluster-status.tsx | 4 +-- .../command-palette/command-container.tsx | 6 ++-- src/renderer/navigation/events.ts | 8 ++--- 11 files changed, 59 insertions(+), 75 deletions(-) diff --git a/src/common/base-store.ts b/src/common/base-store.ts index 608862c2af27..2655aab8fce3 100644 --- a/src/common/base-store.ts +++ b/src/common/base-store.ts @@ -22,12 +22,12 @@ import path from "path"; import Config from "conf"; import type { Options as ConfOptions } from "conf/dist/source/types"; -import { app, ipcMain, IpcMainEvent, ipcRenderer, IpcRendererEvent, remote } from "electron"; +import { app, ipcMain, ipcRenderer, remote } from "electron"; import { IReactionOptions, observable, reaction, runInAction, when } from "mobx"; import Singleton from "./utils/singleton"; import { getAppVersion } from "./utils/app-version"; import logger from "../main/logger"; -import { broadcastMessage, subscribeToBroadcast, unsubscribeFromBroadcast } from "./ipc"; +import { broadcastMessage, ipcMainOn, ipcRendererOn } from "./ipc"; import isEqual from "lodash/isEqual"; export interface BaseStoreParams extends ConfOptions { @@ -118,23 +118,17 @@ export abstract class BaseStore extends Singleton { ); if (ipcMain) { - const callback = (event: IpcMainEvent, model: T) => { + this.syncDisposers.push(ipcMainOn(this.syncMainChannel, (event, model: T) => { logger.silly(`[STORE]: SYNC ${this.name} from renderer`, { model }); this.onSync(model); - }; - - subscribeToBroadcast(this.syncMainChannel, callback); - this.syncDisposers.push(() => unsubscribeFromBroadcast(this.syncMainChannel, callback)); + })); } if (ipcRenderer) { - const callback = (event: IpcRendererEvent, model: T) => { + this.syncDisposers.push(ipcRendererOn(this.syncRendererChannel, (event, model: T) => { logger.silly(`[STORE]: SYNC ${this.name} from main`, { model }); this.onSyncFromMain(model); - }; - - subscribeToBroadcast(this.syncRendererChannel, callback); - this.syncDisposers.push(() => unsubscribeFromBroadcast(this.syncRendererChannel, callback)); + })); } } diff --git a/src/common/cluster-ipc.ts b/src/common/cluster-ipc.ts index 718151c3ed6c..7b62c1415040 100644 --- a/src/common/cluster-ipc.ts +++ b/src/common/cluster-ipc.ts @@ -19,7 +19,6 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { handleRequest } from "./ipc"; import { ClusterId, ClusterStore } from "./cluster-store"; import { appEventBus } from "./event-bus"; import { ResourceApplier } from "../main/resource-applier"; @@ -34,13 +33,13 @@ export const clusterKubectlApplyAllHandler = "cluster:kubectl-apply-all"; export const clusterKubectlDeleteAllHandler = "cluster:kubectl-delete-all"; if (ipcMain) { - handleRequest(clusterActivateHandler, (event, clusterId: ClusterId, force = false) => { + ipcMain.handle(clusterActivateHandler, (event, clusterId: ClusterId, force = false) => { return ClusterStore.getInstance() .getById(clusterId) ?.activate(force); }); - handleRequest(clusterSetFrameIdHandler, (event: IpcMainInvokeEvent, clusterId: ClusterId) => { + ipcMain.handle(clusterSetFrameIdHandler, (event: IpcMainInvokeEvent, clusterId: ClusterId) => { const cluster = ClusterStore.getInstance().getById(clusterId); if (cluster) { @@ -49,13 +48,13 @@ if (ipcMain) { } }); - handleRequest(clusterRefreshHandler, (event, clusterId: ClusterId) => { + ipcMain.handle(clusterRefreshHandler, (event, clusterId: ClusterId) => { return ClusterStore.getInstance() .getById(clusterId) ?.refresh({ refreshMetadata: true }); }); - handleRequest(clusterDisconnectHandler, (event, clusterId: ClusterId) => { + ipcMain.handle(clusterDisconnectHandler, (event, clusterId: ClusterId) => { appEventBus.emit({name: "cluster", action: "stop"}); const cluster = ClusterStore.getInstance().getById(clusterId); @@ -65,7 +64,7 @@ if (ipcMain) { } }); - handleRequest(clusterKubectlApplyAllHandler, async (event, clusterId: ClusterId, resources: string[], extraArgs: string[]) => { + ipcMain.handle(clusterKubectlApplyAllHandler, async (event, clusterId: ClusterId, resources: string[], extraArgs: string[]) => { appEventBus.emit({name: "cluster", action: "kubectl-apply-all"}); const cluster = ClusterStore.getInstance().getById(clusterId); @@ -84,7 +83,7 @@ if (ipcMain) { } }); - handleRequest(clusterKubectlDeleteAllHandler, async (event, clusterId: ClusterId, resources: string[], extraArgs: string[]) => { + ipcMain.handle(clusterKubectlDeleteAllHandler, async (event, clusterId: ClusterId, resources: string[], extraArgs: string[]) => { appEventBus.emit({name: "cluster", action: "kubectl-delete-all"}); const cluster = ClusterStore.getInstance().getById(clusterId); diff --git a/src/common/cluster-store.ts b/src/common/cluster-store.ts index 89c71255c2ab..c50968fd897c 100644 --- a/src/common/cluster-store.ts +++ b/src/common/cluster-store.ts @@ -31,7 +31,7 @@ import { appEventBus } from "./event-bus"; import { dumpConfigYaml } from "./kube-helpers"; import { saveToAppFiles } from "./utils/saveToAppFiles"; import type { KubeConfig } from "@kubernetes/client-node"; -import { handleRequest, requestMain, subscribeToBroadcast, unsubscribeAllFromBroadcast } from "./ipc"; +import { ipcMainOn, ipcRendererOn, requestMain } from "./ipc"; import type { ResourceType } from "../renderer/components/cluster-settings/components/cluster-metrics-setting"; import { disposer, noop } from "./utils"; @@ -114,6 +114,8 @@ export interface ClusterPrometheusPreferences { } export class ClusterStore extends BaseStore { + private static StateChannel = "cluster:state"; + static get storedKubeConfigFolder(): string { return path.resolve((app || remote.app).getPath("userData"), "kubeconfigs"); } @@ -170,7 +172,7 @@ export class ClusterStore extends BaseStore { } }); } else if (ipcMain) { - handleRequest(ClusterStore.stateRequestChannel, (): clusterStateSync[] => { + ipcMain.handle(ClusterStore.stateRequestChannel, (): clusterStateSync[] => { const states: clusterStateSync[] = []; this.clustersList.forEach((cluster) => { @@ -191,17 +193,25 @@ export class ClusterStore extends BaseStore { reaction(() => this.connectedClustersList, () => { this.pushState(); }), - () => unsubscribeAllFromBroadcast("cluster:state"), ); } } + handleStateChange = (event: any, clusterId: string, state: ClusterState) => { + logger.silly(`[CLUSTER-STORE]: received push-state at ${location.host} (${webFrame.routingId})`, clusterId, state); + this.getById(clusterId)?.setState(state); + }; + registerIpcListener() { logger.info(`[CLUSTER-STORE] start to listen (${webFrame.routingId})`); - subscribeToBroadcast("cluster:state", (event, clusterId: string, state: ClusterState) => { - logger.silly(`[CLUSTER-STORE]: received push-state at ${location.host} (${webFrame.routingId})`, clusterId, state); - this.getById(clusterId)?.setState(state); - }); + + if (ipcMain) { + this.disposer.push(ipcMainOn(ClusterStore.StateChannel, this.handleStateChange)); + } + + if (ipcRenderer) { + this.disposer.push(ipcRendererOn(ClusterStore.StateChannel, this.handleStateChange)); + } } unregisterIpcListener() { diff --git a/src/common/ipc/ipc.ts b/src/common/ipc/ipc.ts index 66e591e7653e..917fe29571df 100644 --- a/src/common/ipc/ipc.ts +++ b/src/common/ipc/ipc.ts @@ -27,13 +27,10 @@ import { ipcMain, ipcRenderer, webContents, remote } from "electron"; import { toJS } from "mobx"; import logger from "../../main/logger"; import { ClusterFrameInfo, clusterFrameMap } from "../cluster-frames"; +import type { Disposer } from "../utils"; const subFramesChannel = "ipc:get-sub-frames"; -export function handleRequest(channel: string, listener: (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any) { - ipcMain.handle(channel, listener); -} - export async function requestMain(channel: string, ...args: any[]) { return ipcRenderer.invoke(channel, ...args); } @@ -71,34 +68,18 @@ export function broadcastMessage(channel: string, ...args: any[]) { }); } -export function subscribeToBroadcast(channel: string, listener: (...args: any[]) => any) { - if (ipcRenderer) { - ipcRenderer.on(channel, listener); - } else if (ipcMain) { - ipcMain.on(channel, listener); - } +export function ipcMainOn(channel: string, listener: (event: Electron.IpcMainEvent, ...args: any[]) => any): Disposer { + ipcMain.on(channel, listener); - return listener; + return () => ipcMain.off(channel, listener); } -export function unsubscribeFromBroadcast(channel: string, listener: (...args: any[]) => any) { - if (ipcRenderer) { - ipcRenderer.off(channel, listener); - } else if (ipcMain) { - ipcMain.off(channel, listener); - } -} +export function ipcRendererOn(channel: string, listener: (event: Electron.IpcRendererEvent, ...args: any[]) => any): Disposer { + ipcRenderer.on(channel, listener); -export function unsubscribeAllFromBroadcast(channel: string) { - if (ipcRenderer) { - ipcRenderer.removeAllListeners(channel); - } else if (ipcMain) { - ipcMain.removeAllListeners(channel); - } + return () => ipcRenderer.off(channel, listener); } export function bindBroadcastHandlers() { - handleRequest(subFramesChannel, () => { - return getSubFrames(); - }); + ipcMain.handle(subFramesChannel, getSubFrames); } diff --git a/src/extensions/extension-discovery.ts b/src/extensions/extension-discovery.ts index bc1d5e53319e..cc396985beb7 100644 --- a/src/extensions/extension-discovery.ts +++ b/src/extensions/extension-discovery.ts @@ -20,13 +20,13 @@ */ import { watch } from "chokidar"; -import { ipcRenderer } from "electron"; +import { ipcMain, ipcRenderer } from "electron"; import { EventEmitter } from "events"; import fse from "fs-extra"; import { observable, reaction, toJS, when } from "mobx"; import os from "os"; import path from "path"; -import { broadcastMessage, handleRequest, requestMain, subscribeToBroadcast } from "../common/ipc"; +import { broadcastMessage, ipcRendererOn, requestMain } from "../common/ipc"; import { Singleton } from "../common/utils"; import logger from "../main/logger"; import { ExtensionInstallationStateStore } from "../renderer/components/+extensions/extension-install.store"; @@ -130,13 +130,13 @@ export class ExtensionDiscovery extends Singleton { }; requestMain(ExtensionDiscovery.extensionDiscoveryChannel).then(onMessage); - subscribeToBroadcast(ExtensionDiscovery.extensionDiscoveryChannel, (_event, message: ExtensionDiscoveryChannelMessage) => { + ipcRendererOn(ExtensionDiscovery.extensionDiscoveryChannel, (_event, message: ExtensionDiscoveryChannelMessage) => { onMessage(message); }); } async initMain() { - handleRequest(ExtensionDiscovery.extensionDiscoveryChannel, () => this.toJSON()); + ipcMain.handle(ExtensionDiscovery.extensionDiscoveryChannel, () => this.toJSON()); reaction(() => this.toJSON(), () => { this.broadcast(); diff --git a/src/extensions/extension-loader.ts b/src/extensions/extension-loader.ts index df230601cb81..5328bebdfa6c 100644 --- a/src/extensions/extension-loader.ts +++ b/src/extensions/extension-loader.ts @@ -19,13 +19,13 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { app, ipcRenderer, remote } from "electron"; +import { app, ipcMain, ipcRenderer, remote } from "electron"; import { EventEmitter } from "events"; import { isEqual } from "lodash"; import { action, computed, observable, reaction, toJS, when } from "mobx"; import path from "path"; import { getHostedCluster } from "../common/cluster-store"; -import { broadcastMessage, handleRequest, requestMain, subscribeToBroadcast } from "../common/ipc"; +import { broadcastMessage, ipcMainOn, ipcRendererOn, requestMain } from "../common/ipc"; import { Singleton } from "../common/utils"; import logger from "../main/logger"; import type { InstalledExtension } from "./extension-discovery"; @@ -164,11 +164,11 @@ export class ExtensionLoader extends Singleton { this.broadcastExtensions(); }); - handleRequest(ExtensionLoader.extensionsMainChannel, () => { + ipcMain.handle(ExtensionLoader.extensionsMainChannel, () => { return Array.from(this.toJSON()); }); - subscribeToBroadcast(ExtensionLoader.extensionsRendererChannel, (_event, extensions: [LensExtensionId, InstalledExtension][]) => { + ipcMainOn(ExtensionLoader.extensionsRendererChannel, (event, extensions: [LensExtensionId, InstalledExtension][]) => { this.syncExtensions(extensions); }); } @@ -193,7 +193,7 @@ export class ExtensionLoader extends Singleton { }); requestMain(ExtensionLoader.extensionsMainChannel).then(extensionListHandler); - subscribeToBroadcast(ExtensionLoader.extensionsMainChannel, (_event, extensions: [LensExtensionId, InstalledExtension][]) => { + ipcRendererOn(ExtensionLoader.extensionsMainChannel, (event, extensions: [LensExtensionId, InstalledExtension][]) => { extensionListHandler(extensions); }); } diff --git a/src/main/window-manager.ts b/src/main/window-manager.ts index f1d4073edbd9..6158424a4f99 100644 --- a/src/main/window-manager.ts +++ b/src/main/window-manager.ts @@ -24,7 +24,7 @@ import { observable } from "mobx"; import { app, BrowserWindow, dialog, shell, webContents } from "electron"; import windowStateKeeper from "electron-window-state"; import { appEventBus } from "../common/event-bus"; -import { subscribeToBroadcast } from "../common/ipc"; +import { ipcMainOn } from "../common/ipc"; import { initMenu } from "./menu"; import { initTray } from "./tray"; import { Singleton } from "../common/utils"; @@ -140,7 +140,7 @@ export class WindowManager extends Singleton { protected bindEvents() { // track visible cluster from ui - subscribeToBroadcast(IpcRendererNavigationEvents.CLUSTER_VIEW_CURRENT_ID, (event, clusterId: ClusterId) => { + ipcMainOn(IpcRendererNavigationEvents.CLUSTER_VIEW_CURRENT_ID, (event, clusterId: ClusterId) => { this.activeClusterId = clusterId; }); } diff --git a/src/renderer/api/catalog-entity-registry.ts b/src/renderer/api/catalog-entity-registry.ts index d6e2059edf22..70124b11462a 100644 --- a/src/renderer/api/catalog-entity-registry.ts +++ b/src/renderer/api/catalog-entity-registry.ts @@ -20,7 +20,7 @@ */ import { computed, observable } from "mobx"; -import { subscribeToBroadcast } from "../../common/ipc"; +import { ipcRendererOn } from "../../common/ipc"; import { CatalogCategory, CatalogEntity, CatalogEntityData, catalogCategoryRegistry, CatalogCategoryRegistry, CatalogEntityKindData } from "../../common/catalog"; import "../../common/catalog-entities"; import { iter } from "../utils"; @@ -32,7 +32,7 @@ export class CatalogEntityRegistry { constructor(private categoryRegistry: CatalogCategoryRegistry) {} init() { - subscribeToBroadcast("catalog:items", (ev, items: (CatalogEntityData & CatalogEntityKindData)[]) => { + ipcRendererOn("catalog:items", (event, items: (CatalogEntityData & CatalogEntityKindData)[]) => { this.rawItems.replace(items); }); } diff --git a/src/renderer/components/cluster-manager/cluster-status.tsx b/src/renderer/components/cluster-manager/cluster-status.tsx index 565fee6107a0..b5defce31d82 100644 --- a/src/renderer/components/cluster-manager/cluster-status.tsx +++ b/src/renderer/components/cluster-manager/cluster-status.tsx @@ -26,7 +26,7 @@ import React from "react"; import { observer } from "mobx-react"; import { ipcRenderer } from "electron"; import { computed, observable } from "mobx"; -import { requestMain, subscribeToBroadcast } from "../../../common/ipc"; +import { ipcRendererOn, requestMain } from "../../../common/ipc"; import { Icon } from "../icon"; import { Button } from "../button"; import { cssNames, IClassName } from "../../utils"; @@ -54,7 +54,7 @@ export class ClusterStatus extends React.Component { } async componentDidMount() { - subscribeToBroadcast(`kube-auth:${this.cluster.id}`, (evt, res: KubeAuthProxyLog) => { + ipcRendererOn(`kube-auth:${this.cluster.id}`, (evt, res: KubeAuthProxyLog) => { this.authOutput.push({ data: res.data.trimRight(), error: res.error, diff --git a/src/renderer/components/command-palette/command-container.tsx b/src/renderer/components/command-palette/command-container.tsx index 419e4ef37088..b09463a265c1 100644 --- a/src/renderer/components/command-palette/command-container.tsx +++ b/src/renderer/components/command-palette/command-container.tsx @@ -26,7 +26,7 @@ import { observer } from "mobx-react"; import React from "react"; import { Dialog } from "../dialog"; import { EventEmitter } from "../../../common/event-emitter"; -import { subscribeToBroadcast } from "../../../common/ipc"; +import { ipcRendererOn } from "../../../common/ipc"; import { CommandDialog } from "./command-dialog"; import { CommandRegistration, CommandRegistry } from "../../../extensions/registries/command-registry"; @@ -74,7 +74,7 @@ export class CommandContainer extends React.Component<{ clusterId?: string }> { componentDidMount() { if (this.props.clusterId) { - subscribeToBroadcast(`command-palette:run-action:${this.props.clusterId}`, (event, commandId: string) => { + ipcRendererOn(`command-palette:run-action:${this.props.clusterId}`, (event, commandId: string) => { const command = this.findCommandById(commandId); if (command) { @@ -82,7 +82,7 @@ export class CommandContainer extends React.Component<{ clusterId?: string }> { } }); } else { - subscribeToBroadcast("command-palette:open", () => { + ipcRendererOn("command-palette:open", () => { CommandOverlay.open(); }); } diff --git a/src/renderer/navigation/events.ts b/src/renderer/navigation/events.ts index 0adc53d7aea6..f5a9968f4af7 100644 --- a/src/renderer/navigation/events.ts +++ b/src/renderer/navigation/events.ts @@ -22,7 +22,7 @@ import { ipcRenderer } from "electron"; import { reaction } from "mobx"; import { getMatchedClusterId, navigate } from "./helpers"; -import { broadcastMessage, subscribeToBroadcast } from "../../common/ipc"; +import { broadcastMessage, ipcRendererOn } from "../../common/ipc"; import logger from "../../main/logger"; export const enum IpcRendererNavigationEvents { @@ -45,7 +45,7 @@ export function bindEvents() { } // Reload dashboard window - subscribeToBroadcast(IpcRendererNavigationEvents.RELOAD_PAGE, () => { + ipcRendererOn(IpcRendererNavigationEvents.RELOAD_PAGE, () => { location.reload(); }); } @@ -60,7 +60,7 @@ function bindClusterManagerRouteEvents() { }); // Handle navigation via IPC - subscribeToBroadcast(IpcRendererNavigationEvents.NAVIGATE_IN_APP, (event, url: string) => { + ipcRendererOn(IpcRendererNavigationEvents.NAVIGATE_IN_APP, (event, url: string) => { logger.info(`[IPC]: ${event.type}: ${url}`, { currentLocation: location.href }); navigate(url); }); @@ -68,7 +68,7 @@ function bindClusterManagerRouteEvents() { // Handle cluster-view renderer process events within iframes function bindClusterFrameRouteEvents() { - subscribeToBroadcast(IpcRendererNavigationEvents.NAVIGATE_IN_CLUSTER, (event, url: string) => { + ipcRendererOn(IpcRendererNavigationEvents.NAVIGATE_IN_CLUSTER, (event, url: string) => { logger.info(`[IPC]: ${event.type}: ${url}`, { currentLocation: location.href }); navigate(url); }); From e0a9fff62f15b80dc1ff90381efe757ea18cd939 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 19 May 2021 08:17:51 -0400 Subject: [PATCH 4/5] Ban circular dependencies - ApiManager now creates the instances of all stores - ReleaseStore is Singleton-like - Move most types and helper functions into seperate files Signed-off-by: Sebastian Malton --- .eslintrc.js | 17 + .../kube-object-event-status/src/resolver.tsx | 6 +- package.json | 1 + src/common/.gitkeep | 0 src/common/__tests__/cluster-store.test.ts | 12 +- src/common/base-store.ts | 3 +- .../catalog-entities/kubernetes-cluster.ts | 6 +- src/common/cluster-ipc.ts | 77 ----- src/common/cluster-store.ts | 131 +------- src/common/cluster-types.ts | 145 ++++++++ src/common/ipc/ipc.ts | 2 +- src/common/rbac.ts | 17 - src/common/user-store.ts | 3 +- src/common/utils/index.ts | 3 +- ...{saveToAppFiles.ts => kubeconfig-files.ts} | 28 +- src/extensions/registries/command-registry.ts | 4 + src/extensions/renderer-api/k8s-api.ts | 62 ++-- src/extensions/renderer-api/navigation.ts | 2 +- src/main/catalog-sources/kubeconfig-sync.ts | 7 +- .../cluster-detectors/cluster-id-detector.ts | 2 +- .../cluster-detectors/detector-registry.ts | 2 +- .../distribution-detector.ts | 6 +- .../cluster-detectors/last-seen-detector.ts | 2 +- .../cluster-detectors/nodes-count-detector.ts | 2 +- .../cluster-detectors/version-detector.ts | 2 +- src/main/cluster-manager.ts | 4 +- src/main/cluster.ts | 43 +-- src/main/context-handler.ts | 2 +- src/main/exit-app.ts | 12 +- src/main/helm/helm-release-manager.ts | 2 +- src/main/index.ts | 23 +- src/main/initializers/ipc-handlers.ts | 93 ++++++ src/main/proxy/lens-proxy.ts | 60 ++-- src/main/resource-applier.ts | 8 +- src/main/routes/metrics-route.ts | 4 +- src/main/window-manager.ts | 31 +- src/migrations/cluster-store/3.6.0-beta.1.ts | 7 +- src/migrations/cluster-store/snap.ts | 2 +- .../api/__tests__/api-manager.test.ts | 34 +- src/renderer/api/__tests__/kube-api.test.ts | 3 + src/renderer/api/api-manager.ts | 86 ++++- src/renderer/api/endpoints/cluster.api.ts | 6 +- .../endpoints/persistent-volume-claims.api.ts | 2 +- .../api/endpoints/poddisruptionbudget.api.ts | 2 +- .../api/endpoints/podsecuritypolicy.api.ts | 2 +- .../api/endpoints/resource-applier.api.ts | 20 +- src/renderer/api/kube-api-parse.ts | 54 --- src/renderer/api/kube-api.ts | 20 +- src/renderer/api/kube-object.ts | 6 +- src/renderer/api/kube-watch-api.ts | 37 ++- src/renderer/bootstrap.tsx | 4 +- .../components/+add-cluster/add-cluster.tsx | 3 +- .../+apps-releases/release-details.tsx | 20 +- .../+apps-releases/release-menu.tsx | 4 +- .../release-rollback-dialog.tsx | 4 +- .../+apps-releases/release.store.ts | 48 ++- .../components/+apps-releases/releases.tsx | 20 +- src/renderer/components/+apps/apps.tsx | 7 +- .../components/+cluster/cluster-issues.tsx | 23 +- .../+cluster/cluster-metric-switchers.tsx | 8 +- .../components/+cluster/cluster-metrics.tsx | 5 +- .../+cluster/cluster-overview.store.ts | 28 +- .../components/+cluster/cluster-overview.tsx | 26 +- .../+cluster/cluster-pie-charts.tsx | 9 +- .../+config-autoscalers/hpa-details.tsx | 6 +- .../+config-autoscalers/hpa.store.ts | 6 +- .../components/+config-autoscalers/hpa.tsx | 12 +- .../components/+config-autoscalers/index.ts | 1 + .../components/+config-limit-ranges/index.ts | 1 + .../limit-ranges.store.ts | 4 - .../+config-limit-ranges/limit-ranges.tsx | 11 +- .../+config-maps/config-map-details.tsx | 11 +- .../+config-maps/config-maps.store.ts | 4 - .../components/+config-maps/config-maps.tsx | 12 +- src/renderer/components/+config-maps/index.ts | 1 + .../+config-pod-disruption-budgets/index.ts | 1 + .../pod-disruption-budgets.store.ts | 8 +- .../pod-disruption-budgets.tsx | 11 +- .../+config-resource-quotas/index.ts | 1 + .../resource-quotas.store.ts | 4 - .../resource-quotas.tsx | 12 +- .../components/+config-secrets/index.ts | 1 + .../+config-secrets/secret-details.tsx | 11 +- .../+config-secrets/secrets.store.ts | 4 - .../components/+config-secrets/secrets.tsx | 12 +- src/renderer/components/+config/config.tsx | 20 +- .../components/+custom-resources/crd-list.tsx | 17 +- .../crd-resource-details.tsx | 7 +- .../+custom-resources/crd-resources.tsx | 13 +- .../components/+custom-resources/crd.store.ts | 23 +- .../+custom-resources/custom-resources.tsx | 5 +- .../components/+custom-resources/index.ts | 1 + .../components/+events/event-details.tsx | 4 +- .../components/+events/event.store.ts | 15 +- src/renderer/components/+events/events.tsx | 28 +- src/renderer/components/+events/index.ts | 1 + .../components/+events/kube-event-details.tsx | 12 +- .../components/+events/kube-event-icon.tsx | 11 +- .../+namespaces/add-namespace-dialog.tsx | 11 +- src/renderer/components/+namespaces/index.ts | 1 + .../+namespaces/namespace-details.tsx | 27 +- .../+namespaces/namespace-select-filter.tsx | 15 +- .../+namespaces/namespace-select.tsx | 21 +- .../components/+namespaces/namespace.store.ts | 19 +- .../components/+namespaces/namespaces.tsx | 12 +- .../endpoint-subset-list.tsx | 4 +- .../+network-endpoints/endpoints.store.ts | 4 - .../+network-endpoints/endpoints.tsx | 12 +- .../components/+network-endpoints/index.ts | 1 + .../components/+network-ingresses/index.ts | 1 + .../+network-ingresses/ingress-details.tsx | 17 +- .../+network-ingresses/ingress.store.ts | 4 - .../+network-ingresses/ingresses.tsx | 12 +- .../components/+network-policies/index.ts | 1 + .../+network-policies/network-policies.tsx | 12 +- .../+network-policies/network-policy.store.ts | 4 - .../components/+network-services/index.ts | 1 + .../service-details-endpoint.tsx | 10 +- .../+network-services/service-details.tsx | 20 +- .../+network-services/services.store.ts | 4 - .../components/+network-services/services.tsx | 12 +- src/renderer/components/+network/network.tsx | 16 +- src/renderer/components/+nodes/index.ts | 1 + .../components/+nodes/node-details.tsx | 29 +- src/renderer/components/+nodes/nodes.store.ts | 4 - src/renderer/components/+nodes/nodes.tsx | 36 +- .../+pod-security-policies/index.ts | 1 + .../pod-security-policies.store.ts | 8 +- .../pod-security-policies.tsx | 11 +- .../components/+storage-classes/index.ts | 1 + .../storage-class-details.tsx | 19 +- .../+storage-classes/storage-class.store.ts | 14 +- .../+storage-classes/storage-classes.tsx | 12 +- .../+storage-volume-claims/index.ts | 1 + .../volume-claim-details.tsx | 25 +- .../volume-claim.store.ts | 12 +- .../+storage-volume-claims/volume-claims.tsx | 21 +- .../components/+storage-volumes/index.ts | 1 + .../+storage-volumes/volume-details-list.tsx | 13 +- .../+storage-volumes/volume-details.tsx | 4 +- .../+storage-volumes/volumes.store.ts | 4 - .../components/+storage-volumes/volumes.tsx | 16 +- src/renderer/components/+storage/storage.tsx | 14 +- .../add-role-binding-dialog.tsx | 52 +-- .../+user-management-roles-bindings/index.ts | 1 + .../role-binding-details.tsx | 11 +- .../role-bindings.store.ts | 8 - .../role-bindings.tsx | 11 +- .../add-role-dialog.tsx | 10 +- .../+user-management-roles/index.ts | 1 + .../+user-management-roles/roles.store.ts | 8 - .../+user-management-roles/roles.tsx | 11 +- .../create-service-account-dialog.tsx | 10 +- .../index.ts | 1 + .../service-accounts-details.tsx | 15 +- .../service-accounts.store.ts | 4 - .../service-accounts.tsx | 12 +- .../+user-management/user-management.tsx | 16 +- .../+workloads-cronjobs/cronjob-details.tsx | 21 +- .../+workloads-cronjobs/cronjob.store.ts | 14 +- .../+workloads-cronjobs/cronjobs.tsx | 25 +- .../components/+workloads-cronjobs/index.ts | 1 + .../daemonset-details.tsx | 29 +- .../+workloads-daemonsets/daemonsets.store.ts | 13 +- .../+workloads-daemonsets/daemonsets.tsx | 34 +- .../components/+workloads-daemonsets/index.ts | 1 + .../deployment-details.tsx | 57 ++-- .../deployment-replicasets.tsx | 13 +- .../deployment-scale-dialog.test.tsx | 6 +- .../deployments.store.ts | 13 +- .../+workloads-deployments/deployments.tsx | 38 ++- .../+workloads-deployments/index.ts | 1 + .../components/+workloads-jobs/index.ts | 1 + .../+workloads-jobs/job-details.tsx | 22 +- .../components/+workloads-jobs/job.store.ts | 15 +- .../components/+workloads-jobs/jobs.tsx | 27 +- .../+workloads-overview/overview-statuses.tsx | 43 +-- .../+workloads-overview/overview.tsx | 38 +-- .../components/+workloads-pods/index.ts | 1 + .../+workloads-pods/pod-container-env.tsx | 10 +- .../+workloads-pods/pod-details-list.tsx | 19 +- .../+workloads-pods/pod-details.tsx | 21 +- .../components/+workloads-pods/pods.store.ts | 4 - .../components/+workloads-pods/pods.tsx | 29 +- .../+workloads-replicasets/index.ts | 1 + .../replicaset-details.tsx | 29 +- .../replicaset-scale-dialog.test.tsx | 2 +- .../replicasets.store.ts | 11 +- .../+workloads-replicasets/replicasets.tsx | 12 +- .../+workloads-statefulsets/index.ts | 1 + .../statefulset-details.tsx | 29 +- .../statefulset-scale-dialog.test.tsx | 2 +- .../statefulset.store.ts | 11 +- .../+workloads-statefulsets/statefulsets.tsx | 36 +- src/renderer/components/+workloads/index.ts | 1 - .../components/+workloads/workloads.stores.ts | 40 --- .../components/+workloads/workloads.tsx | 22 +- src/renderer/components/app.tsx | 60 ++-- .../cluster-manager/cluster-status.tsx | 3 +- .../components/cluster-manager/lens-views.ts | 4 +- .../command-palette/command-container.tsx | 61 +--- .../command-palette/command-dialog.tsx | 2 +- .../components/command-palette/index.ts | 1 + .../overlay.ts} | 23 +- src/renderer/components/context.ts | 67 ++-- .../dock/__test__/log-tab.store.test.ts | 8 +- .../components/dock/create-resource.tsx | 2 +- .../components/dock/edit-resource.store.ts | 8 +- .../components/dock/install-chart.tsx | 4 +- .../components/dock/log-resource-selector.tsx | 6 +- src/renderer/components/dock/log-tab.store.ts | 17 +- .../components/dock/upgrade-chart.store.ts | 16 +- .../components/dock/upgrade-chart.tsx | 6 +- .../item-object-list/item-list-layout.tsx | 9 +- .../item-object-list/page-filters-select.tsx | 10 +- src/renderer/components/kube-object/index.ts | 1 + .../kube-object/kube-object-details.tsx | 78 +---- .../kube-object/kube-object-list-layout.tsx | 25 +- .../kube-object/kube-object-menu.tsx | 6 +- .../kube-object/kube-object-meta.tsx | 6 +- src/renderer/components/kube-object/params.ts | 69 ++++ src/renderer/components/layout/sidebar.tsx | 203 +++++++----- src/renderer/components/menu/menu-actions.tsx | 2 +- .../components/virtual-list/virtual-list.tsx | 2 +- .../initializers/api-manager-stores.ts | 85 +++++ src/renderer/kube-object.store.ts | 62 ++-- src/renderer/utils/createStorage.ts | 12 +- src/renderer/utils/storageHelper.ts | 4 +- webpack.extensions.ts | 12 +- webpack.main.ts | 6 + webpack.renderer.ts | 13 +- yarn.lock | 313 +++++++++++++++++- 232 files changed, 2533 insertions(+), 1630 deletions(-) delete mode 100644 src/common/.gitkeep create mode 100644 src/common/cluster-types.ts rename src/common/utils/{saveToAppFiles.ts => kubeconfig-files.ts} (58%) create mode 100644 src/main/initializers/ipc-handlers.ts delete mode 100644 src/renderer/components/+workloads/workloads.stores.ts rename src/renderer/components/{+custom-resources/crd-resource.store.ts => command-palette/overlay.ts} (74%) create mode 100644 src/renderer/components/kube-object/params.ts create mode 100644 src/renderer/initializers/api-manager-stores.ts diff --git a/.eslintrc.js b/.eslintrc.js index 33d28967ff64..b993078333d7 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -33,12 +33,22 @@ module.exports = { } }, overrides: [ + { + files: [ + "extensions/**/*.ts", + "extensions/**/*.tsx", + ], + rules: { + "import/no-unresolved": "off", // warns on @k8slens/extensions + } + }, { files: [ "**/*.js" ], extends: [ "eslint:recommended", + "plugin:import/recommended", ], env: { node: true @@ -53,6 +63,7 @@ module.exports = { ], rules: { "header/header": [2, "./license-header"], + // "import/no-cycle": 2, "indent": ["error", 2, { "SwitchCase": 1, }], @@ -93,6 +104,8 @@ module.exports = { parser: "@typescript-eslint/parser", extends: [ "plugin:@typescript-eslint/recommended", + "plugin:import/recommended", + "plugin:import/typescript", ], plugins: [ "header", @@ -104,6 +117,7 @@ module.exports = { }, rules: { "header/header": [2, "./license-header"], + // "import/no-cycle": 2, "no-invalid-this": "off", "@typescript-eslint/no-invalid-this": ["error"], "@typescript-eslint/explicit-function-return-type": "off", @@ -158,6 +172,8 @@ module.exports = { extends: [ "plugin:@typescript-eslint/recommended", "plugin:react/recommended", + "plugin:import/recommended", + "plugin:import/typescript", ], parserOptions: { ecmaVersion: 2018, @@ -166,6 +182,7 @@ module.exports = { }, rules: { "header/header": [2, "./license-header"], + // "import/no-cycle": 2, "no-invalid-this": "off", "@typescript-eslint/no-invalid-this": ["error"], "@typescript-eslint/explicit-function-return-type": "off", diff --git a/extensions/kube-object-event-status/src/resolver.tsx b/extensions/kube-object-event-status/src/resolver.tsx index 03e1f0cdd9b4..52a0c5c040b5 100644 --- a/extensions/kube-object-event-status/src/resolver.tsx +++ b/extensions/kube-object-event-status/src/resolver.tsx @@ -22,7 +22,7 @@ import { K8sApi } from "@k8slens/extensions"; export function resolveStatus(object: K8sApi.KubeObject): K8sApi.KubeObjectStatus { - const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi); + const eventStore = K8sApi.ApiManager.getInstance().getStore(K8sApi.eventApi); const events = (eventStore as K8sApi.EventStore).getEventsByObject(object); const warnings = events.filter(evt => evt.isWarning()); @@ -42,7 +42,7 @@ export function resolveStatusForPods(pod: K8sApi.Pod): K8sApi.KubeObjectStatus { if (!pod.hasIssues()) { return null; } - const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi); + const eventStore = K8sApi.ApiManager.getInstance().getStore(K8sApi.eventApi); const events = (eventStore as K8sApi.EventStore).getEventsByObject(pod); const warnings = events.filter(evt => evt.isWarning()); @@ -59,7 +59,7 @@ export function resolveStatusForPods(pod: K8sApi.Pod): K8sApi.KubeObjectStatus { } export function resolveStatusForCronJobs(cronJob: K8sApi.CronJob): K8sApi.KubeObjectStatus { - const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi); + const eventStore = K8sApi.ApiManager.getInstance().getStore(K8sApi.eventApi); let events = (eventStore as K8sApi.EventStore).getEventsByObject(cronJob); const warnings = events.filter(evt => evt.isWarning()); diff --git a/package.json b/package.json index 05b64573578d..7d7368093e4f 100644 --- a/package.json +++ b/package.json @@ -315,6 +315,7 @@ "electron-notarize": "^0.3.0", "eslint": "^7.7.0", "eslint-plugin-header": "^3.1.1", + "eslint-plugin-import": "^2.23.2", "eslint-plugin-react": "^7.21.5", "eslint-plugin-unused-imports": "^1.0.1", "file-loader": "^6.0.0", diff --git a/src/common/.gitkeep b/src/common/.gitkeep deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/src/common/__tests__/cluster-store.test.ts b/src/common/__tests__/cluster-store.test.ts index 7a82547e618c..249006c3e626 100644 --- a/src/common/__tests__/cluster-store.test.ts +++ b/src/common/__tests__/cluster-store.test.ts @@ -23,9 +23,11 @@ import fs from "fs"; import mockFs from "mock-fs"; import yaml from "js-yaml"; import { Cluster } from "../../main/cluster"; -import { ClusterStore, getClusterIdFromHost } from "../cluster-store"; +import { ClusterStore } from "../cluster-store"; import { Console } from "console"; import { stdout, stderr } from "process"; +import { embedCustomKubeConfig } from "../utils"; +import { getClusterIdFromHost } from "../cluster-types"; console = new Console(stdout, stderr); @@ -102,7 +104,7 @@ describe("empty config", () => { icon: "data:image/jpeg;base64, iVBORw0KGgoAAAANSUhEUgAAA1wAAAKoCAYAAABjkf5", clusterName: "minikube" }, - kubeConfigPath: ClusterStore.embedCustomKubeConfig("foo", kubeconfig) + kubeConfigPath: embedCustomKubeConfig("foo", kubeconfig) }) ); }); @@ -135,7 +137,7 @@ describe("empty config", () => { preferences: { clusterName: "prod" }, - kubeConfigPath: ClusterStore.embedCustomKubeConfig("prod", kubeconfig) + kubeConfigPath: embedCustomKubeConfig("prod", kubeconfig) }), new Cluster({ id: "dev", @@ -143,7 +145,7 @@ describe("empty config", () => { preferences: { clusterName: "dev" }, - kubeConfigPath: ClusterStore.embedCustomKubeConfig("dev", kubeconfig) + kubeConfigPath: embedCustomKubeConfig("dev", kubeconfig) }) ); }); @@ -154,7 +156,7 @@ describe("empty config", () => { }); it("check if cluster's kubeconfig file saved", () => { - const file = ClusterStore.embedCustomKubeConfig("boo", "kubeconfig"); + const file = embedCustomKubeConfig("boo", "kubeconfig"); expect(fs.readFileSync(file, "utf8")).toBe("kubeconfig"); }); diff --git a/src/common/base-store.ts b/src/common/base-store.ts index 2655aab8fce3..cb2b285b4d1c 100644 --- a/src/common/base-store.ts +++ b/src/common/base-store.ts @@ -24,8 +24,7 @@ import Config from "conf"; import type { Options as ConfOptions } from "conf/dist/source/types"; import { app, ipcMain, ipcRenderer, remote } from "electron"; import { IReactionOptions, observable, reaction, runInAction, when } from "mobx"; -import Singleton from "./utils/singleton"; -import { getAppVersion } from "./utils/app-version"; +import { Singleton, getAppVersion } from "./utils"; import logger from "../main/logger"; import { broadcastMessage, ipcMainOn, ipcRendererOn } from "./ipc"; import isEqual from "lodash/isEqual"; diff --git a/src/common/catalog-entities/kubernetes-cluster.ts b/src/common/catalog-entities/kubernetes-cluster.ts index ca78cba92c43..0e9a4bed67dc 100644 --- a/src/common/catalog-entities/kubernetes-cluster.ts +++ b/src/common/catalog-entities/kubernetes-cluster.ts @@ -20,13 +20,13 @@ */ import { catalogCategoryRegistry } from "../catalog/catalog-category-registry"; -import { CatalogEntity, CatalogEntityActionContext, CatalogEntityAddMenuContext, CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog"; +import { CatalogEntity, CatalogEntityActionContext, CatalogEntityAddMenuContext, CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus, CatalogCategory, CatalogCategorySpec } from "../catalog"; 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 { addClusterURL } from "../routes"; +import { storedKubeConfigFolder } from "../utils"; import { app } from "electron"; export type KubernetesClusterPrometheusMetrics = { @@ -109,7 +109,7 @@ export class KubernetesCluster extends CatalogEntity { - return ClusterStore.getInstance() - .getById(clusterId) - ?.activate(force); - }); - - ipcMain.handle(clusterSetFrameIdHandler, (event: IpcMainInvokeEvent, clusterId: ClusterId) => { - const cluster = ClusterStore.getInstance().getById(clusterId); - - if (cluster) { - clusterFrameMap.set(cluster.id, { frameId: event.frameId, processId: event.processId }); - cluster.pushState(); - } - }); - - ipcMain.handle(clusterRefreshHandler, (event, clusterId: ClusterId) => { - return ClusterStore.getInstance() - .getById(clusterId) - ?.refresh({ refreshMetadata: true }); - }); - - ipcMain.handle(clusterDisconnectHandler, (event, clusterId: ClusterId) => { - appEventBus.emit({name: "cluster", action: "stop"}); - const cluster = ClusterStore.getInstance().getById(clusterId); - - if (cluster) { - cluster.disconnect(); - clusterFrameMap.delete(cluster.id); - } - }); - - ipcMain.handle(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); - - 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`; - } - }); - - ipcMain.handle(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/cluster-store.ts b/src/common/cluster-store.ts index c50968fd897c..56432714d58c 100644 --- a/src/common/cluster-store.ts +++ b/src/common/cluster-store.ts @@ -19,120 +19,24 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import path from "path"; import { app, ipcMain, ipcRenderer, remote, webFrame } from "electron"; -import { unlink } from "fs-extra"; +import * as fse from "fs-extra"; +import path from "path"; import { action, comparer, computed, observable, reaction, toJS } from "mobx"; import { BaseStore } from "./base-store"; -import { Cluster, ClusterState } from "../main/cluster"; +import { Cluster } from "../main/cluster"; import migrations from "../migrations/cluster-store"; import logger from "../main/logger"; import { appEventBus } from "./event-bus"; -import { dumpConfigYaml } from "./kube-helpers"; -import { saveToAppFiles } from "./utils/saveToAppFiles"; -import type { KubeConfig } from "@kubernetes/client-node"; import { ipcMainOn, ipcRendererOn, requestMain } from "./ipc"; import type { ResourceType } from "../renderer/components/cluster-settings/components/cluster-metrics-setting"; -import { disposer, noop } from "./utils"; - -export interface ClusterIconUpload { - clusterId: string; - name: string; - path: string; -} - -export interface ClusterMetadata { - [key: string]: string | number | boolean | object; -} - -export type ClusterPrometheusMetadata = { - success?: boolean; - provider?: string; - autoDetected?: boolean; -}; - -export interface ClusterStoreModel { - activeCluster?: ClusterId; // last opened cluster - clusters?: ClusterModel[]; -} - -export type ClusterId = string; - -export interface UpdateClusterModel extends Omit { - id?: ClusterId; -} - -export interface ClusterModel { - /** Unique id for a cluster */ - id: ClusterId; - - /** Path to cluster kubeconfig */ - kubeConfigPath: string; - - /** - * Workspace id - * - * @deprecated - */ - workspace?: string; - - /** User context in kubeconfig */ - contextName?: string; - - /** Preferences */ - preferences?: ClusterPreferences; - - /** Metadata */ - metadata?: ClusterMetadata; - - /** List of accessible namespaces */ - accessibleNamespaces?: string[]; - - /** @deprecated */ - kubeConfig?: string; // yaml -} - -export interface ClusterPreferences extends ClusterPrometheusPreferences { - terminalCWD?: string; - clusterName?: string; - iconOrder?: number; - icon?: string; - httpsProxy?: string; - hiddenMetrics?: string[]; -} - -export interface ClusterPrometheusPreferences { - prometheus?: { - namespace: string; - service: string; - port: number; - prefix: string; - }; - prometheusProvider?: { - type: string; - }; -} +import { disposer, getCustomKubeConfigPath, noop } from "./utils"; +import type { ClusterStoreModel, ClusterId, ClusterModel, ClusterState } from "./cluster-types"; +import { getHostedClusterId } from "./cluster-types"; export class ClusterStore extends BaseStore { private static StateChannel = "cluster:state"; - static get storedKubeConfigFolder(): string { - return path.resolve((app || remote.app).getPath("userData"), "kubeconfigs"); - } - - static getCustomKubeConfigPath(clusterId: ClusterId): string { - return path.resolve(ClusterStore.storedKubeConfigFolder, clusterId); - } - - static embedCustomKubeConfig(clusterId: ClusterId, kubeConfig: KubeConfig | string): string { - const filePath = ClusterStore.getCustomKubeConfigPath(clusterId); - const fileContents = typeof kubeConfig == "string" ? kubeConfig : dumpConfigYaml(kubeConfig); - - saveToAppFiles(filePath, fileContents, { mode: 0o600 }); - - return filePath; - } - @observable activeCluster: ClusterId; @observable removedClusters = observable.map(); @observable clusters = observable.map(); @@ -311,9 +215,13 @@ export class ClusterStore extends BaseStore { } // remove only custom kubeconfigs (pasted as text) - if (cluster.kubeConfigPath == ClusterStore.getCustomKubeConfigPath(clusterId)) { - await unlink(cluster.kubeConfigPath).catch(noop); + if (cluster.kubeConfigPath == getCustomKubeConfigPath(clusterId)) { + await fse.unlink(cluster.kubeConfigPath).catch(noop); } + + const localStorage = path.resolve((app || remote.app).getPath("userData"), "lens-local-storage", `${cluster.id}.json`); + + await fse.unlink(localStorage).catch(noop); } } @@ -361,21 +269,6 @@ export class ClusterStore extends BaseStore { } } -export function getClusterIdFromHost(host: string): ClusterId | undefined { - // e.g host == "%clusterId.localhost:45345" - const subDomains = host.split(":")[0].split("."); - - return subDomains.slice(-2, -1)[0]; // ClusterId or undefined -} - -export function getClusterFrameUrl(clusterId: ClusterId) { - return `//${clusterId}.${location.host}`; -} - -export function getHostedClusterId() { - return getClusterIdFromHost(location.host); -} - export function getHostedCluster(): Cluster { return ClusterStore.getInstance().getById(getHostedClusterId()); } diff --git a/src/common/cluster-types.ts b/src/common/cluster-types.ts new file mode 100644 index 000000000000..a31cdaf23326 --- /dev/null +++ b/src/common/cluster-types.ts @@ -0,0 +1,145 @@ +/** + * 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 enum ClusterStatus { + AccessGranted = 2, + AccessDenied = 1, + Offline = 0 +} + +export enum ClusterMetadataKey { + VERSION = "version", + CLUSTER_ID = "id", + DISTRIBUTION = "distribution", + NODES_COUNT = "nodes", + LAST_SEEN = "lastSeen", + PROMETHEUS = "prometheus" +} + +export type ClusterRefreshOptions = { + refreshMetadata?: boolean +}; + +export interface ClusterState { + apiUrl: string; + online: boolean; + disconnected: boolean; + accessible: boolean; + ready: boolean; + failureReason: string; + isAdmin: boolean; + allowedNamespaces: string[] + allowedResources: string[] + isGlobalWatchEnabled: boolean; +} + +export interface ClusterIconUpload { + clusterId: string; + name: string; + path: string; +} + +export interface ClusterMetadata { + [key: string]: string | number | boolean | object; +} + +export type ClusterPrometheusMetadata = { + success?: boolean; + provider?: string; + autoDetected?: boolean; +}; + +export interface ClusterStoreModel { + activeCluster?: ClusterId; // last opened cluster + clusters?: ClusterModel[]; +} + +export type ClusterId = string; + +export interface UpdateClusterModel extends Omit { + id?: ClusterId; +} + +export interface ClusterModel { + /** Unique id for a cluster */ + id: ClusterId; + + /** Path to cluster kubeconfig */ + kubeConfigPath: string; + + /** + * Workspace id + * + * @deprecated + */ + workspace?: string; + + /** User context in kubeconfig */ + contextName?: string; + + /** Preferences */ + preferences?: ClusterPreferences; + + /** Metadata */ + metadata?: ClusterMetadata; + + /** List of accessible namespaces */ + accessibleNamespaces?: string[]; + + /** @deprecated */ + kubeConfig?: string; // yaml +} + +export interface ClusterPreferences extends ClusterPrometheusPreferences { + terminalCWD?: string; + clusterName?: string; + iconOrder?: number; + icon?: string; + httpsProxy?: string; + hiddenMetrics?: string[]; +} + +export interface ClusterPrometheusPreferences { + prometheus?: { + namespace: string; + service: string; + port: number; + prefix: string; + }; + prometheusProvider?: { + type: string; + }; +} + +export function getClusterIdFromHost(host: string): ClusterId | undefined { + // e.g host == "%clusterId.localhost:45345" + const subDomains = host.split(":")[0].split("."); + + return subDomains.slice(-2, -1)[0]; // ClusterId or undefined +} + +export function getClusterFrameUrl(clusterId: ClusterId) { + return `//${clusterId}.${location.host}`; +} + +export function getHostedClusterId() { + return getClusterIdFromHost(location.host); +} diff --git a/src/common/ipc/ipc.ts b/src/common/ipc/ipc.ts index 917fe29571df..24750ac4bc31 100644 --- a/src/common/ipc/ipc.ts +++ b/src/common/ipc/ipc.ts @@ -80,6 +80,6 @@ export function ipcRendererOn(channel: string, listener: (event: Electron.IpcRen return () => ipcRenderer.off(channel, listener); } -export function bindBroadcastHandlers() { +export function initGetSubFramesHandler() { ipcMain.handle(subFramesChannel, getSubFrames); } diff --git a/src/common/rbac.ts b/src/common/rbac.ts index 55b8ca414cad..b5260431d747 100644 --- a/src/common/rbac.ts +++ b/src/common/rbac.ts @@ -19,8 +19,6 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { getHostedCluster } from "./cluster-store"; - export type KubeResource = "namespaces" | "nodes" | "events" | "resourcequotas" | "services" | "limitranges" | "secrets" | "configmaps" | "ingresses" | "networkpolicies" | "persistentvolumeclaims" | "persistentvolumes" | "storageclasses" | @@ -73,18 +71,3 @@ export const apiResourceRecord: Record = { // TODO: auto-populate all resources dynamically (see: kubectl api-resources -o=wide -v=7) export const apiResources: KubeApiResource[] = Object.entries(apiResourceRecord) .map(([apiName, data]) => ({ apiName: apiName as KubeResource, ...data })); - -export function isAllowedResource(resources: KubeResource | KubeResource[]) { - if (!Array.isArray(resources)) { - resources = [resources]; - } - const { allowedResources = [] } = getHostedCluster() || {}; - - for (const resource of resources) { - if (!allowedResources.includes(resource)) { - return false; - } - } - - return true; -} diff --git a/src/common/user-store.ts b/src/common/user-store.ts index 19ba33615cab..c07ee8c18862 100644 --- a/src/common/user-store.ts +++ b/src/common/user-store.ts @@ -26,14 +26,13 @@ import { readFile } from "fs-extra"; import { action, computed, observable, reaction, toJS } from "mobx"; import moment from "moment-timezone"; import { BaseStore } from "./base-store"; -import migrations from "../migrations/user-store"; +import migrations, { fileNameMigration } from "../migrations/user-store"; import { getAppVersion } from "./utils/app-version"; import { kubeConfigDefaultPath, loadConfig } from "./kube-helpers"; import { appEventBus } from "./event-bus"; import logger from "../main/logger"; import path from "path"; import os from "os"; -import { fileNameMigration } from "../migrations/user-store"; import { ObservableToggleSet } from "../renderer/utils"; export interface UserStoreModel { diff --git a/src/common/utils/index.ts b/src/common/utils/index.ts index 5b1315954920..8bdf9df343e8 100644 --- a/src/common/utils/index.ts +++ b/src/common/utils/index.ts @@ -32,14 +32,13 @@ export * from "./debouncePromise"; export * from "./defineGlobal"; export * from "./delay"; export * from "./disposer"; -export * from "./disposer"; export * from "./downloadFile"; export * from "./escapeRegExp"; export * from "./extended-map"; export * from "./getRandId"; export * from "./openExternal"; export * from "./reject-promise"; -export * from "./saveToAppFiles"; +export * from "./kubeconfig-files"; export * from "./singleton"; export * from "./splitArray"; export * from "./tar"; diff --git a/src/common/utils/saveToAppFiles.ts b/src/common/utils/kubeconfig-files.ts similarity index 58% rename from src/common/utils/saveToAppFiles.ts rename to src/common/utils/kubeconfig-files.ts index b957cdb38ec7..a75fe8a324f9 100644 --- a/src/common/utils/saveToAppFiles.ts +++ b/src/common/utils/kubeconfig-files.ts @@ -19,17 +19,27 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -// Save file to electron app directory (e.g. "/Users/$USER/Library/Application Support/Lens" for MacOS) -import path from "path"; +import type { KubeConfig } from "@kubernetes/client-node"; import { app, remote } from "electron"; -import { ensureDirSync, writeFileSync } from "fs-extra"; -import type { WriteFileOptions } from "fs"; +import path from "path"; +import type { ClusterId } from "../cluster-types"; +import { dumpConfigYaml } from "../kube-helpers"; +import * as fse from "fs-extra"; + +export function storedKubeConfigFolder(): string { + return path.resolve((app || remote.app).getPath("userData"), "kubeconfigs"); +} + +export function getCustomKubeConfigPath(clusterId: ClusterId): string { + return path.resolve(storedKubeConfigFolder(), clusterId); +} -export function saveToAppFiles(filePath: string, contents: any, options?: WriteFileOptions): string { - const absPath = path.resolve((app || remote.app).getPath("userData"), filePath); +export function embedCustomKubeConfig(clusterId: ClusterId, kubeConfig: KubeConfig | string): string { + const filePath = getCustomKubeConfigPath(clusterId); + const fileContents = typeof kubeConfig == "string" ? kubeConfig : dumpConfigYaml(kubeConfig); - ensureDirSync(path.dirname(absPath)); - writeFileSync(absPath, contents, options); + fse.ensureDirSync(path.dirname(filePath)); + fse.writeFileSync(filePath, fileContents, { mode: 0o600 }); - return absPath; + return filePath; } diff --git a/src/extensions/registries/command-registry.ts b/src/extensions/registries/command-registry.ts index 967fbd12710d..5ecd23dfc8d0 100644 --- a/src/extensions/registries/command-registry.ts +++ b/src/extensions/registries/command-registry.ts @@ -53,4 +53,8 @@ export class CommandRegistry extends BaseRegistry { return super.add(filteredItems, extension); } + + getById(commandId: string): CommandRegistration | undefined { + return this.getItems().find(({ id }) => id == commandId); + } } diff --git a/src/extensions/renderer-api/k8s-api.ts b/src/extensions/renderer-api/k8s-api.ts index d16dbe83f523..ae58e13595e3 100644 --- a/src/extensions/renderer-api/k8s-api.ts +++ b/src/extensions/renderer-api/k8s-api.ts @@ -19,9 +19,8 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export { isAllowedResource } from "../../common/rbac"; export { ResourceStack } from "../../common/k8s/resource-stack"; -export { apiManager } from "../../renderer/api/api-manager"; +export { ApiManager } from "../../renderer/api/api-manager"; export { KubeObjectStore } from "../../renderer/kube-object.store"; export { KubeApi, forCluster } from "../../renderer/api/kube-api"; export { KubeObject } from "../../renderer/api/kube-object"; @@ -38,13 +37,13 @@ export { ReplicaSet, replicaSetApi } from "../../renderer/api/endpoints"; export { ResourceQuota, resourceQuotaApi } from "../../renderer/api/endpoints"; export { LimitRange, limitRangeApi } from "../../renderer/api/endpoints"; export { HorizontalPodAutoscaler, hpaApi } from "../../renderer/api/endpoints"; -export { PodDisruptionBudget, pdbApi } from "../../renderer/api/endpoints"; +export { PodDisruptionBudget, podDisruptionBudgetApi } from "../../renderer/api/endpoints"; export { Service, serviceApi } from "../../renderer/api/endpoints"; export { Endpoint, endpointApi } from "../../renderer/api/endpoints"; export { Ingress, ingressApi, IngressApi } from "../../renderer/api/endpoints"; export { NetworkPolicy, networkPolicyApi } from "../../renderer/api/endpoints"; export { PersistentVolume, persistentVolumeApi } from "../../renderer/api/endpoints"; -export { PersistentVolumeClaim, pvcApi, PersistentVolumeClaimsApi } from "../../renderer/api/endpoints"; +export { PersistentVolumeClaim, persistentVolumeClaimsApi, PersistentVolumeClaimsApi } from "../../renderer/api/endpoints"; export { StorageClass, storageClassApi } from "../../renderer/api/endpoints"; export { Namespace, namespacesApi } from "../../renderer/api/endpoints"; export { KubeEvent, eventApi } from "../../renderer/api/endpoints"; @@ -63,31 +62,30 @@ export type { ISecretRef } from "../../renderer/api/endpoints"; export type { KubeObjectStatus } from "./kube-object-status"; // stores -export type { EventStore } from "../../renderer/components/+events/event.store"; -export type { PodsStore } from "../../renderer/components/+workloads-pods/pods.store"; -export type { NodesStore } from "../../renderer/components/+nodes/nodes.store"; -export type { DeploymentStore } from "../../renderer/components/+workloads-deployments/deployments.store"; -export type { DaemonSetStore } from "../../renderer/components/+workloads-daemonsets/daemonsets.store"; -export type { StatefulSetStore } from "../../renderer/components/+workloads-statefulsets/statefulset.store"; -export type { JobStore } from "../../renderer/components/+workloads-jobs/job.store"; -export type { CronJobStore } from "../../renderer/components/+workloads-cronjobs/cronjob.store"; -export type { ConfigMapsStore } from "../../renderer/components/+config-maps/config-maps.store"; -export type { SecretsStore } from "../../renderer/components/+config-secrets/secrets.store"; -export type { ReplicaSetStore } from "../../renderer/components/+workloads-replicasets/replicasets.store"; -export type { ResourceQuotasStore } from "../../renderer/components/+config-resource-quotas/resource-quotas.store"; -export type { LimitRangesStore } from "../../renderer/components/+config-limit-ranges/limit-ranges.store"; -export type { HPAStore } from "../../renderer/components/+config-autoscalers/hpa.store"; -export type { PodDisruptionBudgetsStore } from "../../renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store"; -export type { ServiceStore } from "../../renderer/components/+network-services/services.store"; -export type { EndpointStore } from "../../renderer/components/+network-endpoints/endpoints.store"; -export type { IngressStore } from "../../renderer/components/+network-ingresses/ingress.store"; -export type { NetworkPolicyStore } from "../../renderer/components/+network-policies/network-policy.store"; -export type { PersistentVolumesStore } from "../../renderer/components/+storage-volumes/volumes.store"; -export type { VolumeClaimStore } from "../../renderer/components/+storage-volume-claims/volume-claim.store"; -export type { StorageClassStore } from "../../renderer/components/+storage-classes/storage-class.store"; -export type { NamespaceStore } from "../../renderer/components/+namespaces/namespace.store"; -export type { ServiceAccountsStore } from "../../renderer/components/+user-management-service-accounts/service-accounts.store"; -export type { RolesStore } from "../../renderer/components/+user-management-roles/roles.store"; -export type { RoleBindingsStore } from "../../renderer/components/+user-management-roles-bindings/role-bindings.store"; -export type { CRDStore } from "../../renderer/components/+custom-resources/crd.store"; -export type { CRDResourceStore } from "../../renderer/components/+custom-resources/crd-resource.store"; +export type { EventStore } from "../../renderer/components/+events"; +export type { PodsStore } from "../../renderer/components/+workloads-pods"; +export type { NodesStore } from "../../renderer/components/+nodes"; +export type { DeploymentStore } from "../../renderer/components/+workloads-deployments"; +export type { DaemonSetStore } from "../../renderer/components/+workloads-daemonsets"; +export type { StatefulSetStore } from "../../renderer/components/+workloads-statefulsets"; +export type { JobStore } from "../../renderer/components/+workloads-jobs"; +export type { CronJobStore } from "../../renderer/components/+workloads-cronjobs"; +export type { ConfigMapsStore } from "../../renderer/components/+config-maps"; +export type { SecretsStore } from "../../renderer/components/+config-secrets"; +export type { ReplicaSetStore } from "../../renderer/components/+workloads-replicasets"; +export type { ResourceQuotasStore } from "../../renderer/components/+config-resource-quotas"; +export type { LimitRangesStore } from "../../renderer/components/+config-limit-ranges"; +export type { HpaStore as HPAStore } from "../../renderer/components/+config-autoscalers"; +export type { PodDisruptionBudgetsStore } from "../../renderer/components/+config-pod-disruption-budgets"; +export type { ServiceStore } from "../../renderer/components/+network-services"; +export type { EndpointStore } from "../../renderer/components/+network-endpoints"; +export type { IngressStore } from "../../renderer/components/+network-ingresses"; +export type { NetworkPolicyStore } from "../../renderer/components/+network-policies"; +export type { PersistentVolumesStore } from "../../renderer/components/+storage-volumes"; +export type { PersistentVolumeClaimStore as VolumeClaimStore } from "../../renderer/components/+storage-volume-claims"; +export type { StorageClassStore } from "../../renderer/components/+storage-classes"; +export type { NamespaceStore } from "../../renderer/components/+namespaces"; +export type { ServiceAccountsStore } from "../../renderer/components/+user-management-service-accounts"; +export type { RolesStore } from "../../renderer/components/+user-management-roles"; +export type { RoleBindingsStore } from "../../renderer/components/+user-management-roles-bindings"; +export type { CrdStore as CRDStore } from "../../renderer/components/+custom-resources"; diff --git a/src/extensions/renderer-api/navigation.ts b/src/extensions/renderer-api/navigation.ts index 7fc321f620ca..86b4fb9c8abe 100644 --- a/src/extensions/renderer-api/navigation.ts +++ b/src/extensions/renderer-api/navigation.ts @@ -24,7 +24,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 { hideDetails, showDetails, getDetailsUrl } from "../../renderer/components/kube-object/params"; export type { URLParams } from "../../common/utils/buildUrl"; // exporting to extensions-api version of helper without `isSystem` flag diff --git a/src/main/catalog-sources/kubeconfig-sync.ts b/src/main/catalog-sources/kubeconfig-sync.ts index c72b6081f2b5..1b36518df330 100644 --- a/src/main/catalog-sources/kubeconfig-sync.ts +++ b/src/main/catalog-sources/kubeconfig-sync.ts @@ -26,14 +26,15 @@ import { watch } from "chokidar"; import fs from "fs"; import fse from "fs-extra"; import type stream from "stream"; -import { Disposer, ExtendedObservableMap, iter, Singleton } from "../../common/utils"; +import { Disposer, ExtendedObservableMap, iter, Singleton, storedKubeConfigFolder } from "../../common/utils"; import logger from "../logger"; import type { KubeConfig } from "@kubernetes/client-node"; import { loadConfigFromString, splitConfig, validateKubeConfig } from "../../common/kube-helpers"; import { Cluster } from "../cluster"; import { catalogEntityFromCluster } from "../cluster-manager"; import { UserStore } from "../../common/user-store"; -import { ClusterStore, UpdateClusterModel } from "../../common/cluster-store"; +import { ClusterStore } from "../../common/cluster-store"; +import type { UpdateClusterModel } from "../../common/cluster-types"; import { createHash } from "crypto"; const logPrefix = "[KUBECONFIG-SYNC]:"; @@ -63,7 +64,7 @@ export class KubeconfigSyncManager extends Singleton { ))); // This must be done so that c&p-ed clusters are visible - this.startNewSync(ClusterStore.storedKubeConfigFolder); + this.startNewSync(storedKubeConfigFolder()); for (const filePath of UserStore.getInstance().syncKubeconfigEntries.keys()) { this.startNewSync(filePath); diff --git a/src/main/cluster-detectors/cluster-id-detector.ts b/src/main/cluster-detectors/cluster-id-detector.ts index 9818b0d990b6..21d7a005b30d 100644 --- a/src/main/cluster-detectors/cluster-id-detector.ts +++ b/src/main/cluster-detectors/cluster-id-detector.ts @@ -21,7 +21,7 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { createHash } from "crypto"; -import { ClusterMetadataKey } from "../cluster"; +import { ClusterMetadataKey } from "../../common/cluster-types"; export class ClusterIdDetector extends BaseClusterDetector { key = ClusterMetadataKey.CLUSTER_ID; diff --git a/src/main/cluster-detectors/detector-registry.ts b/src/main/cluster-detectors/detector-registry.ts index 82a09059e35c..40b4fa694938 100644 --- a/src/main/cluster-detectors/detector-registry.ts +++ b/src/main/cluster-detectors/detector-registry.ts @@ -20,7 +20,7 @@ */ import { observable } from "mobx"; -import type { ClusterMetadata } from "../../common/cluster-store"; +import type { ClusterMetadata } from "../../common/cluster-types"; import type { Cluster } from "../cluster"; import type { BaseClusterDetector, ClusterDetectionResult } from "./base-cluster-detector"; import { ClusterIdDetector } from "./cluster-id-detector"; diff --git a/src/main/cluster-detectors/distribution-detector.ts b/src/main/cluster-detectors/distribution-detector.ts index c7f2791cee64..0deb598b39d8 100644 --- a/src/main/cluster-detectors/distribution-detector.ts +++ b/src/main/cluster-detectors/distribution-detector.ts @@ -20,7 +20,7 @@ */ import { BaseClusterDetector } from "./base-cluster-detector"; -import { ClusterMetadataKey } from "../cluster"; +import { ClusterMetadataKey } from "../../common/cluster-types"; export class DistributionDetector extends BaseClusterDetector { key = ClusterMetadataKey.DISTRIBUTION; @@ -60,7 +60,7 @@ export class DistributionDetector extends BaseClusterDetector { if (this.isK0s()) { return { value: "k0s", accuracy: 80}; } - + if (this.isVMWare()) { return { value: "vmware", accuracy: 90}; } @@ -179,7 +179,7 @@ export class DistributionDetector extends BaseClusterDetector { protected isK0s() { return this.version.includes("-k0s"); } - + protected isAlibaba() { return this.version.includes("-aliyun"); } diff --git a/src/main/cluster-detectors/last-seen-detector.ts b/src/main/cluster-detectors/last-seen-detector.ts index 537fef96cb16..2aed3d0640a5 100644 --- a/src/main/cluster-detectors/last-seen-detector.ts +++ b/src/main/cluster-detectors/last-seen-detector.ts @@ -20,7 +20,7 @@ */ import { BaseClusterDetector } from "./base-cluster-detector"; -import { ClusterMetadataKey } from "../cluster"; +import { ClusterMetadataKey } from "../../common/cluster-types"; export class LastSeenDetector extends BaseClusterDetector { key = ClusterMetadataKey.LAST_SEEN; diff --git a/src/main/cluster-detectors/nodes-count-detector.ts b/src/main/cluster-detectors/nodes-count-detector.ts index f30f5e6c70a8..2e136a7acdfc 100644 --- a/src/main/cluster-detectors/nodes-count-detector.ts +++ b/src/main/cluster-detectors/nodes-count-detector.ts @@ -19,8 +19,8 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +import { ClusterMetadataKey } from "../../common/cluster-types"; import { BaseClusterDetector } from "./base-cluster-detector"; -import { ClusterMetadataKey } from "../cluster"; export class NodesCountDetector extends BaseClusterDetector { key = ClusterMetadataKey.NODES_COUNT; diff --git a/src/main/cluster-detectors/version-detector.ts b/src/main/cluster-detectors/version-detector.ts index f7240ab3ea3c..2b7b76786f8f 100644 --- a/src/main/cluster-detectors/version-detector.ts +++ b/src/main/cluster-detectors/version-detector.ts @@ -19,8 +19,8 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +import { ClusterMetadataKey } from "../../common/cluster-types"; import { BaseClusterDetector } from "./base-cluster-detector"; -import { ClusterMetadataKey } from "../cluster"; export class VersionDetector extends BaseClusterDetector { key = ClusterMetadataKey.VERSION; diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index 9ef28c8f9f50..8fc9a4d3ca2a 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -19,11 +19,11 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import "../common/cluster-ipc"; import type http from "http"; import { ipcMain } from "electron"; import { action, autorun, reaction, toJS } from "mobx"; -import { ClusterStore, getClusterIdFromHost } from "../common/cluster-store"; +import { ClusterStore } from "../common/cluster-store"; +import { getClusterIdFromHost } from "../common/cluster-types"; import type { Cluster } from "./cluster"; import logger from "./logger"; import { apiKubePrefix } from "../common/vars"; diff --git a/src/main/cluster.ts b/src/main/cluster.ts index 6def60b08f86..a6fa888d304e 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -20,7 +20,6 @@ */ import { ipcMain } from "electron"; -import type { ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences, ClusterPrometheusPreferences, UpdateClusterModel } from "../common/cluster-store"; import { action, comparer, computed, observable, reaction, toJS, when } from "mobx"; import { broadcastMessage, ClusterListNamespaceForbiddenChannel } from "../common/ipc"; import { ContextHandler } from "./context-handler"; @@ -33,38 +32,8 @@ import logger from "./logger"; import { VersionDetector } from "./cluster-detectors/version-detector"; import { detectorRegistry } from "./cluster-detectors/detector-registry"; import plimit from "p-limit"; - -export enum ClusterStatus { - AccessGranted = 2, - AccessDenied = 1, - Offline = 0 -} - -export enum ClusterMetadataKey { - VERSION = "version", - CLUSTER_ID = "id", - DISTRIBUTION = "distribution", - NODES_COUNT = "nodes", - LAST_SEEN = "lastSeen", - PROMETHEUS = "prometheus" -} - -export type ClusterRefreshOptions = { - refreshMetadata?: boolean -}; - -export interface ClusterState { - apiUrl: string; - online: boolean; - disconnected: boolean; - accessible: boolean; - ready: boolean; - failureReason: string; - isAdmin: boolean; - allowedNamespaces: string[] - allowedResources: string[] - isGlobalWatchEnabled: boolean; -} +import type { ClusterModel, ClusterState, ClusterId, ClusterPreferences, ClusterMetadata, ClusterPrometheusPreferences, UpdateClusterModel, ClusterRefreshOptions } from "../common/cluster-types"; +import { ClusterStatus } from "../common/cluster-types"; /** * Cluster @@ -711,4 +680,12 @@ export class Cluster implements ClusterModel, ClusterState { return true; // allowed by default for other resources } + + isAllowedResources(...kinds: string[]): boolean { + return kinds.every(kind => this.isAllowedResource(kind)); + } + + isAnyAllowedResources(...kinds: string[]): boolean { + return kinds.length === 0 || kinds.some(kind => this.isAllowedResource(kind)); + } } diff --git a/src/main/context-handler.ts b/src/main/context-handler.ts index 6fa7ca1ef5ba..446718f8d6f5 100644 --- a/src/main/context-handler.ts +++ b/src/main/context-handler.ts @@ -20,7 +20,7 @@ */ import type { PrometheusService } from "./prometheus/provider-registry"; -import type { ClusterPrometheusPreferences } from "../common/cluster-store"; +import type { ClusterPrometheusPreferences } from "../common/cluster-types"; import type { Cluster } from "./cluster"; import type httpProxy from "http-proxy"; import url, { UrlWithStringQuery } from "url"; diff --git a/src/main/exit-app.ts b/src/main/exit-app.ts index 2f9e3b00c727..cd53b995ef43 100644 --- a/src/main/exit-app.ts +++ b/src/main/exit-app.ts @@ -26,17 +26,11 @@ import { ClusterManager } from "./cluster-manager"; import logger from "./logger"; export function exitApp() { - console.log("before windowManager"); - const windowManager = WindowManager.getInstance(false); - - console.log("before clusterManager"); - const clusterManager = ClusterManager.getInstance(false); + appEventBus.emit({ name: "service", action: "close" }); - console.log("after clusterManager"); + WindowManager.getInstance(false)?.hide(); + ClusterManager.getInstance(false)?.stop(); - appEventBus.emit({ name: "service", action: "close" }); - windowManager?.hide(); - clusterManager?.stop(); logger.info("SERVICE:QUIT"); setTimeout(() => { app.exit(); diff --git a/src/main/helm/helm-release-manager.ts b/src/main/helm/helm-release-manager.ts index 852c649ede2c..7853977e1d53 100644 --- a/src/main/helm/helm-release-manager.ts +++ b/src/main/helm/helm-release-manager.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import * as tempy from "tempy"; +import tempy from "tempy"; import fse from "fs-extra"; import * as yaml from "js-yaml"; import { promiseExec} from "../promise-exec"; diff --git a/src/main/index.ts b/src/main/index.ts index 7ded3e220973..f78dcc393032 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -46,7 +46,7 @@ import { FilesystemProvisionerStore } from "./extension-filesystem"; import { installDeveloperTools } from "./developer-tools"; import { LensProtocolRouterMain } from "./protocol-handler"; import { disposer, getAppVersion, getAppVersionFromProxyServer } from "../common/utils"; -import { bindBroadcastHandlers } from "../common/ipc"; +import { initGetSubFramesHandler } from "../common/ipc"; import { startUpdateChecking } from "./app-updater"; import { IpcRendererNavigationEvents } from "../renderer/navigation/events"; import { pushCatalogToRenderer } from "./catalog-pusher"; @@ -54,8 +54,11 @@ import { catalogEntityRegistry } from "./catalog"; import { HotbarStore } from "../common/hotbar-store"; import { HelmRepoManager } from "./helm/helm-repo-manager"; import { KubeconfigSyncManager } from "./catalog-sources"; -import { handleWsUpgrade } from "./proxy/ws-upgrade"; import { initRegistries } from "./initializers"; +import { initIpcMainHandlers } from "./initializers/ipc-handlers"; +import { Router } from "./router"; +import { initMenu } from "./menu"; +import { initTray } from "./tray"; const workingDir = path.join(app.getPath("appData"), appName); const cleanup = disposer(); @@ -115,7 +118,8 @@ app.on("ready", async () => { logger.info("🐚 Syncing shell environment"); await shellSync(); - bindBroadcastHandlers(); + initGetSubFramesHandler(); + initIpcMainHandlers(); powerMonitor.on("shutdown", () => { app.exit(); @@ -141,14 +145,15 @@ app.on("ready", async () => { filesystemStore.load(), ]); - const lensProxy = LensProxy.createInstance(handleWsUpgrade); - ClusterManager.createInstance(); KubeconfigSyncManager.createInstance(); try { logger.info("🔌 Starting LensProxy"); - await lensProxy.listen(); + await LensProxy.createInstance( + new Router(), + req => ClusterManager.getInstance().getClusterForRequest(req), + ).listen(); } catch (error) { dialog.showErrorBox("Lens Error", `Could not start proxy: ${error?.message || "unknown error"}`); app.exit(); @@ -157,7 +162,7 @@ app.on("ready", async () => { // test proxy connection try { logger.info("🔎 Testing LensProxy connection ..."); - const versionFromProxy = await getAppVersionFromProxyServer(lensProxy.port); + const versionFromProxy = await getAppVersionFromProxyServer(LensProxy.getInstance().port); if (getAppVersion() !== versionFromProxy) { logger.error("Proxy server responded with invalid response"); @@ -183,6 +188,8 @@ app.on("ready", async () => { logger.info("🖥️ Starting WindowManager"); const windowManager = WindowManager.createInstance(); + cleanup.push(initMenu(windowManager), initTray(windowManager)); + installDeveloperTools(); if (!startHidden) { @@ -262,6 +269,8 @@ app.on("will-quit", (event) => { return; // skip exit to make tray work, to quit go to app's global menu or tray's menu } + + cleanup(); }); app.on("open-url", (event, rawUrl) => { diff --git a/src/main/initializers/ipc-handlers.ts b/src/main/initializers/ipc-handlers.ts new file mode 100644 index 000000000000..9cf0eb4b76d9 --- /dev/null +++ b/src/main/initializers/ipc-handlers.ts @@ -0,0 +1,93 @@ +/** + * 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, IpcMainInvokeEvent } from "electron"; +import { clusterFrameMap } from "../../common/cluster-frames"; +import * as channels from "../../common/cluster-ipc"; +import { ClusterStore } from "../../common/cluster-store"; +import type { ClusterId } from "../../common/cluster-types"; +import { appEventBus } from "../../common/event-bus"; +import { ResourceApplier } from "../resource-applier"; + +export function initIpcMainHandlers() { + ipcMain.handle(channels.clusterActivateHandler, (event, clusterId: ClusterId, force = false) => { + return ClusterStore.getInstance() + .getById(clusterId) + ?.activate(force); + }); + + ipcMain.handle(channels.clusterSetFrameIdHandler, (event: IpcMainInvokeEvent, clusterId: ClusterId) => { + const cluster = ClusterStore.getInstance().getById(clusterId); + + if (cluster) { + clusterFrameMap.set(cluster.id, { frameId: event.frameId, processId: event.processId }); + cluster.pushState(); + } + }); + + ipcMain.handle(channels.clusterRefreshHandler, (event, clusterId: ClusterId) => { + return ClusterStore.getInstance() + .getById(clusterId) + ?.refresh({ refreshMetadata: true }); + }); + + ipcMain.handle(channels.clusterDisconnectHandler, (event, clusterId: ClusterId) => { + appEventBus.emit({ name: "cluster", action: "stop" }); + const cluster = ClusterStore.getInstance().getById(clusterId); + + if (cluster) { + cluster.disconnect(); + clusterFrameMap.delete(cluster.id); + } + }); + + ipcMain.handle(channels.clusterKubectlApplyAllHandler, (event, clusterId: ClusterId, resources: 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); + } else { + throw `${clusterId} is not a valid cluster id`; + } + }); + + ipcMain.handle(channels.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/main/proxy/lens-proxy.ts b/src/main/proxy/lens-proxy.ts index 199d48398b60..b1dfc2735156 100644 --- a/src/main/proxy/lens-proxy.ts +++ b/src/main/proxy/lens-proxy.ts @@ -25,41 +25,40 @@ import spdy from "spdy"; import httpProxy from "http-proxy"; import url from "url"; import { apiPrefix, apiKubePrefix } from "../../common/vars"; -import { Router } from "../router"; +import type { Router } from "../router"; import type { ContextHandler } from "../context-handler"; import logger from "../logger"; import { Singleton } from "../../common/utils"; -import { ClusterManager } from "../cluster-manager"; - -type WSUpgradeHandler = (req: http.IncomingMessage, socket: net.Socket, head: Buffer) => void; +import type { Cluster } from "../cluster"; +import { LocalShellSession, NodeShellSession } from "../shell-session"; +import type * as WebSocket from "ws"; +import { Server } from "ws"; export class LensProxy extends Singleton { protected origin: string; protected proxyServer: http.Server; - protected router = new Router(); protected closed = false; protected retryCounters = new Map(); public port: number; - constructor(handleWsUpgrade: WSUpgradeHandler) { + constructor(protected router: Router, protected getClusterForRequest: (req: http.IncomingMessage) => Cluster) { super(); const proxy = this.createProxy(); - this.proxyServer = spdy.createServer({ - spdy: { - plain: true, - protocols: ["http/1.1", "spdy/3.1"] - } - }, (req: http.IncomingMessage, res: http.ServerResponse) => { - this.handleRequest(proxy, req, res); - }); - - this.proxyServer + this.proxyServer = spdy + .createServer({ + spdy: { + plain: true, + protocols: ["http/1.1", "spdy/3.1"] + } + }, (req: http.IncomingMessage, res: http.ServerResponse) => { + this.handleRequest(proxy, req, res); + }) .on("upgrade", (req: http.IncomingMessage, socket: net.Socket, head: Buffer) => { if (req.url.startsWith(`${apiPrefix}?`)) { - handleWsUpgrade(req, socket, head); + this.handleWsUpgrade(req, socket, head); } else { this.handleProxyUpgrade(proxy, req, socket, head); } @@ -103,8 +102,27 @@ export class LensProxy extends Singleton { this.closed = true; } + protected async handleWsUpgrade(req: http.IncomingMessage, socket: net.Socket, head: Buffer) { + const wsServer = new Server({ noServer: true }); + + wsServer.on("connection", ((socket: WebSocket, req: http.IncomingMessage) => { + const cluster = this.getClusterForRequest(req); + const nodeParam = url.parse(req.url, true).query["node"]?.toString(); + const shell = nodeParam + ? new NodeShellSession(socket, cluster, nodeParam) + : new LocalShellSession(socket, cluster); + + shell.open() + .catch(error => logger.error(`[SHELL-SESSION]: failed to open: ${error}`, { error })); + })); + + wsServer.handleUpgrade(req, socket, head, (con) => { + wsServer.emit("connection", con, req); + }); + } + protected async handleProxyUpgrade(proxy: httpProxy, req: http.IncomingMessage, socket: net.Socket, head: Buffer) { - const cluster = ClusterManager.getInstance().getClusterForRequest(req); + const cluster = this.getClusterForRequest(req); if (cluster) { const proxyUrl = await cluster.contextHandler.resolveAuthProxyUrl() + req.url.replace(apiKubePrefix, ""); @@ -205,7 +223,7 @@ 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, ""); @@ -213,6 +231,8 @@ export class LensProxy extends Singleton { return contextHandler.getApiTarget(isWatchRequest); } + + return null; } protected getRequestId(req: http.IncomingMessage) { @@ -220,7 +240,7 @@ export class LensProxy extends Singleton { } protected async handleRequest(proxy: httpProxy, req: http.IncomingMessage, res: http.ServerResponse) { - const cluster = ClusterManager.getInstance().getClusterForRequest(req); + const cluster = this.getClusterForRequest(req); if (cluster) { const proxyTarget = await this.getProxyTarget(req, cluster.contextHandler); diff --git a/src/main/resource-applier.ts b/src/main/resource-applier.ts index 5dd02cc6179e..8e6e3177e7e3 100644 --- a/src/main/resource-applier.ts +++ b/src/main/resource-applier.ts @@ -25,7 +25,7 @@ import { exec } from "child_process"; import fs from "fs"; import * as yaml from "js-yaml"; import path from "path"; -import * as tempy from "tempy"; +import tempy from "tempy"; import logger from "./logger"; import { appEventBus } from "../common/event-bus"; import { cloneJsonObject } from "../common/utils"; @@ -34,19 +34,19 @@ export class ResourceApplier { constructor(protected cluster: Cluster) { } - async apply(resource: KubernetesObject | any): Promise { + async apply(resource: KubernetesObject | any): Promise { resource = this.sanitizeObject(resource); appEventBus.emit({name: "resource", action: "apply"}); return await this.kubectlApply(yaml.safeDump(resource)); } - protected async kubectlApply(content: string): Promise { + protected async kubectlApply(content: string): Promise { const { kubeCtl } = this.cluster; const kubectlPath = await kubeCtl.getPath(); const proxyKubeconfigPath = await this.cluster.getProxyKubeconfigPath(); - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const fileName = tempy.file({ name: "resource.yaml" }); fs.writeFileSync(fileName, content); diff --git a/src/main/routes/metrics-route.ts b/src/main/routes/metrics-route.ts index 059911421956..fea79ef851c1 100644 --- a/src/main/routes/metrics-route.ts +++ b/src/main/routes/metrics-route.ts @@ -22,10 +22,10 @@ import _ from "lodash"; import type { LensApiRequest } from "../router"; import { respondJson } from "../utils/http-responses"; -import { Cluster, ClusterMetadataKey } from "../cluster"; -import type { ClusterPrometheusMetadata } from "../../common/cluster-store"; +import type { Cluster } from "../cluster"; import logger from "../logger"; import { getMetrics } from "../k8s-request"; +import { ClusterPrometheusMetadata, ClusterMetadataKey } from "../../common/cluster-types"; export type IMetricsQuery = string | string[] | { [metricName: string]: string; diff --git a/src/main/window-manager.ts b/src/main/window-manager.ts index 6158424a4f99..ded4d8faecf9 100644 --- a/src/main/window-manager.ts +++ b/src/main/window-manager.ts @@ -19,14 +19,12 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import type { ClusterId } from "../common/cluster-store"; +import type { ClusterId } from "../common/cluster-types"; import { observable } from "mobx"; import { app, BrowserWindow, dialog, shell, webContents } from "electron"; import windowStateKeeper from "electron-window-state"; import { appEventBus } from "../common/event-bus"; import { ipcMainOn } from "../common/ipc"; -import { initMenu } from "./menu"; -import { initTray } from "./tray"; import { Singleton } from "../common/utils"; import { ClusterFrameInfo, clusterFrameMap } from "../common/cluster-frames"; import { IpcRendererNavigationEvents } from "../renderer/navigation/events"; @@ -38,15 +36,15 @@ export class WindowManager extends Singleton { protected mainWindow: BrowserWindow; protected splashWindow: BrowserWindow; protected windowState: windowStateKeeper.State; - protected disposers: Record = {}; @observable activeClusterId: ClusterId; constructor() { super(); - this.bindEvents(); - this.initMenu(); - this.initTray(); + + ipcMainOn(IpcRendererNavigationEvents.CLUSTER_VIEW_CURRENT_ID, (event, clusterId: ClusterId) => { + this.activeClusterId = clusterId; + }); } get mainUrl() { @@ -130,21 +128,6 @@ export class WindowManager extends Singleton { } } - protected async initMenu() { - this.disposers.menuAutoUpdater = initMenu(this); - } - - protected initTray() { - this.disposers.trayAutoUpdater = initTray(this); - } - - protected bindEvents() { - // track visible cluster from ui - ipcMainOn(IpcRendererNavigationEvents.CLUSTER_VIEW_CURRENT_ID, (event, clusterId: ClusterId) => { - this.activeClusterId = clusterId; - }); - } - async ensureMainWindow(): Promise { if (!this.mainWindow) await this.initMainWindow(); this.mainWindow.show(); @@ -214,9 +197,5 @@ export class WindowManager extends Singleton { this.splashWindow.destroy(); this.mainWindow = null; this.splashWindow = null; - Object.entries(this.disposers).forEach(([name, dispose]) => { - dispose(); - delete this.disposers[name]; - }); } } 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 df51510f234e..e47046ddd143 100644 --- a/src/migrations/cluster-store/3.6.0-beta.1.ts +++ b/src/migrations/cluster-store/3.6.0-beta.1.ts @@ -26,14 +26,15 @@ import path from "path"; import { app, remote } from "electron"; import { migration } from "../migration-wrapper"; import fse from "fs-extra"; -import { ClusterModel, ClusterStore } from "../../common/cluster-store"; import { loadConfig } from "../../common/kube-helpers"; +import type { ClusterModel } from "../../common/cluster-types"; +import { getCustomKubeConfigPath, embedCustomKubeConfig } from "../../common/utils"; export default migration({ version: "3.6.0-beta.1", run(store, printLog) { const userDataPath = (app || remote.app).getPath("userData"); - const kubeConfigBase = ClusterStore.getCustomKubeConfigPath(""); + const kubeConfigBase = getCustomKubeConfigPath(""); const storedClusters: ClusterModel[] = store.get("clusters") || []; if (!storedClusters.length) return; @@ -47,7 +48,7 @@ export default migration({ */ try { // take the embedded kubeconfig and dump it into a file - cluster.kubeConfigPath = ClusterStore.embedCustomKubeConfig(cluster.id, cluster.kubeConfig); + cluster.kubeConfigPath = embedCustomKubeConfig(cluster.id, cluster.kubeConfig); cluster.contextName = loadConfig(cluster.kubeConfigPath).getCurrentContext(); delete cluster.kubeConfig; diff --git a/src/migrations/cluster-store/snap.ts b/src/migrations/cluster-store/snap.ts index 3dcf998f1cd8..4ca354eb9379 100644 --- a/src/migrations/cluster-store/snap.ts +++ b/src/migrations/cluster-store/snap.ts @@ -22,9 +22,9 @@ // Fix embedded kubeconfig paths under snap config import { migration } from "../migration-wrapper"; -import type { ClusterModel } from "../../common/cluster-store"; import { getAppVersion } from "../../common/utils/app-version"; import fs from "fs"; +import type { ClusterModel } from "../../common/cluster-types"; export default migration({ version: getAppVersion(), // Run always after upgrade diff --git a/src/renderer/api/__tests__/api-manager.test.ts b/src/renderer/api/__tests__/api-manager.test.ts index 8c7beb12c95c..25f8a308a3b6 100644 --- a/src/renderer/api/__tests__/api-manager.test.ts +++ b/src/renderer/api/__tests__/api-manager.test.ts @@ -19,43 +19,59 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { ingressStore } from "../../components/+network-ingresses/ingress.store"; -import { apiManager } from "../api-manager"; +import { Cluster } from "../../../main/cluster"; +import { KubeObjectStore } from "../../kube-object.store"; +import { ApiManager } from "../api-manager"; import { KubeApi } from "../kube-api"; +import { KubeObject } from "../kube-object"; class TestApi extends KubeApi { - protected async checkPreferredVersion() { return; } } describe("ApiManager", () => { + beforeEach(() => { + ApiManager.createInstance(new Cluster({ + id: "foobar", + kubeConfigPath: "/foobar", + })); + }); + + afterEach(() => { + ApiManager.resetInstance(); + }); + describe("registerApi", () => { it("re-register store if apiBase changed", async () => { const apiBase = "apis/v1/foo"; const fallbackApiBase = "/apis/extensions/v1beta1/foo"; const kubeApi = new TestApi({ + objectConstructor: KubeObject, apiBase, fallbackApiBases: [fallbackApiBase], checkPreferredVersion: true, }); - apiManager.registerApi(apiBase, kubeApi); + ApiManager.getInstance().registerApi(apiBase, kubeApi); + + class TestStore extends KubeObjectStore { + api = kubeApi; + } // Define to use test api for ingress store - Object.defineProperty(ingressStore, "api", { value: kubeApi }); - apiManager.registerStore(ingressStore, [kubeApi]); + ApiManager.getInstance().registerStore(TestStore); // Test that store is returned with original apiBase - expect(apiManager.getStore(kubeApi)).toBe(ingressStore); + expect(ApiManager.getInstance().getStore(kubeApi)).toBeInstanceOf(TestStore); // Change apiBase similar as checkPreferredVersion does Object.defineProperty(kubeApi, "apiBase", { value: fallbackApiBase }); - apiManager.registerApi(fallbackApiBase, kubeApi); + ApiManager.getInstance().registerApi(fallbackApiBase, kubeApi); // Test that store is returned with new apiBase - expect(apiManager.getStore(kubeApi)).toBe(ingressStore); + expect(ApiManager.getInstance().getStore(kubeApi)).toBeInstanceOf(TestStore); }); }); }); diff --git a/src/renderer/api/__tests__/kube-api.test.ts b/src/renderer/api/__tests__/kube-api.test.ts index c7415cba7310..99454c0133f8 100644 --- a/src/renderer/api/__tests__/kube-api.test.ts +++ b/src/renderer/api/__tests__/kube-api.test.ts @@ -20,6 +20,7 @@ */ import { KubeApi } from "../kube-api"; +import { KubeObject } from "../kube-object"; describe("KubeApi", () => { it("uses url from apiBase if apiBase contains the resource", async () => { @@ -53,6 +54,7 @@ describe("KubeApi", () => { const apiBase = "/apis/networking.k8s.io/v1/ingresses"; const fallbackApiBase = "/apis/extensions/v1beta1/ingresses"; const kubeApi = new KubeApi({ + objectConstructor: KubeObject, apiBase, fallbackApiBases: [fallbackApiBase], checkPreferredVersion: true, @@ -91,6 +93,7 @@ describe("KubeApi", () => { const apiBase = "apis/networking.k8s.io/v1/ingresses"; const fallbackApiBase = "/apis/extensions/v1beta1/ingresses"; const kubeApi = new KubeApi({ + objectConstructor: KubeObject, apiBase, fallbackApiBases: [fallbackApiBase], checkPreferredVersion: true, diff --git a/src/renderer/api/api-manager.ts b/src/renderer/api/api-manager.ts index ada5424bef10..95e14ae9068b 100644 --- a/src/renderer/api/api-manager.ts +++ b/src/renderer/api/api-manager.ts @@ -19,16 +19,37 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import type { KubeObjectStore } from "../kube-object.store"; +import type { KubeObjectStore, KubeObjectStoreConstructor } from "../kube-object.store"; import { action, observable } from "mobx"; -import { autobind } from "../utils"; -import { KubeApi, parseKubeApi } from "./kube-api"; +import { autobind, Singleton } from "../utils"; +import type { KubeApi } from "./kube-api"; +import { parseKubeApi } from "./kube-api-parse"; +import type { IKubeApiLinkRef, IKubeObjectRef } from "./kube-api-parse"; +import type { KubeObject } from "./kube-object"; +import type { Cluster } from "../../main/cluster"; + +export function createKubeApiURL(ref: IKubeApiLinkRef): string { + const { apiPrefix = "/apis", resource, apiVersion, name } = ref; + let { namespace } = ref; + + if (namespace) { + namespace = `namespaces/${namespace}`; + } + + return [apiPrefix, apiVersion, namespace, resource, name] + .filter(v => v) + .join("/"); +} @autobind() -export class ApiManager { +export class ApiManager extends Singleton { private apis = observable.map(); - private stores = observable.map(); + private stores = observable.map>(); + + constructor(protected cluster: Cluster) { + super(); + } getApi(pathOrCallback: string | ((api: KubeApi) => boolean)) { if (typeof pathOrCallback === "string") { @@ -71,15 +92,56 @@ export class ApiManager { } @action - registerStore(store: KubeObjectStore, apis: KubeApi[] = [store.api]) { - apis.forEach(api => { + registerStore>(storeConstructor: KubeObjectStoreConstructor, apis?: KubeApi[]): this { + const store = new storeConstructor(this.cluster); + + for (const api of apis ?? [store.api]) { this.stores.set(api.apiBase, store); - }); + } + + return this; } - getStore(api: string | KubeApi): S { - return this.stores.get(this.resolveApi(api)?.apiBase) as S; + getStore>(api: string | KubeApi): Store | undefined { + return this.stores.get(this.resolveApi(api)?.apiBase) as Store; } -} -export const apiManager = new ApiManager(); + lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): string { + const { + kind, apiVersion, name, + namespace = parentObject.getNs() + } = ref; + + if (!kind) return ""; + + // search in registered apis by 'kind' & 'apiVersion' + const api = this.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion); + + if (api) { + return api.getUrl({ namespace, name }); + } + + // lookup api by generated resource link + const apiPrefixes = ["/apis", "/api"]; + const resource = kind.endsWith("s") ? `${kind.toLowerCase()}es` : `${kind.toLowerCase()}s`; + + for (const apiPrefix of apiPrefixes) { + const apiLink = createKubeApiURL({ apiPrefix, apiVersion, name, namespace, resource }); + + if (this.getApi(apiLink)) { + return apiLink; + } + } + + // resolve by kind only (hpa's might use refs to older versions of resources for example) + const apiByKind = this.getApi(api => api.kind === kind); + + if (apiByKind) { + return apiByKind.getUrl({ name, namespace }); + } + + // otherwise generate link with default prefix + // resource still might exists in k8s, but api is not registered in the app + return createKubeApiURL({ apiVersion, name, namespace, resource }); + } +} diff --git a/src/renderer/api/endpoints/cluster.api.ts b/src/renderer/api/endpoints/cluster.api.ts index 309f936ac737..299602a6c942 100644 --- a/src/renderer/api/endpoints/cluster.api.ts +++ b/src/renderer/api/endpoints/cluster.api.ts @@ -23,7 +23,7 @@ import { IMetrics, IMetricsReqParams, metricsApi } from "./metrics.api"; import { KubeObject } from "../kube-object"; import { KubeApi } from "../kube-api"; -export class ClusterApi extends KubeApi { +export class ClusterApi extends KubeApi { static kind = "Cluster"; static namespaced = true; @@ -71,7 +71,7 @@ export interface IClusterMetrics { fsUsage: T; } -export class Cluster extends KubeObject { +export class KubeCluster extends KubeObject { static kind = "Cluster"; static apiBase = "/apis/cluster.k8s.io/v1alpha1/clusters"; @@ -117,5 +117,5 @@ export class Cluster extends KubeObject { } export const clusterApi = new ClusterApi({ - objectConstructor: Cluster, + objectConstructor: KubeCluster, }); diff --git a/src/renderer/api/endpoints/persistent-volume-claims.api.ts b/src/renderer/api/endpoints/persistent-volume-claims.api.ts index 92641945d7ca..028f605ee5ec 100644 --- a/src/renderer/api/endpoints/persistent-volume-claims.api.ts +++ b/src/renderer/api/endpoints/persistent-volume-claims.api.ts @@ -108,6 +108,6 @@ export class PersistentVolumeClaim extends KubeObject { } } -export const pvcApi = new PersistentVolumeClaimsApi({ +export const persistentVolumeClaimsApi = new PersistentVolumeClaimsApi({ objectConstructor: PersistentVolumeClaim, }); diff --git a/src/renderer/api/endpoints/poddisruptionbudget.api.ts b/src/renderer/api/endpoints/poddisruptionbudget.api.ts index b9763b093cb3..7569484607b5 100644 --- a/src/renderer/api/endpoints/poddisruptionbudget.api.ts +++ b/src/renderer/api/endpoints/poddisruptionbudget.api.ts @@ -65,6 +65,6 @@ export class PodDisruptionBudget extends KubeObject { } -export const pdbApi = new KubeApi({ +export const podDisruptionBudgetApi = new KubeApi({ objectConstructor: PodDisruptionBudget, }); diff --git a/src/renderer/api/endpoints/podsecuritypolicy.api.ts b/src/renderer/api/endpoints/podsecuritypolicy.api.ts index 1244c3e13eac..59c384950c1b 100644 --- a/src/renderer/api/endpoints/podsecuritypolicy.api.ts +++ b/src/renderer/api/endpoints/podsecuritypolicy.api.ts @@ -110,6 +110,6 @@ export class PodSecurityPolicy extends KubeObject { } } -export const pspApi = new KubeApi({ +export const podSecurityPolicyApi = new KubeApi({ objectConstructor: PodSecurityPolicy, }); diff --git a/src/renderer/api/endpoints/resource-applier.api.ts b/src/renderer/api/endpoints/resource-applier.api.ts index 1756977c95ba..f2a9cff5bf51 100644 --- a/src/renderer/api/endpoints/resource-applier.api.ts +++ b/src/renderer/api/endpoints/resource-applier.api.ts @@ -20,35 +20,21 @@ */ import jsYaml from "js-yaml"; -import { KubeObject } from "../kube-object"; import type { KubeJsonApiData } from "../kube-json-api"; import { apiBase } from "../index"; -import { apiManager } from "../api-manager"; export const resourceApplierApi = { annotations: [ "kubectl.kubernetes.io/last-applied-configuration" ], - async update(resource: object | string): Promise { + async update(resource: object | string): Promise { if (typeof resource === "string") { resource = jsYaml.safeLoad(resource); } - return apiBase - .post("/stack", { data: resource }) - .then(data => { - const items = data.map(obj => { - const api = apiManager.getApiByKind(obj.kind, obj.apiVersion); + const result = await apiBase.post("/stack", { data: resource }); - if (api) { - return new api.objectConstructor(obj); - } else { - return new KubeObject(obj); - } - }); - - return items.length === 1 ? items[0] : items; - }); + return result[0]; } }; diff --git a/src/renderer/api/kube-api-parse.ts b/src/renderer/api/kube-api-parse.ts index b02067fb6311..45e69e20b4de 100644 --- a/src/renderer/api/kube-api-parse.ts +++ b/src/renderer/api/kube-api-parse.ts @@ -21,9 +21,7 @@ // Parse kube-api path and get api-version, group, etc. -import type { KubeObject } from "./kube-object"; import { splitArray } from "../../common/utils"; -import { apiManager } from "./api-manager"; export interface IKubeObjectRef { kind: string; @@ -123,55 +121,3 @@ export function parseKubeApi(path: string): IKubeApiParsed { namespace, resource, name, }; } - -export function createKubeApiURL(ref: IKubeApiLinkRef): string { - const { apiPrefix = "/apis", resource, apiVersion, name } = ref; - let { namespace } = ref; - - if (namespace) { - namespace = `namespaces/${namespace}`; - } - - return [apiPrefix, apiVersion, namespace, resource, name] - .filter(v => v) - .join("/"); -} - -export function lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): string { - const { - kind, apiVersion, name, - namespace = parentObject.getNs() - } = ref; - - if (!kind) return ""; - - // search in registered apis by 'kind' & 'apiVersion' - const api = apiManager.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion); - - if (api) { - return api.getUrl({ namespace, name }); - } - - // lookup api by generated resource link - const apiPrefixes = ["/apis", "/api"]; - const resource = kind.endsWith("s") ? `${kind.toLowerCase()}es` : `${kind.toLowerCase()}s`; - - for (const apiPrefix of apiPrefixes) { - const apiLink = createKubeApiURL({ apiPrefix, apiVersion, name, namespace, resource }); - - if (apiManager.getApi(apiLink)) { - return apiLink; - } - } - - // resolve by kind only (hpa's might use refs to older versions of resources for example) - const apiByKind = apiManager.getApi(api => api.kind === kind); - - if (apiByKind) { - return apiByKind.getUrl({ name, namespace }); - } - - // otherwise generate link with default prefix - // resource still might exists in k8s, but api is not registered in the app - return createKubeApiURL({ apiVersion, name, namespace, resource }); -} diff --git a/src/renderer/api/kube-api.ts b/src/renderer/api/kube-api.ts index 21e370a207d2..4cef93015930 100644 --- a/src/renderer/api/kube-api.ts +++ b/src/renderer/api/kube-api.ts @@ -25,9 +25,9 @@ import merge from "lodash/merge"; import { stringify } from "querystring"; import { apiKubePrefix, isDevelopment, isTestEnv } from "../../common/vars"; import logger from "../../main/logger"; -import { apiManager } from "./api-manager"; +import { ApiManager, createKubeApiURL } from "./api-manager"; import { apiKube } from "./index"; -import { createKubeApiURL, parseKubeApi } from "./kube-api-parse"; +import { parseKubeApi } from "./kube-api-parse"; import { IKubeObjectConstructor, KubeObject, KubeStatus } from "./kube-object"; import byline from "byline"; import type { IKubeWatchEvent } from "./kube-watch-api"; @@ -49,18 +49,13 @@ export interface IKubeApiOptions { */ fallbackApiBases?: string[]; - objectConstructor?: IKubeObjectConstructor; + objectConstructor: IKubeObjectConstructor; request?: KubeJsonApi; isNamespaced?: boolean; kind?: string; checkPreferredVersion?: boolean; } -export interface KubeApiListOptions { - namespace?: string; - reqInit?: RequestInit; -} - export interface IKubeApiQueryParams { watch?: boolean | number; resourceVersion?: string; @@ -152,7 +147,7 @@ export class KubeApi { constructor(protected options: IKubeApiOptions) { const { - objectConstructor = KubeObject as IKubeObjectConstructor, + objectConstructor, request = apiKube, kind = options.objectConstructor?.kind, isNamespaced = options.objectConstructor?.namespaced @@ -174,8 +169,7 @@ export class KubeApi { this.objectConstructor = objectConstructor; this.checkPreferredVersion(); - this.parseResponse = this.parseResponse.bind(this); - apiManager.registerApi(apiBase, this); + ApiManager.getInstance().registerApi(apiBase, this); } get apiVersionWithGroup() { @@ -264,7 +258,7 @@ export class KubeApi { if (this.apiVersionPreferred) { Object.defineProperty(this, "apiBase", { value: this.getUrl() }); - apiManager.registerApi(this.apiBase, this); + ApiManager.getInstance().registerApi(this.apiBase, this); } } } @@ -506,5 +500,3 @@ export class KubeApi { } } } - -export * from "./kube-api-parse"; diff --git a/src/renderer/api/kube-object.ts b/src/renderer/api/kube-object.ts index 06c431851cbf..ecdfaeedcf1a 100644 --- a/src/renderer/api/kube-object.ts +++ b/src/renderer/api/kube-object.ts @@ -265,11 +265,11 @@ export class KubeObject implements ItemObject { } // use unified resource-applier api for updating all k8s objects - async update(data: Partial) { - return resourceApplierApi.update({ + async updateReturnNew(data: Partial): Promise { + return new (this.constructor as any)(resourceApplierApi.update({ ...this.toPlainObject(), ...data, - }); + })); } delete(params?: JsonApiParams) { diff --git a/src/renderer/api/kube-watch-api.ts b/src/renderer/api/kube-watch-api.ts index 4c68e0fdfa4c..317e9bdbafce 100644 --- a/src/renderer/api/kube-watch-api.ts +++ b/src/renderer/api/kube-watch-api.ts @@ -23,14 +23,17 @@ // API: https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Using_readable_streams import type { KubeObjectStore } from "../kube-object.store"; -import type { ClusterContext } from "../components/context"; +import { allNamespaces, selectedNamespaces } from "../components/context"; import plimit from "p-limit"; -import { comparer, IReactionDisposer, observable, reaction, when } from "mobx"; -import { autobind, noop } from "../utils"; -import type { KubeApi } from "./kube-api"; +import { comparer, IReactionDisposer, reaction } from "mobx"; +import { autobind, Disposer, noop, Singleton } from "../utils"; import type { KubeJsonApiData } from "./kube-json-api"; import { isDebugging, isProduction } from "../../common/vars"; +import type { Cluster } from "../../main/cluster"; +import type { KubeObject } from "./kube-object"; +import type { KubeApi } from "./kube-api"; +import { ApiManager } from "./api-manager"; export interface IKubeWatchEvent { type: "ADDED" | "MODIFIED" | "DELETED" | "ERROR"; @@ -51,16 +54,12 @@ export interface IKubeWatchLog { } @autobind() -export class KubeWatchApi { - @observable context: ClusterContext = null; - - contextReady = when(() => Boolean(this.context)); - - isAllowedApi(api: KubeApi): boolean { - return Boolean(this.context?.cluster.isAllowedResource(api.kind)); +export class KubeWatchApi extends Singleton { + constructor(protected cluster: Cluster) { + super(); } - preloadStores(stores: KubeObjectStore[], opts: { namespaces?: string[], loadOnce?: boolean } = {}) { + private preloadStores(stores: KubeObjectStore[], opts: { namespaces?: string[], loadOnce?: boolean } = {}) { const limitRequests = plimit(1); // load stores one by one to allow quick skipping when fast clicking btw pages const preloading: Promise[] = []; @@ -78,9 +77,15 @@ export class KubeWatchApi { }; } - subscribeStores(stores: KubeObjectStore[], opts: IKubeWatchSubscribeStoreOptions = {}): () => void { + subscribeApis(apis: KubeApi[], opts: IKubeWatchSubscribeStoreOptions = {}): Disposer { + const manager = ApiManager.getInstance(); + + return this.subscribeStores(apis.map(api => manager.getStore(api)), opts); + } + + subscribeStores(stores: KubeObjectStore[], opts: IKubeWatchSubscribeStoreOptions = {}): Disposer { const { preload = true, waitUntilLoaded = true, loadOnce = false, } = opts; - const subscribingNamespaces = opts.namespaces ?? this.context?.allNamespaces ?? []; + const subscribingNamespaces = opts.namespaces ?? allNamespaces(this.cluster); const unsubscribeList: Function[] = []; let isUnsubscribed = false; @@ -109,7 +114,7 @@ export class KubeWatchApi { } // reload stores only for context namespaces change - cancelReloading = reaction(() => this.context?.contextNamespaces, namespaces => { + cancelReloading = reaction(() => selectedNamespaces(), namespaces => { preloading?.cancelLoading(); unsubscribeList.forEach(unsubscribe => unsubscribe()); unsubscribeList.length = 0; @@ -149,5 +154,3 @@ export class KubeWatchApi { } } } - -export const kubeWatchApi = new KubeWatchApi(); diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx index 0a59d069282a..db1f39c28412 100644 --- a/src/renderer/bootstrap.tsx +++ b/src/renderer/bootstrap.tsx @@ -37,7 +37,7 @@ import { ExtensionDiscovery } from "../extensions/extension-discovery"; import { ExtensionLoader } from "../extensions/extension-loader"; import { ExtensionsStore } from "../extensions/extensions-store"; import { FilesystemProvisionerStore } from "../main/extension-filesystem"; -import { App } from "./components/app"; +import { ClusterFrame } from "./components/app"; import { LensApp } from "./lens-app"; import { ThemeStore } from "./theme.store"; import { HelmRepoManager } from "../main/helm/helm-repo-manager"; @@ -127,4 +127,4 @@ export async function bootstrap(App: AppComponent) { } // run -bootstrap(process.isMainFrame ? LensApp : App); +bootstrap(process.isMainFrame ? LensApp : ClusterFrame); diff --git a/src/renderer/components/+add-cluster/add-cluster.tsx b/src/renderer/components/+add-cluster/add-cluster.tsx index e211c2d6f143..2320076a37c0 100644 --- a/src/renderer/components/+add-cluster/add-cluster.tsx +++ b/src/renderer/components/+add-cluster/add-cluster.tsx @@ -38,6 +38,7 @@ import { PageLayout } from "../layout/page-layout"; import { docsUrl } from "../../../common/vars"; import { Input } from "../input"; import { catalogURL, preferencesURL } from "../../../common/routes"; +import { embedCustomKubeConfig } from "../../utils"; @observer export class AddCluster extends React.Component { @@ -107,7 +108,7 @@ export class AddCluster extends React.Component { }).map(context => { const clusterId = uuid(); const kubeConfig = this.kubeContexts.get(context); - const kubeConfigPath = ClusterStore.embedCustomKubeConfig(clusterId, kubeConfig); // save in app-files folder + const kubeConfigPath = embedCustomKubeConfig(clusterId, kubeConfig); // save in app-files folder return { id: clusterId, diff --git a/src/renderer/components/+apps-releases/release-details.tsx b/src/renderer/components/+apps-releases/release-details.tsx index 260611e420a7..fe225db7b5cb 100644 --- a/src/renderer/components/+apps-releases/release-details.tsx +++ b/src/renderer/components/+apps-releases/release-details.tsx @@ -37,14 +37,14 @@ import { Spinner } from "../spinner"; import { Table, TableCell, TableHead, TableRow } from "../table"; import { AceEditor } from "../ace-editor"; import { Button } from "../button"; -import { releaseStore } from "./release.store"; +import { ReleaseStore } from "./release.store"; import { Notifications } from "../notifications"; import { createUpgradeChartTab } from "../dock/upgrade-chart.store"; import { ThemeStore } from "../../theme.store"; -import { apiManager } from "../../api/api-manager"; +import { ApiManager } from "../../api/api-manager"; import { SubTitle } from "../layout/sub-title"; -import { secretsStore } from "../+config-secrets/secrets.store"; -import { Secret } from "../../api/endpoints"; +import type { SecretsStore } from "../+config-secrets/secrets.store"; +import { Secret, secretsApi } from "../../api/endpoints"; import { getDetailsUrl } from "../kube-object"; import { Checkbox } from "../checkbox"; @@ -62,6 +62,10 @@ export class ReleaseDetails extends Component { @observable saving = false; @observable releaseSecret: Secret; + private get secretsStore() { + return ApiManager.getInstance().getStore(secretsApi); + } + @disposeOnUnmount releaseSelector = reaction(() => this.props.release, release => { if (!release) return; @@ -72,9 +76,9 @@ export class ReleaseDetails extends Component { ); @disposeOnUnmount - secretWatcher = reaction(() => secretsStore.items.toJS(), () => { + secretWatcher = reaction(() => this.secretsStore.items.toJS(), () => { if (!this.props.release) return; - const { getReleaseSecret } = releaseStore; + const { getReleaseSecret } = ReleaseStore.getInstance(); const { release } = this.props; const secret = getReleaseSecret(release); @@ -115,7 +119,7 @@ export class ReleaseDetails extends Component { this.saving = true; try { - await releaseStore.update(name, namespace, data); + await ReleaseStore.getInstance().update(name, namespace, data); Notifications.ok(

    Release {name} successfully updated!

    ); @@ -197,7 +201,7 @@ export class ReleaseDetails extends Component { {items.map(item => { const name = item.getName(); const namespace = item.getNs(); - const api = apiManager.getApi(item.metadata.selfLink); + const api = ApiManager.getInstance().getApi(item.metadata.selfLink); const detailsUrl = api ? getDetailsUrl(api.getUrl({ name, namespace })) : ""; return ( diff --git a/src/renderer/components/+apps-releases/release-menu.tsx b/src/renderer/components/+apps-releases/release-menu.tsx index 78e4c8e94ba0..5b13ab77be0e 100644 --- a/src/renderer/components/+apps-releases/release-menu.tsx +++ b/src/renderer/components/+apps-releases/release-menu.tsx @@ -22,12 +22,12 @@ import React from "react"; 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"; import { MenuItem } from "../menu"; import { Icon } from "../icon"; import { ReleaseRollbackDialog } from "./release-rollback-dialog"; import { createUpgradeChartTab } from "../dock/upgrade-chart.store"; +import { ReleaseStore } from "./release.store"; interface Props extends MenuActionsProps { release: HelmRelease; @@ -37,7 +37,7 @@ interface Props extends MenuActionsProps { export class HelmReleaseMenu extends React.Component { @autobind() remove() { - return releaseStore.remove(this.props.release); + return ReleaseStore.getInstance().remove(this.props.release); } @autobind() diff --git a/src/renderer/components/+apps-releases/release-rollback-dialog.tsx b/src/renderer/components/+apps-releases/release-rollback-dialog.tsx index bb25f6f5d66b..8d17f89d65b0 100644 --- a/src/renderer/components/+apps-releases/release-rollback-dialog.tsx +++ b/src/renderer/components/+apps-releases/release-rollback-dialog.tsx @@ -27,7 +27,7 @@ import { observer } from "mobx-react"; import { Dialog, DialogProps } from "../dialog"; import { Wizard, WizardStep } from "../wizard"; import { getReleaseHistory, HelmRelease, IReleaseRevision } from "../../api/endpoints/helm-releases.api"; -import { releaseStore } from "./release.store"; +import { ReleaseStore } from "./release.store"; import { Select, SelectOption } from "../select"; import { Notifications } from "../notifications"; import orderBy from "lodash/orderBy"; @@ -73,7 +73,7 @@ export class ReleaseRollbackDialog extends React.Component { const revisionNumber = this.revision.revision; try { - await releaseStore.rollback(this.release.getName(), this.release.getNs(), revisionNumber); + await ReleaseStore.getInstance().rollback(this.release.getName(), this.release.getNs(), revisionNumber); this.close(); } catch (err) { Notifications.error(err); diff --git a/src/renderer/components/+apps-releases/release.store.ts b/src/renderer/components/+apps-releases/release.store.ts index 7ed2ac42c73d..55133b3c585d 100644 --- a/src/renderer/components/+apps-releases/release.store.ts +++ b/src/renderer/components/+apps-releases/release.store.ts @@ -24,24 +24,44 @@ 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 type { Secret } from "../../api/endpoints"; -import { secretsStore } from "../+config-secrets/secrets.store"; -import { namespaceStore } from "../+namespaces/namespace.store"; +import { Secret, secretsApi } from "../../api/endpoints"; +import type { SecretsStore } from "../+config-secrets/secrets.store"; import { Notifications } from "../notifications"; +import { ApiManager } from "../../api/api-manager"; +import { isLoadingFromAllNamespaces, selectedNamespaces } from "../context"; +import type { Cluster } from "../../../main/cluster"; @autobind() export class ReleaseStore extends ItemStore { + private static instance?: ReleaseStore; + + static getInstance() { + if (!this.instance) { + throw new TypeError("instance of ReleaseStore is not created"); + } + + return this.instance; + } + + static createInstance(cluster: Cluster) { + return this.instance ??= new this(cluster); + } + + private get secretsStore() { + return ApiManager.getInstance().getStore(secretsApi); + } + releaseSecrets = observable.map(); - constructor() { + private constructor(protected cluster: Cluster) { super(); - when(() => secretsStore.isLoaded, () => { + when(() => this.secretsStore.isLoaded, () => { this.releaseSecrets.replace(this.getReleaseSecrets()); }); } watchAssociatedSecrets(): (() => void) { - return reaction(() => secretsStore.items.toJS(), () => { + return reaction(() => this.secretsStore.items.toJS(), () => { if (this.isLoading) return; const newSecrets = this.getReleaseSecrets(); const amountChanged = newSecrets.length !== this.releaseSecrets.size; @@ -57,19 +77,19 @@ export class ReleaseStore extends ItemStore { } watchSelecteNamespaces(): (() => void) { - return reaction(() => namespaceStore.context.contextNamespaces, namespaces => { + return reaction(() => selectedNamespaces(), namespaces => { this.loadAll(namespaces); }); } private getReleaseSecrets() { - return secretsStore + return this.secretsStore .getByLabel({ owner: "helm" }) .map(s => [s.getId(), s] as const); } getReleaseSecret(release: HelmRelease) { - return secretsStore.getByLabel({ + return this.secretsStore.getByLabel({ owner: "helm", name: release.getName() }) @@ -100,15 +120,11 @@ export class ReleaseStore extends ItemStore { } async loadFromContextNamespaces(): Promise { - return this.loadAll(namespaceStore.context.contextNamespaces); + return this.loadAll(selectedNamespaces()); } async loadItems(namespaces: string[]) { - const isLoadingAll = namespaceStore.context.allNamespaces?.length > 1 - && namespaceStore.context.cluster.accessibleNamespaces.length === 0 - && namespaceStore.context.allNamespaces.every(ns => namespaces.includes(ns)); - - if (isLoadingAll) { + if (isLoadingFromAllNamespaces(this.cluster, namespaces)) { return listReleases(); } @@ -149,5 +165,3 @@ export class ReleaseStore extends ItemStore { return Promise.all(this.selectedItems.map(this.remove)); } } - -export const releaseStore = new ReleaseStore(); diff --git a/src/renderer/components/+apps-releases/releases.tsx b/src/renderer/components/+apps-releases/releases.tsx index 32fa7ada4342..b3ee7d1e7cf9 100644 --- a/src/renderer/components/+apps-releases/releases.tsx +++ b/src/renderer/components/+apps-releases/releases.tsx @@ -25,15 +25,17 @@ import React, { Component } from "react"; import kebabCase from "lodash/kebabCase"; import { disposeOnUnmount, observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; -import { releaseStore } from "./release.store"; +import { ReleaseStore } from "./release.store"; import type { HelmRelease } from "../../api/endpoints/helm-releases.api"; import { ReleaseDetails } from "./release-details"; import { ReleaseRollbackDialog } from "./release-rollback-dialog"; import { navigation } from "../../navigation"; import { ItemListLayout } from "../item-object-list/item-list-layout"; import { HelmReleaseMenu } from "./release-menu"; -import { secretsStore } from "../+config-secrets/secrets.store"; +import type { SecretsStore } from "../+config-secrets/secrets.store"; import { ReleaseRouteParams, releaseURL } from "../../../common/routes"; +import { secretsApi } from "../../api/endpoints"; +import { ApiManager } from "../../api/api-manager"; enum columnId { name = "name", @@ -51,17 +53,21 @@ interface Props extends RouteComponentProps { @observer export class HelmReleases extends Component { + private get secretsStore() { + return ApiManager.getInstance().getStore(secretsApi); + } + componentDidMount() { disposeOnUnmount(this, [ - releaseStore.watchAssociatedSecrets(), - releaseStore.watchSelecteNamespaces(), + ReleaseStore.getInstance().watchAssociatedSecrets(), + ReleaseStore.getInstance().watchSelecteNamespaces(), ]); } get selectedRelease() { const { match: { params: { name, namespace } } } = this.props; - return releaseStore.items.find(release => { + return ReleaseStore.getInstance().items.find(release => { return release.getName() == name && release.getNs() == namespace; }); } @@ -99,8 +105,8 @@ export class HelmReleases extends Component { isConfigurable tableId="helm_releases" className="HelmReleases" - store={releaseStore} - dependentStores={[secretsStore]} + store={ReleaseStore.getInstance()} + dependentStores={[this.secretsStore]} sortingCallbacks={{ [columnId.name]: (release: HelmRelease) => release.getName(), [columnId.namespace]: (release: HelmRelease) => release.getNs(), diff --git a/src/renderer/components/+apps/apps.tsx b/src/renderer/components/+apps/apps.tsx index 346dd255a4e3..550e61a6d9d6 100644 --- a/src/renderer/components/+apps/apps.tsx +++ b/src/renderer/components/+apps/apps.tsx @@ -26,10 +26,11 @@ import { HelmCharts } from "../+apps-helm-charts"; import { HelmReleases } from "../+apps-releases"; import { namespaceUrlParam } from "../+namespaces/namespace.store"; import { helmChartsURL, helmChartsRoute, releaseURL, releaseRoute } from "../../../common/routes"; +import type { Cluster } from "../../../main/cluster"; @observer -export class Apps extends React.Component { - static get tabRoutes(): TabLayoutRoute[] { +export class Apps extends React.Component<{ cluster: Cluster }> { + static tabRoutes(): TabLayoutRoute[] { const query = namespaceUrlParam.toObjectParam(); return [ @@ -50,7 +51,7 @@ export class Apps extends React.Component { render() { return ( - + ); } } diff --git a/src/renderer/components/+cluster/cluster-issues.tsx b/src/renderer/components/+cluster/cluster-issues.tsx index ce6496f4905f..771b6d0ebb9a 100644 --- a/src/renderer/components/+cluster/cluster-issues.tsx +++ b/src/renderer/components/+cluster/cluster-issues.tsx @@ -27,14 +27,15 @@ import { computed } from "mobx"; import { Icon } from "../icon"; import { SubHeader } from "../layout/sub-header"; import { Table, TableCell, TableHead, TableRow } from "../table"; -import { nodesStore } from "../+nodes/nodes.store"; -import { eventStore } from "../+events/event.store"; +import type { NodesStore } from "../+nodes"; +import type { EventStore } from "../+events/event.store"; import { autobind, cssNames, prevDefault } from "../../utils"; import type { ItemObject } from "../../item.store"; import { Spinner } from "../spinner"; import { ThemeStore } from "../../theme.store"; -import { lookupApiLink } from "../../api/kube-api"; import { kubeSelectedUrlParam, showDetails } from "../kube-object"; +import { ApiManager } from "../../api/api-manager"; +import { eventApi, nodesApi } from "../../api/endpoints"; interface Props { className?: string; @@ -62,11 +63,19 @@ export class ClusterIssues extends React.Component { [sortBy.age]: (warning: IWarning) => warning.timeDiffFromNow, }; + private get nodesStore() { + return ApiManager.getInstance().getStore(nodesApi); + } + + private get eventStore() { + return ApiManager.getInstance().getStore(eventApi); + } + @computed get warnings() { const warnings: IWarning[] = []; // Node bad conditions - nodesStore.items.forEach(node => { + this.nodesStore.items.forEach(node => { const { kind, selfLink, getId, getName, getAge, getTimeDiffFromNow } = node; node.getWarningConditions().forEach(({ message }) => { @@ -83,7 +92,7 @@ export class ClusterIssues extends React.Component { }); // Warning events for Workloads - const events = eventStore.getWarnings(); + const events = this.eventStore.getWarnings(); events.forEach(error => { const { message, involvedObject, getAge, getTimeDiffFromNow } = error; @@ -96,7 +105,7 @@ export class ClusterIssues extends React.Component { age: getAge(), message, kind, - selfLink: lookupApiLink(involvedObject, error), + selfLink: ApiManager.getInstance().lookupApiLink(involvedObject, error), }); }); @@ -135,7 +144,7 @@ export class ClusterIssues extends React.Component { renderContent() { const { warnings } = this; - if (!eventStore.isLoaded) { + if (!this.eventStore.isLoaded) { return ( ); diff --git a/src/renderer/components/+cluster/cluster-metric-switchers.tsx b/src/renderer/components/+cluster/cluster-metric-switchers.tsx index b80dd10527e1..8b41c512b605 100644 --- a/src/renderer/components/+cluster/cluster-metric-switchers.tsx +++ b/src/renderer/components/+cluster/cluster-metric-switchers.tsx @@ -23,12 +23,16 @@ import "./cluster-metric-switchers.scss"; import React from "react"; import { observer } from "mobx-react"; -import { nodesStore } from "../+nodes/nodes.store"; +import type { NodesStore } from "../+nodes"; import { cssNames } from "../../utils"; import { Radio, RadioGroup } from "../radio"; -import { clusterOverviewStore, MetricNodeRole, MetricType } from "./cluster-overview.store"; +import { ClusterObjectStore, MetricNodeRole, MetricType } from "./cluster-overview.store"; +import { ApiManager } from "../../api/api-manager"; +import { clusterApi, nodesApi } from "../../api/endpoints"; export const ClusterMetricSwitchers = observer(() => { + const nodesStore = ApiManager.getInstance().getStore(nodesApi); + const clusterOverviewStore = ApiManager.getInstance().getStore(clusterApi); const { metricType, metricNodeRole, getMetricsValues, metrics } = clusterOverviewStore; const { masterNodes, workerNodes } = nodesStore; const metricsValues = getMetricsValues(metrics); diff --git a/src/renderer/components/+cluster/cluster-metrics.tsx b/src/renderer/components/+cluster/cluster-metrics.tsx index 0c4910e7e578..f6b8757546d4 100644 --- a/src/renderer/components/+cluster/cluster-metrics.tsx +++ b/src/renderer/components/+cluster/cluster-metrics.tsx @@ -24,7 +24,7 @@ import "./cluster-metrics.scss"; import React from "react"; import { observer } from "mobx-react"; import type { ChartOptions, ChartPoint } from "chart.js"; -import { clusterOverviewStore, MetricType } from "./cluster-overview.store"; +import { ClusterObjectStore, MetricType } from "./cluster-overview.store"; import { BarChart } from "../chart"; import { bytesToUnits } from "../../utils"; import { Spinner } from "../spinner"; @@ -32,8 +32,11 @@ import { ZebraStripes } from "../chart/zebra-stripes.plugin"; import { ClusterNoMetrics } from "./cluster-no-metrics"; import { ClusterMetricSwitchers } from "./cluster-metric-switchers"; import { getMetricLastPoints } from "../../api/endpoints/metrics.api"; +import { ApiManager } from "../../api/api-manager"; +import { clusterApi } from "../../api/endpoints"; export const ClusterMetrics = observer(() => { + const clusterOverviewStore = ApiManager.getInstance().getStore(clusterApi); const { metricType, metricNodeRole, getMetricsValues, metricsLoaded, metrics } = clusterOverviewStore; const { memoryCapacity, cpuCapacity } = getMetricLastPoints(clusterOverviewStore.metrics); const metricValues = getMetricsValues(metrics); diff --git a/src/renderer/components/+cluster/cluster-overview.store.ts b/src/renderer/components/+cluster/cluster-overview.store.ts index c9ffc4008c02..031a5dab2bc3 100644 --- a/src/renderer/components/+cluster/cluster-overview.store.ts +++ b/src/renderer/components/+cluster/cluster-overview.store.ts @@ -21,11 +21,11 @@ import { action, observable, reaction, when } from "mobx"; import { KubeObjectStore } from "../../kube-object.store"; -import { Cluster, clusterApi, IClusterMetrics } from "../../api/endpoints"; +import { KubeCluster, clusterApi, IClusterMetrics, nodesApi } from "../../api/endpoints"; import { autobind, createStorage } from "../../utils"; import { IMetricsReqParams, normalizeMetrics } from "../../api/endpoints/metrics.api"; -import { nodesStore } from "../+nodes/nodes.store"; -import { apiManager } from "../../api/api-manager"; +import type { NodesStore } from "../+nodes/nodes.store"; +import { ApiManager } from "../../api/api-manager"; export enum MetricType { MEMORY = "memory", @@ -43,7 +43,7 @@ export interface ClusterOverviewStorageState { } @autobind() -export class ClusterOverviewStore extends KubeObjectStore implements ClusterOverviewStorageState { +export class ClusterObjectStore extends KubeObjectStore implements ClusterOverviewStorageState { api = clusterApi; @observable metrics: Partial = {}; @@ -70,12 +70,11 @@ export class ClusterOverviewStore extends KubeObjectStore implements Cl this.storage.merge({ metricNodeRole: value }); } - constructor() { - super(); - this.init(); + private get nodesStore() { + return ApiManager.getInstance().getStore(nodesApi); } - private init() { + protected init = () => { // TODO: refactor, seems not a correct place to be // auto-refresh metrics on user-action reaction(() => this.metricNodeRole, () => { @@ -85,18 +84,18 @@ export class ClusterOverviewStore extends KubeObjectStore implements Cl }); // check which node type to select - reaction(() => nodesStore.items.length, () => { - const { masterNodes, workerNodes } = nodesStore; + reaction(() => this.nodesStore.items.length, () => { + const { masterNodes, workerNodes } = this.nodesStore; if (!masterNodes.length) this.metricNodeRole = MetricNodeRole.WORKER; if (!workerNodes.length) this.metricNodeRole = MetricNodeRole.MASTER; }); - } + }; @action async loadMetrics(params?: IMetricsReqParams) { - await when(() => nodesStore.isLoaded); - const { masterNodes, workerNodes } = nodesStore; + await when(() => this.nodesStore.isLoaded); + const { masterNodes, workerNodes } = this.nodesStore; const nodes = this.metricNodeRole === MetricNodeRole.MASTER && masterNodes.length ? masterNodes : workerNodes; this.metrics = await clusterApi.getMetrics(nodes.map(node => node.getName()), params); @@ -126,6 +125,3 @@ export class ClusterOverviewStore extends KubeObjectStore implements Cl this.storage?.reset(); } } - -export const clusterOverviewStore = new ClusterOverviewStore(); -apiManager.registerStore(clusterOverviewStore); diff --git a/src/renderer/components/+cluster/cluster-overview.tsx b/src/renderer/components/+cluster/cluster-overview.tsx index cc72c7cc6328..4466d475ab69 100644 --- a/src/renderer/components/+cluster/cluster-overview.tsx +++ b/src/renderer/components/+cluster/cluster-overview.tsx @@ -24,24 +24,38 @@ import "./cluster-overview.scss"; import React from "react"; import { reaction } from "mobx"; import { disposeOnUnmount, observer } from "mobx-react"; -import { nodesStore } from "../+nodes/nodes.store"; -import { podsStore } from "../+workloads-pods/pods.store"; import { ClusterStore, getHostedCluster } from "../../../common/cluster-store"; import { interval } from "../../utils"; import { TabLayout } from "../layout/tab-layout"; import { Spinner } from "../spinner"; import { ClusterIssues } from "./cluster-issues"; import { ClusterMetrics } from "./cluster-metrics"; -import { clusterOverviewStore } from "./cluster-overview.store"; import { ClusterPieCharts } from "./cluster-pie-charts"; import { ResourceType } from "../cluster-settings/components/cluster-metrics-setting"; +import { clusterApi, nodesApi, podsApi } from "../../api/endpoints"; +import type { NodesStore } from "../+nodes"; +import type { PodsStore } from "../+workloads-pods"; +import { ApiManager } from "../../api/api-manager"; +import type { ClusterObjectStore } from "./cluster-overview.store"; @observer export class ClusterOverview extends React.Component { + private get nodesStore() { + return ApiManager.getInstance().getStore(nodesApi); + } + + private get podsStore() { + return ApiManager.getInstance().getStore(podsApi); + } + + private get clusterObjectStore() { + return ApiManager.getInstance().getStore(clusterApi); + } + private metricPoller = interval(60, () => this.loadMetrics()); loadMetrics() { - getHostedCluster().available && clusterOverviewStore.loadMetrics(); + getHostedCluster().available && this.clusterObjectStore.loadMetrics(); } componentDidMount() { @@ -49,7 +63,7 @@ export class ClusterOverview extends React.Component { disposeOnUnmount(this, [ reaction( - () => clusterOverviewStore.metricNodeRole, // Toggle Master/Worker node switcher + () => this.clusterObjectStore.metricNodeRole, // Toggle Master/Worker node switcher () => this.metricPoller.restart(true) ), ]); @@ -86,7 +100,7 @@ export class ClusterOverview extends React.Component { } render() { - const isLoaded = nodesStore.isLoaded && podsStore.isLoaded; + const isLoaded = this.nodesStore.isLoaded && this.podsStore.isLoaded; const isMetricsHidden = ClusterStore.getInstance().isMetricHidden(ResourceType.Cluster); return ( diff --git a/src/renderer/components/+cluster/cluster-pie-charts.tsx b/src/renderer/components/+cluster/cluster-pie-charts.tsx index b7b84c817dd0..a78c486062e0 100644 --- a/src/renderer/components/+cluster/cluster-pie-charts.tsx +++ b/src/renderer/components/+cluster/cluster-pie-charts.tsx @@ -23,17 +23,22 @@ import "./cluster-pie-charts.scss"; import React from "react"; import { observer } from "mobx-react"; -import { clusterOverviewStore, MetricNodeRole } from "./cluster-overview.store"; +import { ClusterObjectStore, MetricNodeRole } from "./cluster-overview.store"; import { Spinner } from "../spinner"; import { Icon } from "../icon"; -import { nodesStore } from "../+nodes/nodes.store"; +import type { NodesStore } from "../+nodes"; import { ChartData, PieChart } from "../chart"; import { ClusterNoMetrics } from "./cluster-no-metrics"; import { bytesToUnits } from "../../utils"; import { ThemeStore } from "../../theme.store"; import { getMetricLastPoints } from "../../api/endpoints/metrics.api"; +import { ApiManager } from "../../api/api-manager"; +import { clusterApi, nodesApi } from "../../api/endpoints"; export const ClusterPieCharts = observer(() => { + const clusterOverviewStore = ApiManager.getInstance().getStore(clusterApi); + const nodesStore = ApiManager.getInstance().getStore(nodesApi); + const renderLimitWarning = () => { return (
    diff --git a/src/renderer/components/+config-autoscalers/hpa-details.tsx b/src/renderer/components/+config-autoscalers/hpa-details.tsx index 1a6db54e78c6..31d83931e4d2 100644 --- a/src/renderer/components/+config-autoscalers/hpa-details.tsx +++ b/src/renderer/components/+config-autoscalers/hpa-details.tsx @@ -30,8 +30,8 @@ import { KubeObjectDetailsProps, getDetailsUrl } from "../kube-object"; import { cssNames } from "../../utils"; import { HorizontalPodAutoscaler, HpaMetricType, IHpaMetric } from "../../api/endpoints/hpa.api"; import { Table, TableCell, TableHead, TableRow } from "../table"; -import { lookupApiLink } from "../../api/kube-api"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import { ApiManager } from "../../api/api-manager"; interface Props extends KubeObjectDetailsProps { } @@ -54,7 +54,7 @@ export class HpaDetails extends React.Component { case HpaMetricType.Object: const { target } = metric.object; const { kind, name } = target; - const objectUrl = getDetailsUrl(lookupApiLink(target, hpa)); + const objectUrl = getDetailsUrl(ApiManager.getInstance().lookupApiLink(target, hpa)); return ( <> @@ -107,7 +107,7 @@ export class HpaDetails extends React.Component { {scaleTargetRef && ( - + {scaleTargetRef.kind}/{scaleTargetRef.name} )} diff --git a/src/renderer/components/+config-autoscalers/hpa.store.ts b/src/renderer/components/+config-autoscalers/hpa.store.ts index aa94a4a3cd1e..3553ac7dcdba 100644 --- a/src/renderer/components/+config-autoscalers/hpa.store.ts +++ b/src/renderer/components/+config-autoscalers/hpa.store.ts @@ -22,12 +22,8 @@ import { autobind } from "../../utils"; import { KubeObjectStore } from "../../kube-object.store"; import { HorizontalPodAutoscaler, hpaApi } from "../../api/endpoints/hpa.api"; -import { apiManager } from "../../api/api-manager"; @autobind() -export class HPAStore extends KubeObjectStore { +export class HpaStore extends KubeObjectStore { api = hpaApi; } - -export const hpaStore = new HPAStore(); -apiManager.registerStore(hpaStore); diff --git a/src/renderer/components/+config-autoscalers/hpa.tsx b/src/renderer/components/+config-autoscalers/hpa.tsx index d5c65216bed2..2c50f3f9a39f 100644 --- a/src/renderer/components/+config-autoscalers/hpa.tsx +++ b/src/renderer/components/+config-autoscalers/hpa.tsx @@ -25,12 +25,13 @@ import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; import { KubeObjectListLayout } from "../kube-object"; -import type { HorizontalPodAutoscaler } from "../../api/endpoints/hpa.api"; -import { hpaStore } from "./hpa.store"; +import { HorizontalPodAutoscaler, hpaApi } from "../../api/endpoints/hpa.api"; import { Badge } from "../badge"; import { cssNames } from "../../utils"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { IHpaRouteParams } from "../../../common/routes"; +import { ApiManager } from "../../api/api-manager"; +import type { HpaStore } from "./hpa.store"; enum columnId { name = "name", @@ -48,6 +49,10 @@ interface Props extends RouteComponentProps { @observer export class HorizontalPodAutoscalers extends React.Component { + private get hpaStore() { + return ApiManager.getInstance().getStore(hpaApi); + } + getTargets(hpa: HorizontalPodAutoscaler) { const metrics = hpa.getMetrics(); const metricsRemainCount = metrics.length - 1; @@ -62,7 +67,8 @@ export class HorizontalPodAutoscalers extends React.Component { item.getName(), [columnId.namespace]: (item: HorizontalPodAutoscaler) => item.getNs(), diff --git a/src/renderer/components/+config-autoscalers/index.ts b/src/renderer/components/+config-autoscalers/index.ts index d7c91afc1567..d6a715f35e89 100644 --- a/src/renderer/components/+config-autoscalers/index.ts +++ b/src/renderer/components/+config-autoscalers/index.ts @@ -20,4 +20,5 @@ */ export * from "./hpa"; +export * from "./hpa.store"; export * from "./hpa-details"; diff --git a/src/renderer/components/+config-limit-ranges/index.ts b/src/renderer/components/+config-limit-ranges/index.ts index 5666fc77c4cd..0c9e384eb33a 100644 --- a/src/renderer/components/+config-limit-ranges/index.ts +++ b/src/renderer/components/+config-limit-ranges/index.ts @@ -20,4 +20,5 @@ */ export * from "./limit-ranges"; +export * from "./limit-ranges.store"; export * from "./limit-range-details"; diff --git a/src/renderer/components/+config-limit-ranges/limit-ranges.store.ts b/src/renderer/components/+config-limit-ranges/limit-ranges.store.ts index a6c7cc770cb3..d9fe5524b069 100644 --- a/src/renderer/components/+config-limit-ranges/limit-ranges.store.ts +++ b/src/renderer/components/+config-limit-ranges/limit-ranges.store.ts @@ -21,13 +21,9 @@ import { autobind } from "../../../common/utils/autobind"; import { KubeObjectStore } from "../../kube-object.store"; -import { apiManager } from "../../api/api-manager"; import { LimitRange, limitRangeApi } from "../../api/endpoints/limit-range.api"; @autobind() export class LimitRangesStore extends KubeObjectStore { api = limitRangeApi; } - -export const limitRangeStore = new LimitRangesStore(); -apiManager.registerStore(limitRangeStore); diff --git a/src/renderer/components/+config-limit-ranges/limit-ranges.tsx b/src/renderer/components/+config-limit-ranges/limit-ranges.tsx index 664654814c34..a1af127729c8 100644 --- a/src/renderer/components/+config-limit-ranges/limit-ranges.tsx +++ b/src/renderer/components/+config-limit-ranges/limit-ranges.tsx @@ -24,11 +24,12 @@ import "./limit-ranges.scss"; 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 React from "react"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; -import type { LimitRange } from "../../api/endpoints/limit-range.api"; +import { LimitRange, limitRangeApi } from "../../api/endpoints/limit-range.api"; import type { LimitRangeRouteParams } from "../../../common/routes"; +import { ApiManager } from "../../api/api-manager"; +import type { LimitRangesStore } from "./limit-ranges.store"; enum columnId { name = "name", @@ -41,13 +42,17 @@ interface Props extends RouteComponentProps { @observer export class LimitRanges extends React.Component { + private get limitRangeStore() { + return ApiManager.getInstance().getStore(limitRangeApi); + } + render() { return ( item.getName(), [columnId.namespace]: (item: LimitRange) => item.getNs(), diff --git a/src/renderer/components/+config-maps/config-map-details.tsx b/src/renderer/components/+config-maps/config-map-details.tsx index f1af70047d7b..05f3454f7061 100644 --- a/src/renderer/components/+config-maps/config-map-details.tsx +++ b/src/renderer/components/+config-maps/config-map-details.tsx @@ -28,16 +28,21 @@ import { DrawerTitle } from "../drawer"; import { Notifications } from "../notifications"; import { Input } from "../input"; import { Button } from "../button"; -import { configMapsStore } from "./config-maps.store"; import type { KubeObjectDetailsProps } from "../kube-object"; -import type { ConfigMap } from "../../api/endpoints"; +import { ConfigMap, configMapApi } from "../../api/endpoints"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import type { ConfigMapsStore } from "."; +import { ApiManager } from "../../api/api-manager"; interface Props extends KubeObjectDetailsProps { } @observer export class ConfigMapDetails extends React.Component { + private get configMapsStore() { + return ApiManager.getInstance().getStore(configMapApi); + } + @observable isSaving = false; @observable data = observable.map(); @@ -58,7 +63,7 @@ export class ConfigMapDetails extends React.Component { try { this.isSaving = true; - await configMapsStore.update(configMap, { ...configMap, data: this.data.toJSON() }); + await this.configMapsStore.update(configMap, { ...configMap, data: this.data.toJSON() }); Notifications.ok(

    <>ConfigMap {configMap.getName()} successfully updated. diff --git a/src/renderer/components/+config-maps/config-maps.store.ts b/src/renderer/components/+config-maps/config-maps.store.ts index 51457c8c20c0..f5ccdd234970 100644 --- a/src/renderer/components/+config-maps/config-maps.store.ts +++ b/src/renderer/components/+config-maps/config-maps.store.ts @@ -22,12 +22,8 @@ import { KubeObjectStore } from "../../kube-object.store"; import { autobind } from "../../utils"; import { ConfigMap, configMapApi } from "../../api/endpoints/configmap.api"; -import { apiManager } from "../../api/api-manager"; @autobind() export class ConfigMapsStore extends KubeObjectStore { api = configMapApi; } - -export const configMapsStore = new ConfigMapsStore(); -apiManager.registerStore(configMapsStore); diff --git a/src/renderer/components/+config-maps/config-maps.tsx b/src/renderer/components/+config-maps/config-maps.tsx index fb757a69bf9c..0029bcc3fdff 100644 --- a/src/renderer/components/+config-maps/config-maps.tsx +++ b/src/renderer/components/+config-maps/config-maps.tsx @@ -24,11 +24,12 @@ import "./config-maps.scss"; import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; -import { configMapsStore } from "./config-maps.store"; -import type { ConfigMap } from "../../api/endpoints/configmap.api"; +import { ConfigMap, configMapApi } from "../../api/endpoints/configmap.api"; import { KubeObjectListLayout } from "../kube-object"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { ConfigMapsRouteParams } from "../../../common/routes"; +import { ApiManager } from "../../api/api-manager"; +import type { ConfigMapsStore } from "./config-maps.store"; enum columnId { name = "name", @@ -42,12 +43,17 @@ interface Props extends RouteComponentProps { @observer export class ConfigMaps extends React.Component { + private get configMapsStore() { + return ApiManager.getInstance().getStore(configMapApi); + } + render() { return ( item.getName(), [columnId.namespace]: (item: ConfigMap) => item.getNs(), diff --git a/src/renderer/components/+config-maps/index.ts b/src/renderer/components/+config-maps/index.ts index b4ca786263c7..36f41cdd6630 100644 --- a/src/renderer/components/+config-maps/index.ts +++ b/src/renderer/components/+config-maps/index.ts @@ -20,4 +20,5 @@ */ export * from "./config-maps"; +export * from "./config-maps.store"; export * from "./config-map-details"; diff --git a/src/renderer/components/+config-pod-disruption-budgets/index.ts b/src/renderer/components/+config-pod-disruption-budgets/index.ts index d494a1fa36cd..2154ef04a626 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/index.ts +++ b/src/renderer/components/+config-pod-disruption-budgets/index.ts @@ -20,4 +20,5 @@ */ export * from "./pod-disruption-budgets"; +export * from "./pod-disruption-budgets.store"; export * from "./pod-disruption-budgets-details"; diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store.ts b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store.ts index d97593542d53..c614624e7b50 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store.ts +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store.ts @@ -21,13 +21,9 @@ import { KubeObjectStore } from "../../kube-object.store"; import { autobind } from "../../utils"; -import { PodDisruptionBudget, pdbApi } from "../../api/endpoints/poddisruptionbudget.api"; -import { apiManager } from "../../api/api-manager"; +import { PodDisruptionBudget, podDisruptionBudgetApi } from "../../api/endpoints/poddisruptionbudget.api"; @autobind() export class PodDisruptionBudgetsStore extends KubeObjectStore { - api = pdbApi; + api = podDisruptionBudgetApi; } - -export const podDisruptionBudgetsStore = new PodDisruptionBudgetsStore(); -apiManager.registerStore(podDisruptionBudgetsStore); 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 abc87a6a4d06..eff9e02baf0c 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 @@ -23,10 +23,11 @@ import "./pod-disruption-budgets.scss"; import * as React from "react"; import { observer } from "mobx-react"; -import { podDisruptionBudgetsStore } from "./pod-disruption-budgets.store"; -import type { PodDisruptionBudget } from "../../api/endpoints/poddisruptionbudget.api"; +import { PodDisruptionBudget, podDisruptionBudgetApi } from "../../api/endpoints/poddisruptionbudget.api"; import { KubeObjectDetailsProps, KubeObjectListLayout } from "../kube-object"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; +import type { PodDisruptionBudgetsStore } from "./pod-disruption-budgets.store"; +import { ApiManager } from "../../api/api-manager"; enum columnId { name = "name", @@ -43,13 +44,17 @@ interface Props extends KubeObjectDetailsProps { @observer export class PodDisruptionBudgets extends React.Component { + private get podDisruptionBudgetsStore() { + return ApiManager.getInstance().getStore(podDisruptionBudgetApi); + } + render() { return ( pdb.getName(), [columnId.namespace]: (pdb: PodDisruptionBudget) => pdb.getNs(), diff --git a/src/renderer/components/+config-resource-quotas/index.ts b/src/renderer/components/+config-resource-quotas/index.ts index e6f87451e560..acbd8645ffac 100644 --- a/src/renderer/components/+config-resource-quotas/index.ts +++ b/src/renderer/components/+config-resource-quotas/index.ts @@ -20,4 +20,5 @@ */ export * from "./resource-quotas"; +export * from "./resource-quotas.store"; export * from "./resource-quota-details"; diff --git a/src/renderer/components/+config-resource-quotas/resource-quotas.store.ts b/src/renderer/components/+config-resource-quotas/resource-quotas.store.ts index 5d8907a0b061..6cfd12dca851 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quotas.store.ts +++ b/src/renderer/components/+config-resource-quotas/resource-quotas.store.ts @@ -22,12 +22,8 @@ import { KubeObjectStore } from "../../kube-object.store"; import { autobind } from "../../utils"; import { ResourceQuota, resourceQuotaApi } from "../../api/endpoints/resource-quota.api"; -import { apiManager } from "../../api/api-manager"; @autobind() export class ResourceQuotasStore extends KubeObjectStore { api = resourceQuotaApi; } - -export const resourceQuotaStore = new ResourceQuotasStore(); -apiManager.registerStore(resourceQuotaStore); diff --git a/src/renderer/components/+config-resource-quotas/resource-quotas.tsx b/src/renderer/components/+config-resource-quotas/resource-quotas.tsx index d1ce05c0985a..4fd78eefd371 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quotas.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quotas.tsx @@ -25,11 +25,12 @@ import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; import { KubeObjectListLayout } from "../kube-object"; -import type { ResourceQuota } from "../../api/endpoints/resource-quota.api"; +import { ResourceQuota, resourceQuotaApi } from "../../api/endpoints/resource-quota.api"; import { AddQuotaDialog } from "./add-quota-dialog"; -import { resourceQuotaStore } from "./resource-quotas.store"; +import type { ResourceQuotasStore } from "./resource-quotas.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { ResourceQuotaRouteParams } from "../../../common/routes"; +import { ApiManager } from "../../api/api-manager"; enum columnId { name = "name", @@ -42,13 +43,18 @@ interface Props extends RouteComponentProps { @observer export class ResourceQuotas extends React.Component { + private get resourceQuotaStore() { + return ApiManager.getInstance().getStore(resourceQuotaApi); + } + render() { return ( <> item.getName(), [columnId.namespace]: (item: ResourceQuota) => item.getNs(), diff --git a/src/renderer/components/+config-secrets/index.ts b/src/renderer/components/+config-secrets/index.ts index 783c83455dda..7373eaed9211 100644 --- a/src/renderer/components/+config-secrets/index.ts +++ b/src/renderer/components/+config-secrets/index.ts @@ -20,4 +20,5 @@ */ export * from "./secrets"; +export * from "./secrets.store"; export * from "./secret-details"; diff --git a/src/renderer/components/+config-secrets/secret-details.tsx b/src/renderer/components/+config-secrets/secret-details.tsx index 18ea67d5f7e9..2cfe754e21be 100644 --- a/src/renderer/components/+config-secrets/secret-details.tsx +++ b/src/renderer/components/+config-secrets/secret-details.tsx @@ -31,16 +31,21 @@ import { Button } from "../button"; import { Notifications } from "../notifications"; import { base64 } from "../../utils"; import { Icon } from "../icon"; -import { secretsStore } from "./secrets.store"; import type { KubeObjectDetailsProps } from "../kube-object"; -import type { Secret } from "../../api/endpoints"; +import { Secret, secretsApi } from "../../api/endpoints"; import { KubeObjectMeta } from "../kube-object/kube-object-meta"; +import type { SecretsStore } from "."; +import { ApiManager } from "../../api/api-manager"; interface Props extends KubeObjectDetailsProps { } @observer export class SecretDetails extends React.Component { + private get secretsStore() { + return ApiManager.getInstance().getStore(secretsApi); + } + @observable isSaving = false; @observable data: { [name: string]: string } = {}; @observable revealSecret: { [name: string]: boolean } = {}; @@ -64,7 +69,7 @@ export class SecretDetails extends React.Component { this.isSaving = true; try { - await secretsStore.update(secret, { ...secret, data: this.data }); + await this.secretsStore.update(secret, { ...secret, data: this.data }); Notifications.ok("Secret successfully updated."); } catch (err) { Notifications.error(err); diff --git a/src/renderer/components/+config-secrets/secrets.store.ts b/src/renderer/components/+config-secrets/secrets.store.ts index c680c5fb9a4b..079d252e89bd 100644 --- a/src/renderer/components/+config-secrets/secrets.store.ts +++ b/src/renderer/components/+config-secrets/secrets.store.ts @@ -22,12 +22,8 @@ import { KubeObjectStore } from "../../kube-object.store"; import { autobind } from "../../utils"; import { Secret, secretsApi } from "../../api/endpoints"; -import { apiManager } from "../../api/api-manager"; @autobind() export class SecretsStore extends KubeObjectStore { api = secretsApi; } - -export const secretsStore = new SecretsStore(); -apiManager.registerStore(secretsStore); diff --git a/src/renderer/components/+config-secrets/secrets.tsx b/src/renderer/components/+config-secrets/secrets.tsx index d74305a499dd..1e43002861fc 100644 --- a/src/renderer/components/+config-secrets/secrets.tsx +++ b/src/renderer/components/+config-secrets/secrets.tsx @@ -24,13 +24,14 @@ import "./secrets.scss"; import React from "react"; import { observer } from "mobx-react"; import type { RouteComponentProps } from "react-router"; -import type { Secret } from "../../api/endpoints"; +import { Secret, secretsApi } from "../../api/endpoints"; import { AddSecretDialog } from "./add-secret-dialog"; import { KubeObjectListLayout } from "../kube-object"; import { Badge } from "../badge"; -import { secretsStore } from "./secrets.store"; import { KubeObjectStatusIcon } from "../kube-object-status-icon"; import type { SecretsRouteParams } from "../../../common/routes"; +import type { SecretsStore } from "./secrets.store"; +import { ApiManager } from "../../api/api-manager"; enum columnId { name = "name", @@ -46,13 +47,18 @@ interface Props extends RouteComponentProps { @observer export class Secrets extends React.Component { + private get secretsStore() { + return ApiManager.getInstance().getStore(secretsApi); + } + render() { return ( <> item.getName(), [columnId.namespace]: (item: Secret) => item.getNs(), diff --git a/src/renderer/components/+config/config.tsx b/src/renderer/components/+config/config.tsx index c5948ed37fdb..13c0f38541fb 100644 --- a/src/renderer/components/+config/config.tsx +++ b/src/renderer/components/+config/config.tsx @@ -28,17 +28,17 @@ import { namespaceUrlParam } from "../+namespaces/namespace.store"; import { ResourceQuotas } from "../+config-resource-quotas"; import { PodDisruptionBudgets } from "../+config-pod-disruption-budgets"; import { HorizontalPodAutoscalers } from "../+config-autoscalers"; -import { isAllowedResource } from "../../../common/rbac"; import { LimitRanges } from "../+config-limit-ranges"; import * as routes from "../../../common/routes"; +import type { Cluster } from "../../../main/cluster"; @observer -export class Config extends React.Component { - static get tabRoutes(): TabLayoutRoute[] { +export class Config extends React.Component<{ cluster: Cluster }> { + static tabRoutes(cluster: Cluster): TabLayoutRoute[] { const query = namespaceUrlParam.toObjectParam(); const tabs: TabLayoutRoute[] = []; - if (isAllowedResource("configmaps")) { + if (cluster.isAllowedResource("configmaps")) { tabs.push({ title: "ConfigMaps", component: ConfigMaps, @@ -47,7 +47,7 @@ export class Config extends React.Component { }); } - if (isAllowedResource("secrets")) { + if (cluster.isAllowedResource("secrets")) { tabs.push({ title: "Secrets", component: Secrets, @@ -56,7 +56,7 @@ export class Config extends React.Component { }); } - if (isAllowedResource("resourcequotas")) { + if (cluster.isAllowedResource("resourcequotas")) { tabs.push({ title: "Resource Quotas", component: ResourceQuotas, @@ -65,7 +65,7 @@ export class Config extends React.Component { }); } - if (isAllowedResource("limitranges")) { + if (cluster.isAllowedResource("limitranges")) { tabs.push({ title: "Limit Ranges", component: LimitRanges, @@ -74,7 +74,7 @@ export class Config extends React.Component { }); } - if (isAllowedResource("horizontalpodautoscalers")) { + if (cluster.isAllowedResource("horizontalpodautoscalers")) { tabs.push({ title: "HPA", component: HorizontalPodAutoscalers, @@ -83,7 +83,7 @@ export class Config extends React.Component { }); } - if (isAllowedResource("poddisruptionbudgets")) { + if (cluster.isAllowedResource("poddisruptionbudgets")) { tabs.push({ title: "Pod Disruption Budgets", component: PodDisruptionBudgets, @@ -97,7 +97,7 @@ export class Config extends React.Component { render() { return ( - + ); } } diff --git a/src/renderer/components/+custom-resources/crd-list.tsx b/src/renderer/components/+custom-resources/crd-list.tsx index bb6753dce23e..67cb66b35519 100644 --- a/src/renderer/components/+custom-resources/crd-list.tsx +++ b/src/renderer/components/+custom-resources/crd-list.tsx @@ -27,11 +27,12 @@ import { observer } from "mobx-react"; import { Link } from "react-router-dom"; import { stopPropagation } from "../../utils"; import { KubeObjectListLayout } from "../kube-object"; -import { crdStore } from "./crd.store"; -import type { CustomResourceDefinition } from "../../api/endpoints/crd.api"; +import type { CrdStore } from "./crd.store"; +import { crdApi, CustomResourceDefinition } from "../../api/endpoints/crd.api"; import { Select, SelectOption } from "../select"; import { createPageParam } from "../../navigation"; import { Icon } from "../icon"; +import { ApiManager } from "../../api/api-manager"; export const crdGroupsUrlParam = createPageParam({ name: "groups", @@ -54,12 +55,16 @@ export class CrdList extends React.Component { return crdGroupsUrlParam.get(); } + private get crdStore() { + return ApiManager.getInstance().getStore(crdApi); + } + @computed get items() { if (this.selectedGroups.length) { - return crdStore.items.filter(item => this.selectedGroups.includes(item.getGroup())); + return this.crdStore.items.filter(item => this.selectedGroups.includes(item.getGroup())); } - return crdStore.items; // show all by default + return this.crdStore.items; // show all by default } toggleSelection(group: string) { @@ -88,7 +93,7 @@ export class CrdList extends React.Component { tableId="crd" className="CrdList" isClusterScoped={true} - store={crdStore} + store={this.crdStore} items={items} sortingCallbacks={sortingCallbacks} searchFilters={Object.values(sortingCallbacks)} @@ -105,7 +110,7 @@ export class CrdList extends React.Component {