mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Fix rerendering of KubeObject views every 30s (#4801)
Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
parent
00314aabc0
commit
76f48df56b
@ -233,16 +233,16 @@ const commonPageTests: CommonPageTest[] = [{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
drawerId: "apps",
|
drawerId: "helm",
|
||||||
pages: [
|
pages: [
|
||||||
{
|
{
|
||||||
name: "Charts",
|
name: "Charts",
|
||||||
href: "/apps/charts",
|
href: "/helm/charts",
|
||||||
expectedSelector: "div.HelmCharts input",
|
expectedSelector: "div.HelmCharts input",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Releases",
|
name: "Releases",
|
||||||
href: "/apps/releases",
|
href: "/helm/releases",
|
||||||
expectedSelector: "h5.title",
|
expectedSelector: "h5.title",
|
||||||
expectedText: "Releases",
|
expectedText: "Releases",
|
||||||
},
|
},
|
||||||
|
|||||||
21
src/common/cluster-store/allowed-resources.injectable.ts
Normal file
21
src/common/cluster-store/allowed-resources.injectable.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
|
import { comparer, computed } from "mobx";
|
||||||
|
import hostedClusterInjectable from "./hosted-cluster.injectable";
|
||||||
|
|
||||||
|
const allowedResourcesInjectable = getInjectable({
|
||||||
|
instantiate: (di) => {
|
||||||
|
const cluster = di.inject(hostedClusterInjectable);
|
||||||
|
|
||||||
|
return computed(() => new Set(cluster.allowedResources), {
|
||||||
|
// This needs to be here so that during refresh changes are only propogated when necessary
|
||||||
|
equals: (cur, prev) => comparer.structural(cur, prev),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
lifecycle: lifecycleEnum.singleton,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default allowedResourcesInjectable;
|
||||||
@ -3,8 +3,8 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
import { getHostedClusterId } from "../../utils";
|
import { getHostedClusterId } from "../utils";
|
||||||
import clusterStoreInjectable from "../cluster-store.injectable";
|
import clusterStoreInjectable from "./cluster-store.injectable";
|
||||||
|
|
||||||
const hostedClusterInjectable = getInjectable({
|
const hostedClusterInjectable = getInjectable({
|
||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
@ -7,7 +7,7 @@ import yaml from "js-yaml";
|
|||||||
import { formatDuration } from "../../utils";
|
import { formatDuration } from "../../utils";
|
||||||
import capitalize from "lodash/capitalize";
|
import capitalize from "lodash/capitalize";
|
||||||
import { apiBase } from "../index";
|
import { apiBase } from "../index";
|
||||||
import { helmChartStore } from "../../../renderer/components/+apps-helm-charts/helm-chart.store";
|
import { helmChartStore } from "../../../renderer/components/+helm-charts/helm-chart.store";
|
||||||
import type { ItemObject } from "../../item.store";
|
import type { ItemObject } from "../../item.store";
|
||||||
import { KubeObject } from "../kube-object";
|
import { KubeObject } from "../kube-object";
|
||||||
import type { JsonApiData } from "../json-api";
|
import type { JsonApiData } from "../json-api";
|
||||||
|
|||||||
@ -16,12 +16,9 @@ import { KubeObjectConstructor, KubeObject, KubeStatus } from "./kube-object";
|
|||||||
import byline from "byline";
|
import byline from "byline";
|
||||||
import type { IKubeWatchEvent } from "./kube-watch-event";
|
import type { IKubeWatchEvent } from "./kube-watch-event";
|
||||||
import { KubeJsonApi, KubeJsonApiData } from "./kube-json-api";
|
import { KubeJsonApi, KubeJsonApiData } from "./kube-json-api";
|
||||||
import { noop } from "../utils";
|
import { noop, WrappedAbortController } from "../utils";
|
||||||
import type { RequestInit } from "node-fetch";
|
import type { RequestInit } from "node-fetch";
|
||||||
|
import type AbortController from "abort-controller";
|
||||||
// BUG: https://github.com/mysticatea/abort-controller/pull/22
|
|
||||||
// eslint-disable-next-line import/no-named-as-default
|
|
||||||
import AbortController from "abort-controller";
|
|
||||||
import { Agent, AgentOptions } from "https";
|
import { Agent, AgentOptions } from "https";
|
||||||
import type { Patch } from "rfc6902";
|
import type { Patch } from "rfc6902";
|
||||||
|
|
||||||
@ -582,14 +579,7 @@ export class KubeApi<T extends KubeObject> {
|
|||||||
const { watchId = `${this.kind.toLowerCase()}-${this.watchId++}` } = opts;
|
const { watchId = `${this.kind.toLowerCase()}-${this.watchId++}` } = opts;
|
||||||
|
|
||||||
// Create AbortController for this request
|
// Create AbortController for this request
|
||||||
const abortController = new AbortController();
|
const abortController = new WrappedAbortController(opts.abortController);
|
||||||
|
|
||||||
// If caller aborts, abort using request's abortController
|
|
||||||
if (opts.abortController) {
|
|
||||||
opts.abortController.signal.addEventListener("abort", () => {
|
|
||||||
abortController.abort();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
abortController.signal.addEventListener("abort", () => {
|
abortController.signal.addEventListener("abort", () => {
|
||||||
logger.info(`[KUBE-API] watch (${watchId}) aborted ${watchUrl}`);
|
logger.info(`[KUBE-API] watch (${watchId}) aborted ${watchUrl}`);
|
||||||
@ -687,7 +677,6 @@ export class KubeApi<T extends KubeObject> {
|
|||||||
protected modifyWatchEvent(event: IKubeWatchEvent<KubeJsonApiData>) {
|
protected modifyWatchEvent(event: IKubeWatchEvent<KubeJsonApiData>) {
|
||||||
if (event.type === "ERROR") {
|
if (event.type === "ERROR") {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ensureObjectSelfLink(this, event.object);
|
ensureObjectSelfLink(this, event.object);
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
import type { ClusterContext } from "./cluster-context";
|
import type { ClusterContext } from "./cluster-context";
|
||||||
|
|
||||||
import { action, computed, makeObservable, observable, reaction, when } from "mobx";
|
import { action, computed, makeObservable, observable, reaction, when } from "mobx";
|
||||||
import { autoBind, noop, rejectPromiseBy } from "../utils";
|
import { autoBind, Disposer, noop, rejectPromiseBy } from "../utils";
|
||||||
import { KubeObject, KubeStatus } from "./kube-object";
|
import { KubeObject, KubeStatus } from "./kube-object";
|
||||||
import type { IKubeWatchEvent } from "./kube-watch-event";
|
import type { IKubeWatchEvent } from "./kube-watch-event";
|
||||||
import { ItemStore } from "../item.store";
|
import { ItemStore } from "../item.store";
|
||||||
@ -378,7 +378,7 @@ export abstract class KubeObjectStore<T extends KubeObject> extends ItemStore<T>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribe({ onLoadFailure, abortController = new AbortController() }: KubeObjectStoreSubscribeParams = {}) {
|
subscribe({ onLoadFailure, abortController = new AbortController() }: KubeObjectStoreSubscribeParams = {}): Disposer {
|
||||||
if (this.api.isNamespaced) {
|
if (this.api.isNamespaced) {
|
||||||
Promise.race([rejectPromiseBy(abortController.signal), Promise.all([this.contextReady, this.namespacesReady])])
|
Promise.race([rejectPromiseBy(abortController.signal), Promise.all([this.contextReady, this.namespacesReady])])
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|||||||
@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
import type { RouteProps } from "react-router";
|
import type { RouteProps } from "react-router";
|
||||||
import { buildURL } from "../utils/buildUrl";
|
import { buildURL } from "../utils/buildUrl";
|
||||||
import { appsRoute } from "./apps";
|
import { helmRoute } from "./helm";
|
||||||
|
|
||||||
export const helmChartsRoute: RouteProps = {
|
export const helmChartsRoute: RouteProps = {
|
||||||
path: `${appsRoute.path}/charts/:repo?/:chartName?`,
|
path: `${helmRoute.path}/charts/:repo?/:chartName?`,
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface HelmChartsRouteParams {
|
export interface HelmChartsRouteParams {
|
||||||
|
|||||||
@ -6,8 +6,8 @@
|
|||||||
import type { RouteProps } from "react-router";
|
import type { RouteProps } from "react-router";
|
||||||
import { buildURL } from "../utils/buildUrl";
|
import { buildURL } from "../utils/buildUrl";
|
||||||
|
|
||||||
export const appsRoute: RouteProps = {
|
export const helmRoute: RouteProps = {
|
||||||
path: "/apps",
|
path: "/helm",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const appsURL = buildURL(appsRoute.path);
|
export const helmURL = buildURL(helmRoute.path);
|
||||||
@ -4,7 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export * from "./add-cluster";
|
export * from "./add-cluster";
|
||||||
export * from "./apps";
|
|
||||||
export * from "./catalog";
|
export * from "./catalog";
|
||||||
export * from "./cluster-view";
|
export * from "./cluster-view";
|
||||||
export * from "./cluster";
|
export * from "./cluster";
|
||||||
@ -16,6 +15,7 @@ export * from "./entity-settings";
|
|||||||
export * from "./events";
|
export * from "./events";
|
||||||
export * from "./extensions";
|
export * from "./extensions";
|
||||||
export * from "./helm-charts";
|
export * from "./helm-charts";
|
||||||
|
export * from "./helm";
|
||||||
export * from "./hpa";
|
export * from "./hpa";
|
||||||
export * from "./ingresses";
|
export * from "./ingresses";
|
||||||
export * from "./limit-ranges";
|
export * from "./limit-ranges";
|
||||||
|
|||||||
@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
import type { RouteProps } from "react-router";
|
import type { RouteProps } from "react-router";
|
||||||
import { buildURL } from "../utils/buildUrl";
|
import { buildURL } from "../utils/buildUrl";
|
||||||
import { appsRoute } from "./apps";
|
import { helmRoute } from "./helm";
|
||||||
|
|
||||||
export const releaseRoute: RouteProps = {
|
export const releaseRoute: RouteProps = {
|
||||||
path: `${appsRoute.path}/releases/:namespace?/:name?`,
|
path: `${helmRoute.path}/releases/:namespace?/:name?`,
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface ReleaseRouteParams {
|
export interface ReleaseRouteParams {
|
||||||
|
|||||||
15
src/common/utils/abort-controller.ts
Normal file
15
src/common/utils/abort-controller.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import AbortController from "abort-controller";
|
||||||
|
|
||||||
|
export class WrappedAbortController extends AbortController {
|
||||||
|
constructor(parent?: AbortController) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
parent?.signal.addEventListener("abort", () => {
|
||||||
|
this.abort();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,25 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { ClusterStore } from "../cluster-store/cluster-store";
|
|
||||||
import type { KubeResource } from "../rbac";
|
|
||||||
import { getHostedClusterId } from "./cluster-id-url-parsing";
|
|
||||||
|
|
||||||
export function isAllowedResource(resource: KubeResource | KubeResource[]) {
|
|
||||||
const resources = [resource].flat();
|
|
||||||
const cluster = ClusterStore.getInstance().getById(getHostedClusterId());
|
|
||||||
|
|
||||||
if (!cluster?.allowedResources) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resources.length === 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const allowedResources = new Set(cluster.allowedResources);
|
|
||||||
|
|
||||||
return resources.every(resource => allowedResources.has(resource));
|
|
||||||
}
|
|
||||||
@ -10,6 +10,7 @@ export function noop<T extends any[]>(...args: T): void {
|
|||||||
return void args;
|
return void args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export * from "./abort-controller";
|
||||||
export * from "./app-version";
|
export * from "./app-version";
|
||||||
export * from "./autobind";
|
export * from "./autobind";
|
||||||
export * from "./camelCase";
|
export * from "./camelCase";
|
||||||
|
|||||||
22
src/common/utils/is-allowed-resource.injectable.ts
Normal file
22
src/common/utils/is-allowed-resource.injectable.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
|
import allowedResourcesInjectable from "../cluster-store/allowed-resources.injectable";
|
||||||
|
import type { KubeResource } from "../rbac";
|
||||||
|
|
||||||
|
export type IsAllowedResource = (resource: KubeResource) => boolean;
|
||||||
|
|
||||||
|
// TODO: This injectable obscures MobX de-referencing. Make it more apparent in usage.
|
||||||
|
const isAllowedResourceInjectable = getInjectable({
|
||||||
|
instantiate: (di) => {
|
||||||
|
const allowedResources = di.inject(allowedResourcesInjectable);
|
||||||
|
|
||||||
|
return (resource: KubeResource) => allowedResources.get().has(resource);
|
||||||
|
},
|
||||||
|
|
||||||
|
lifecycle: lifecycleEnum.singleton,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default isAllowedResourceInjectable;
|
||||||
@ -3,7 +3,14 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export { isAllowedResource } from "../../common/utils/allowed-resource";
|
/**
|
||||||
|
* @deprecated This function never works
|
||||||
|
* @returns false
|
||||||
|
*/
|
||||||
|
export function isAllowedResource(...args: any[]) {
|
||||||
|
return Boolean(void args);
|
||||||
|
}
|
||||||
|
|
||||||
export { ResourceStack } from "../../common/k8s/resource-stack";
|
export { ResourceStack } from "../../common/k8s/resource-stack";
|
||||||
export { apiManager } from "../../common/k8s-api/api-manager";
|
export { apiManager } from "../../common/k8s-api/api-manager";
|
||||||
export { KubeApi, forCluster, forRemoteCluster } from "../../common/k8s-api/kube-api";
|
export { KubeApi, forCluster, forRemoteCluster } from "../../common/k8s-api/kube-api";
|
||||||
|
|||||||
@ -2,8 +2,19 @@
|
|||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
import type { KubeResource } from "../../common/rbac";
|
||||||
|
import isAllowedResourceInjectable from "../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import { asLegacyGlobalFunctionForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api";
|
||||||
|
import { castArray } from "lodash/fp";
|
||||||
|
|
||||||
|
export function isAllowedResource(resource: KubeResource | KubeResource[]) {
|
||||||
|
const _isAllowedResource = asLegacyGlobalFunctionForExtensionApi(isAllowedResourceInjectable);
|
||||||
|
|
||||||
|
const resources = castArray(resource);
|
||||||
|
|
||||||
|
return resources.every(x => _isAllowedResource(x));
|
||||||
|
}
|
||||||
|
|
||||||
export { isAllowedResource } from "../../common/utils/allowed-resource";
|
|
||||||
export { ResourceStack } from "../../common/k8s/resource-stack";
|
export { ResourceStack } from "../../common/k8s/resource-stack";
|
||||||
export { apiManager } from "../../common/k8s-api/api-manager";
|
export { apiManager } from "../../common/k8s-api/api-manager";
|
||||||
export { KubeObjectStore } from "../../common/k8s-api/kube-object.store";
|
export { KubeObjectStore } from "../../common/k8s-api/kube-object.store";
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
import { ClusterFrameContext } from "./cluster-frame-context";
|
import { ClusterFrameContext } from "./cluster-frame-context";
|
||||||
import namespaceStoreInjectable from "../components/+namespaces/namespace-store/namespace-store.injectable";
|
import namespaceStoreInjectable from "../components/+namespaces/namespace-store/namespace-store.injectable";
|
||||||
import hostedClusterInjectable from "../../common/cluster-store/hosted-cluster/hosted-cluster.injectable";
|
import hostedClusterInjectable from "../../common/cluster-store/hosted-cluster.injectable";
|
||||||
|
|
||||||
const clusterFrameContextInjectable = getInjectable({
|
const clusterFrameContextInjectable = getInjectable({
|
||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
|
|||||||
@ -1,38 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from "react";
|
|
||||||
import { observer } from "mobx-react";
|
|
||||||
import { TabLayout, TabLayoutRoute } from "../layout/tab-layout";
|
|
||||||
import { HelmCharts } from "../+apps-helm-charts";
|
|
||||||
import { HelmReleases } from "../+apps-releases";
|
|
||||||
import { helmChartsURL, helmChartsRoute, releaseURL, releaseRoute } from "../../../common/routes";
|
|
||||||
|
|
||||||
@observer
|
|
||||||
export class Apps extends React.Component {
|
|
||||||
static get tabRoutes(): TabLayoutRoute[] {
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
title: "Charts",
|
|
||||||
component: HelmCharts,
|
|
||||||
url: helmChartsURL(),
|
|
||||||
routePath: helmChartsRoute.path.toString(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Releases",
|
|
||||||
component: HelmReleases,
|
|
||||||
url: releaseURL(),
|
|
||||||
routePath: releaseRoute.path.toString(),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<TabLayout className="Apps" tabs={Apps.tabRoutes}/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export * from "./apps";
|
|
||||||
37
src/renderer/components/+cluster/sidebar-item.tsx
Normal file
37
src/renderer/components/+cluster/sidebar-item.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import React from "react";
|
||||||
|
import { clusterRoute, clusterURL } from "../../../common/routes";
|
||||||
|
import type { IsAllowedResource } from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import isAllowedResourceInjectable from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import { isActiveRoute } from "../../navigation";
|
||||||
|
import { Icon } from "../icon";
|
||||||
|
import { SidebarItem } from "../layout/sidebar-item";
|
||||||
|
|
||||||
|
export interface ClusterSidebarItemProps {}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
isAllowedResource: IsAllowedResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedClusterSidebarItem = observer(({ isAllowedResource }: Dependencies & ClusterSidebarItemProps) => (
|
||||||
|
<SidebarItem
|
||||||
|
id="cluster"
|
||||||
|
text="Cluster"
|
||||||
|
isActive={isActiveRoute(clusterRoute)}
|
||||||
|
isHidden={!isAllowedResource("nodes")}
|
||||||
|
url={clusterURL()}
|
||||||
|
icon={<Icon svg="kube"/>}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
|
export const ClusterSidebarItem = withInjectables<Dependencies, ClusterSidebarItemProps>(NonInjectedClusterSidebarItem, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
isAllowedResource: di.inject(isAllowedResourceInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
@ -1,6 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export * from "./config";
|
|
||||||
@ -2,22 +2,24 @@
|
|||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
import React from "react";
|
import { computed } from "mobx";
|
||||||
import { observer } from "mobx-react";
|
|
||||||
import { TabLayout, TabLayoutRoute } from "../layout/tab-layout";
|
|
||||||
import { ConfigMaps } from "../+config-maps";
|
|
||||||
import { Secrets } from "../+config-secrets";
|
|
||||||
import { ResourceQuotas } from "../+config-resource-quotas";
|
|
||||||
import { PodDisruptionBudgets } from "../+config-pod-disruption-budgets";
|
|
||||||
import { HorizontalPodAutoscalers } from "../+config-autoscalers";
|
import { HorizontalPodAutoscalers } from "../+config-autoscalers";
|
||||||
import { isAllowedResource } from "../../../common/utils/allowed-resource";
|
|
||||||
import { LimitRanges } from "../+config-limit-ranges";
|
import { LimitRanges } from "../+config-limit-ranges";
|
||||||
|
import { ConfigMaps } from "../+config-maps";
|
||||||
|
import { PodDisruptionBudgets } from "../+config-pod-disruption-budgets";
|
||||||
|
import { ResourceQuotas } from "../+config-resource-quotas";
|
||||||
|
import { Secrets } from "../+config-secrets";
|
||||||
|
import isAllowedResourceInjectable, { IsAllowedResource } from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import type { TabLayoutRoute } from "../layout/tab-layout";
|
||||||
import * as routes from "../../../common/routes";
|
import * as routes from "../../../common/routes";
|
||||||
|
|
||||||
@observer
|
interface Dependencies {
|
||||||
export class Config extends React.Component {
|
isAllowedResource: IsAllowedResource;
|
||||||
static get tabRoutes(): TabLayoutRoute[] {
|
}
|
||||||
|
|
||||||
|
function getRouteTabs({ isAllowedResource }: Dependencies) {
|
||||||
|
return computed(() => {
|
||||||
const tabs: TabLayoutRoute[] = [];
|
const tabs: TabLayoutRoute[] = [];
|
||||||
|
|
||||||
if (isAllowedResource("configmaps")) {
|
if (isAllowedResource("configmaps")) {
|
||||||
@ -75,11 +77,14 @@ export class Config extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return tabs;
|
return tabs;
|
||||||
}
|
});
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<TabLayout className="Config" tabs={Config.tabRoutes}/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const configRoutesInjectable = getInjectable({
|
||||||
|
instantiate: (di) => getRouteTabs({
|
||||||
|
isAllowedResource: di.inject(isAllowedResourceInjectable),
|
||||||
|
}),
|
||||||
|
lifecycle: lifecycleEnum.singleton,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default configRoutesInjectable;
|
||||||
31
src/renderer/components/+config/route.tsx
Normal file
31
src/renderer/components/+config/route.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import { TabLayout, TabLayoutRoute } from "../layout/tab-layout";
|
||||||
|
import type { IComputedValue } from "mobx";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import configRoutesInjectable from "./route-tabs.injectable";
|
||||||
|
|
||||||
|
export interface ConfigRouteProps {}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
routes: IComputedValue<TabLayoutRoute[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedConfigRoute = observer(({ routes }: Dependencies & ConfigRouteProps) => (
|
||||||
|
<TabLayout
|
||||||
|
className="Config"
|
||||||
|
tabs={routes.get()}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
|
export const ConfigRoute = withInjectables<Dependencies, ConfigRouteProps>(NonInjectedConfigRoute, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
routes: di.inject(configRoutesInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
45
src/renderer/components/+config/sidebar-item.tsx
Normal file
45
src/renderer/components/+config/sidebar-item.tsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import type { IComputedValue } from "mobx";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import React from "react";
|
||||||
|
import { configRoute, configURL } from "../../../common/routes";
|
||||||
|
import { isActiveRoute } from "../../navigation";
|
||||||
|
import { Icon } from "../icon";
|
||||||
|
import { SidebarItem } from "../layout/sidebar-item";
|
||||||
|
import type { TabLayoutRoute } from "../layout/tab-layout";
|
||||||
|
import { TabRoutesSidebarItems } from "../layout/tab-routes-sidebar-items";
|
||||||
|
import configRoutesInjectable from "./route-tabs.injectable";
|
||||||
|
|
||||||
|
export interface ConfigSidebarItemProps {}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
routes: IComputedValue<TabLayoutRoute[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedConfigSidebarItem = observer(({ routes }: Dependencies & ConfigSidebarItemProps) => {
|
||||||
|
const tabRoutes = routes.get();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarItem
|
||||||
|
id="config"
|
||||||
|
text="Configuration"
|
||||||
|
isActive={isActiveRoute(configRoute)}
|
||||||
|
isHidden={tabRoutes.length == 0}
|
||||||
|
url={configURL()}
|
||||||
|
icon={<Icon material="list"/>}
|
||||||
|
>
|
||||||
|
<TabRoutesSidebarItems routes={tabRoutes} />
|
||||||
|
</SidebarItem>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ConfigSidebarItem = withInjectables<Dependencies, ConfigSidebarItemProps>(NonInjectedConfigSidebarItem, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
routes: di.inject(configRoutesInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
@ -1,38 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from "react";
|
|
||||||
import { observer } from "mobx-react";
|
|
||||||
import { Redirect, Route, Switch } from "react-router";
|
|
||||||
import { TabLayout, TabLayoutRoute } from "../layout/tab-layout";
|
|
||||||
import { CrdList } from "./crd-list";
|
|
||||||
import { CrdResources } from "./crd-resources";
|
|
||||||
import { crdURL, crdDefinitionsRoute, crdResourcesRoute } from "../../../common/routes";
|
|
||||||
|
|
||||||
@observer
|
|
||||||
export class CustomResources extends React.Component {
|
|
||||||
static get tabRoutes(): TabLayoutRoute[] {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
title: "Definitions",
|
|
||||||
component: CustomResources,
|
|
||||||
url: crdURL(),
|
|
||||||
routePath: String(crdDefinitionsRoute.path),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<TabLayout>
|
|
||||||
<Switch>
|
|
||||||
<Route component={CrdList} {...crdDefinitionsRoute} exact/>
|
|
||||||
<Route component={CrdResources} {...crdResourcesRoute}/>
|
|
||||||
<Redirect to={crdURL()}/>
|
|
||||||
</Switch>
|
|
||||||
</TabLayout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
|
import { computed, IComputedValue } from "mobx";
|
||||||
|
import type { CustomResourceDefinition } from "../../../common/k8s-api/endpoints";
|
||||||
|
import { getOrInsert } from "../../utils";
|
||||||
|
import customResourceDefinitionsInjectable from "./custom-resources.injectable";
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
definitions: IComputedValue<CustomResourceDefinition[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getGroupedCustomResourceDefinitions({ definitions }: Dependencies) {
|
||||||
|
return computed(() => {
|
||||||
|
const groups = new Map<string, CustomResourceDefinition[]>();
|
||||||
|
|
||||||
|
for (const crd of definitions.get()) {
|
||||||
|
getOrInsert(groups, crd.getGroup(), []).push(crd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const groupedCustomResourceDefinitionsInjectable = getInjectable({
|
||||||
|
instantiate: (di) => getGroupedCustomResourceDefinitions({
|
||||||
|
definitions: di.inject(customResourceDefinitionsInjectable),
|
||||||
|
}),
|
||||||
|
lifecycle: lifecycleEnum.singleton,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default groupedCustomResourceDefinitionsInjectable;
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
|
import { computed, IComputedValue } from "mobx";
|
||||||
|
import type { CustomResourceDefinition } from "../../../common/k8s-api/endpoints";
|
||||||
|
import { crdURL, crdDefinitionsRoute } from "../../../common/routes";
|
||||||
|
import type { TabLayoutRoute } from "../layout/tab-layout";
|
||||||
|
import { CrdList } from "./crd-list";
|
||||||
|
import { CrdResources } from "./crd-resources";
|
||||||
|
import groupedCustomResourceDefinitionsInjectable from "./grouped-custom-resources.injectable";
|
||||||
|
|
||||||
|
export interface CustomResourceTabLayoutRoute extends TabLayoutRoute {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CustomResourceGroupTabLayoutRoute extends CustomResourceTabLayoutRoute {
|
||||||
|
subRoutes?: CustomResourceTabLayoutRoute[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
customResourcesDefinitions: IComputedValue<Map<string, CustomResourceDefinition[]>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRouteTabs({ customResourcesDefinitions }: Dependencies) {
|
||||||
|
return computed(() => {
|
||||||
|
const tabs: CustomResourceGroupTabLayoutRoute[] = [
|
||||||
|
{
|
||||||
|
id: "definitions",
|
||||||
|
title: "Definitions",
|
||||||
|
component: CrdList,
|
||||||
|
url: crdURL(),
|
||||||
|
routePath: String(crdDefinitionsRoute.path),
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const [group, definitions] of customResourcesDefinitions.get()) {
|
||||||
|
tabs.push({
|
||||||
|
id: `crd-group:${group}`,
|
||||||
|
title: group,
|
||||||
|
routePath: crdURL({ query: { groups: group }}),
|
||||||
|
component: CrdResources,
|
||||||
|
subRoutes: definitions.map(crd => ({
|
||||||
|
id: `crd-resource:${crd.getResourceApiBase()}`,
|
||||||
|
title: crd.getResourceKind(),
|
||||||
|
routePath: crd.getResourceUrl(),
|
||||||
|
component: CrdResources,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return tabs;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const customResourcesRouteTabsInjectable = getInjectable({
|
||||||
|
instantiate: (di) => getRouteTabs({
|
||||||
|
customResourcesDefinitions: di.inject(groupedCustomResourceDefinitionsInjectable),
|
||||||
|
}),
|
||||||
|
lifecycle: lifecycleEnum.singleton,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default customResourcesRouteTabsInjectable;
|
||||||
43
src/renderer/components/+custom-resources/route.tsx
Normal file
43
src/renderer/components/+custom-resources/route.tsx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import { Redirect, Route, Switch } from "react-router";
|
||||||
|
import { TabLayout } from "../layout/tab-layout";
|
||||||
|
import { crdURL } from "../../../common/routes";
|
||||||
|
import type { IComputedValue } from "mobx";
|
||||||
|
import type { CustomResourceGroupTabLayoutRoute } from "./route-tabs.injectable";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import customResourcesRouteTabsInjectable from "./route-tabs.injectable";
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
routes: IComputedValue<CustomResourceGroupTabLayoutRoute[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedCustomResourcesRoute = observer(({ routes }: Dependencies) => (
|
||||||
|
<TabLayout>
|
||||||
|
<Switch>
|
||||||
|
{
|
||||||
|
routes.get().map(({ id, component, routePath, exact }) => (
|
||||||
|
<Route
|
||||||
|
key={id}
|
||||||
|
component={component}
|
||||||
|
path={routePath}
|
||||||
|
exact={exact}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
<Redirect to={crdURL()}/>
|
||||||
|
</Switch>
|
||||||
|
</TabLayout>
|
||||||
|
));
|
||||||
|
|
||||||
|
export const CustomResourcesRoute = withInjectables<Dependencies>(NonInjectedCustomResourcesRoute, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
routes: di.inject(customResourcesRouteTabsInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
76
src/renderer/components/+custom-resources/sidebar-item.tsx
Normal file
76
src/renderer/components/+custom-resources/sidebar-item.tsx
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import React, { useEffect } from "react";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import type { IComputedValue } from "mobx";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import customResourcesRouteTabsInjectable, { type CustomResourceGroupTabLayoutRoute } from "./route-tabs.injectable";
|
||||||
|
import type { IsAllowedResource } from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import isAllowedResourceInjectable from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import { crdURL, crdRoute } from "../../../common/routes";
|
||||||
|
import { isActiveRoute } from "../../navigation";
|
||||||
|
import { Icon } from "../icon";
|
||||||
|
import { SidebarItem } from "../layout/sidebar-item";
|
||||||
|
import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable";
|
||||||
|
import type { SubscribeStores } from "../../kube-watch-api/kube-watch-api";
|
||||||
|
import { crdStore } from "./crd.store";
|
||||||
|
import { Spinner } from "../spinner";
|
||||||
|
|
||||||
|
export interface CustomResourcesSidebarItemProps {}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
routes: IComputedValue<CustomResourceGroupTabLayoutRoute[]>;
|
||||||
|
isAllowedResource: IsAllowedResource;
|
||||||
|
subscribeStores: SubscribeStores;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedCustomResourcesSidebarItem = observer(({ routes, isAllowedResource, subscribeStores }: Dependencies & CustomResourcesSidebarItemProps) => {
|
||||||
|
useEffect(() => subscribeStores([
|
||||||
|
crdStore,
|
||||||
|
]), []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarItem
|
||||||
|
id="custom-resources"
|
||||||
|
text="Custom Resources"
|
||||||
|
url={crdURL()}
|
||||||
|
isActive={isActiveRoute(crdRoute)}
|
||||||
|
isHidden={!isAllowedResource("customresourcedefinitions")}
|
||||||
|
icon={<Icon material="extension"/>}
|
||||||
|
>
|
||||||
|
{routes.get().map((route) => (
|
||||||
|
<SidebarItem
|
||||||
|
key={route.id}
|
||||||
|
id={route.id}
|
||||||
|
text={route.title}
|
||||||
|
url={route.routePath}
|
||||||
|
>
|
||||||
|
{route.subRoutes?.map((subRoute) => (
|
||||||
|
<SidebarItem
|
||||||
|
key={subRoute.id}
|
||||||
|
id={subRoute.id}
|
||||||
|
url={subRoute.routePath}
|
||||||
|
text={subRoute.title}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</SidebarItem>
|
||||||
|
))}
|
||||||
|
{crdStore.isLoading && (
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<Spinner />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</SidebarItem>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const CustomResourcesSidebarItem = withInjectables<Dependencies, CustomResourcesSidebarItemProps>(NonInjectedCustomResourcesSidebarItem, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
routes: di.inject(customResourcesRouteTabsInjectable),
|
||||||
|
isAllowedResource: di.inject(isAllowedResourceInjectable),
|
||||||
|
subscribeStores: di.inject(subscribeStoresInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
@ -3,5 +3,4 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export * from "./events";
|
|
||||||
export * from "./event-details";
|
export * from "./event-details";
|
||||||
|
|||||||
37
src/renderer/components/+events/sidebar-item.tsx
Normal file
37
src/renderer/components/+events/sidebar-item.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import React from "react";
|
||||||
|
import { eventRoute, eventsURL } from "../../../common/routes";
|
||||||
|
import type { IsAllowedResource } from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import isAllowedResourceInjectable from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import { isActiveRoute } from "../../navigation";
|
||||||
|
import { Icon } from "../icon";
|
||||||
|
import { SidebarItem } from "../layout/sidebar-item";
|
||||||
|
|
||||||
|
export interface EventsSidebarItemProps {}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
isAllowedResource: IsAllowedResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedEventsSidebarItem = observer(({ isAllowedResource }: Dependencies & EventsSidebarItemProps) => (
|
||||||
|
<SidebarItem
|
||||||
|
id="events"
|
||||||
|
text="Events"
|
||||||
|
isActive={isActiveRoute(eventRoute)}
|
||||||
|
isHidden={!isAllowedResource("events")}
|
||||||
|
url={eventsURL()}
|
||||||
|
icon={<Icon material="access_time"/>}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
|
export const EventsSidebarItem = withInjectables<Dependencies, EventsSidebarItemProps>(NonInjectedEventsSidebarItem, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
isAllowedResource: di.inject(isAllowedResourceInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
34
src/renderer/components/+helm/route-tabs.injectable.ts
Normal file
34
src/renderer/components/+helm/route-tabs.injectable.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
|
import { computed } from "mobx";
|
||||||
|
import type { TabLayoutRoute } from "../layout/tab-layout";
|
||||||
|
import { HelmCharts } from "../+helm-charts";
|
||||||
|
import { HelmReleases } from "../+helm-releases";
|
||||||
|
import { helmChartsURL, helmChartsRoute, releaseURL, releaseRoute } from "../../../common/routes";
|
||||||
|
|
||||||
|
function getRouteTabs() {
|
||||||
|
return computed((): TabLayoutRoute[] => [
|
||||||
|
{
|
||||||
|
title: "Charts",
|
||||||
|
component: HelmCharts,
|
||||||
|
url: helmChartsURL(),
|
||||||
|
routePath: helmChartsRoute.path.toString(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Releases",
|
||||||
|
component: HelmReleases,
|
||||||
|
url: releaseURL(),
|
||||||
|
routePath: releaseRoute.path.toString(),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const helmRoutesInjectable = getInjectable({
|
||||||
|
instantiate: () => getRouteTabs(),
|
||||||
|
lifecycle: lifecycleEnum.singleton,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default helmRoutesInjectable;
|
||||||
31
src/renderer/components/+helm/route.tsx
Normal file
31
src/renderer/components/+helm/route.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import { TabLayout, TabLayoutRoute } from "../layout/tab-layout";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import type { IComputedValue } from "mobx";
|
||||||
|
import helmRoutesInjectable from "./route-tabs.injectable";
|
||||||
|
|
||||||
|
export interface HelmRouteProps {}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
routes: IComputedValue<TabLayoutRoute[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedHelmRoute = observer(({ routes }: Dependencies & HelmRouteProps) => (
|
||||||
|
<TabLayout
|
||||||
|
className="Apps"
|
||||||
|
tabs={routes.get()}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
|
export const HelmRoute = withInjectables<Dependencies, HelmRouteProps>(NonInjectedHelmRoute, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
routes: di.inject(helmRoutesInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
44
src/renderer/components/+helm/sidebar-item.tsx
Normal file
44
src/renderer/components/+helm/sidebar-item.tsx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import React from "react";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import type { IComputedValue } from "mobx";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import { isActiveRoute } from "../../navigation";
|
||||||
|
import { Icon } from "../icon";
|
||||||
|
import { SidebarItem } from "../layout/sidebar-item";
|
||||||
|
import type { TabLayoutRoute } from "../layout/tab-layout";
|
||||||
|
import { TabRoutesSidebarItems } from "../layout/tab-routes-sidebar-items";
|
||||||
|
import { helmRoute, helmURL } from "../../../common/routes";
|
||||||
|
import networkRouteTabsInjectable from "./route-tabs.injectable";
|
||||||
|
|
||||||
|
export interface HelmSidebarItemProps {}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
routes: IComputedValue<TabLayoutRoute[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedHelmSidebarItem = observer(({ routes }: Dependencies & HelmSidebarItemProps) => {
|
||||||
|
const tabRoutes = routes.get();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarItem
|
||||||
|
id="helm"
|
||||||
|
text="Helm"
|
||||||
|
isActive={isActiveRoute(helmRoute)}
|
||||||
|
url={helmURL()}
|
||||||
|
icon={<Icon material="apps"/>}
|
||||||
|
>
|
||||||
|
<TabRoutesSidebarItems routes={tabRoutes} />
|
||||||
|
</SidebarItem>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const HelmSidebarItem = withInjectables<Dependencies, HelmSidebarItemProps>(NonInjectedHelmSidebarItem, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
routes: di.inject(networkRouteTabsInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
@ -3,6 +3,5 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export * from "./namespaces";
|
|
||||||
export * from "./namespace-details";
|
export * from "./namespace-details";
|
||||||
export * from "./add-namespace-dialog";
|
export * from "./add-namespace-dialog";
|
||||||
|
|||||||
@ -1,96 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import "./namespaces.scss";
|
|
||||||
|
|
||||||
import React from "react";
|
|
||||||
import { NamespaceStatus } from "../../../common/k8s-api/endpoints";
|
|
||||||
import { AddNamespaceDialog } from "./add-namespace-dialog";
|
|
||||||
import { TabLayout } from "../layout/tab-layout";
|
|
||||||
import { Badge } from "../badge";
|
|
||||||
import type { RouteComponentProps } from "react-router";
|
|
||||||
import { KubeObjectListLayout } from "../kube-object-list-layout";
|
|
||||||
import type { NamespaceStore } from "./namespace-store/namespace.store";
|
|
||||||
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
|
||||||
import type { NamespacesRouteParams } from "../../../common/routes";
|
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
|
||||||
import namespaceStoreInjectable from "./namespace-store/namespace-store.injectable";
|
|
||||||
import addNamespaceDialogModelInjectable
|
|
||||||
from "./add-namespace-dialog-model/add-namespace-dialog-model.injectable";
|
|
||||||
|
|
||||||
enum columnId {
|
|
||||||
name = "name",
|
|
||||||
labels = "labels",
|
|
||||||
age = "age",
|
|
||||||
status = "status",
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props extends RouteComponentProps<NamespacesRouteParams> {
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Dependencies {
|
|
||||||
namespaceStore: NamespaceStore
|
|
||||||
openAddNamespaceDialog: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
class NonInjectedNamespaces extends React.Component<Props & Dependencies> {
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<TabLayout>
|
|
||||||
<KubeObjectListLayout
|
|
||||||
isConfigurable
|
|
||||||
tableId="namespaces"
|
|
||||||
className="Namespaces"
|
|
||||||
store={this.props.namespaceStore}
|
|
||||||
sortingCallbacks={{
|
|
||||||
[columnId.name]: ns => ns.getName(),
|
|
||||||
[columnId.labels]: ns => ns.getLabels(),
|
|
||||||
[columnId.age]: ns => ns.getTimeDiffFromNow(),
|
|
||||||
[columnId.status]: ns => ns.getStatus(),
|
|
||||||
}}
|
|
||||||
searchFilters={[
|
|
||||||
item => item.getSearchFields(),
|
|
||||||
item => item.getStatus(),
|
|
||||||
]}
|
|
||||||
renderHeaderTitle="Namespaces"
|
|
||||||
renderTableHeader={[
|
|
||||||
{ title: "Name", className: "name", sortBy: columnId.name, id: columnId.name },
|
|
||||||
{ className: "warning", showWithColumn: columnId.name },
|
|
||||||
{ title: "Labels", className: "labels scrollable", sortBy: columnId.labels, id: columnId.labels },
|
|
||||||
{ title: "Age", className: "age", sortBy: columnId.age, id: columnId.age },
|
|
||||||
{ title: "Status", className: "status", sortBy: columnId.status, id: columnId.status },
|
|
||||||
]}
|
|
||||||
renderTableContents={item => [
|
|
||||||
item.getName(),
|
|
||||||
<KubeObjectStatusIcon key="icon" object={item} />,
|
|
||||||
item.getLabels().map(label => <Badge scrollable key={label} label={label}/>),
|
|
||||||
item.getAge(),
|
|
||||||
{ title: item.getStatus(), className: item.getStatus().toLowerCase() },
|
|
||||||
]}
|
|
||||||
addRemoveButtons={{
|
|
||||||
addTooltip: "Add Namespace",
|
|
||||||
onAdd: () => this.props.openAddNamespaceDialog(),
|
|
||||||
}}
|
|
||||||
customizeTableRowProps={item => ({
|
|
||||||
disabled: item.getStatus() === NamespaceStatus.TERMINATING,
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<AddNamespaceDialog/>
|
|
||||||
</TabLayout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Namespaces = withInjectables<Dependencies, Props>(
|
|
||||||
NonInjectedNamespaces,
|
|
||||||
|
|
||||||
{
|
|
||||||
getProps: (di, props) => ({
|
|
||||||
namespaceStore: di.inject(namespaceStoreInjectable),
|
|
||||||
openAddNamespaceDialog: di.inject(addNamespaceDialogModelInjectable).open,
|
|
||||||
...props,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
89
src/renderer/components/+namespaces/route.tsx
Normal file
89
src/renderer/components/+namespaces/route.tsx
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "./namespaces.scss";
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { NamespaceStatus } from "../../../common/k8s-api/endpoints";
|
||||||
|
import { AddNamespaceDialog } from "./add-namespace-dialog";
|
||||||
|
import { TabLayout } from "../layout/tab-layout";
|
||||||
|
import { Badge } from "../badge";
|
||||||
|
import type { RouteComponentProps } from "react-router";
|
||||||
|
import { KubeObjectListLayout } from "../kube-object-list-layout";
|
||||||
|
import type { NamespaceStore } from "./namespace-store/namespace.store";
|
||||||
|
import { KubeObjectStatusIcon } from "../kube-object-status-icon";
|
||||||
|
import type { NamespacesRouteParams } from "../../../common/routes";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import namespaceStoreInjectable from "./namespace-store/namespace-store.injectable";
|
||||||
|
import addNamespaceDialogModelInjectable
|
||||||
|
from "./add-namespace-dialog-model/add-namespace-dialog-model.injectable";
|
||||||
|
|
||||||
|
enum columnId {
|
||||||
|
name = "name",
|
||||||
|
labels = "labels",
|
||||||
|
age = "age",
|
||||||
|
status = "status",
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NamespacesRouteProps extends RouteComponentProps<NamespacesRouteParams> {
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
namespaceStore: NamespaceStore
|
||||||
|
openAddNamespaceDialog: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const NonInjectedNamespacesRoute = ({ namespaceStore, openAddNamespaceDialog }: Dependencies & NamespacesRouteProps) => (
|
||||||
|
<TabLayout>
|
||||||
|
<KubeObjectListLayout
|
||||||
|
isConfigurable
|
||||||
|
tableId="namespaces"
|
||||||
|
className="Namespaces"
|
||||||
|
store={namespaceStore}
|
||||||
|
sortingCallbacks={{
|
||||||
|
[columnId.name]: ns => ns.getName(),
|
||||||
|
[columnId.labels]: ns => ns.getLabels(),
|
||||||
|
[columnId.age]: ns => ns.getTimeDiffFromNow(),
|
||||||
|
[columnId.status]: ns => ns.getStatus(),
|
||||||
|
}}
|
||||||
|
searchFilters={[
|
||||||
|
item => item.getSearchFields(),
|
||||||
|
item => item.getStatus(),
|
||||||
|
]}
|
||||||
|
renderHeaderTitle="Namespaces"
|
||||||
|
renderTableHeader={[
|
||||||
|
{ title: "Name", className: "name", sortBy: columnId.name, id: columnId.name },
|
||||||
|
{ className: "warning", showWithColumn: columnId.name },
|
||||||
|
{ title: "Labels", className: "labels scrollable", sortBy: columnId.labels, id: columnId.labels },
|
||||||
|
{ title: "Age", className: "age", sortBy: columnId.age, id: columnId.age },
|
||||||
|
{ title: "Status", className: "status", sortBy: columnId.status, id: columnId.status },
|
||||||
|
]}
|
||||||
|
renderTableContents={item => [
|
||||||
|
item.getName(),
|
||||||
|
<KubeObjectStatusIcon key="icon" object={item} />,
|
||||||
|
item.getLabels().map(label => <Badge scrollable key={label} label={label}/>),
|
||||||
|
item.getAge(),
|
||||||
|
{ title: item.getStatus(), className: item.getStatus().toLowerCase() },
|
||||||
|
]}
|
||||||
|
addRemoveButtons={{
|
||||||
|
addTooltip: "Add Namespace",
|
||||||
|
onAdd: openAddNamespaceDialog,
|
||||||
|
}}
|
||||||
|
customizeTableRowProps={item => ({
|
||||||
|
disabled: item.getStatus() === NamespaceStatus.TERMINATING,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<AddNamespaceDialog/>
|
||||||
|
</TabLayout>
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
export const NamespacesRoute = withInjectables<Dependencies, NamespacesRouteProps>(NonInjectedNamespacesRoute, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
namespaceStore: di.inject(namespaceStoreInjectable),
|
||||||
|
openAddNamespaceDialog: di.inject(addNamespaceDialogModelInjectable).open,
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
37
src/renderer/components/+namespaces/sidebar-item.tsx
Normal file
37
src/renderer/components/+namespaces/sidebar-item.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import React from "react";
|
||||||
|
import { namespacesRoute, namespacesURL } from "../../../common/routes";
|
||||||
|
import type { IsAllowedResource } from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import isAllowedResourceInjectable from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import { isActiveRoute } from "../../navigation";
|
||||||
|
import { Icon } from "../icon";
|
||||||
|
import { SidebarItem } from "../layout/sidebar-item";
|
||||||
|
|
||||||
|
export interface NamespacesSidebarItemProps {}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
isAllowedResource: IsAllowedResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedNamespacesSidebarItem = observer(({ isAllowedResource }: Dependencies & NamespacesSidebarItemProps) => (
|
||||||
|
<SidebarItem
|
||||||
|
id="namespaces"
|
||||||
|
text="Namespaces"
|
||||||
|
isActive={isActiveRoute(namespacesRoute)}
|
||||||
|
isHidden={!isAllowedResource("namespaces")}
|
||||||
|
url={namespacesURL()}
|
||||||
|
icon={<Icon material="layers"/>}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
|
export const NamespacesSidebarItem = withInjectables<Dependencies, NamespacesSidebarItemProps>(NonInjectedNamespacesSidebarItem, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
isAllowedResource: di.inject(isAllowedResourceInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
@ -1,6 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export * from "./network";
|
|
||||||
@ -2,23 +2,24 @@
|
|||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
import "./network.scss";
|
import { computed } from "mobx";
|
||||||
|
import type { TabLayoutRoute } from "../layout/tab-layout";
|
||||||
import React from "react";
|
|
||||||
import { observer } from "mobx-react";
|
|
||||||
import { TabLayout, TabLayoutRoute } from "../layout/tab-layout";
|
|
||||||
import { Services } from "../+network-services";
|
import { Services } from "../+network-services";
|
||||||
import { Endpoints } from "../+network-endpoints";
|
import { Endpoints } from "../+network-endpoints";
|
||||||
import { Ingresses } from "../+network-ingresses";
|
import { Ingresses } from "../+network-ingresses";
|
||||||
import { NetworkPolicies } from "../+network-policies";
|
import { NetworkPolicies } from "../+network-policies";
|
||||||
import { PortForwards } from "../+network-port-forwards";
|
import { PortForwards } from "../+network-port-forwards";
|
||||||
import { isAllowedResource } from "../../../common/utils/allowed-resource";
|
|
||||||
import * as routes from "../../../common/routes";
|
import * as routes from "../../../common/routes";
|
||||||
|
import type { IsAllowedResource } from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import isAllowedResourceInjectable from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
|
||||||
@observer
|
interface Dependencies {
|
||||||
export class Network extends React.Component {
|
isAllowedResource: IsAllowedResource;
|
||||||
static get tabRoutes(): TabLayoutRoute[] {
|
}
|
||||||
|
|
||||||
|
function getRouteTabs({ isAllowedResource }: Dependencies) {
|
||||||
|
return computed(() => {
|
||||||
const tabs: TabLayoutRoute[] = [];
|
const tabs: TabLayoutRoute[] = [];
|
||||||
|
|
||||||
if (isAllowedResource("services")) {
|
if (isAllowedResource("services")) {
|
||||||
@ -65,11 +66,14 @@ export class Network extends React.Component {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return tabs;
|
return tabs;
|
||||||
}
|
});
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<TabLayout className="Network" tabs={Network.tabRoutes}/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const networkRouteTabsInjectable = getInjectable({
|
||||||
|
instantiate: (di) => getRouteTabs({
|
||||||
|
isAllowedResource: di.inject(isAllowedResourceInjectable),
|
||||||
|
}),
|
||||||
|
lifecycle: lifecycleEnum.singleton,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default networkRouteTabsInjectable;
|
||||||
33
src/renderer/components/+network/route.tsx
Normal file
33
src/renderer/components/+network/route.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "./network.scss";
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import { TabLayout, TabLayoutRoute } from "../layout/tab-layout";
|
||||||
|
import type { IComputedValue } from "mobx";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import networkRouteTabsInjectable from "./route-tabs.injectable";
|
||||||
|
|
||||||
|
export interface NetworksRouteProps {}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
routes: IComputedValue<TabLayoutRoute[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedNetworksRoute = observer(({ routes }: Dependencies & NetworksRouteProps) => (
|
||||||
|
<TabLayout
|
||||||
|
className="Network"
|
||||||
|
tabs={routes.get()}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
|
export const NetworkRoute = withInjectables<Dependencies, NetworksRouteProps>(NonInjectedNetworksRoute, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
routes: di.inject(networkRouteTabsInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
45
src/renderer/components/+network/sidebar-item.tsx
Normal file
45
src/renderer/components/+network/sidebar-item.tsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import React from "react";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import type { IComputedValue } from "mobx";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import { isActiveRoute } from "../../navigation";
|
||||||
|
import { Icon } from "../icon";
|
||||||
|
import { SidebarItem } from "../layout/sidebar-item";
|
||||||
|
import type { TabLayoutRoute } from "../layout/tab-layout";
|
||||||
|
import { TabRoutesSidebarItems } from "../layout/tab-routes-sidebar-items";
|
||||||
|
import { networkRoute, networkURL } from "../../../common/routes";
|
||||||
|
import networkRouteTabsInjectable from "./route-tabs.injectable";
|
||||||
|
|
||||||
|
export interface NetworkSidebarItemProps {}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
routes: IComputedValue<TabLayoutRoute[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedNetworkSidebarItem = observer(({ routes }: Dependencies & NetworkSidebarItemProps) => {
|
||||||
|
const tabRoutes = routes.get();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarItem
|
||||||
|
id="networks"
|
||||||
|
text="Network"
|
||||||
|
isActive={isActiveRoute(networkRoute)}
|
||||||
|
isHidden={tabRoutes.length == 0}
|
||||||
|
url={networkURL()}
|
||||||
|
icon={<Icon material="device_hub"/>}
|
||||||
|
>
|
||||||
|
<TabRoutesSidebarItems routes={tabRoutes} />
|
||||||
|
</SidebarItem>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const NetworkSidebarItem = withInjectables<Dependencies, NetworkSidebarItemProps>(NonInjectedNetworkSidebarItem, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
routes: di.inject(networkRouteTabsInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
@ -3,7 +3,7 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "./node-details-resources.scss";
|
import "./details-resources.scss";
|
||||||
|
|
||||||
import { Table } from "../table/table";
|
import { Table } from "../table/table";
|
||||||
import { TableHead } from "../table/table-head";
|
import { TableHead } from "../table/table-head";
|
||||||
@ -3,7 +3,7 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "./node-details.scss";
|
import "./details.scss";
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import upperFirst from "lodash/upperFirst";
|
import upperFirst from "lodash/upperFirst";
|
||||||
@ -21,7 +21,7 @@ import { PodDetailsList } from "../+workloads-pods/pod-details-list";
|
|||||||
import { KubeObjectMeta } from "../kube-object-meta";
|
import { KubeObjectMeta } from "../kube-object-meta";
|
||||||
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
import { getActiveClusterEntity } from "../../api/catalog-entity-registry";
|
||||||
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
import { ClusterMetricsResourceType } from "../../../common/cluster-types";
|
||||||
import { NodeDetailsResources } from "./node-details-resources";
|
import { NodeDetailsResources } from "./details-resources";
|
||||||
import { DrawerTitle } from "../drawer/drawer-title";
|
import { DrawerTitle } from "../drawer/drawer-title";
|
||||||
import { boundMethod, Disposer } from "../../utils";
|
import { boundMethod, Disposer } from "../../utils";
|
||||||
import logger from "../../../common/logger";
|
import logger from "../../../common/logger";
|
||||||
@ -1,7 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export * from "./nodes";
|
|
||||||
export * from "./node-details";
|
|
||||||
@ -50,7 +50,7 @@ interface UsageArgs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class Nodes extends React.Component<Props> {
|
export class NodesRoute extends React.Component<Props> {
|
||||||
@observable.ref metrics: Partial<INodeMetrics> = {};
|
@observable.ref metrics: Partial<INodeMetrics> = {};
|
||||||
private metricsWatcher = interval(30, async () => this.metrics = await getMetricsForAllNodes());
|
private metricsWatcher = interval(30, async () => this.metrics = await getMetricsForAllNodes());
|
||||||
|
|
||||||
37
src/renderer/components/+nodes/sidebar-item.tsx
Normal file
37
src/renderer/components/+nodes/sidebar-item.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import React from "react";
|
||||||
|
import { nodesRoute, nodesURL } from "../../../common/routes";
|
||||||
|
import type { IsAllowedResource } from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import isAllowedResourceInjectable from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import { isActiveRoute } from "../../navigation";
|
||||||
|
import { Icon } from "../icon";
|
||||||
|
import { SidebarItem } from "../layout/sidebar-item";
|
||||||
|
|
||||||
|
export interface NodeSidebarItemProps {}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
isAllowedResource: IsAllowedResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedNodeSidebarItem = observer(({ isAllowedResource }: Dependencies & NodeSidebarItemProps) => (
|
||||||
|
<SidebarItem
|
||||||
|
id="nodes"
|
||||||
|
text="Nodes"
|
||||||
|
isActive={isActiveRoute(nodesRoute)}
|
||||||
|
isHidden={!isAllowedResource("nodes")}
|
||||||
|
url={nodesURL()}
|
||||||
|
icon={<Icon svg="nodes"/>}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
|
export const NodesSidebarItem = withInjectables<Dependencies, NodeSidebarItemProps>(NonInjectedNodeSidebarItem, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
isAllowedResource: di.inject(isAllowedResourceInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
@ -1,6 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export * from "./storage";
|
|
||||||
@ -2,21 +2,22 @@
|
|||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
import "./storage.scss";
|
import { computed } from "mobx";
|
||||||
|
import type { TabLayoutRoute } from "../layout/tab-layout";
|
||||||
import React from "react";
|
|
||||||
import { observer } from "mobx-react";
|
|
||||||
import { TabLayout, TabLayoutRoute } from "../layout/tab-layout";
|
|
||||||
import { PersistentVolumes } from "../+storage-volumes";
|
import { PersistentVolumes } from "../+storage-volumes";
|
||||||
import { StorageClasses } from "../+storage-classes";
|
import { StorageClasses } from "../+storage-classes";
|
||||||
import { PersistentVolumeClaims } from "../+storage-volume-claims";
|
import { PersistentVolumeClaims } from "../+storage-volume-claims";
|
||||||
import { isAllowedResource } from "../../../common/utils/allowed-resource";
|
import type { IsAllowedResource } from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import isAllowedResourceInjectable from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
import * as routes from "../../../common/routes";
|
import * as routes from "../../../common/routes";
|
||||||
|
|
||||||
@observer
|
interface Dependencies {
|
||||||
export class Storage extends React.Component {
|
isAllowedResource: IsAllowedResource;
|
||||||
static get tabRoutes() {
|
}
|
||||||
|
|
||||||
|
function getRouteTabs({ isAllowedResource }: Dependencies) {
|
||||||
|
return computed(() => {
|
||||||
const tabs: TabLayoutRoute[] = [];
|
const tabs: TabLayoutRoute[] = [];
|
||||||
|
|
||||||
if (isAllowedResource("persistentvolumeclaims")) {
|
if (isAllowedResource("persistentvolumeclaims")) {
|
||||||
@ -47,11 +48,14 @@ export class Storage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return tabs;
|
return tabs;
|
||||||
}
|
});
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<TabLayout className="Storage" tabs={Storage.tabRoutes}/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const storageRouteTabsInjectable = getInjectable({
|
||||||
|
instantiate: (di) => getRouteTabs({
|
||||||
|
isAllowedResource: di.inject(isAllowedResourceInjectable),
|
||||||
|
}),
|
||||||
|
lifecycle: lifecycleEnum.singleton,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default storageRouteTabsInjectable;
|
||||||
34
src/renderer/components/+storage/route.tsx
Normal file
34
src/renderer/components/+storage/route.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "./storage.scss";
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import { TabLayout, TabLayoutRoute } from "../layout/tab-layout";
|
||||||
|
import type { IComputedValue } from "mobx";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import storageRouteTabsInjectable from "./route-tabs.injectable";
|
||||||
|
|
||||||
|
export interface StorageRouteProps {}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
routes: IComputedValue<TabLayoutRoute[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedStorageRoute = observer(({ routes }: Dependencies & StorageRouteProps) => (
|
||||||
|
<TabLayout
|
||||||
|
className="Storage"
|
||||||
|
tabs={routes.get()}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
|
export const StorageRoute = withInjectables<Dependencies, StorageRouteProps>(NonInjectedStorageRoute, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
routes: di.inject(storageRouteTabsInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
45
src/renderer/components/+storage/sidebar-item.tsx
Normal file
45
src/renderer/components/+storage/sidebar-item.tsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import type { IComputedValue } from "mobx";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import React from "react";
|
||||||
|
import { storageRoute, storageURL } from "../../../common/routes";
|
||||||
|
import { isActiveRoute } from "../../navigation";
|
||||||
|
import { Icon } from "../icon";
|
||||||
|
import { SidebarItem } from "../layout/sidebar-item";
|
||||||
|
import type { TabLayoutRoute } from "../layout/tab-layout";
|
||||||
|
import { TabRoutesSidebarItems } from "../layout/tab-routes-sidebar-items";
|
||||||
|
import storageRouteTabsInjectable from "./route-tabs.injectable";
|
||||||
|
|
||||||
|
export interface StorageSidebarItemProps {}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
routes: IComputedValue<TabLayoutRoute[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedStorageSidebarItem = observer(({ routes }: Dependencies & StorageSidebarItemProps) => {
|
||||||
|
const tabRoutes = routes.get();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarItem
|
||||||
|
id="storage"
|
||||||
|
text="Storage"
|
||||||
|
isActive={isActiveRoute(storageRoute)}
|
||||||
|
isHidden={tabRoutes.length == 0}
|
||||||
|
url={storageURL()}
|
||||||
|
icon={<Icon svg="storage"/>}
|
||||||
|
>
|
||||||
|
<TabRoutesSidebarItems routes={tabRoutes} />
|
||||||
|
</SidebarItem>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const StorageSidebarItem = withInjectables<Dependencies, StorageSidebarItemProps>(NonInjectedStorageSidebarItem, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
routes: di.inject(storageRouteTabsInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
@ -1,6 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export * from "./user-management";
|
|
||||||
@ -2,28 +2,29 @@
|
|||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
import "./user-management.scss";
|
import { computed } from "mobx";
|
||||||
|
import type { TabLayoutRoute } from "../layout/tab-layout";
|
||||||
import React from "react";
|
import type { IsAllowedResource } from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
import { observer } from "mobx-react";
|
import isAllowedResourceInjectable from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
import { TabLayout, TabLayoutRoute } from "../layout/tab-layout";
|
|
||||||
import { PodSecurityPolicies } from "../+pod-security-policies";
|
|
||||||
import { isAllowedResource } from "../../../common/utils/allowed-resource";
|
|
||||||
import * as routes from "../../../common/routes";
|
import * as routes from "../../../common/routes";
|
||||||
|
import { PodSecurityPolicies } from "../+pod-security-policies";
|
||||||
import { ClusterRoleBindings } from "./+cluster-role-bindings";
|
import { ClusterRoleBindings } from "./+cluster-role-bindings";
|
||||||
import { ServiceAccounts } from "./+service-accounts";
|
|
||||||
import { Roles } from "./+roles";
|
|
||||||
import { RoleBindings } from "./+role-bindings";
|
|
||||||
import { ClusterRoles } from "./+cluster-roles";
|
import { ClusterRoles } from "./+cluster-roles";
|
||||||
|
import { RoleBindings } from "./+role-bindings";
|
||||||
|
import { Roles } from "./+roles";
|
||||||
|
import { ServiceAccounts } from "./+service-accounts";
|
||||||
|
|
||||||
@observer
|
interface Dependencies {
|
||||||
export class UserManagement extends React.Component {
|
isAllowedResource: IsAllowedResource;
|
||||||
static get tabRoutes() {
|
}
|
||||||
const tabRoutes: TabLayoutRoute[] = [];
|
|
||||||
|
function getRouteTabs({ isAllowedResource }: Dependencies) {
|
||||||
|
return computed(() => {
|
||||||
|
const tabs: TabLayoutRoute[] = [];
|
||||||
|
|
||||||
if (isAllowedResource("serviceaccounts")) {
|
if (isAllowedResource("serviceaccounts")) {
|
||||||
tabRoutes.push({
|
tabs.push({
|
||||||
title: "Service Accounts",
|
title: "Service Accounts",
|
||||||
component: ServiceAccounts,
|
component: ServiceAccounts,
|
||||||
url: routes.serviceAccountsURL(),
|
url: routes.serviceAccountsURL(),
|
||||||
@ -32,7 +33,7 @@ export class UserManagement extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isAllowedResource("clusterroles")) {
|
if (isAllowedResource("clusterroles")) {
|
||||||
tabRoutes.push({
|
tabs.push({
|
||||||
title: "Cluster Roles",
|
title: "Cluster Roles",
|
||||||
component: ClusterRoles,
|
component: ClusterRoles,
|
||||||
url: routes.clusterRolesURL(),
|
url: routes.clusterRolesURL(),
|
||||||
@ -41,7 +42,7 @@ export class UserManagement extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isAllowedResource("roles")) {
|
if (isAllowedResource("roles")) {
|
||||||
tabRoutes.push({
|
tabs.push({
|
||||||
title: "Roles",
|
title: "Roles",
|
||||||
component: Roles,
|
component: Roles,
|
||||||
url: routes.rolesURL(),
|
url: routes.rolesURL(),
|
||||||
@ -50,7 +51,7 @@ export class UserManagement extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isAllowedResource("clusterrolebindings")) {
|
if (isAllowedResource("clusterrolebindings")) {
|
||||||
tabRoutes.push({
|
tabs.push({
|
||||||
title: "Cluster Role Bindings",
|
title: "Cluster Role Bindings",
|
||||||
component: ClusterRoleBindings,
|
component: ClusterRoleBindings,
|
||||||
url: routes.clusterRoleBindingsURL(),
|
url: routes.clusterRoleBindingsURL(),
|
||||||
@ -59,7 +60,7 @@ export class UserManagement extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isAllowedResource("rolebindings")) {
|
if (isAllowedResource("rolebindings")) {
|
||||||
tabRoutes.push({
|
tabs.push({
|
||||||
title: "Role Bindings",
|
title: "Role Bindings",
|
||||||
component: RoleBindings,
|
component: RoleBindings,
|
||||||
url: routes.roleBindingsURL(),
|
url: routes.roleBindingsURL(),
|
||||||
@ -68,7 +69,7 @@ export class UserManagement extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isAllowedResource("podsecuritypolicies")) {
|
if (isAllowedResource("podsecuritypolicies")) {
|
||||||
tabRoutes.push({
|
tabs.push({
|
||||||
title: "Pod Security Policies",
|
title: "Pod Security Policies",
|
||||||
component: PodSecurityPolicies,
|
component: PodSecurityPolicies,
|
||||||
url: routes.podSecurityPoliciesURL(),
|
url: routes.podSecurityPoliciesURL(),
|
||||||
@ -76,12 +77,15 @@ export class UserManagement extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return tabRoutes;
|
return tabs;
|
||||||
}
|
});
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<TabLayout className="UserManagement" tabs={UserManagement.tabRoutes}/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const userManagementRouteTabsInjectable = getInjectable({
|
||||||
|
instantiate: (di) => getRouteTabs({
|
||||||
|
isAllowedResource: di.inject(isAllowedResourceInjectable),
|
||||||
|
}),
|
||||||
|
lifecycle: lifecycleEnum.singleton,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default userManagementRouteTabsInjectable;
|
||||||
31
src/renderer/components/+user-management/route.tsx
Normal file
31
src/renderer/components/+user-management/route.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "./user-management.scss";
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import { TabLayout, TabLayoutRoute } from "../layout/tab-layout";
|
||||||
|
import type { IComputedValue } from "mobx";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import userManagementRouteTabsInjectable from "./route-tabs.injectable";
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
routes: IComputedValue<TabLayoutRoute[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedUserManagementRoute = observer(({ routes }: Dependencies) => (
|
||||||
|
<TabLayout
|
||||||
|
className="UserManagement"
|
||||||
|
tabs={routes.get()}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
|
export const UserManagementRoute = withInjectables<Dependencies>(NonInjectedUserManagementRoute, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
routes: di.inject(userManagementRouteTabsInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
45
src/renderer/components/+user-management/sidebar-item.tsx
Normal file
45
src/renderer/components/+user-management/sidebar-item.tsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import type { IComputedValue } from "mobx";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import React from "react";
|
||||||
|
import { usersManagementRoute, usersManagementURL } from "../../../common/routes";
|
||||||
|
import { isActiveRoute } from "../../navigation";
|
||||||
|
import { Icon } from "../icon";
|
||||||
|
import { SidebarItem } from "../layout/sidebar-item";
|
||||||
|
import type { TabLayoutRoute } from "../layout/tab-layout";
|
||||||
|
import { TabRoutesSidebarItems } from "../layout/tab-routes-sidebar-items";
|
||||||
|
import userManagementRouteTabsInjectable from "./route-tabs.injectable";
|
||||||
|
|
||||||
|
export interface UserManagementSidebarItemProps {}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
routes: IComputedValue<TabLayoutRoute[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedUserManagementSidebarItem = observer(({ routes }: Dependencies & UserManagementSidebarItemProps) => {
|
||||||
|
const tabRoutes = routes.get();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarItem
|
||||||
|
id="users"
|
||||||
|
text="Access Control"
|
||||||
|
isActive={isActiveRoute(usersManagementRoute)}
|
||||||
|
isHidden={tabRoutes.length === 0}
|
||||||
|
url={usersManagementURL()}
|
||||||
|
icon={<Icon material="security"/>}
|
||||||
|
>
|
||||||
|
<TabRoutesSidebarItems routes={tabRoutes} />
|
||||||
|
</SidebarItem>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const UserManagementSidebarItem = withInjectables<Dependencies, UserManagementSidebarItemProps>(NonInjectedUserManagementSidebarItem, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
routes: di.inject(userManagementRouteTabsInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
@ -9,73 +9,49 @@ import React from "react";
|
|||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { OverviewWorkloadStatus } from "./overview-workload-status";
|
import { OverviewWorkloadStatus } from "./overview-workload-status";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { workloadStores } from "../+workloads";
|
|
||||||
import type { NamespaceStore } from "../+namespaces/namespace-store/namespace.store";
|
|
||||||
import type { KubeResource } from "../../../common/rbac";
|
import type { KubeResource } from "../../../common/rbac";
|
||||||
import { ResourceNames } from "../../utils/rbac";
|
|
||||||
import { boundMethod } from "../../utils";
|
|
||||||
import { workloadURL } from "../../../common/routes";
|
|
||||||
import { isAllowedResource } from "../../../common/utils/allowed-resource";
|
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import namespaceStoreInjectable from "../+namespaces/namespace-store/namespace-store.injectable";
|
import type { IComputedValue } from "mobx";
|
||||||
|
import workloadsInjectable from "./workloads.injectable";
|
||||||
|
|
||||||
const resources: KubeResource[] = [
|
export interface OverviewStatusesProps {}
|
||||||
"pods",
|
|
||||||
"deployments",
|
interface Workload {
|
||||||
"statefulsets",
|
resource: KubeResource;
|
||||||
"daemonsets",
|
amountOfItems: number;
|
||||||
"replicasets",
|
href: string;
|
||||||
"jobs",
|
status: Record<string, number>;
|
||||||
"cronjobs",
|
title: string
|
||||||
];
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
namespaceStore: NamespaceStore
|
workloads: IComputedValue<Workload[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
const NonInjectedOverviewStatuses = observer(
|
||||||
class NonInjectedOverviewStatuses extends React.Component<Dependencies> {
|
({ workloads }: Dependencies & OverviewStatusesProps) => (
|
||||||
@boundMethod
|
<div className="OverviewStatuses">
|
||||||
renderWorkload(resource: KubeResource): React.ReactElement {
|
<div className="workloads">
|
||||||
const store = workloadStores.get(resource);
|
{workloads.get()
|
||||||
|
.map(({ resource, title, href, status, amountOfItems }) => (
|
||||||
|
<div className="workload" key={resource}>
|
||||||
|
<div className="title">
|
||||||
|
<Link to={href}>
|
||||||
|
{title} ({amountOfItems})
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
if (!store) {
|
<OverviewWorkloadStatus status={status} />
|
||||||
return null;
|
</div>
|
||||||
}
|
))}
|
||||||
|
|
||||||
const items = store.getAllByNs(this.props.namespaceStore.contextNamespaces);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="workload" key={resource}>
|
|
||||||
<div className="title">
|
|
||||||
<Link to={workloadURL[resource]()}>{ResourceNames[resource]} ({items.length})</Link>
|
|
||||||
</div>
|
|
||||||
<OverviewWorkloadStatus status={store.getStatuses(items)} />
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
}
|
),
|
||||||
|
|
||||||
render() {
|
|
||||||
const workloads = resources
|
|
||||||
.filter(isAllowedResource)
|
|
||||||
.map(this.renderWorkload);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="OverviewStatuses">
|
|
||||||
<div className="workloads">
|
|
||||||
{workloads}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const OverviewStatuses = withInjectables<Dependencies>(
|
|
||||||
NonInjectedOverviewStatuses,
|
|
||||||
|
|
||||||
{
|
|
||||||
getProps: (di) => ({
|
|
||||||
namespaceStore: di.inject(namespaceStoreInjectable),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const OverviewStatuses = withInjectables<Dependencies, OverviewStatusesProps>(NonInjectedOverviewStatuses, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
workloads: di.inject(workloadsInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|||||||
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
|
import type { KubeResource } from "../../../common/rbac";
|
||||||
|
import type { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
|
||||||
|
import type { KubeObject } from "../../../common/k8s-api/kube-object";
|
||||||
|
import { podsStore } from "../+workloads-pods/pods.store";
|
||||||
|
import { deploymentStore } from "../+workloads-deployments/deployments.store";
|
||||||
|
import { daemonSetStore } from "../+workloads-daemonsets/daemonsets.store";
|
||||||
|
import { statefulSetStore } from "../+workloads-statefulsets/statefulset.store";
|
||||||
|
import { replicaSetStore } from "../+workloads-replicasets/replicasets.store";
|
||||||
|
import { jobStore } from "../+workloads-jobs/job.store";
|
||||||
|
import { cronJobStore } from "../+workloads-cronjobs/cronjob.store";
|
||||||
|
import isAllowedResourceInjectable from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import namespaceStoreInjectable from "../+namespaces/namespace-store/namespace-store.injectable";
|
||||||
|
import { workloads } from "./workloads";
|
||||||
|
|
||||||
|
const workloadsInjectable = getInjectable({
|
||||||
|
instantiate: (di) =>
|
||||||
|
workloads({
|
||||||
|
isAllowedResource: di.inject(isAllowedResourceInjectable),
|
||||||
|
namespaceStore: di.inject(namespaceStoreInjectable),
|
||||||
|
|
||||||
|
workloadStores: new Map<KubeResource, KubeObjectStore<KubeObject>>([
|
||||||
|
["pods", podsStore],
|
||||||
|
["deployments", deploymentStore],
|
||||||
|
["daemonsets", daemonSetStore],
|
||||||
|
["statefulsets", statefulSetStore],
|
||||||
|
["replicasets", replicaSetStore],
|
||||||
|
["jobs", jobStore],
|
||||||
|
["cronjobs", cronJobStore],
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
|
||||||
|
lifecycle: lifecycleEnum.singleton,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default workloadsInjectable;
|
||||||
39
src/renderer/components/+workloads-overview/workloads.ts
Normal file
39
src/renderer/components/+workloads-overview/workloads.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { computed } from "mobx";
|
||||||
|
import type { KubeResource } from "../../../common/rbac";
|
||||||
|
import type { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
|
||||||
|
import type { KubeObject } from "../../../common/k8s-api/kube-object";
|
||||||
|
import { workloadURL } from "../../../common/routes";
|
||||||
|
import { ResourceNames } from "../../utils/rbac";
|
||||||
|
import type { NamespaceStore } from "../+namespaces/namespace-store/namespace.store";
|
||||||
|
import type { IsAllowedResource } from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
workloadStores: Map<KubeResource, KubeObjectStore<KubeObject>>;
|
||||||
|
isAllowedResource: IsAllowedResource;
|
||||||
|
namespaceStore: NamespaceStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const workloads = ({
|
||||||
|
workloadStores,
|
||||||
|
isAllowedResource,
|
||||||
|
namespaceStore,
|
||||||
|
}: Dependencies) =>
|
||||||
|
computed(() =>
|
||||||
|
[...workloadStores.entries()]
|
||||||
|
.filter(([resource]) => isAllowedResource(resource))
|
||||||
|
.map(([resource, store]) => {
|
||||||
|
const items = store.getAllByNs(namespaceStore.contextNamespaces);
|
||||||
|
|
||||||
|
return {
|
||||||
|
resource,
|
||||||
|
href: workloadURL[resource](),
|
||||||
|
amountOfItems: items.length,
|
||||||
|
status: store.getStatuses(items),
|
||||||
|
title: ResourceNames[resource],
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
@ -1,7 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export * from "./workloads";
|
|
||||||
export * from "./workloads.stores";
|
|
||||||
@ -2,11 +2,9 @@
|
|||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
import "./workloads.scss";
|
import { computed } from "mobx";
|
||||||
|
import type { TabLayoutRoute } from "../layout/tab-layout";
|
||||||
import React from "react";
|
|
||||||
import { TabLayout, TabLayoutRoute } from "../layout/tab-layout";
|
|
||||||
import { WorkloadsOverview } from "../+workloads-overview/overview";
|
import { WorkloadsOverview } from "../+workloads-overview/overview";
|
||||||
import { Pods } from "../+workloads-pods";
|
import { Pods } from "../+workloads-pods";
|
||||||
import { Deployments } from "../+workloads-deployments";
|
import { Deployments } from "../+workloads-deployments";
|
||||||
@ -14,12 +12,17 @@ import { DaemonSets } from "../+workloads-daemonsets";
|
|||||||
import { StatefulSets } from "../+workloads-statefulsets";
|
import { StatefulSets } from "../+workloads-statefulsets";
|
||||||
import { Jobs } from "../+workloads-jobs";
|
import { Jobs } from "../+workloads-jobs";
|
||||||
import { CronJobs } from "../+workloads-cronjobs";
|
import { CronJobs } from "../+workloads-cronjobs";
|
||||||
import { isAllowedResource } from "../../../common/utils/allowed-resource";
|
|
||||||
import { ReplicaSets } from "../+workloads-replicasets";
|
import { ReplicaSets } from "../+workloads-replicasets";
|
||||||
import * as routes from "../../../common/routes";
|
import * as routes from "../../../common/routes";
|
||||||
|
import type { IsAllowedResource } from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import isAllowedResourceInjectable from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
|
||||||
export class Workloads extends React.Component {
|
interface Dependencies {
|
||||||
static get tabRoutes(): TabLayoutRoute[] {
|
isAllowedResource: IsAllowedResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRouteTabs({ isAllowedResource }: Dependencies) {
|
||||||
|
return computed(() => {
|
||||||
const tabs: TabLayoutRoute[] = [
|
const tabs: TabLayoutRoute[] = [
|
||||||
{
|
{
|
||||||
title: "Overview",
|
title: "Overview",
|
||||||
@ -93,11 +96,14 @@ export class Workloads extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return tabs;
|
return tabs;
|
||||||
}
|
});
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<TabLayout className="Workloads" tabs={Workloads.tabRoutes}/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const workloadsRouteTabsInjectable = getInjectable({
|
||||||
|
instantiate: (di) => getRouteTabs({
|
||||||
|
isAllowedResource: di.inject(isAllowedResourceInjectable),
|
||||||
|
}),
|
||||||
|
lifecycle: lifecycleEnum.singleton,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default workloadsRouteTabsInjectable;
|
||||||
34
src/renderer/components/+workloads/route.tsx
Normal file
34
src/renderer/components/+workloads/route.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "./workloads.scss";
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { TabLayout, TabLayoutRoute } from "../layout/tab-layout";
|
||||||
|
import type { IComputedValue } from "mobx";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import workloadsRouteTabsInjectable from "./route-tabs.injectable";
|
||||||
|
|
||||||
|
export interface WorkloadsRouteProps {}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
routes: IComputedValue<TabLayoutRoute[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedWorkloadsRoute = observer(({ routes }: Dependencies & WorkloadsRouteProps) => (
|
||||||
|
<TabLayout
|
||||||
|
className="Workloads"
|
||||||
|
tabs={routes.get()}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
|
export const WorkloadsRoute = withInjectables<Dependencies, WorkloadsRouteProps>(NonInjectedWorkloadsRoute, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
routes: di.inject(workloadsRouteTabsInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
45
src/renderer/components/+workloads/sidebar-item.tsx
Normal file
45
src/renderer/components/+workloads/sidebar-item.tsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import React from "react";
|
||||||
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
|
import type { IComputedValue } from "mobx";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
import { workloadsRoute, workloadsURL } from "../../../common/routes";
|
||||||
|
import { isActiveRoute } from "../../navigation";
|
||||||
|
import { Icon } from "../icon";
|
||||||
|
import { SidebarItem } from "../layout/sidebar-item";
|
||||||
|
import type { TabLayoutRoute } from "../layout/tab-layout";
|
||||||
|
import { TabRoutesSidebarItems } from "../layout/tab-routes-sidebar-items";
|
||||||
|
import workloadsRouteTabsInjectable from "./route-tabs.injectable";
|
||||||
|
|
||||||
|
export interface WorkloadSidebarItemProps {}
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
routes: IComputedValue<TabLayoutRoute[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NonInjectedWorkloadsSidebarItem = observer(({ routes }: Dependencies & WorkloadSidebarItemProps) => {
|
||||||
|
const tabRoutes = routes.get();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarItem
|
||||||
|
id="workloads"
|
||||||
|
text="Workloads"
|
||||||
|
isActive={isActiveRoute(workloadsRoute)}
|
||||||
|
isHidden={tabRoutes.length == 0}
|
||||||
|
url={workloadsURL()}
|
||||||
|
icon={<Icon svg="workloads"/>}
|
||||||
|
>
|
||||||
|
<TabRoutesSidebarItems routes={tabRoutes} />
|
||||||
|
</SidebarItem>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const WorkloadsSidebarItem = withInjectables<Dependencies, WorkloadSidebarItemProps>(NonInjectedWorkloadsSidebarItem, {
|
||||||
|
getProps: (di, props) => ({
|
||||||
|
routes: di.inject(workloadsRouteTabsInjectable),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
@ -1,25 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import type { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
|
|
||||||
import { podsStore } from "../+workloads-pods/pods.store";
|
|
||||||
import { deploymentStore } from "../+workloads-deployments/deployments.store";
|
|
||||||
import { daemonSetStore } from "../+workloads-daemonsets/daemonsets.store";
|
|
||||||
import { statefulSetStore } from "../+workloads-statefulsets/statefulset.store";
|
|
||||||
import { jobStore } from "../+workloads-jobs/job.store";
|
|
||||||
import { cronJobStore } from "../+workloads-cronjobs/cronjob.store";
|
|
||||||
import type { KubeResource } from "../../../common/rbac";
|
|
||||||
import { replicaSetStore } from "../+workloads-replicasets/replicasets.store";
|
|
||||||
import type { KubeObject } from "../../../common/k8s-api/kube-object";
|
|
||||||
|
|
||||||
export const workloadStores = new Map<KubeResource, KubeObjectStore<KubeObject>>([
|
|
||||||
["pods", podsStore],
|
|
||||||
["deployments", deploymentStore],
|
|
||||||
["daemonsets", daemonSetStore],
|
|
||||||
["statefulsets", statefulSetStore],
|
|
||||||
["replicasets", replicaSetStore],
|
|
||||||
["jobs", jobStore],
|
|
||||||
["cronjobs", cronJobStore],
|
|
||||||
]);
|
|
||||||
@ -27,7 +27,7 @@ import type { IReleaseCreatePayload, IReleaseUpdateDetails } from "../../../../c
|
|||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import installChartTabStoreInjectable from "./store.injectable";
|
import installChartTabStoreInjectable from "./store.injectable";
|
||||||
import dockStoreInjectable from "../dock/store.injectable";
|
import dockStoreInjectable from "../dock/store.injectable";
|
||||||
import createReleaseInjectable from "../../+apps-releases/create-release/create-release.injectable";
|
import createReleaseInjectable from "../../+helm-releases/create-release/create-release.injectable";
|
||||||
import { Notifications } from "../../notifications";
|
import { Notifications } from "../../notifications";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|||||||
@ -15,13 +15,13 @@ import type { UpgradeChartTabStore } from "./store";
|
|||||||
import { Spinner } from "../../spinner";
|
import { Spinner } from "../../spinner";
|
||||||
import { Badge } from "../../badge";
|
import { Badge } from "../../badge";
|
||||||
import { EditorPanel } from "../editor-panel";
|
import { EditorPanel } from "../editor-panel";
|
||||||
import { helmChartStore, IChartVersion } from "../../+apps-helm-charts/helm-chart.store";
|
import { helmChartStore, IChartVersion } from "../../+helm-charts/helm-chart.store";
|
||||||
import type { HelmRelease, IReleaseUpdateDetails, IReleaseUpdatePayload } from "../../../../common/k8s-api/endpoints/helm-releases.api";
|
import type { HelmRelease, IReleaseUpdateDetails, IReleaseUpdatePayload } from "../../../../common/k8s-api/endpoints/helm-releases.api";
|
||||||
import { Select, SelectOption } from "../../select";
|
import { Select, SelectOption } from "../../select";
|
||||||
import { IAsyncComputed, withInjectables } from "@ogre-tools/injectable-react";
|
import { IAsyncComputed, withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import upgradeChartTabStoreInjectable from "./store.injectable";
|
import upgradeChartTabStoreInjectable from "./store.injectable";
|
||||||
import updateReleaseInjectable from "../../+apps-releases/update-release/update-release.injectable";
|
import updateReleaseInjectable from "../../+helm-releases/update-release/update-release.injectable";
|
||||||
import releasesInjectable from "../../+apps-releases/releases.injectable";
|
import releasesInjectable from "../../+helm-releases/releases.injectable";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: string;
|
className?: string;
|
||||||
|
|||||||
@ -7,99 +7,34 @@ import styles from "./sidebar.module.scss";
|
|||||||
import type { TabLayoutRoute } from "./tab-layout";
|
import type { TabLayoutRoute } from "./tab-layout";
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { cssNames, Disposer } from "../../utils";
|
import { cssNames } from "../../utils";
|
||||||
import { Icon } from "../icon";
|
|
||||||
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 { CustomResources } from "../+custom-resources/custom-resources";
|
|
||||||
import { isActiveRoute } from "../../navigation";
|
import { isActiveRoute } from "../../navigation";
|
||||||
import { isAllowedResource } from "../../../common/utils/allowed-resource";
|
|
||||||
import { Spinner } from "../spinner";
|
|
||||||
import { ClusterPageMenuRegistration, ClusterPageMenuRegistry, ClusterPageRegistry, getExtensionPageUrl } from "../../../extensions/registries";
|
import { ClusterPageMenuRegistration, ClusterPageMenuRegistry, ClusterPageRegistry, getExtensionPageUrl } from "../../../extensions/registries";
|
||||||
import { SidebarItem } from "./sidebar-item";
|
import { SidebarItem } from "./sidebar-item";
|
||||||
import { Apps } from "../+apps";
|
|
||||||
import * as routes from "../../../common/routes";
|
|
||||||
import { Config } from "../+config";
|
|
||||||
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
|
||||||
import { SidebarCluster } from "./sidebar-cluster";
|
import { SidebarCluster } from "./sidebar-cluster";
|
||||||
import type { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
|
import { TabRoutesSidebarItems } from "./tab-routes-sidebar-items";
|
||||||
import type { KubeObject } from "../../../common/k8s-api/kube-object";
|
import { ConfigSidebarItem } from "../+config/sidebar-item";
|
||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { ClusterSidebarItem } from "../+cluster/sidebar-item";
|
||||||
import kubeWatchApiInjectable
|
import { NodesSidebarItem } from "../+nodes/sidebar-item";
|
||||||
from "../../kube-watch-api/kube-watch-api.injectable";
|
import { WorkloadsSidebarItem } from "../+workloads/sidebar-item";
|
||||||
|
import { NetworkSidebarItem } from "../+network/sidebar-item";
|
||||||
|
import { StorageSidebarItem } from "../+storage/sidebar-item";
|
||||||
|
import { NamespacesSidebarItem } from "../+namespaces/sidebar-item";
|
||||||
|
import { EventsSidebarItem } from "../+events/sidebar-item";
|
||||||
|
import { HelmSidebarItem } from "../+helm/sidebar-item";
|
||||||
|
import { UserManagementSidebarItem } from "../+user-management/sidebar-item";
|
||||||
|
import { CustomResourcesSidebarItem } from "../+custom-resources/sidebar-item";
|
||||||
|
|
||||||
interface Props {
|
interface SidebarProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Dependencies {
|
|
||||||
subscribeStores: (stores: KubeObjectStore<KubeObject>[]) => Disposer
|
|
||||||
}
|
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
class NonInjectedSidebar extends React.Component<Props & Dependencies> {
|
export class Sidebar extends React.Component<SidebarProps> {
|
||||||
static displayName = "Sidebar";
|
static displayName = "Sidebar";
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
disposeOnUnmount(this, [
|
|
||||||
this.props.subscribeStores([
|
|
||||||
crdStore,
|
|
||||||
]),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderCustomResources() {
|
|
||||||
if (crdStore.isLoading) {
|
|
||||||
return (
|
|
||||||
<div className="flex justify-center">
|
|
||||||
<Spinner/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Object.entries(crdStore.groups).map(([group, crds]) => {
|
|
||||||
const id = `crd-group:${group}`;
|
|
||||||
const crdGroupsPageUrl = routes.crdURL({ query: { groups: group }});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SidebarItem key={id} id={id} text={group} url={crdGroupsPageUrl}>
|
|
||||||
{crds.map((crd) => (
|
|
||||||
<SidebarItem
|
|
||||||
key={crd.getResourceApiBase()}
|
|
||||||
id={`crd-resource:${crd.getResourceApiBase()}`}
|
|
||||||
url={crd.getResourceUrl()}
|
|
||||||
text={crd.getResourceKind()}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</SidebarItem>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
renderTreeFromTabRoutes(tabRoutes: TabLayoutRoute[] = []): React.ReactNode {
|
|
||||||
if (!tabRoutes.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tabRoutes.map(({ title, routePath, url = routePath, exact = true }) => {
|
|
||||||
const subMenuItemId = `tab-route-item-${url}`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SidebarItem
|
|
||||||
key={subMenuItemId}
|
|
||||||
id={subMenuItemId}
|
|
||||||
url={url}
|
|
||||||
text={title}
|
|
||||||
isActive={isActiveRoute({ path: routePath, exact })}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getTabLayoutRoutes(menu: ClusterPageMenuRegistration): TabLayoutRoute[] {
|
getTabLayoutRoutes(menu: ClusterPageMenuRegistration): TabLayoutRoute[] {
|
||||||
if (!menu.id) {
|
if (!menu.id) {
|
||||||
return [];
|
return [];
|
||||||
@ -169,7 +104,7 @@ class NonInjectedSidebar extends React.Component<Props & Dependencies> {
|
|||||||
text={menuItem.title}
|
text={menuItem.title}
|
||||||
icon={<menuItem.components.Icon/>}
|
icon={<menuItem.components.Icon/>}
|
||||||
>
|
>
|
||||||
{this.renderTreeFromTabRoutes(tabRoutes)}
|
<TabRoutesSidebarItems routes={tabRoutes} />
|
||||||
</SidebarItem>
|
</SidebarItem>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -186,122 +121,20 @@ class NonInjectedSidebar extends React.Component<Props & Dependencies> {
|
|||||||
<div className={cssNames("flex flex-col", className)} data-testid="cluster-sidebar">
|
<div className={cssNames("flex flex-col", className)} data-testid="cluster-sidebar">
|
||||||
<SidebarCluster clusterEntity={this.clusterEntity}/>
|
<SidebarCluster clusterEntity={this.clusterEntity}/>
|
||||||
<div className={styles.sidebarNav}>
|
<div className={styles.sidebarNav}>
|
||||||
<SidebarItem
|
<ClusterSidebarItem />
|
||||||
id="cluster"
|
<NodesSidebarItem />
|
||||||
text="Cluster"
|
<WorkloadsSidebarItem />
|
||||||
isActive={isActiveRoute(routes.clusterRoute)}
|
<ConfigSidebarItem />
|
||||||
isHidden={!isAllowedResource("nodes")}
|
<NetworkSidebarItem />
|
||||||
url={routes.clusterURL()}
|
<StorageSidebarItem />
|
||||||
icon={<Icon svg="kube"/>}
|
<NamespacesSidebarItem />
|
||||||
/>
|
<EventsSidebarItem />
|
||||||
<SidebarItem
|
<HelmSidebarItem />
|
||||||
id="nodes"
|
<UserManagementSidebarItem />
|
||||||
text="Nodes"
|
<CustomResourcesSidebarItem />
|
||||||
isActive={isActiveRoute(routes.nodesRoute)}
|
|
||||||
isHidden={!isAllowedResource("nodes")}
|
|
||||||
url={routes.nodesURL()}
|
|
||||||
icon={<Icon svg="nodes"/>}
|
|
||||||
/>
|
|
||||||
<SidebarItem
|
|
||||||
id="workloads"
|
|
||||||
text="Workloads"
|
|
||||||
isActive={isActiveRoute(routes.workloadsRoute)}
|
|
||||||
isHidden={Workloads.tabRoutes.length == 0}
|
|
||||||
url={routes.workloadsURL()}
|
|
||||||
icon={<Icon svg="workloads"/>}
|
|
||||||
>
|
|
||||||
{this.renderTreeFromTabRoutes(Workloads.tabRoutes)}
|
|
||||||
</SidebarItem>
|
|
||||||
<SidebarItem
|
|
||||||
id="config"
|
|
||||||
text="Configuration"
|
|
||||||
isActive={isActiveRoute(routes.configRoute)}
|
|
||||||
isHidden={Config.tabRoutes.length == 0}
|
|
||||||
url={routes.configURL()}
|
|
||||||
icon={<Icon material="list"/>}
|
|
||||||
>
|
|
||||||
{this.renderTreeFromTabRoutes(Config.tabRoutes)}
|
|
||||||
</SidebarItem>
|
|
||||||
<SidebarItem
|
|
||||||
id="networks"
|
|
||||||
text="Network"
|
|
||||||
isActive={isActiveRoute(routes.networkRoute)}
|
|
||||||
isHidden={Network.tabRoutes.length == 0}
|
|
||||||
url={routes.networkURL()}
|
|
||||||
icon={<Icon material="device_hub"/>}
|
|
||||||
>
|
|
||||||
{this.renderTreeFromTabRoutes(Network.tabRoutes)}
|
|
||||||
</SidebarItem>
|
|
||||||
<SidebarItem
|
|
||||||
id="storage"
|
|
||||||
text="Storage"
|
|
||||||
isActive={isActiveRoute(routes.storageRoute)}
|
|
||||||
isHidden={Storage.tabRoutes.length == 0}
|
|
||||||
url={routes.storageURL()}
|
|
||||||
icon={<Icon svg="storage"/>}
|
|
||||||
>
|
|
||||||
{this.renderTreeFromTabRoutes(Storage.tabRoutes)}
|
|
||||||
</SidebarItem>
|
|
||||||
<SidebarItem
|
|
||||||
id="namespaces"
|
|
||||||
text="Namespaces"
|
|
||||||
isActive={isActiveRoute(routes.namespacesRoute)}
|
|
||||||
isHidden={!isAllowedResource("namespaces")}
|
|
||||||
url={routes.namespacesURL()}
|
|
||||||
icon={<Icon material="layers"/>}
|
|
||||||
/>
|
|
||||||
<SidebarItem
|
|
||||||
id="events"
|
|
||||||
text="Events"
|
|
||||||
isActive={isActiveRoute(routes.eventRoute)}
|
|
||||||
isHidden={!isAllowedResource("events")}
|
|
||||||
url={routes.eventsURL()}
|
|
||||||
icon={<Icon material="access_time"/>}
|
|
||||||
/>
|
|
||||||
<SidebarItem
|
|
||||||
id="apps"
|
|
||||||
text="Apps" // helm charts
|
|
||||||
isActive={isActiveRoute(routes.appsRoute)}
|
|
||||||
url={routes.appsURL()}
|
|
||||||
icon={<Icon material="apps"/>}
|
|
||||||
>
|
|
||||||
{this.renderTreeFromTabRoutes(Apps.tabRoutes)}
|
|
||||||
</SidebarItem>
|
|
||||||
<SidebarItem
|
|
||||||
id="users"
|
|
||||||
text="Access Control"
|
|
||||||
isActive={isActiveRoute(routes.usersManagementRoute)}
|
|
||||||
isHidden={UserManagement.tabRoutes.length === 0}
|
|
||||||
url={routes.usersManagementURL()}
|
|
||||||
icon={<Icon material="security"/>}
|
|
||||||
>
|
|
||||||
{this.renderTreeFromTabRoutes(UserManagement.tabRoutes)}
|
|
||||||
</SidebarItem>
|
|
||||||
<SidebarItem
|
|
||||||
id="custom-resources"
|
|
||||||
text="Custom Resources"
|
|
||||||
url={routes.crdURL()}
|
|
||||||
isActive={isActiveRoute(routes.crdRoute)}
|
|
||||||
isHidden={!isAllowedResource("customresourcedefinitions")}
|
|
||||||
icon={<Icon material="extension"/>}
|
|
||||||
>
|
|
||||||
{this.renderTreeFromTabRoutes(CustomResources.tabRoutes)}
|
|
||||||
{this.renderCustomResources()}
|
|
||||||
</SidebarItem>
|
|
||||||
{this.renderRegisteredMenus()}
|
{this.renderRegisteredMenus()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Sidebar = withInjectables<Dependencies, Props>(
|
|
||||||
NonInjectedSidebar,
|
|
||||||
|
|
||||||
{
|
|
||||||
getProps: (di, props) => ({
|
|
||||||
subscribeStores: di.inject(kubeWatchApiInjectable).subscribeStores,
|
|
||||||
...props,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|||||||
37
src/renderer/components/layout/tab-routes-sidebar-items.tsx
Normal file
37
src/renderer/components/layout/tab-routes-sidebar-items.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { isActiveRoute } from "../../navigation";
|
||||||
|
import { SidebarItem } from "./sidebar-item";
|
||||||
|
import type { TabLayoutRoute } from "./tab-layout";
|
||||||
|
|
||||||
|
export interface SidebarTreeProps {
|
||||||
|
routes: TabLayoutRoute[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function withId(src: TabLayoutRoute) {
|
||||||
|
return {
|
||||||
|
...src,
|
||||||
|
id: `tab-route-item-${src.url ?? src.routePath}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TabRoutesSidebarItems = ({ routes }: SidebarTreeProps) => (
|
||||||
|
<>
|
||||||
|
{
|
||||||
|
routes
|
||||||
|
.map(withId)
|
||||||
|
.map(({ title, routePath, url = routePath, exact = true, id }) => (
|
||||||
|
<SidebarItem
|
||||||
|
key={id}
|
||||||
|
id={id}
|
||||||
|
url={url}
|
||||||
|
text={title}
|
||||||
|
isActive={isActiveRoute({ path: routePath, exact })} />
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
);
|
||||||
@ -3,17 +3,16 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { observable, makeObservable } from "mobx";
|
import { makeObservable, computed } from "mobx";
|
||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import { Redirect, Route, Router, Switch } from "react-router";
|
import { Redirect, Route, Router, Switch } from "react-router";
|
||||||
import { UserManagement } from "../../components/+user-management/user-management";
|
import { UserManagementRoute } from "../../components/+user-management/route";
|
||||||
import { ConfirmDialog } from "../../components/confirm-dialog";
|
import { ConfirmDialog } from "../../components/confirm-dialog";
|
||||||
import { ClusterOverview } from "../../components/+cluster/cluster-overview";
|
import { ClusterOverview } from "../../components/+cluster/cluster-overview";
|
||||||
import { Events } from "../../components/+events/events";
|
import { Events } from "../../components/+events/events";
|
||||||
import { DeploymentScaleDialog } from "../../components/+workloads-deployments/deployment-scale-dialog";
|
import { DeploymentScaleDialog } from "../../components/+workloads-deployments/deployment-scale-dialog";
|
||||||
import { CronJobTriggerDialog } from "../../components/+workloads-cronjobs/cronjob-trigger-dialog";
|
import { CronJobTriggerDialog } from "../../components/+workloads-cronjobs/cronjob-trigger-dialog";
|
||||||
import { CustomResources } from "../../components/+custom-resources/custom-resources";
|
import { CustomResourcesRoute } from "../../components/+custom-resources/route";
|
||||||
import { isAllowedResource } from "../../../common/utils/allowed-resource";
|
|
||||||
import { ClusterPageRegistry, getExtensionPageUrl } from "../../../extensions/registries/page-registry";
|
import { ClusterPageRegistry, getExtensionPageUrl } from "../../../extensions/registries/page-registry";
|
||||||
import { ClusterPageMenuRegistration, ClusterPageMenuRegistry } from "../../../extensions/registries";
|
import { ClusterPageMenuRegistration, ClusterPageMenuRegistry } from "../../../extensions/registries";
|
||||||
import { StatefulSetScaleDialog } from "../../components/+workloads-statefulsets/statefulset-scale-dialog";
|
import { StatefulSetScaleDialog } from "../../components/+workloads-statefulsets/statefulset-scale-dialog";
|
||||||
@ -28,13 +27,12 @@ import { KubeObjectDetails } from "../../components/kube-object-details";
|
|||||||
import { KubeConfigDialog } from "../../components/kubeconfig-dialog";
|
import { KubeConfigDialog } from "../../components/kubeconfig-dialog";
|
||||||
import { Sidebar } from "../../components/layout/sidebar";
|
import { Sidebar } from "../../components/layout/sidebar";
|
||||||
import { Dock } from "../../components/dock";
|
import { Dock } from "../../components/dock";
|
||||||
import { Apps } from "../../components/+apps";
|
import { NamespacesRoute } from "../../components/+namespaces/route";
|
||||||
import { Namespaces } from "../../components/+namespaces";
|
import { NetworkRoute } from "../../components/+network/route";
|
||||||
import { Network } from "../../components/+network";
|
import { NodesRoute } from "../../components/+nodes/route";
|
||||||
import { Nodes } from "../../components/+nodes";
|
import { WorkloadsRoute } from "../../components/+workloads/route";
|
||||||
import { Workloads } from "../../components/+workloads";
|
import { ConfigRoute } from "../../components/+config/route";
|
||||||
import { Config } from "../../components/+config";
|
import { StorageRoute } from "../../components/+storage/route";
|
||||||
import { Storage } from "../../components/+storage";
|
|
||||||
import { watchHistoryState } from "../../remote-helpers/history-updater";
|
import { watchHistoryState } from "../../remote-helpers/history-updater";
|
||||||
import { PortForwardDialog } from "../../port-forward";
|
import { PortForwardDialog } from "../../port-forward";
|
||||||
import { DeleteClusterDialog } from "../../components/delete-cluster-dialog";
|
import { DeleteClusterDialog } from "../../components/delete-cluster-dialog";
|
||||||
@ -42,19 +40,24 @@ import type { NamespaceStore } from "../../components/+namespaces/namespace-stor
|
|||||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||||
import namespaceStoreInjectable from "../../components/+namespaces/namespace-store/namespace-store.injectable";
|
import namespaceStoreInjectable from "../../components/+namespaces/namespace-store/namespace-store.injectable";
|
||||||
import type { ClusterId } from "../../../common/cluster-types";
|
import type { ClusterId } from "../../../common/cluster-types";
|
||||||
import hostedClusterInjectable from "../../../common/cluster-store/hosted-cluster/hosted-cluster.injectable";
|
import hostedClusterInjectable from "../../../common/cluster-store/hosted-cluster.injectable";
|
||||||
import type { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
|
import type { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
|
||||||
import type { KubeObject } from "../../../common/k8s-api/kube-object";
|
import type { KubeObject } from "../../../common/k8s-api/kube-object";
|
||||||
import type { Disposer } from "../../../common/utils";
|
import type { Disposer } from "../../../common/utils";
|
||||||
import kubeWatchApiInjectable from "../../kube-watch-api/kube-watch-api.injectable";
|
import kubeWatchApiInjectable from "../../kube-watch-api/kube-watch-api.injectable";
|
||||||
import historyInjectable from "../../navigation/history.injectable";
|
import historyInjectable from "../../navigation/history.injectable";
|
||||||
import type { History } from "history";
|
import type { History } from "history";
|
||||||
|
import type { IsAllowedResource } from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import isAllowedResourceInjectable from "../../../common/utils/is-allowed-resource.injectable";
|
||||||
|
import { HelmRoute } from "../../components/+helm/route";
|
||||||
|
import type { KubeResource } from "../../../common/rbac";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
history: History,
|
history: History;
|
||||||
namespaceStore: NamespaceStore
|
namespaceStore: NamespaceStore;
|
||||||
hostedClusterId: ClusterId
|
hostedClusterId: ClusterId;
|
||||||
subscribeStores: (stores: KubeObjectStore<KubeObject>[]) => Disposer
|
subscribeStores: (stores: KubeObjectStore<KubeObject>[]) => Disposer;
|
||||||
|
isAllowedResource: IsAllowedResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -75,7 +78,13 @@ class NonInjectedClusterFrame extends React.Component<Dependencies> {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@observable startUrl = isAllowedResource(["events", "nodes", "pods"]) ? routes.clusterURL() : routes.workloadsURL();
|
@computed get startUrl() {
|
||||||
|
const resources : KubeResource[] = ["events", "nodes", "pods"];
|
||||||
|
|
||||||
|
return resources.every(x => this.props.isAllowedResource(x))
|
||||||
|
? routes.clusterURL()
|
||||||
|
: routes.workloadsURL();
|
||||||
|
}
|
||||||
|
|
||||||
getTabLayoutRoutes(menuItem: ClusterPageMenuRegistration) {
|
getTabLayoutRoutes(menuItem: ClusterPageMenuRegistration) {
|
||||||
const routes: TabLayoutRoute[] = [];
|
const routes: TabLayoutRoute[] = [];
|
||||||
@ -138,18 +147,17 @@ class NonInjectedClusterFrame extends React.Component<Dependencies> {
|
|||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<MainLayout sidebar={<Sidebar />} footer={<Dock />}>
|
<MainLayout sidebar={<Sidebar />} footer={<Dock />}>
|
||||||
<Switch>
|
<Switch>
|
||||||
|
|
||||||
<Route component={ClusterOverview} {...routes.clusterRoute}/>
|
<Route component={ClusterOverview} {...routes.clusterRoute}/>
|
||||||
<Route component={Nodes} {...routes.nodesRoute}/>
|
<Route component={NodesRoute} {...routes.nodesRoute}/>
|
||||||
<Route component={Workloads} {...routes.workloadsRoute}/>
|
<Route component={WorkloadsRoute} {...routes.workloadsRoute}/>
|
||||||
<Route component={Config} {...routes.configRoute}/>
|
<Route component={ConfigRoute} {...routes.configRoute}/>
|
||||||
<Route component={Network} {...routes.networkRoute}/>
|
<Route component={NetworkRoute} {...routes.networkRoute}/>
|
||||||
<Route component={Storage} {...routes.storageRoute}/>
|
<Route component={StorageRoute} {...routes.storageRoute}/>
|
||||||
<Route component={Namespaces} {...routes.namespacesRoute}/>
|
<Route component={NamespacesRoute} {...routes.namespacesRoute}/>
|
||||||
<Route component={Events} {...routes.eventRoute}/>
|
<Route component={Events} {...routes.eventRoute}/>
|
||||||
<Route component={CustomResources} {...routes.crdRoute}/>
|
<Route component={CustomResourcesRoute} {...routes.crdRoute}/>
|
||||||
<Route component={UserManagement} {...routes.usersManagementRoute}/>
|
<Route component={UserManagementRoute} {...routes.usersManagementRoute}/>
|
||||||
<Route component={Apps} {...routes.appsRoute}/>
|
<Route component={HelmRoute} {...routes.helmRoute}/>
|
||||||
{this.renderExtensionTabLayoutRoutes()}
|
{this.renderExtensionTabLayoutRoutes()}
|
||||||
{this.renderExtensionRoutes()}
|
{this.renderExtensionRoutes()}
|
||||||
<Redirect exact from="/" to={this.startUrl}/>
|
<Redirect exact from="/" to={this.startUrl}/>
|
||||||
@ -185,5 +193,6 @@ export const ClusterFrame = withInjectables<Dependencies>(NonInjectedClusterFram
|
|||||||
namespaceStore: di.inject(namespaceStoreInjectable),
|
namespaceStore: di.inject(namespaceStoreInjectable),
|
||||||
hostedClusterId: di.inject(hostedClusterInjectable).id,
|
hostedClusterId: di.inject(hostedClusterInjectable).id,
|
||||||
subscribeStores: di.inject(kubeWatchApiInjectable).subscribeStores,
|
subscribeStores: di.inject(kubeWatchApiInjectable).subscribeStores,
|
||||||
|
isAllowedResource: di.inject(isAllowedResourceInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user