1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Extract ClusterContext into deps for KubeObjectStore to fix circular import

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-11-28 09:21:03 -05:00
parent 40a7bf8830
commit 4504283041
123 changed files with 993 additions and 991 deletions

View File

@ -5,7 +5,8 @@
import { getInjectionToken } from "@ogre-tools/injectable"; import { getInjectionToken } from "@ogre-tools/injectable";
import type { IComputedValue } from "mobx"; import type { IComputedValue } from "mobx";
import type { KubeApiResourceDescriptor } from "../rbac";
export const allowedResourcesInjectionToken = getInjectionToken<IComputedValue<Set<string>>>({ export const shouldShowResourceInjectionToken = getInjectionToken<IComputedValue<boolean>, KubeApiResourceDescriptor>({
id: "allowed-resources", id: "should-show-resource",
}); });

View File

@ -1,89 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { KubeConfig } from "@kubernetes/client-node";
import { AuthorizationV1Api } from "@kubernetes/client-node";
import { getInjectable } from "@ogre-tools/injectable";
import loggerInjectable from "../logger.injectable";
import type { KubeApiResource } from "../rbac";
/**
* Requests the permissions for actions on the kube cluster
* @param namespace The namespace of the resources
* @param availableResources List of available resources in the cluster to resolve glob values fir api groups
* @returns list of allowed resources names
*/
export type RequestNamespaceResources = (namespace: string, availableResources: KubeApiResource[]) => Promise<string[]>;
/**
* @param proxyConfig This config's `currentContext` field must be set, and will be used as the target cluster
*/
export type AuthorizationNamespaceReview = (proxyConfig: KubeConfig) => RequestNamespaceResources;
const authorizationNamespaceReviewInjectable = getInjectable({
id: "authorization-namespace-review",
instantiate: (di): AuthorizationNamespaceReview => {
const logger = di.inject(loggerInjectable);
return (proxyConfig) => {
const api = proxyConfig.makeApiClient(AuthorizationV1Api);
return async (namespace, availableResources) => {
try {
const { body: { status }} = await api.createSelfSubjectRulesReview({
apiVersion: "authorization.k8s.io/v1",
kind: "SelfSubjectRulesReview",
spec: { namespace },
});
const allowedResources = new Set<string>();
if (!status || status.incomplete) {
logger.warn(`[AUTHORIZATION-NAMESPACE-REVIEW]: allowing all resources in namespace="${namespace}" due to incomplete SelfSubjectRulesReview: ${status?.evaluationError}`);
return availableResources.map(r => r.apiName);
}
for (const { verbs, resources, apiGroups } of status.resourceRules) {
if (
!resources
|| (!verbs.includes("*") && !verbs.includes("list"))
) {
continue;
}
if (resources[0] !== "*" || !apiGroups) {
for (const resource of resources) {
allowedResources.add(resource);
}
continue;
}
if (apiGroups[0] === "*") {
for (const resource of availableResources) {
allowedResources.add(resource.apiName);
}
continue;
}
for (const resource of availableResources) {
if (apiGroups.includes(resource.group || "")) {
allowedResources.add(resource.apiName);
}
}
}
return [...allowedResources];
} catch (error) {
logger.error(`[AUTHORIZATION-NAMESPACE-REVIEW]: failed to create subject rules review: ${error}`, { namespace });
return [];
}
};
};
},
});
export default authorizationNamespaceReviewInjectable;

View File

@ -9,8 +9,8 @@ import type { KubeConfig } from "@kubernetes/client-node";
import { HttpError } from "@kubernetes/client-node"; import { HttpError } from "@kubernetes/client-node";
import type { Kubectl } from "../../main/kubectl/kubectl"; import type { Kubectl } from "../../main/kubectl/kubectl";
import type { KubeconfigManager } from "../../main/kubeconfig-manager/kubeconfig-manager"; import type { KubeconfigManager } from "../../main/kubeconfig-manager/kubeconfig-manager";
import type { KubeApiResource, KubeResource } from "../rbac"; import type { KubeApiResource, KubeApiResourceDescriptor } from "../rbac";
import { apiResourceRecord, apiResources } from "../rbac"; import { formatKubeApiResource } from "../rbac";
import type { VersionDetector } from "../../main/cluster-detectors/version-detector"; import type { VersionDetector } from "../../main/cluster-detectors/version-detector";
import type { DetectorRegistry } from "../../main/cluster-detectors/detector-registry"; import type { DetectorRegistry } from "../../main/cluster-detectors/detector-registry";
import plimit from "p-limit"; import plimit from "p-limit";
@ -25,8 +25,8 @@ import assert from "assert";
import type { Logger } from "../logger"; import type { Logger } from "../logger";
import type { BroadcastMessage } from "../ipc/broadcast-message.injectable"; import type { BroadcastMessage } from "../ipc/broadcast-message.injectable";
import type { LoadConfigfromFile } from "../kube-helpers/load-config-from-file.injectable"; import type { LoadConfigfromFile } from "../kube-helpers/load-config-from-file.injectable";
import type { RequestNamespaceResources } from "./authorization-namespace-review.injectable"; import type { CanListResource, RequestNamespaceListPermissions, RequestNamespaceListPermissionsFor } from "./request-namespace-list-permissions.injectable";
import type { RequestListApiResources } from "./list-api-resources.injectable"; import type { RequestApiResources } from "./request-api-resources.injectable";
export interface ClusterDependencies { export interface ClusterDependencies {
readonly directoryForKubeConfigs: string; readonly directoryForKubeConfigs: string;
@ -36,8 +36,8 @@ export interface ClusterDependencies {
createContextHandler: (cluster: Cluster) => ClusterContextHandler; createContextHandler: (cluster: Cluster) => ClusterContextHandler;
createKubectl: (clusterVersion: string) => Kubectl; createKubectl: (clusterVersion: string) => Kubectl;
createAuthorizationReview: (config: KubeConfig) => CanI; createAuthorizationReview: (config: KubeConfig) => CanI;
createAuthorizationNamespaceReview: (config: KubeConfig) => RequestNamespaceResources; requestApiResources: RequestApiResources;
createListApiResources: (cluster: Cluster) => RequestListApiResources; requestNamespaceListPermissionsFor: RequestNamespaceListPermissionsFor;
createListNamespaces: (config: KubeConfig) => ListNamespaces; createListNamespaces: (config: KubeConfig) => ListNamespaces;
createVersionDetector: (cluster: Cluster) => VersionDetector; createVersionDetector: (cluster: Cluster) => VersionDetector;
broadcastMessage: BroadcastMessage; broadcastMessage: BroadcastMessage;
@ -49,7 +49,7 @@ export interface ClusterDependencies {
* *
* @beta * @beta
*/ */
export class Cluster implements ClusterModel, ClusterState { export class Cluster implements ClusterModel {
/** Unique id for a cluster */ /** Unique id for a cluster */
public readonly id: ClusterId; public readonly id: ClusterId;
private kubeCtl: Kubectl | undefined; private kubeCtl: Kubectl | undefined;
@ -62,7 +62,6 @@ export class Cluster implements ClusterModel, ClusterState {
protected readonly _proxyKubeconfigManager: KubeconfigManager | undefined; protected readonly _proxyKubeconfigManager: KubeconfigManager | undefined;
protected readonly eventsDisposer = disposer(); protected readonly eventsDisposer = disposer();
protected activated = false; protected activated = false;
private readonly resourceAccessStatuses = new Map<KubeApiResource, boolean>();
public get contextHandler() { public get contextHandler() {
// TODO: remove these once main/renderer are seperate classes // TODO: remove these once main/renderer are seperate classes
@ -163,25 +162,30 @@ export class Cluster implements ClusterModel, ClusterState {
* @observable * @observable
*/ */
@observable metadata: ClusterMetadata = {}; @observable metadata: ClusterMetadata = {};
/** /**
* List of allowed namespaces verified via K8S::SelfSubjectAccessReview api * List of allowed namespaces verified via K8S::SelfSubjectAccessReview api
*
* @observable
*/ */
@observable allowedNamespaces: string[] = []; readonly allowedNamespaces = observable.array<string>();
/**
* List of allowed resources
*
* @observable
* @internal
*/
@observable allowedResources: string[] = [];
/** /**
* List of accessible namespaces provided by user in the Cluster Settings * List of accessible namespaces provided by user in the Cluster Settings
*
* @observable
*/ */
@observable accessibleNamespaces: string[] = []; readonly accessibleNamespaces = observable.array<string>();
private readonly knownResources = observable.array<KubeApiResource>();
private readonly knownNamespacedResources = computed(() => (
this.knownResources
.filter(r => r.namespaced === true)
));
private readonly knownClusterscopedResources = computed(() => (
this.knownResources
.filter(r => r.namespaced === false)
));
// The formatting of this is `group.name` or `name` (if in core)
private readonly allowedResources = observable.set<string>();
/** /**
* Labels for the catalog entity * Labels for the catalog entity
@ -299,7 +303,7 @@ export class Cluster implements ClusterModel, ClusterState {
} }
if (model.accessibleNamespaces) { if (model.accessibleNamespaces) {
this.accessibleNamespaces = model.accessibleNamespaces; this.accessibleNamespaces.replace(model.accessibleNamespaces);
} }
if (model.labels) { if (model.labels) {
@ -433,8 +437,7 @@ export class Cluster implements ClusterModel, ClusterState {
this.accessible = false; this.accessible = false;
this.ready = false; this.ready = false;
this.activated = false; this.activated = false;
this.allowedNamespaces = []; this.allowedNamespaces.clear();
this.resourceAccessStatuses.clear();
this.dependencies.logger.info(`[CLUSTER]: disconnected`, { id: this.id }); this.dependencies.logger.info(`[CLUSTER]: disconnected`, { id: this.id });
} }
@ -474,8 +477,7 @@ export class Cluster implements ClusterModel, ClusterState {
this.dependencies.logger.info(`[CLUSTER]: refreshAccessibility`, this.getMeta()); this.dependencies.logger.info(`[CLUSTER]: refreshAccessibility`, this.getMeta());
const proxyConfig = await this.getProxyKubeconfig(); const proxyConfig = await this.getProxyKubeconfig();
const canI = this.dependencies.createAuthorizationReview(proxyConfig); const canI = this.dependencies.createAuthorizationReview(proxyConfig);
const requestNamespaceResources = this.dependencies.createAuthorizationNamespaceReview(proxyConfig); const requestNamespaceListPermissions = this.dependencies.requestNamespaceListPermissionsFor(proxyConfig);
const listApiResources = this.dependencies.createListApiResources(this);
this.isAdmin = await canI({ this.isAdmin = await canI({
namespace: "kube-system", namespace: "kube-system",
@ -486,8 +488,9 @@ export class Cluster implements ClusterModel, ClusterState {
verb: "watch", verb: "watch",
resource: "*", resource: "*",
}); });
this.allowedNamespaces = await this.getAllowedNamespaces(proxyConfig); this.allowedNamespaces.replace(await this.requestAllowedNamespaces(proxyConfig));
this.allowedResources = await this.getAllowedResources(listApiResources, requestNamespaceResources); this.knownResources.replace(await this.dependencies.requestApiResources(this));
this.allowedResources.replace(await this.getAllowedResources(requestNamespaceListPermissions));
this.ready = true; this.ready = true;
} }
@ -600,7 +603,7 @@ export class Cluster implements ClusterModel, ClusterState {
accessible: this.accessible, accessible: this.accessible,
isAdmin: this.isAdmin, isAdmin: this.isAdmin,
allowedNamespaces: this.allowedNamespaces, allowedNamespaces: this.allowedNamespaces,
allowedResources: this.allowedResources, allowedResources: [...this.allowedResources],
isGlobalWatchEnabled: this.isGlobalWatchEnabled, isGlobalWatchEnabled: this.isGlobalWatchEnabled,
}); });
} }
@ -611,8 +614,8 @@ export class Cluster implements ClusterModel, ClusterState {
*/ */
@action setState(state: ClusterState) { @action setState(state: ClusterState) {
this.accessible = state.accessible; this.accessible = state.accessible;
this.allowedNamespaces = state.allowedNamespaces; this.allowedNamespaces.replace(state.allowedNamespaces);
this.allowedResources = state.allowedResources; this.allowedResources.replace(state.allowedResources);
this.apiUrl = state.apiUrl; this.apiUrl = state.apiUrl;
this.disconnected = state.disconnected; this.disconnected = state.disconnected;
this.isAdmin = state.isAdmin; this.isAdmin = state.isAdmin;
@ -644,7 +647,7 @@ export class Cluster implements ClusterModel, ClusterState {
this.dependencies.broadcastMessage(`cluster:${this.id}:connection-update`, update); this.dependencies.broadcastMessage(`cluster:${this.id}:connection-update`, update);
} }
protected async getAllowedNamespaces(proxyConfig: KubeConfig) { protected async requestAllowedNamespaces(proxyConfig: KubeConfig) {
if (this.accessibleNamespaces.length) { if (this.accessibleNamespaces.length) {
return this.accessibleNamespaces; return this.accessibleNamespaces;
} }
@ -668,69 +671,35 @@ export class Cluster implements ClusterModel, ClusterState {
} }
} }
protected async getAllowedResources(listApiResources:RequestListApiResources, requestNamespaceResources: RequestNamespaceResources) { protected async getAllowedResources(requestNamespaceListPermissions: RequestNamespaceListPermissions) {
if (!this.allowedNamespaces.length) {
return [];
}
try { try {
if (!this.allowedNamespaces.length) { const canListClusterScopedResource = await requestNamespaceListPermissions("");
return []; const apiLimit = plimit(5); // 5 concurrent api requests
} const canListNamespacedResourceCheckers = await Promise.all((
this.allowedNamespaces.map(namespace => apiLimit(() => requestNamespaceListPermissions(namespace)))
));
const canListNamespacedResource: CanListResource = (resource) => canListNamespacedResourceCheckers.some(fn => fn(resource));
const unknownResources = new Map<string, KubeApiResource>(apiResources.map(resource => ([resource.apiName, resource]))); const allowedClusterScopedResources = this.knownClusterscopedResources
.get()
.filter(canListClusterScopedResource);
const allowedNamespaceScopedResources = this.knownNamespacedResources
.get()
.filter(canListNamespacedResource);
const availableResources = await listApiResources(); return [...allowedClusterScopedResources, ...allowedNamespaceScopedResources]
const availableResourcesNames = new Set(availableResources.map(apiResource => apiResource.apiName)); .map(formatKubeApiResource);
[...unknownResources.values()].map(unknownResource => {
if (!availableResourcesNames.has(unknownResource.apiName)) {
this.resourceAccessStatuses.set(unknownResource, false);
unknownResources.delete(unknownResource.apiName);
}
});
if (unknownResources.size > 0) {
const apiLimit = plimit(5); // 5 concurrent api requests
await Promise.all(this.allowedNamespaces.map(namespace => apiLimit(async () => {
if (unknownResources.size === 0) {
return;
}
const namespaceResources = await requestNamespaceResources(namespace, availableResources);
for (const resourceName of namespaceResources) {
const unknownResource = unknownResources.get(resourceName);
if (unknownResource) {
this.resourceAccessStatuses.set(unknownResource, true);
unknownResources.delete(resourceName);
}
}
})));
for (const forbiddenResource of unknownResources.values()) {
this.resourceAccessStatuses.set(forbiddenResource, false);
}
}
return apiResources
.filter((resource) => this.resourceAccessStatuses.get(resource))
.map(apiResource => apiResource.apiName);
} catch (error) { } catch (error) {
return []; return [];
} }
} }
isAllowedResource(kind: string): boolean { shouldShowResource(resource: KubeApiResourceDescriptor): boolean {
if ((kind as KubeResource) in apiResourceRecord) { return this.allowedResources.has(formatKubeApiResource(resource));
return this.allowedResources.includes(kind);
}
const apiResource = apiResources.find(resource => resource.kind === kind);
if (apiResource) {
return this.allowedResources.includes(apiResource.apiName);
}
return true; // allowed by default for other resources
} }
isMetricHidden(resource: ClusterMetricsResourceType): boolean { isMetricHidden(resource: ClusterMetricsResourceType): boolean {

View File

@ -1,99 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type {
V1APIGroupList,
V1APIResourceList,
V1APIVersions,
} from "@kubernetes/client-node";
import { getInjectable } from "@ogre-tools/injectable";
import k8SRequestInjectable from "../../main/k8s-request.injectable";
import loggerInjectable from "../logger.injectable";
import type { KubeApiResource } from "../rbac";
import type { Cluster } from "./cluster";
import plimit from "p-limit";
export type RequestListApiResources = () => Promise<KubeApiResource[]>;
/**
* @param proxyConfig This config's `currentContext` field must be set, and will be used as the target cluster
*/
export type ListApiResources = (cluster: Cluster) => RequestListApiResources;
interface KubeResourceListGroup {
group: string;
path: string;
}
const listApiResourcesInjectable = getInjectable({
id: "list-api-resources",
instantiate: (di): ListApiResources => {
const k8sRequest = di.inject(k8SRequestInjectable);
const logger = di.inject(loggerInjectable);
return (cluster) => {
const apiLimit = plimit(5);
return async () => {
const kubeApiResources: KubeApiResource[] = [];
const resourceListGroups: KubeResourceListGroup[] = [];
try {
await Promise.all([
(async () => {
const { versions } = await k8sRequest(cluster, "/api") as V1APIVersions;
for (const version of versions) {
resourceListGroups.push({
group: version,
path: `/api/${version}`,
});
}
})(),
(async () => {
const { groups } = await k8sRequest(cluster, "/apis") as V1APIGroupList;
for (const { preferredVersion, name } of groups) {
const { groupVersion } = preferredVersion ?? {};
if (groupVersion) {
resourceListGroups.push({
group: name,
path: `/apis/${groupVersion}`,
});
}
}
})(),
]);
await Promise.all(
resourceListGroups.map(({ group, path }) => apiLimit(async () => {
const { resources } = await k8sRequest(cluster, path) as V1APIResourceList;
for (const resource of resources) {
if (!resource.verbs.includes("list")) {
continue;
}
kubeApiResources.push({
apiName: resource.name,
kind: resource.kind,
group,
namespaced: resource.namespaced,
});
}
})),
);
} catch (error) {
logger.error(`[LIST-API-RESOURCES]: failed to list api resources: ${error}`);
}
return kubeApiResources;
};
};
},
});
export default listApiResourcesInjectable;

View File

@ -0,0 +1,83 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { V1APIGroupList, V1APIResourceList, V1APIVersions } from "@kubernetes/client-node";
import { getInjectable } from "@ogre-tools/injectable";
import k8SRequestInjectable from "../../main/k8s-request.injectable";
import loggerInjectable from "../logger.injectable";
import type { KubeApiResource } from "../rbac";
import type { Cluster } from "./cluster";
import plimit from "p-limit";
export type RequestApiResources = (cluster: Cluster) => Promise<KubeApiResource[]>;
interface KubeResourceListGroup {
group: string;
path: string;
}
const requestApiResourcesInjectable = getInjectable({
id: "request-api-resources",
instantiate: (di): RequestApiResources => {
const k8sRequest = di.inject(k8SRequestInjectable);
const logger = di.inject(loggerInjectable);
return async (cluster) => {
const apiLimit = plimit(5);
const kubeApiResources: KubeApiResource[] = [];
const resourceListGroups: KubeResourceListGroup[] = [];
try {
await Promise.all([
(async () => {
const { versions } = await k8sRequest(cluster, "/api") as V1APIVersions;
for (const version of versions) {
resourceListGroups.push({
group: version,
path: `/api/${version}`,
});
}
})(),
(async () => {
const { groups } = await k8sRequest(cluster, "/apis") as V1APIGroupList;
for (const { preferredVersion, name } of groups) {
const { groupVersion } = preferredVersion ?? {};
if (groupVersion) {
resourceListGroups.push({
group: name,
path: `/apis/${groupVersion}`,
});
}
}
})(),
]);
await Promise.all(
resourceListGroups.map(({ group, path }) => apiLimit(async () => {
const { resources } = await k8sRequest(cluster, path) as V1APIResourceList;
for (const resource of resources) {
kubeApiResources.push({
apiName: resource.name,
kind: resource.kind,
group,
namespaced: resource.namespaced,
});
}
})),
);
} catch (error) {
logger.error(`[LIST-API-RESOURCES]: failed to list api resources: ${error}`);
}
return kubeApiResources;
};
},
});
export default requestApiResourcesInjectable;

View File

@ -0,0 +1,75 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { KubeConfig } from "@kubernetes/client-node";
import { AuthorizationV1Api } from "@kubernetes/client-node";
import { getInjectable } from "@ogre-tools/injectable";
import loggerInjectable from "../logger.injectable";
import type { KubeApiResource } from "../rbac";
export type CanListResource = (resource: KubeApiResource) => boolean;
/**
* Requests the permissions for actions on the kube cluster
* @param namespace The namespace of the resources
*/
export type RequestNamespaceListPermissions = (namespace: string) => Promise<CanListResource>;
/**
* @param proxyConfig This config's `currentContext` field must be set, and will be used as the target cluster
*/
export type RequestNamespaceListPermissionsFor = (proxyConfig: KubeConfig) => RequestNamespaceListPermissions;
const requestNamespaceListPermissionsForInjectable = getInjectable({
id: "request-namespace-list-permissions-for",
instantiate: (di): RequestNamespaceListPermissionsFor => {
const logger = di.inject(loggerInjectable);
return (proxyConfig) => {
const api = proxyConfig.makeApiClient(AuthorizationV1Api);
return async (namespace) => {
try {
const { body: { status }} = await api.createSelfSubjectRulesReview({
apiVersion: "authorization.k8s.io/v1",
kind: "SelfSubjectRulesReview",
spec: { namespace },
});
if (!status || status.incomplete) {
logger.warn(`[AUTHORIZATION-NAMESPACE-REVIEW]: allowing all resources in namespace="${namespace}" due to incomplete SelfSubjectRulesReview: ${status?.evaluationError}`);
return () => true;
}
const { resourceRules } = status;
return (resource) => {
const resourceRule = resourceRules.find(rule => {
console.log(rule);
void resource;
return true;
});
if (!resourceRule) {
return false;
}
const { verbs } = resourceRule;
return verbs.includes("*") || verbs.includes("list");
};
} catch (error) {
logger.error(`[AUTHORIZATION-NAMESPACE-REVIEW]: failed to create subject rules review: ${error}`, { namespace });
return () => true;
}
};
};
},
});
export default requestNamespaceListPermissionsForInjectable;

View File

@ -3,22 +3,18 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import shouldShowResourceInjectable from "../../../../../../renderer/cluster-frame-context/should-show-resource.injectable";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const configMapsRouteInjectable = getInjectable({ const configMapsRouteInjectable = getInjectable({
id: "config-maps-route", id: "config-maps-route",
instantiate: (di) => ({
instantiate: (di) => { path: "/configmaps",
const isAllowedResource = di.inject(isAllowedResourceInjectable, "configmaps"); clusterFrame: true,
isEnabled: di.inject(shouldShowResourceInjectable, {
return { apiName: "configmaps",
path: "/configmaps", }),
clusterFrame: true, }),
isEnabled: isAllowedResource,
};
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,20 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import shouldShowResourceInjectable from "../../../../../../renderer/cluster-frame-context/should-show-resource.injectable";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const horizontalPodAutoscalersRouteInjectable = getInjectable({ const horizontalPodAutoscalersRouteInjectable = getInjectable({
id: "horizontal-pod-autoscalers-route", id: "horizontal-pod-autoscalers-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "horizontalpodautoscalers"); path: "/hpa",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectable, {
path: "/hpa", apiName: "horizontalpodautoscalers",
clusterFrame: true, group: "autoscaling",
isEnabled: isAllowedResource, }),
}; }),
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,19 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const leasesRouteInjectable = getInjectable({ const leasesRouteInjectable = getInjectable({
id: "leases", id: "leases",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "leases"); path: "/leases",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/leases", apiName: "leases",
clusterFrame: true, }),
isEnabled: isAllowedResource, }),
};
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,24 +3,19 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const limitRangesRouteInjectable = getInjectable({ const limitRangesRouteInjectable = getInjectable({
id: "limit-ranges-route", id: "limit-ranges-route",
instantiate: (di) => { instantiate: (di) => ({
const limitRangesIsAllowed = di.inject( path: "/limitranges",
isAllowedResourceInjectable, clusterFrame: true,
"limitranges", isEnabled: di.inject(shouldShowResourceInjectionToken, {
); apiName: "limitranges",
}),
return { }),
path: "/limitranges",
clusterFrame: true,
isEnabled: limitRangesIsAllowed,
};
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,20 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const podDisruptionBudgetsRouteInjectable = getInjectable({ const podDisruptionBudgetsRouteInjectable = getInjectable({
id: "pod-disruption-budgets-route", id: "pod-disruption-budgets-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "poddisruptionbudgets"); path: "/poddisruptionbudgets",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/poddisruptionbudgets", apiName: "poddisruptionbudgets",
clusterFrame: true, group: "policy",
isEnabled: isAllowedResource, }),
}; }),
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,20 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const priorityClassesRouteInjectable = getInjectable({ const priorityClassesRouteInjectable = getInjectable({
id: "priority-classes-route", id: "priority-classes-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "priorityclasses"); path: "/priorityclasses",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/priorityclasses", apiName: "priorityclasses",
clusterFrame: true, group: "scheduling.k8s.io",
isEnabled: isAllowedResource, }),
}; }),
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,19 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const resourceQuotasRouteInjectable = getInjectable({ const resourceQuotasRouteInjectable = getInjectable({
id: "resource-quotas-route", id: "resource-quotas-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "resourcequotas"); path: "/resourcequotas",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/resourcequotas", apiName: "resourcequotas",
clusterFrame: true, }),
isEnabled: isAllowedResource, }),
};
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,20 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const runtimeClassesRouteInjectable = getInjectable({ const runtimeClassesRouteInjectable = getInjectable({
id: "runtime-classes-route", id: "runtime-classes-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "runtimeclasses"); path: "/runtimeclasses",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/runtimeclasses", apiName: "runtimeclasses",
clusterFrame: true, group: "node.k8s.io",
isEnabled: isAllowedResource, }),
}; }),
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,19 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const secretsRouteInjectable = getInjectable({ const secretsRouteInjectable = getInjectable({
id: "secrets-route", id: "secrets-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "secrets"); path: "/secrets",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/secrets", apiName: "secrets",
clusterFrame: true, }),
isEnabled: isAllowedResource, }),
};
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,19 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../front-end-route-injection-token";
const eventsRouteInjectable = getInjectable({ const eventsRouteInjectable = getInjectable({
id: "events-route", id: "events-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "events"); path: "/events",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/events", apiName: "events",
clusterFrame: true, }),
isEnabled: isAllowedResource, }),
};
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,19 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../front-end-route-injection-token";
const namespacesRouteInjectable = getInjectable({ const namespacesRouteInjectable = getInjectable({
id: "namespaces-route", id: "namespaces-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "namespaces"); path: "/namespaces",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/namespaces", apiName: "namespaces",
clusterFrame: true, }),
isEnabled: isAllowedResource, }),
};
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,19 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const endpointsRouteInjectable = getInjectable({ const endpointsRouteInjectable = getInjectable({
id: "endpoints-route", id: "endpoints-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "endpoints"); path: "/endpoints",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/endpoints", apiName: "endpoints",
clusterFrame: true, }),
isEnabled: isAllowedResource, }),
};
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,27 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { computedOr } from "../../../../../utils/computed-or";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const ingressesRouteInjectable = getInjectable({ const ingressesRouteInjectable = getInjectable({
id: "ingresses-route", id: "ingresses-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "ingresses"); path: "/ingresses",
clusterFrame: true,
return { isEnabled: computedOr(
path: "/ingresses", di.inject(shouldShowResourceInjectionToken, {
clusterFrame: true, apiName: "ingresses",
isEnabled: isAllowedResource, group: "networking.k8s.io",
}; }),
}, di.inject(shouldShowResourceInjectionToken, {
apiName: "ingresses",
group: "extensions",
}),
),
}),
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,20 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const networkPoliciesRouteInjectable = getInjectable({ const networkPoliciesRouteInjectable = getInjectable({
id: "network-policies-route", id: "network-policies-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "networkpolicies"); path: "/network-policies",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/network-policies", apiName: "networkpolicies",
clusterFrame: true, group: "networking.k8s.io",
isEnabled: isAllowedResource, }),
}; }),
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,19 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const servicesRouteInjectable = getInjectable({ const servicesRouteInjectable = getInjectable({
id: "services-route", id: "services-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "services"); path: "/services",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/services", apiName: "services",
clusterFrame: true, }),
isEnabled: isAllowedResource, }),
};
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,19 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../front-end-route-injection-token";
const nodesRouteInjectable = getInjectable({ const nodesRouteInjectable = getInjectable({
id: "nodes-route", id: "nodes-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "nodes"); path: "/nodes",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/nodes", apiName: "nodes",
clusterFrame: true, }),
isEnabled: isAllowedResource, }),
};
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,19 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../front-end-route-injection-token";
const clusterOverviewRouteInjectable = getInjectable({ const clusterOverviewRouteInjectable = getInjectable({
id: "cluster-overview-route", id: "cluster-overview-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "nodes"); path: "/overview",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/overview", apiName: "nodes",
clusterFrame: true, }),
isEnabled: isAllowedResource, }),
};
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,19 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const persistentVolumeClaimsRouteInjectable = getInjectable({ const persistentVolumeClaimsRouteInjectable = getInjectable({
id: "persistent-volume-claims-route", id: "persistent-volume-claims-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "persistentvolumeclaims"); path: "/persistent-volume-claims",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/persistent-volume-claims", apiName: "persistentvolumeclaims",
clusterFrame: true, }),
isEnabled: isAllowedResource, }),
};
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,19 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const persistentVolumesRouteInjectable = getInjectable({ const persistentVolumesRouteInjectable = getInjectable({
id: "persistent-volumes-route", id: "persistent-volumes-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "persistentvolumes"); path: "/persistent-volumes",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/persistent-volumes", apiName: "persistentvolumes",
clusterFrame: true, }),
isEnabled: isAllowedResource, }),
};
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,20 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const storageClassesRouteInjectable = getInjectable({ const storageClassesRouteInjectable = getInjectable({
id: "storage-classes-route", id: "storage-classes-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "storageclasses"); path: "/storage-classes",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/storage-classes", apiName: "storageclasses",
clusterFrame: true, group: "storage.k8s.io",
isEnabled: isAllowedResource, }),
}; }),
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,20 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const clusterRoleBindingsRouteInjectable = getInjectable({ const clusterRoleBindingsRouteInjectable = getInjectable({
id: "cluster-role-bindings-route", id: "cluster-role-bindings-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "clusterrolebindings"); path: "/cluster-role-bindings",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/cluster-role-bindings", apiName: "clusterrolebindings",
clusterFrame: true, group: "rbac.authorization.k8s.io",
isEnabled: isAllowedResource, }),
}; }),
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,20 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const clusterRolesRouteInjectable = getInjectable({ const clusterRolesRouteInjectable = getInjectable({
id: "cluster-roles-route", id: "cluster-roles-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "clusterroles"); path: "/cluster-roles",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/cluster-roles", apiName: "clusterroles",
clusterFrame: true, group: "rbac.authorization.k8s.io",
isEnabled: isAllowedResource, }),
}; }),
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,19 +3,20 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const podSecurityPoliciesRouteInjectable = getInjectable({ const podSecurityPoliciesRouteInjectable = getInjectable({
id: "pod-security-policies-route", id: "pod-security-policies-route",
instantiate: (di) => { instantiate: (di) => {
const isAllowedResource = di.inject(isAllowedResourceInjectable, "podsecuritypolicies");
return { return {
path: "/pod-security-policies", path: "/pod-security-policies",
clusterFrame: true, clusterFrame: true,
isEnabled: isAllowedResource, isEnabled: di.inject(shouldShowResourceInjectionToken, {
apiName: "podsecuritypolicies",
group: "policy",
}),
}; };
}, },

View File

@ -3,19 +3,20 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const roleBindingsRouteInjectable = getInjectable({ const roleBindingsRouteInjectable = getInjectable({
id: "role-bindings-route", id: "role-bindings-route",
instantiate: (di) => { instantiate: (di) => {
const isAllowedResource = di.inject(isAllowedResourceInjectable, "rolebindings");
return { return {
path: "/role-bindings", path: "/role-bindings",
clusterFrame: true, clusterFrame: true,
isEnabled: isAllowedResource, isEnabled: di.inject(shouldShowResourceInjectionToken, {
apiName: "rolebindings",
group: "rbac.authorization.k8s.io",
}),
}; };
}, },

View File

@ -3,21 +3,20 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const rolesRouteInjectable = getInjectable({ const rolesRouteInjectable = getInjectable({
id: "roles-route", id: "roles-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "roles"); path: "/roles",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/roles", apiName: "roles",
clusterFrame: true, group: "rbac.authorization.k8s.io",
isEnabled: isAllowedResource, }),
}; }),
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,19 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const serviceAccountsRouteInjectable = getInjectable({ const serviceAccountsRouteInjectable = getInjectable({
id: "service-accounts-route", id: "service-accounts-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "serviceaccounts"); path: "/service-accounts",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/service-accounts", apiName: "serviceaccounts",
clusterFrame: true, }),
isEnabled: isAllowedResource, }),
};
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,20 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const cronJobsRouteInjectable = getInjectable({ const cronJobsRouteInjectable = getInjectable({
id: "cron-jobs-route", id: "cron-jobs-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "cronjobs"); path: "/cronjobs",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/cronjobs", apiName: "cronjobs",
clusterFrame: true, group: "batch",
isEnabled: isAllowedResource, }),
}; }),
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,20 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const daemonsetsRouteInjectable = getInjectable({ const daemonsetsRouteInjectable = getInjectable({
id: "daemonsets-route", id: "daemonsets-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "daemonsets"); path: "/daemonsets",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/daemonsets", apiName: "daemonsets",
clusterFrame: true, group: "apps",
isEnabled: isAllowedResource, }),
}; }),
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,20 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const deploymentsRouteInjectable = getInjectable({ const deploymentsRouteInjectable = getInjectable({
id: "deployments-route", id: "deployments-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "deployments"); path: "/deployments",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/deployments", apiName: "deployments",
clusterFrame: true, group: "apps",
isEnabled: isAllowedResource, }),
}; }),
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,20 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const jobsRouteInjectable = getInjectable({ const jobsRouteInjectable = getInjectable({
id: "jobs-route", id: "jobs-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "jobs"); path: "/jobs",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/jobs", apiName: "jobs",
clusterFrame: true, group: "batch",
isEnabled: isAllowedResource, }),
}; }),
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,19 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const podsRouteInjectable = getInjectable({ const podsRouteInjectable = getInjectable({
id: "pods-route", id: "pods-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "pods"); path: "/pods",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/pods", apiName: "pods",
clusterFrame: true, }),
isEnabled: isAllowedResource, }),
};
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,20 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const replicasetsRouteInjectable = getInjectable({ const replicasetsRouteInjectable = getInjectable({
id: "replicasets-route", id: "replicasets-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "replicasets"); path: "/replicasets",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/replicasets", apiName: "replicasets",
clusterFrame: true, group: "apps",
isEnabled: isAllowedResource, }),
}; }),
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,21 +3,20 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import isAllowedResourceInjectable from "../../../../../utils/is-allowed-resource.injectable"; import { shouldShowResourceInjectionToken } from "../../../../../cluster-store/allowed-resources-injection-token";
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
const statefulsetsRouteInjectable = getInjectable({ const statefulsetsRouteInjectable = getInjectable({
id: "statefulsets-route", id: "statefulsets-route",
instantiate: (di) => { instantiate: (di) => ({
const isAllowedResource = di.inject(isAllowedResourceInjectable, "statefulsets"); path: "/statefulsets",
clusterFrame: true,
return { isEnabled: di.inject(shouldShowResourceInjectionToken, {
path: "/statefulsets", apiName: "statefulsets",
clusterFrame: true, group: "apps",
isEnabled: isAllowedResource, }),
}; }),
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -3,6 +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 type { DiContainer } from "@ogre-tools/injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../../renderer/cluster-frame-context/for-namespaced-resources.injectable";
import { getDiForUnitTesting } from "../../../renderer/getDiForUnitTesting"; import { getDiForUnitTesting } from "../../../renderer/getDiForUnitTesting";
import type { ApiManager } from "../api-manager"; import type { ApiManager } from "../api-manager";
import apiManagerInjectable from "../api-manager/manager.injectable"; import apiManagerInjectable from "../api-manager/manager.injectable";
@ -22,10 +24,10 @@ class TestStore extends KubeObjectStore<KubeObject, TestApi> {
describe("ApiManager", () => { describe("ApiManager", () => {
let apiManager: ApiManager; let apiManager: ApiManager;
let di: DiContainer;
beforeEach(() => { beforeEach(() => {
const di = getDiForUnitTesting({ doGeneralOverrides: true }); di = getDiForUnitTesting({ doGeneralOverrides: true });
apiManager = di.inject(apiManagerInjectable); apiManager = di.inject(apiManagerInjectable);
}); });
@ -40,7 +42,9 @@ describe("ApiManager", () => {
fallbackApiBases: [fallbackApiBase], fallbackApiBases: [fallbackApiBase],
checkPreferredVersion: true, checkPreferredVersion: true,
}); });
const kubeStore = new TestStore(kubeApi); const kubeStore = new TestStore({
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, kubeApi);
apiManager.registerApi(apiBase, kubeApi); apiManager.registerApi(apiBase, kubeApi);

View File

@ -3,27 +3,23 @@
* 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 { Cluster } from "../../cluster/cluster";
import type { ClusterContext } from "../cluster-context";
import type { KubeApi } from "../kube-api"; import type { KubeApi } from "../kube-api";
import { KubeObject } from "../kube-object"; import { KubeObject } from "../kube-object";
import type { KubeObjectStoreLoadingParams } from "../kube-object.store"; import type { KubeObjectStoreLoadingParams } from "../kube-object.store";
import { KubeObjectStore } from "../kube-object.store"; import { KubeObjectStore } from "../kube-object.store";
class FakeKubeObjectStore extends KubeObjectStore<KubeObject> { class FakeKubeObjectStore extends KubeObjectStore<KubeObject> {
_context = {
allNamespaces: [],
contextNamespaces: [],
hasSelectedAll: false,
cluster: {} as Cluster,
} as ClusterContext;
get context() {
return this._context;
}
constructor(private readonly _loadItems: (params: KubeObjectStoreLoadingParams) => KubeObject[], api: Partial<KubeApi<KubeObject>>) { constructor(private readonly _loadItems: (params: KubeObjectStoreLoadingParams) => KubeObject[], api: Partial<KubeApi<KubeObject>>) {
super(api as KubeApi<KubeObject>); super({
context: {
allNamespaces: [],
contextNamespaces: [],
hasSelectedAll: false,
isGlobalWatchEnabled: () => true,
isLoadingAll: () => true,
isNamespaceListStatic: () => false,
},
}, api as KubeApi<KubeObject>);
} }
async loadItems(params: KubeObjectStoreLoadingParams) { async loadItems(params: KubeObjectStoreLoadingParams) {

View File

@ -3,9 +3,11 @@
* 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 } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../../renderer/cluster-frame-context/for-namespaced-resources.injectable";
import type { CustomResourceDefinition } from "../endpoints"; import type { CustomResourceDefinition } from "../endpoints";
import { KubeApi } from "../kube-api"; import { KubeApi } from "../kube-api";
import { KubeObject } from "../kube-object"; import { KubeObject } from "../kube-object";
import type { KubeObjectStoreDependencies } from "../kube-object.store";
import autoRegistrationEmitterInjectable from "./auto-registration-emitter.injectable"; import autoRegistrationEmitterInjectable from "./auto-registration-emitter.injectable";
import apiManagerInjectable from "./manager.injectable"; import apiManagerInjectable from "./manager.injectable";
import { CustomResourceStore } from "./resource.store"; import { CustomResourceStore } from "./resource.store";
@ -16,6 +18,9 @@ const autoRegistrationInjectable = getInjectable({
const autoRegistrationEmitter = di.inject(autoRegistrationEmitterInjectable); const autoRegistrationEmitter = di.inject(autoRegistrationEmitterInjectable);
const beforeApiManagerInitializationCrds: CustomResourceDefinition[] = []; const beforeApiManagerInitializationCrds: CustomResourceDefinition[] = [];
const beforeApiManagerInitializationApis: KubeApi[] = []; const beforeApiManagerInitializationApis: KubeApi[] = [];
const deps: KubeObjectStoreDependencies = {
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
};
let initialized = false; let initialized = false;
const autoInitCustomResourceStore = (crd: CustomResourceDefinition) => { const autoInitCustomResourceStore = (crd: CustomResourceDefinition) => {
@ -40,7 +45,7 @@ const autoRegistrationInjectable = getInjectable({
})(); })();
if (!apiManager.getStore(api)) { if (!apiManager.getStore(api)) {
apiManager.registerStore(new CustomResourceStore(api)); apiManager.registerStore(new CustomResourceStore(deps, api));
} }
}; };
const autoInitKubeApi = (api: KubeApi) => { const autoInitKubeApi = (api: KubeApi) => {

View File

@ -4,11 +4,12 @@
*/ */
import type { KubeApi } from "../kube-api"; import type { KubeApi } from "../kube-api";
import type { KubeObjectStoreDependencies } from "../kube-object.store";
import { KubeObjectStore } from "../kube-object.store"; import { KubeObjectStore } from "../kube-object.store";
import type { KubeObject } from "../kube-object"; import type { KubeObject } from "../kube-object";
export class CustomResourceStore<K extends KubeObject> extends KubeObjectStore<K, KubeApi<K>> { export class CustomResourceStore<K extends KubeObject> extends KubeObjectStore<K, KubeApi<K>> {
constructor(api: KubeApi<K>) { constructor(deps: KubeObjectStoreDependencies, api: KubeApi<K>) {
super(api); super(deps, api);
} }
} }

View File

@ -1,13 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { Cluster } from "../cluster/cluster";
export interface ClusterContext {
cluster: Cluster;
allNamespaces: string[]; // available / allowed namespaces from cluster.ts
contextNamespaces: string[]; // selected by user (see: namespace-select.tsx)
hasSelectedAll: boolean;
}

View File

@ -3,11 +3,9 @@
* 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 { ClusterContext } from "./cluster-context"; import { action, computed, makeObservable, observable, reaction } from "mobx";
import { action, computed, makeObservable, observable, reaction, when } from "mobx";
import type { Disposer } from "../utils"; import type { Disposer } from "../utils";
import { waitUntilDefined, autoBind, includes, noop, rejectPromiseBy } from "../utils"; import { waitUntilDefined, autoBind, includes, rejectPromiseBy } from "../utils";
import type { KubeJsonApiDataFor, KubeObject } from "./kube-object"; import type { KubeJsonApiDataFor, KubeObject } from "./kube-object";
import { KubeStatus } from "./kube-object"; import { KubeStatus } from "./kube-object";
import type { IKubeWatchEvent } from "./kube-watch-event"; import type { IKubeWatchEvent } from "./kube-watch-event";
@ -21,6 +19,7 @@ import assert from "assert";
import type { PartialDeep } from "type-fest"; import type { PartialDeep } from "type-fest";
import { entries } from "../utils/objects"; import { entries } from "../utils/objects";
import AbortController from "abort-controller"; import AbortController from "abort-controller";
import type { ClusterContext } from "../../renderer/cluster-frame-context/cluster-frame-context";
export type OnLoadFailure = (error: unknown) => void; export type OnLoadFailure = (error: unknown) => void;
@ -85,38 +84,26 @@ export type KubeApiDataFrom<K extends KubeObject, A> = A extends KubeApi<K, infe
export type JsonPatch = Patch; export type JsonPatch = Patch;
export interface KubeObjectStoreDependencies {
readonly context: ClusterContext;
}
export abstract class KubeObjectStore< export abstract class KubeObjectStore<
K extends KubeObject = KubeObject, K extends KubeObject = KubeObject,
A extends KubeApi<K, D> = KubeApi<K, KubeJsonApiDataFor<K>>, A extends KubeApi<K, D> = KubeApi<K, KubeJsonApiDataFor<K>>,
D extends KubeJsonApiDataFor<K> = KubeApiDataFrom<K, A>, D extends KubeJsonApiDataFor<K> = KubeApiDataFrom<K, A>,
> extends ItemStore<K> { > extends ItemStore<K> {
static readonly defaultContext = observable.box<ClusterContext>(); // TODO: support multiple cluster contexts
public readonly api!: A;
public readonly limit: number | undefined; public readonly limit: number | undefined;
public readonly bufferSize: number; public readonly bufferSize: number;
@observable private loadedNamespaces: string[] | undefined = undefined;
get contextReady() { private readonly loadedNamespaces = observable.box<string[]>();
return when(() => Boolean(this.context));
}
get namespacesReady() { constructor(
return when(() => Boolean(this.loadedNamespaces)); protected readonly dependencies: KubeObjectStoreDependencies,
} public readonly api: A,
opts?: KubeObjectStoreOptions,
constructor(api: A, opts?: KubeObjectStoreOptions); ) {
/**
* @deprecated Supply API instance through constructor
*/
constructor();
constructor(api?: A, opts?: KubeObjectStoreOptions) {
super(); super();
if (api) {
this.api = api;
}
this.limit = opts?.limit; this.limit = opts?.limit;
this.bufferSize = opts?.bufferSize ?? 50_000; this.bufferSize = opts?.bufferSize ?? 50_000;
@ -125,13 +112,9 @@ export abstract class KubeObjectStore<
this.bindWatchEventsUpdater(); this.bindWatchEventsUpdater();
} }
get context(): ClusterContext | undefined {
return KubeObjectStore.defaultContext.get();
}
// TODO: Circular dependency: KubeObjectStore -> ClusterFrameContext -> NamespaceStore -> KubeObjectStore // TODO: Circular dependency: KubeObjectStore -> ClusterFrameContext -> NamespaceStore -> KubeObjectStore
@computed get contextItems(): K[] { @computed get contextItems(): K[] {
const namespaces = this.context?.contextNamespaces ?? []; const namespaces = this.dependencies.context.contextNamespaces;
return this.items.filter(item => { return this.items.filter(item => {
const itemNamespace = item.getNs(); const itemNamespace = item.getNs();
@ -202,17 +185,11 @@ export abstract class KubeObjectStore<
} }
protected async loadItems({ namespaces, reqInit, onLoadFailure }: KubeObjectStoreLoadingParams): Promise<K[]> { protected async loadItems({ namespaces, reqInit, onLoadFailure }: KubeObjectStoreLoadingParams): Promise<K[]> {
if (!this.context?.cluster?.isAllowedResource(this.api.kind)) { const isLoadingAll = this.dependencies.context.isLoadingAll(namespaces);
return [];
}
const isLoadingAll = this.context.allNamespaces?.length > 1
&& this.context.cluster.accessibleNamespaces.length === 0
&& this.context.allNamespaces.every(ns => namespaces.includes(ns));
if (!this.api.isNamespaced || isLoadingAll) { if (!this.api.isNamespaced || isLoadingAll) {
if (this.api.isNamespaced) { if (this.api.isNamespaced) {
this.loadedNamespaces = []; this.loadedNamespaces.set([]);
} }
const res = this.api.list({ reqInit }, this.query); const res = this.api.list({ reqInit }, this.query);
@ -234,7 +211,7 @@ export abstract class KubeObjectStore<
return await res ?? []; return await res ?? [];
} }
this.loadedNamespaces = namespaces; this.loadedNamespaces.set(namespaces);
const results = await Promise.allSettled( const results = await Promise.allSettled(
namespaces.map(namespace => this.api.list({ namespace, reqInit }, this.query)), namespaces.map(namespace => this.api.list({ namespace, reqInit }, this.query)),
@ -266,9 +243,7 @@ export abstract class KubeObjectStore<
@action @action
async loadAll({ namespaces, merge = true, reqInit, onLoadFailure }: KubeObjectStoreLoadAllParams = {}): Promise<undefined | K[]> { async loadAll({ namespaces, merge = true, reqInit, onLoadFailure }: KubeObjectStoreLoadAllParams = {}): Promise<undefined | K[]> {
const context = await waitUntilDefined(() => this.context); namespaces ??= this.dependencies.context.contextNamespaces;
namespaces ??= context.contextNamespaces;
this.isLoading = true; this.isLoading = true;
try { try {
@ -425,7 +400,7 @@ export abstract class KubeObjectStore<
} }
// collect items from watch-api events to avoid UI blowing up with huge streams of data // collect items from watch-api events to avoid UI blowing up with huge streams of data
protected eventsBuffer = observable.array<IKubeWatchEvent<D>>([], { deep: false }); protected readonly eventsBuffer = observable.array<IKubeWatchEvent<D>>([], { deep: false });
protected bindWatchEventsUpdater(delay = 1000) { protected bindWatchEventsUpdater(delay = 1000) {
reaction(() => [...this.eventsBuffer], this.updateFromEventsBuffer, { reaction(() => [...this.eventsBuffer], this.updateFromEventsBuffer, {
@ -435,25 +410,24 @@ export abstract class KubeObjectStore<
subscribe({ onLoadFailure, abortController = new AbortController() }: KubeObjectStoreSubscribeParams = {}): Disposer { subscribe({ onLoadFailure, abortController = new AbortController() }: KubeObjectStoreSubscribeParams = {}): Disposer {
if (this.api.isNamespaced) { if (this.api.isNamespaced) {
Promise.race([ void (async () => {
rejectPromiseBy(abortController.signal), try {
Promise.all([ const [loadedNamespaces] = await Promise.race([
waitUntilDefined(() => this.context), rejectPromiseBy(abortController.signal),
this.namespacesReady, waitUntilDefined(() => this.loadedNamespaces.get()),
] as const), ]);
])
.then(([context]) => {
assert(this.loadedNamespaces);
if (context.cluster?.isGlobalWatchEnabled && this.loadedNamespaces.length === 0) { if (this.dependencies.context.isGlobalWatchEnabled() && loadedNamespaces.length === 0) {
return this.watchNamespace("", abortController, { onLoadFailure }); this.watchNamespace("", abortController, { onLoadFailure });
} else {
for (const namespace of loadedNamespaces) {
this.watchNamespace(namespace, abortController, { onLoadFailure });
}
} }
} catch {
for (const namespace of this.loadedNamespaces) { // ignore
this.watchNamespace(namespace, abortController, { onLoadFailure }); }
} })();
})
.catch(noop); // ignore DOMExceptions
} else { } else {
this.watchNamespace("", abortController, { onLoadFailure }); this.watchNamespace("", abortController, { onLoadFailure });
} }

View File

@ -11,11 +11,22 @@ export type KubeResource =
"priorityclasses" | "runtimeclasses" | "priorityclasses" | "runtimeclasses" |
"roles" | "clusterroles" | "rolebindings" | "clusterrolebindings" | "serviceaccounts"; "roles" | "clusterroles" | "rolebindings" | "clusterrolebindings" | "serviceaccounts";
export interface KubeApiResource extends KubeApiResourceData { export interface KubeApiResource extends KubeApiResourceData, KubeApiResourceDescriptor {
apiName: string; apiName: string;
namespaced: boolean; namespaced: boolean;
} }
export interface KubeApiResourceDescriptor {
apiName: string;
group?: string;
}
export const formatKubeApiResource = (res: KubeApiResourceDescriptor) => (
res.group
? `${res.group}/${res.apiName}`
: res.apiName
);
export interface KubeApiResourceData { export interface KubeApiResourceData {
kind: string; // resource type (e.g. "Namespace") kind: string; // resource type (e.g. "Namespace")
group?: string; // api-group group?: string; // api-group

View File

@ -0,0 +1,11 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { IComputedValue } from "mobx";
import { computed } from "mobx";
export const computedOr = (...values: IComputedValue<boolean>[]) => computed((
() => values.some(value => value.get())
));

View File

@ -1,26 +0,0 @@
/**
* 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 { KubeResource } from "../rbac";
import { allowedResourcesInjectionToken } from "../cluster-store/allowed-resources-injection-token";
export type IsAllowedResource = (resource: KubeResource) => boolean;
const isAllowedResourceInjectable = getInjectable({
id: "is-allowed-resource",
instantiate: (di, resourceName: string) => {
const allowedResources = di.inject(allowedResourcesInjectionToken);
return computed(() => allowedResources.get().has(resourceName));
},
lifecycle: lifecycleEnum.keyedSingleton({
getInstanceKey: (di, resource: string) => resource,
}),
});
export default isAllowedResourceInjectable;

View File

@ -15,6 +15,11 @@ import type { ResourceApplyingStack } from "../../common/k8s/resource-stack";
import { asLegacyGlobalFunctionForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api"; import { asLegacyGlobalFunctionForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-function-for-extension-api";
import { asLegacyGlobalForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; import { asLegacyGlobalForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api";
import type { KubernetesCluster } from "./catalog"; import type { KubernetesCluster } from "./catalog";
import type { KubeApiDataFrom, KubeObjectStoreOptions } from "../../common/k8s-api/kube-object.store";
import { KubeObjectStore as InternalKubeObjectStore } from "../../common/k8s-api/kube-object.store";
import type { KubeJsonApiDataFor, KubeObject } from "../../common/k8s-api/kube-object";
import type { KubeApi } from "../../common/k8s-api/kube-api";
import clusterFrameContextForNamespacedResourcesInjectable from "../../renderer/cluster-frame-context/for-namespaced-resources.injectable";
export const apiManager = asLegacyGlobalForExtensionApi(apiManagerInjectable); export const apiManager = asLegacyGlobalForExtensionApi(apiManagerInjectable);
export const forCluster = asLegacyGlobalFunctionForExtensionApi(createKubeApiForClusterInjectable); export const forCluster = asLegacyGlobalFunctionForExtensionApi(createKubeApiForClusterInjectable);
@ -72,8 +77,33 @@ export {
type KubeJsonApiData, type KubeJsonApiData,
} from "../../common/k8s-api/kube-json-api"; } from "../../common/k8s-api/kube-json-api";
export abstract class KubeObjectStore<
K extends KubeObject = KubeObject,
A extends KubeApi<K, D> = KubeApi<K, KubeJsonApiDataFor<K>>,
D extends KubeJsonApiDataFor<K> = KubeApiDataFrom<K, A>,
> extends InternalKubeObjectStore<K, A, D> {
get context() {
return this.dependencies.context;
}
constructor(api: A, opts?: KubeObjectStoreOptions);
/**
* @deprecated Supply API instance through constructor
*/
constructor();
constructor(api?: A, opts?: KubeObjectStoreOptions) {
super(
{
context: asLegacyGlobalForExtensionApi(clusterFrameContextForNamespacedResourcesInjectable),
},
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
api!,
opts,
);
}
}
export { export {
KubeObjectStore,
type JsonPatch, type JsonPatch,
type KubeObjectStoreLoadAllParams, type KubeObjectStoreLoadAllParams,
type KubeObjectStoreLoadingParams, type KubeObjectStoreLoadingParams,

View File

@ -3,8 +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 type { KubeResource } from "../../common/rbac"; import type { KubeResource } from "../../common/rbac";
import isAllowedResourceInjectable from "../../common/utils/is-allowed-resource.injectable"; import { apiResourceRecord } from "../../common/rbac";
import { castArray } from "lodash/fp";
import { getLegacyGlobalDiForExtensionApi } from "../as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; import { getLegacyGlobalDiForExtensionApi } from "../as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
import clusterRoleBindingApiInjectable from "../../common/k8s-api/endpoints/cluster-role-binding.api.injectable"; import clusterRoleBindingApiInjectable from "../../common/k8s-api/endpoints/cluster-role-binding.api.injectable";
import clusterRoleApiInjectable from "../../common/k8s-api/endpoints/cluster-role.api.injectable"; import clusterRoleApiInjectable from "../../common/k8s-api/endpoints/cluster-role.api.injectable";
@ -37,13 +36,22 @@ import namespaceApiInjectable from "../../common/k8s-api/endpoints/namespace.api
import kubeEventApiInjectable from "../../common/k8s-api/endpoints/events.api.injectable"; import kubeEventApiInjectable from "../../common/k8s-api/endpoints/events.api.injectable";
import roleBindingApiInjectable from "../../common/k8s-api/endpoints/role-binding.api.injectable"; import roleBindingApiInjectable from "../../common/k8s-api/endpoints/role-binding.api.injectable";
import customResourceDefinitionApiInjectable from "../../common/k8s-api/endpoints/custom-resource-definition.api.injectable"; import customResourceDefinitionApiInjectable from "../../common/k8s-api/endpoints/custom-resource-definition.api.injectable";
import { shouldShowResourceInjectionToken } from "../../common/cluster-store/allowed-resources-injection-token";
export function isAllowedResource(resource: KubeResource | KubeResource[]) { export function isAllowedResource(resources: KubeResource | KubeResource[]) {
const resources = castArray(resource);
const di = getLegacyGlobalDiForExtensionApi(); const di = getLegacyGlobalDiForExtensionApi();
return resources.every((resourceName: any) => { return [resources].flat().every((resourceName) => {
const _isAllowedResource = di.inject(isAllowedResourceInjectable, resourceName); const resource = apiResourceRecord[resourceName];
if (!resource) {
return true;
}
const _isAllowedResource = di.inject(shouldShowResourceInjectionToken, {
apiName: resourceName,
group: resource.group,
});
// Note: Legacy isAllowedResource does not advertise reactivity // Note: Legacy isAllowedResource does not advertise reactivity
return _isAllowedResource.get(); return _isAllowedResource.get();

View File

@ -9,11 +9,11 @@ import { sidebarItemsInjectionToken } from "../../renderer/components/layout/sid
import { computed, runInAction } from "mobx"; import { computed, runInAction } from "mobx";
import { routeSpecificComponentInjectionToken } from "../../renderer/routes/route-specific-component-injection-token"; import { routeSpecificComponentInjectionToken } from "../../renderer/routes/route-specific-component-injection-token";
import React from "react"; import React from "react";
import isAllowedResourceInjectable from "../../common/utils/is-allowed-resource.injectable";
import { frontEndRouteInjectionToken } from "../../common/front-end-routing/front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../common/front-end-routing/front-end-route-injection-token";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token"; import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token";
import { shouldShowResourceInjectionToken } from "../../common/cluster-store/allowed-resources-injection-token";
describe("cluster - visibility of sidebar items", () => { describe("cluster - visibility of sidebar items", () => {
let builder: ApplicationBuilder; let builder: ApplicationBuilder;
@ -69,20 +69,13 @@ describe("cluster - visibility of sidebar items", () => {
const testRouteInjectable = getInjectable({ const testRouteInjectable = getInjectable({
id: "some-route-injectable-id", id: "some-route-injectable-id",
instantiate: (di) => { instantiate: (di) => ({
const someKubeResourceName = "namespaces"; path: "/some-child-page",
clusterFrame: true,
const kubeResourceIsAllowed = di.inject( isEnabled: di.inject(shouldShowResourceInjectionToken, {
isAllowedResourceInjectable, apiName: "namespaces",
someKubeResourceName, }),
); }),
return {
path: "/some-child-page",
isEnabled: kubeResourceIsAllowed,
clusterFrame: true,
};
},
injectionToken: frontEndRouteInjectionToken, injectionToken: frontEndRouteInjectionToken,
}); });

View File

@ -10,7 +10,7 @@ import { getDiForUnitTesting } from "../getDiForUnitTesting";
import type { CreateCluster } from "../../common/cluster/create-cluster-injection-token"; import type { CreateCluster } from "../../common/cluster/create-cluster-injection-token";
import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token"; import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token";
import authorizationReviewInjectable from "../../common/cluster/authorization-review.injectable"; import authorizationReviewInjectable from "../../common/cluster/authorization-review.injectable";
import authorizationNamespaceReviewInjectable from "../../common/cluster/authorization-namespace-review.injectable"; import requestNamespaceListPermissionsForInjectable from "../../common/cluster/request-namespace-list-permissions.injectable";
import listNamespacesInjectable from "../../common/cluster/list-namespaces.injectable"; import listNamespacesInjectable from "../../common/cluster/list-namespaces.injectable";
import createContextHandlerInjectable from "../context-handler/create-context-handler.injectable"; import createContextHandlerInjectable from "../context-handler/create-context-handler.injectable";
import type { ClusterContextHandler } from "../context-handler/context-handler"; import type { ClusterContextHandler } from "../context-handler/context-handler";
@ -20,8 +20,6 @@ import directoryForTempInjectable from "../../common/app-paths/directory-for-tem
import normalizedPlatformInjectable from "../../common/vars/normalized-platform.injectable"; import normalizedPlatformInjectable from "../../common/vars/normalized-platform.injectable";
import kubectlBinaryNameInjectable from "../kubectl/binary-name.injectable"; import kubectlBinaryNameInjectable from "../kubectl/binary-name.injectable";
import kubectlDownloadingNormalizedArchInjectable from "../kubectl/normalized-arch.injectable"; import kubectlDownloadingNormalizedArchInjectable from "../kubectl/normalized-arch.injectable";
import { apiResourceRecord, apiResources } from "../../common/rbac";
import listApiResourcesInjectable from "../../common/cluster/list-api-resources.injectable";
import pathExistsSyncInjectable from "../../common/fs/path-exists-sync.injectable"; import pathExistsSyncInjectable from "../../common/fs/path-exists-sync.injectable";
import pathExistsInjectable from "../../common/fs/path-exists.injectable"; import pathExistsInjectable from "../../common/fs/path-exists.injectable";
import readJsonSyncInjectable from "../../common/fs/read-json-sync.injectable"; import readJsonSyncInjectable from "../../common/fs/read-json-sync.injectable";
@ -46,8 +44,7 @@ describe("create clusters", () => {
di.override(normalizedPlatformInjectable, () => "darwin"); di.override(normalizedPlatformInjectable, () => "darwin");
di.override(broadcastMessageInjectable, () => async () => {}); di.override(broadcastMessageInjectable, () => async () => {});
di.override(authorizationReviewInjectable, () => () => () => Promise.resolve(true)); di.override(authorizationReviewInjectable, () => () => () => Promise.resolve(true));
di.override(authorizationNamespaceReviewInjectable, () => () => () => Promise.resolve(Object.keys(apiResourceRecord))); di.override(requestNamespaceListPermissionsForInjectable, () => () => async () => () => true);
di.override(listApiResourcesInjectable, () => () => () => Promise.resolve(apiResources));
di.override(listNamespacesInjectable, () => () => () => Promise.resolve([ "default" ])); di.override(listNamespacesInjectable, () => () => () => Promise.resolve([ "default" ]));
di.override(createContextHandlerInjectable, () => (cluster) => ({ di.override(createContextHandlerInjectable, () => (cluster) => ({
restartServer: jest.fn(), restartServer: jest.fn(),

View File

@ -4,13 +4,13 @@
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx"; import { computed } from "mobx";
import { allowedResourcesInjectionToken } from "../../common/cluster-store/allowed-resources-injection-token"; import { shouldShowResourceInjectionToken } from "../../common/cluster-store/allowed-resources-injection-token";
// TODO: Figure out implementation for this later. // TODO: Figure out implementation for this later.
const allowedResourcesInjectable = getInjectable({ const allowedResourcesInjectable = getInjectable({
id: "allowed-resources", id: "allowed-resources",
instantiate: () => computed(() => new Set<string>()), instantiate: () => computed(() => new Set<string>()),
injectionToken: allowedResourcesInjectionToken, injectionToken: shouldShowResourceInjectionToken,
}); });
export default allowedResourcesInjectable; export default allowedResourcesInjectable;

View File

@ -11,9 +11,9 @@ import createKubectlInjectable from "../kubectl/create-kubectl.injectable";
import createContextHandlerInjectable from "../context-handler/create-context-handler.injectable"; import createContextHandlerInjectable from "../context-handler/create-context-handler.injectable";
import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token"; import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token";
import authorizationReviewInjectable from "../../common/cluster/authorization-review.injectable"; import authorizationReviewInjectable from "../../common/cluster/authorization-review.injectable";
import createAuthorizationNamespaceReview from "../../common/cluster/authorization-namespace-review.injectable"; import createAuthorizationNamespaceReview from "../../common/cluster/request-namespace-list-permissions.injectable";
import listNamespacesInjectable from "../../common/cluster/list-namespaces.injectable"; import listNamespacesInjectable from "../../common/cluster/list-namespaces.injectable";
import createListApiResourcesInjectable from "../../common/cluster/list-api-resources.injectable"; import createListApiResourcesInjectable from "../../common/cluster/request-api-resources.injectable";
import loggerInjectable from "../../common/logger.injectable"; import loggerInjectable from "../../common/logger.injectable";
import detectorRegistryInjectable from "../cluster-detectors/detector-registry.injectable"; import detectorRegistryInjectable from "../cluster-detectors/detector-registry.injectable";
import createVersionDetectorInjectable from "../cluster-detectors/create-version-detector.injectable"; import createVersionDetectorInjectable from "../cluster-detectors/create-version-detector.injectable";
@ -31,7 +31,7 @@ const createClusterInjectable = getInjectable({
createContextHandler: di.inject(createContextHandlerInjectable), createContextHandler: di.inject(createContextHandlerInjectable),
createAuthorizationReview: di.inject(authorizationReviewInjectable), createAuthorizationReview: di.inject(authorizationReviewInjectable),
createAuthorizationNamespaceReview: di.inject(createAuthorizationNamespaceReview), createAuthorizationNamespaceReview: di.inject(createAuthorizationNamespaceReview),
createListApiResources: di.inject(createListApiResourcesInjectable), requestApiResources: di.inject(createListApiResourcesInjectable),
createListNamespaces: di.inject(listNamespacesInjectable), createListNamespaces: di.inject(listNamespacesInjectable),
logger: di.inject(loggerInjectable), logger: di.inject(loggerInjectable),
detectorRegistry: di.inject(detectorRegistryInjectable), detectorRegistry: di.inject(detectorRegistryInjectable),

View File

@ -1,25 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { comparer, computed } from "mobx";
import hostedClusterInjectable from "./hosted-cluster.injectable";
import { allowedResourcesInjectionToken } from "../../common/cluster-store/allowed-resources-injection-token";
const allowedResourcesInjectable = getInjectable({
id: "allowed-resources",
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),
});
},
injectionToken: allowedResourcesInjectionToken,
});
export default allowedResourcesInjectable;

View File

@ -1,25 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { ClusterFrameContext } from "./cluster-frame-context";
import namespaceStoreInjectable from "../components/+namespaces/store.injectable";
import hostedClusterInjectable from "./hosted-cluster.injectable";
import assert from "assert";
const clusterFrameContextInjectable = getInjectable({
id: "cluster-frame-context",
instantiate: (di) => {
const cluster = di.inject(hostedClusterInjectable);
assert(cluster, "This can only be injected within a cluster frame");
return new ClusterFrameContext(cluster, {
namespaceStore: di.inject(namespaceStoreInjectable),
});
},
});
export default clusterFrameContextInjectable;

View File

@ -3,44 +3,15 @@
* 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 { Cluster } from "../../common/cluster/cluster"; /**
import type { NamespaceStore } from "../components/+namespaces/store"; * This type is used for KubeObjectStores
import type { ClusterContext } from "../../common/k8s-api/cluster-context"; */
import { computed, makeObservable } from "mobx"; export interface ClusterContext {
readonly allNamespaces: string[]; // available / allowed namespaces from cluster.ts
readonly contextNamespaces: string[]; // selected by user (see: namespace-select.tsx)
readonly hasSelectedAll: boolean;
interface Dependencies { isNamespaceListStatic(): boolean;
namespaceStore: NamespaceStore; isLoadingAll(namespaces: string[]): boolean;
} isGlobalWatchEnabled(): boolean;
export class ClusterFrameContext implements ClusterContext {
constructor(public cluster: Cluster, private dependencies: Dependencies) {
makeObservable(this);
}
@computed get allNamespaces(): string[] {
// user given list of namespaces
if (this.cluster.accessibleNamespaces.length) {
return this.cluster.accessibleNamespaces;
}
if (this.dependencies.namespaceStore.items.length > 0) {
// namespaces from kubernetes api
return this.dependencies.namespaceStore.items.map((namespace) => namespace.getName());
} else {
// fallback to cluster resolved namespaces because we could not load list
return this.cluster.allowedNamespaces || [];
}
}
@computed get contextNamespaces(): string[] {
return this.dependencies.namespaceStore.contextNamespaces;
}
@computed get hasSelectedAll(): boolean {
const namespaces = new Set(this.contextNamespaces);
return this.allNamespaces?.length > 1
&& this.cluster.accessibleNamespaces.length === 0
&& this.allNamespaces.every(ns => namespaces.has(ns));
}
} }

View File

@ -0,0 +1,29 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert";
import type { ClusterContext } from "./cluster-frame-context";
import hostedClusterInjectable from "./hosted-cluster.injectable";
const clusterFrameContextForClusterScopedResourcesInjectable = getInjectable({
id: "cluster-frame-context-for-cluster-scoped-resources",
instantiate: (di): ClusterContext => {
const cluster = di.inject(hostedClusterInjectable);
assert(cluster, "This can only be injected within a cluster frame");
return {
isGlobalWatchEnabled: () => cluster.isGlobalWatchEnabled,
// This is always the case for cluster scoped resources
isLoadingAll: () => true,
isNamespaceListStatic: () => cluster.accessibleNamespaces.length > 0,
allNamespaces: [],
contextNamespaces: [], // This value is used as a sentinal
hasSelectedAll: true,
};
},
});
export default clusterFrameContextForClusterScopedResourcesInjectable;

View File

@ -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 } from "@ogre-tools/injectable";
import type { ClusterContext } from "./cluster-frame-context";
import namespaceStoreInjectable from "../components/+namespaces/store.injectable";
import hostedClusterInjectable from "./hosted-cluster.injectable";
import assert from "assert";
import { computed } from "mobx";
const clusterFrameContextForNamespacedResourcesInjectable = getInjectable({
id: "cluster-frame-context-for-namespaced-resources",
instantiate: (di): ClusterContext => {
const cluster = di.inject(hostedClusterInjectable);
const namespaceStore = di.inject(namespaceStoreInjectable);
assert(cluster, "This can only be injected within a cluster frame");
const allNamespaces = computed(() => {
// user given list of namespaces
if (cluster.accessibleNamespaces.length) {
return cluster.accessibleNamespaces.slice();
}
if (namespaceStore.items.length > 0) {
// namespaces from kubernetes api
return namespaceStore.items.map((namespace) => namespace.getName());
}
// fallback to cluster resolved namespaces because we could not load list
return cluster.allowedNamespaces.slice();
});
const contextNamespaces = computed(() => namespaceStore.contextNamespaces);
const hasSelectedAll = computed(() => {
const namespaces = new Set(contextNamespaces.get());
return allNamespaces.get().length > 1
&& cluster.accessibleNamespaces.length === 0
&& allNamespaces.get().every(ns => namespaces.has(ns));
});
return {
isNamespaceListStatic: () => cluster.accessibleNamespaces.length > 0,
isLoadingAll: (namespaces) => (
allNamespaces.get().length > 1
&& cluster.accessibleNamespaces.length === 0
&& allNamespaces.get().every(ns => namespaces.includes(ns))
),
isGlobalWatchEnabled: () => cluster.isGlobalWatchEnabled,
get allNamespaces() {
return allNamespaces.get();
},
get contextNamespaces() {
return contextNamespaces.get();
},
get hasSelectedAll() {
return hasSelectedAll.get();
},
};
},
});
export default clusterFrameContextForNamespacedResourcesInjectable;

View File

@ -0,0 +1,27 @@
/**
* 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 hostedClusterInjectable from "./hosted-cluster.injectable";
import { shouldShowResourceInjectionToken } from "../../common/cluster-store/allowed-resources-injection-token";
import type { KubeApiResourceDescriptor } from "../../common/rbac";
import { formatKubeApiResource } from "../../common/rbac";
const shouldShowResourceInjectable = getInjectable({
id: "should-show-resource",
instantiate: (di, resource) => {
const cluster = di.inject(hostedClusterInjectable);
return cluster
? computed(() => cluster.shouldShowResource(resource))
: computed(() => false);
},
injectionToken: shouldShowResourceInjectionToken,
lifecycle: lifecycleEnum.keyedSingleton({
getInstanceKey: (di, resource: KubeApiResourceDescriptor) => formatKubeApiResource(resource),
}),
});
export default shouldShowResourceInjectable;

View File

@ -13,6 +13,7 @@ import storesAndApisCanBeCreatedInjectable from "../../../stores-apis-can-be-cre
import assert from "assert"; import assert from "assert";
import nodeStoreInjectable from "../../+nodes/store.injectable"; import nodeStoreInjectable from "../../+nodes/store.injectable";
import requestClusterMetricsByNodeNamesInjectable from "../../../../common/k8s-api/endpoints/metrics.api/request-cluster-metrics-by-node-names.injectable"; import requestClusterMetricsByNodeNamesInjectable from "../../../../common/k8s-api/endpoints/metrics.api/request-cluster-metrics-by-node-names.injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../../cluster-frame-context/for-namespaced-resources.injectable";
const clusterOverviewStoreInjectable = getInjectable({ const clusterOverviewStoreInjectable = getInjectable({
id: "cluster-overview-store", id: "cluster-overview-store",
@ -32,6 +33,7 @@ const clusterOverviewStoreInjectable = getInjectable({
), ),
nodeStore: di.inject(nodeStoreInjectable), nodeStore: di.inject(nodeStoreInjectable),
requestClusterMetricsByNodeNames: di.inject(requestClusterMetricsByNodeNamesInjectable), requestClusterMetricsByNodeNames: di.inject(requestClusterMetricsByNodeNamesInjectable),
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, clusterApi); }, clusterApi);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,

View File

@ -4,6 +4,7 @@
*/ */
import { action, observable, reaction, when, makeObservable } from "mobx"; import { action, observable, reaction, when, makeObservable } from "mobx";
import type { KubeObjectStoreDependencies } from "../../../../common/k8s-api/kube-object.store";
import { KubeObjectStore } from "../../../../common/k8s-api/kube-object.store"; import { KubeObjectStore } from "../../../../common/k8s-api/kube-object.store";
import type { Cluster, ClusterApi } from "../../../../common/k8s-api/endpoints"; import type { Cluster, ClusterApi } from "../../../../common/k8s-api/endpoints";
import type { StorageLayer } from "../../../utils"; import type { StorageLayer } from "../../../utils";
@ -28,7 +29,7 @@ export interface ClusterOverviewStorageState {
metricNodeRole: MetricNodeRole; metricNodeRole: MetricNodeRole;
} }
interface ClusterOverviewStoreDependencies { interface ClusterOverviewStoreDependencies extends KubeObjectStoreDependencies {
readonly storage: StorageLayer<ClusterOverviewStorageState>; readonly storage: StorageLayer<ClusterOverviewStorageState>;
readonly nodeStore: NodeStore; readonly nodeStore: NodeStore;
requestClusterMetricsByNodeNames: RequestClusterMetricsByNodeNames; requestClusterMetricsByNodeNames: RequestClusterMetricsByNodeNames;
@ -58,7 +59,7 @@ export class ClusterOverviewStore extends KubeObjectStore<Cluster, ClusterApi> i
} }
constructor(protected readonly dependencies: ClusterOverviewStoreDependencies, api: ClusterApi) { constructor(protected readonly dependencies: ClusterOverviewStoreDependencies, api: ClusterApi) {
super(api); super(dependencies, api);
makeObservable(this); makeObservable(this);
autoBind(this); autoBind(this);

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert"; import assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import horizontalPodAutoscalerApiInjectable from "../../../common/k8s-api/endpoints/horizontal-pod-autoscaler.api.injectable"; import horizontalPodAutoscalerApiInjectable from "../../../common/k8s-api/endpoints/horizontal-pod-autoscaler.api.injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { HorizontalPodAutoscalerStore } from "./store"; import { HorizontalPodAutoscalerStore } from "./store";
@ -16,7 +17,9 @@ const horizontalPodAutoscalerStoreInjectable = getInjectable({
const api = di.inject(horizontalPodAutoscalerApiInjectable); const api = di.inject(horizontalPodAutoscalerApiInjectable);
return new HorizontalPodAutoscalerStore(api); return new HorizontalPodAutoscalerStore({
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert"; import assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import leaseApiInjectable from "../../../common/k8s-api/endpoints/lease.api.injectable"; import leaseApiInjectable from "../../../common/k8s-api/endpoints/lease.api.injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { LeaseStore } from "./store"; import { LeaseStore } from "./store";
@ -16,7 +17,9 @@ const leaseStoreInjectable = getInjectable({
const api = di.inject(leaseApiInjectable); const api = di.inject(leaseApiInjectable);
return new LeaseStore(api); return new LeaseStore({
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert"; import assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import limitRangeApiInjectable from "../../../common/k8s-api/endpoints/limit-range.api.injectable"; import limitRangeApiInjectable from "../../../common/k8s-api/endpoints/limit-range.api.injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { LimitRangeStore } from "./store"; import { LimitRangeStore } from "./store";
@ -16,7 +17,9 @@ const limitRangeStoreInjectable = getInjectable({
const api = di.inject(limitRangeApiInjectable); const api = di.inject(limitRangeApiInjectable);
return new LimitRangeStore(api); return new LimitRangeStore({
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert"; import assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import configMapApiInjectable from "../../../common/k8s-api/endpoints/config-map.api.injectable"; import configMapApiInjectable from "../../../common/k8s-api/endpoints/config-map.api.injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { ConfigMapStore } from "./store"; import { ConfigMapStore } from "./store";
@ -16,7 +17,9 @@ const configMapStoreInjectable = getInjectable({
const api = di.inject(configMapApiInjectable); const api = di.inject(configMapApiInjectable);
return new ConfigMapStore(api); return new ConfigMapStore({
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert"; import assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import podDisruptionBudgetApiInjectable from "../../../common/k8s-api/endpoints/pod-disruption-budget.api.injectable"; import podDisruptionBudgetApiInjectable from "../../../common/k8s-api/endpoints/pod-disruption-budget.api.injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { PodDisruptionBudgetStore } from "./store"; import { PodDisruptionBudgetStore } from "./store";
@ -16,7 +17,9 @@ const podDisruptionBudgetStoreInjectable = getInjectable({
const api = di.inject(podDisruptionBudgetApiInjectable); const api = di.inject(podDisruptionBudgetApiInjectable);
return new PodDisruptionBudgetStore(api); return new PodDisruptionBudgetStore({
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert"; import assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import priorityClassApiInjectable from "../../../common/k8s-api/endpoints/priority-class.api.injectable"; import priorityClassApiInjectable from "../../../common/k8s-api/endpoints/priority-class.api.injectable";
import clusterFrameContextForClusterScopedResourcesInjectable from "../../cluster-frame-context/for-cluster-scoped-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { PriorityClassStore } from "./store"; import { PriorityClassStore } from "./store";
@ -16,7 +17,9 @@ const priorityClassStoreInjectable = getInjectable({
const api = di.inject(priorityClassApiInjectable); const api = di.inject(priorityClassApiInjectable);
return new PriorityClassStore(api); return new PriorityClassStore({
context: di.inject(clusterFrameContextForClusterScopedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert"; import assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import resourceQuotaApiInjectable from "../../../common/k8s-api/endpoints/resource-quota.api.injectable"; import resourceQuotaApiInjectable from "../../../common/k8s-api/endpoints/resource-quota.api.injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { ResourceQuotaStore } from "./store"; import { ResourceQuotaStore } from "./store";
@ -16,7 +17,9 @@ const resourceQuotaStoreInjectable = getInjectable({
const api = di.inject(resourceQuotaApiInjectable); const api = di.inject(resourceQuotaApiInjectable);
return new ResourceQuotaStore(api); return new ResourceQuotaStore({
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert"; import assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import secretApiInjectable from "../../../common/k8s-api/endpoints/secret.api.injectable"; import secretApiInjectable from "../../../common/k8s-api/endpoints/secret.api.injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { SecretStore } from "./store"; import { SecretStore } from "./store";
@ -16,7 +17,9 @@ const secretStoreInjectable = getInjectable({
const api = di.inject(secretApiInjectable); const api = di.inject(secretApiInjectable);
return new SecretStore(api); return new SecretStore({
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -7,6 +7,7 @@ import assert from "assert";
import autoRegistrationEmitterInjectable from "../../../common/k8s-api/api-manager/auto-registration-emitter.injectable"; import autoRegistrationEmitterInjectable from "../../../common/k8s-api/api-manager/auto-registration-emitter.injectable";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import customResourceDefinitionApiInjectable from "../../../common/k8s-api/endpoints/custom-resource-definition.api.injectable"; import customResourceDefinitionApiInjectable from "../../../common/k8s-api/endpoints/custom-resource-definition.api.injectable";
import clusterFrameContextForClusterScopedResourcesInjectable from "../../cluster-frame-context/for-cluster-scoped-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { CustomResourceDefinitionStore } from "./definition.store"; import { CustomResourceDefinitionStore } from "./definition.store";
@ -19,6 +20,7 @@ const customResourceDefinitionStoreInjectable = getInjectable({
return new CustomResourceDefinitionStore({ return new CustomResourceDefinitionStore({
autoRegistration: di.inject(autoRegistrationEmitterInjectable), autoRegistration: di.inject(autoRegistrationEmitterInjectable),
context: di.inject(clusterFrameContextForClusterScopedResourcesInjectable),
}, api); }, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,

View File

@ -4,7 +4,7 @@
*/ */
import { computed, reaction, makeObservable } from "mobx"; import { computed, reaction, makeObservable } from "mobx";
import type { KubeObjectStoreOptions } from "../../../common/k8s-api/kube-object.store"; import type { KubeObjectStoreDependencies, KubeObjectStoreOptions } from "../../../common/k8s-api/kube-object.store";
import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
import { autoBind } from "../../utils"; import { autoBind } from "../../utils";
import type { CustomResourceDefinition, CustomResourceDefinitionApi } from "../../../common/k8s-api/endpoints/custom-resource-definition.api"; import type { CustomResourceDefinition, CustomResourceDefinitionApi } from "../../../common/k8s-api/endpoints/custom-resource-definition.api";
@ -12,7 +12,7 @@ import type { KubeObject } from "../../../common/k8s-api/kube-object";
import type TypedEventEmitter from "typed-emitter"; import type TypedEventEmitter from "typed-emitter";
import type { LegacyAutoRegistration } from "../../../common/k8s-api/api-manager/auto-registration-emitter.injectable"; import type { LegacyAutoRegistration } from "../../../common/k8s-api/api-manager/auto-registration-emitter.injectable";
export interface CustomResourceDefinitionStoreDependencies { export interface CustomResourceDefinitionStoreDependencies extends KubeObjectStoreDependencies {
readonly autoRegistration: TypedEventEmitter<LegacyAutoRegistration>; readonly autoRegistration: TypedEventEmitter<LegacyAutoRegistration>;
} }
@ -22,7 +22,7 @@ export class CustomResourceDefinitionStore extends KubeObjectStore<CustomResourc
api: CustomResourceDefinitionApi, api: CustomResourceDefinitionApi,
opts?: KubeObjectStoreOptions, opts?: KubeObjectStoreOptions,
) { ) {
super(api, opts); super(dependencies, api, opts);
makeObservable(this); makeObservable(this);
autoBind(this); autoBind(this);

View File

@ -4,7 +4,7 @@
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { asyncComputed } from "@ogre-tools/injectable-react"; import { asyncComputed } from "@ogre-tools/injectable-react";
import clusterFrameContextInjectable from "../../cluster-frame-context/cluster-frame-context.injectable"; import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
import releaseSecretsInjectable from "./release-secrets.injectable"; import releaseSecretsInjectable from "./release-secrets.injectable";
import requestHelmReleasesInjectable from "../../../common/k8s-api/endpoints/helm-releases.api/request-releases.injectable"; import requestHelmReleasesInjectable from "../../../common/k8s-api/endpoints/helm-releases.api/request-releases.injectable";
import toHelmReleaseInjectable from "./to-helm-release.injectable"; import toHelmReleaseInjectable from "./to-helm-release.injectable";
@ -13,7 +13,7 @@ const releasesInjectable = getInjectable({
id: "releases", id: "releases",
instantiate: (di) => { instantiate: (di) => {
const clusterContext = di.inject(clusterFrameContextInjectable); const clusterContext = di.inject(clusterFrameContextForNamespacedResourcesInjectable);
const releaseSecrets = di.inject(releaseSecretsInjectable); const releaseSecrets = di.inject(releaseSecretsInjectable);
const requestHelmReleases = di.inject(requestHelmReleasesInjectable); const requestHelmReleases = di.inject(requestHelmReleasesInjectable);
const toHelmRelease = di.inject(toHelmReleaseInjectable); const toHelmRelease = di.inject(toHelmReleaseInjectable);

View File

@ -9,6 +9,7 @@ import createStorageInjectable from "../../utils/create-storage/create-storage.i
import namespaceApiInjectable from "../../../common/k8s-api/endpoints/namespace.api.injectable"; import namespaceApiInjectable from "../../../common/k8s-api/endpoints/namespace.api.injectable";
import assert from "assert"; import assert from "assert";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import clusterFrameContextForClusterScopedResourcesInjectable from "../../cluster-frame-context/for-cluster-scoped-resources.injectable";
const namespaceStoreInjectable = getInjectable({ const namespaceStoreInjectable = getInjectable({
id: "namespace-store", id: "namespace-store",
@ -20,6 +21,7 @@ const namespaceStoreInjectable = getInjectable({
const api = di.inject(namespaceApiInjectable); const api = di.inject(namespaceApiInjectable);
return new NamespaceStore({ return new NamespaceStore({
context: di.inject(clusterFrameContextForClusterScopedResourcesInjectable),
storage: createStorage<string[] | undefined>("selected_namespaces", undefined), storage: createStorage<string[] | undefined>("selected_namespaces", undefined),
}, api); }, api);
}, },

View File

@ -7,18 +7,18 @@ import type { IReactionDisposer } from "mobx";
import { action, comparer, computed, makeObservable, reaction } from "mobx"; import { action, comparer, computed, makeObservable, reaction } from "mobx";
import type { StorageLayer } from "../../utils"; import type { StorageLayer } from "../../utils";
import { autoBind, noop, toggle } from "../../utils"; import { autoBind, noop, toggle } from "../../utils";
import type { KubeObjectStoreLoadingParams } from "../../../common/k8s-api/kube-object.store"; import type { KubeObjectStoreDependencies, KubeObjectStoreLoadingParams } from "../../../common/k8s-api/kube-object.store";
import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
import type { NamespaceApi } from "../../../common/k8s-api/endpoints/namespace.api"; import type { NamespaceApi } from "../../../common/k8s-api/endpoints/namespace.api";
import { Namespace } from "../../../common/k8s-api/endpoints/namespace.api"; import { Namespace } from "../../../common/k8s-api/endpoints/namespace.api";
interface Dependencies { interface Dependencies extends KubeObjectStoreDependencies {
storage: StorageLayer<string[] | undefined>; readonly storage: StorageLayer<string[] | undefined>;
} }
export class NamespaceStore extends KubeObjectStore<Namespace, NamespaceApi> { export class NamespaceStore extends KubeObjectStore<Namespace, NamespaceApi> {
constructor(protected readonly dependencies: Dependencies, api: NamespaceApi) { constructor(protected readonly dependencies: Dependencies, api: NamespaceApi) {
super(api); super(dependencies, api);
makeObservable(this); makeObservable(this);
autoBind(this); autoBind(this);
@ -26,7 +26,6 @@ export class NamespaceStore extends KubeObjectStore<Namespace, NamespaceApi> {
} }
private async init() { private async init() {
await this.contextReady;
await this.dependencies.storage.whenReady; await this.dependencies.storage.whenReady;
this.selectNamespaces(this.initialNamespaces); this.selectNamespaces(this.initialNamespaces);
@ -75,10 +74,7 @@ export class NamespaceStore extends KubeObjectStore<Namespace, NamespaceApi> {
} }
@computed get allowedNamespaces(): string[] { @computed get allowedNamespaces(): string[] {
return Array.from(new Set([ return this.items.map(item => item.getName());
...(this.context?.allNamespaces ?? []), // allowed namespaces from cluster (main), updating every 30s
...this.items.map(item => item.getName()), // loaded namespaces from k8s api
].flat()));
} }
/** /**
@ -114,7 +110,7 @@ export class NamespaceStore extends KubeObjectStore<Namespace, NamespaceApi> {
* if user has given static list of namespaces let's not start watches * if user has given static list of namespaces let's not start watches
* because watch adds stuff that's not wanted or will just fail * because watch adds stuff that's not wanted or will just fail
*/ */
if ((this.context?.cluster.accessibleNamespaces.length ?? 0) > 0) { if (this.dependencies.context.isNamespaceListStatic()) {
return noop; return noop;
} }

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert"; import assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import endpointsApiInjectable from "../../../common/k8s-api/endpoints/endpoint.api.injectable"; import endpointsApiInjectable from "../../../common/k8s-api/endpoints/endpoint.api.injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { EndpointsStore } from "./store"; import { EndpointsStore } from "./store";
@ -16,7 +17,9 @@ const endpointsStoreInjectable = getInjectable({
const api = di.inject(endpointsApiInjectable); const api = di.inject(endpointsApiInjectable);
return new EndpointsStore(api); return new EndpointsStore({
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert"; import assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import ingressApiInjectable from "../../../common/k8s-api/endpoints/ingress.api.injectable"; import ingressApiInjectable from "../../../common/k8s-api/endpoints/ingress.api.injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { IngressStore } from "./store"; import { IngressStore } from "./store";
@ -16,7 +17,9 @@ const ingressStoreInjectable = getInjectable({
const api = di.inject(ingressApiInjectable); const api = di.inject(ingressApiInjectable);
return new IngressStore(api); return new IngressStore({
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert"; import assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import networkPolicyApiInjectable from "../../../common/k8s-api/endpoints/network-policy.api.injectable"; import networkPolicyApiInjectable from "../../../common/k8s-api/endpoints/network-policy.api.injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { NetworkPolicyStore } from "./store"; import { NetworkPolicyStore } from "./store";
@ -16,7 +17,9 @@ const networkPolicyStoreInjectable = getInjectable({
const api = di.inject(networkPolicyApiInjectable); const api = di.inject(networkPolicyApiInjectable);
return new NetworkPolicyStore(api); return new NetworkPolicyStore({
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert"; import assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import serviceApiInjectable from "../../../common/k8s-api/endpoints/service.api.injectable"; import serviceApiInjectable from "../../../common/k8s-api/endpoints/service.api.injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { ServiceStore } from "./store"; import { ServiceStore } from "./store";
@ -16,7 +17,9 @@ const serviceStoreInjectable = getInjectable({
const api = di.inject(serviceApiInjectable); const api = di.inject(serviceApiInjectable);
return new ServiceStore(api); return new ServiceStore({
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert"; import assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import nodeApiInjectable from "../../../common/k8s-api/endpoints/node.api.injectable"; import nodeApiInjectable from "../../../common/k8s-api/endpoints/node.api.injectable";
import clusterFrameContextForClusterScopedResourcesInjectable from "../../cluster-frame-context/for-cluster-scoped-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { NodeStore } from "./store"; import { NodeStore } from "./store";
@ -16,7 +17,9 @@ const nodeStoreInjectable = getInjectable({
const api = di.inject(nodeApiInjectable); const api = di.inject(nodeApiInjectable);
return new NodeStore(api); return new NodeStore({
context: di.inject(clusterFrameContextForClusterScopedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -6,13 +6,13 @@ import { sum } from "lodash";
import { computed, makeObservable } from "mobx"; import { computed, makeObservable } from "mobx";
import type { Node, NodeApi } from "../../../common/k8s-api/endpoints"; import type { Node, NodeApi } from "../../../common/k8s-api/endpoints";
import type { KubeObjectStoreOptions } from "../../../common/k8s-api/kube-object.store"; import type { KubeObjectStoreDependencies, KubeObjectStoreOptions } from "../../../common/k8s-api/kube-object.store";
import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
import { autoBind } from "../../utils"; import { autoBind } from "../../utils";
export class NodeStore extends KubeObjectStore<Node, NodeApi> { export class NodeStore extends KubeObjectStore<Node, NodeApi> {
constructor(api: NodeApi, opts?: KubeObjectStoreOptions) { constructor(dependencies: KubeObjectStoreDependencies, api: NodeApi, opts?: KubeObjectStoreOptions) {
super(api, opts); super(dependencies, api, opts);
makeObservable(this); makeObservable(this);
autoBind(this); autoBind(this);

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert"; import assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import podSecurityPolicyApiInjectable from "../../../common/k8s-api/endpoints/pod-security-policy.api.injectable"; import podSecurityPolicyApiInjectable from "../../../common/k8s-api/endpoints/pod-security-policy.api.injectable";
import clusterFrameContextForClusterScopedResourcesInjectable from "../../cluster-frame-context/for-cluster-scoped-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { PodSecurityPolicyStore } from "./store"; import { PodSecurityPolicyStore } from "./store";
@ -16,7 +17,9 @@ const podSecurityPolicyStoreInjectable = getInjectable({
const api = di.inject(podSecurityPolicyApiInjectable); const api = di.inject(podSecurityPolicyApiInjectable);
return new PodSecurityPolicyStore(api); return new PodSecurityPolicyStore({
context: di.inject(clusterFrameContextForClusterScopedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -7,6 +7,7 @@ import assert from "assert";
import getPersistentVolumesByStorageClassInjectable from "../+storage-volumes/get-persisten-volumes-by-storage-class.injectable"; import getPersistentVolumesByStorageClassInjectable from "../+storage-volumes/get-persisten-volumes-by-storage-class.injectable";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import storageClassApiInjectable from "../../../common/k8s-api/endpoints/storage-class.api.injectable"; import storageClassApiInjectable from "../../../common/k8s-api/endpoints/storage-class.api.injectable";
import clusterFrameContextForClusterScopedResourcesInjectable from "../../cluster-frame-context/for-cluster-scoped-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { StorageClassStore } from "./store"; import { StorageClassStore } from "./store";
@ -19,6 +20,7 @@ const storageClassStoreInjectable = getInjectable({
return new StorageClassStore({ return new StorageClassStore({
getPersistentVolumesByStorageClass: di.inject(getPersistentVolumesByStorageClassInjectable), getPersistentVolumesByStorageClass: di.inject(getPersistentVolumesByStorageClassInjectable),
context: di.inject(clusterFrameContextForClusterScopedResourcesInjectable),
}, api); }, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,

View File

@ -3,12 +3,12 @@
* 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 { KubeObjectStoreOptions } from "../../../common/k8s-api/kube-object.store"; import type { KubeObjectStoreDependencies, KubeObjectStoreOptions } from "../../../common/k8s-api/kube-object.store";
import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
import type { StorageClass, StorageClassApi, StorageClassData } from "../../../common/k8s-api/endpoints/storage-class.api"; import type { StorageClass, StorageClassApi, StorageClassData } from "../../../common/k8s-api/endpoints/storage-class.api";
import type { GetPersistentVolumesByStorageClass } from "../+storage-volumes/get-persisten-volumes-by-storage-class.injectable"; import type { GetPersistentVolumesByStorageClass } from "../+storage-volumes/get-persisten-volumes-by-storage-class.injectable";
export interface StorageClassStoreDependencies { export interface StorageClassStoreDependencies extends KubeObjectStoreDependencies {
getPersistentVolumesByStorageClass: GetPersistentVolumesByStorageClass; getPersistentVolumesByStorageClass: GetPersistentVolumesByStorageClass;
} }
@ -18,7 +18,7 @@ export class StorageClassStore extends KubeObjectStore<StorageClass, StorageClas
api: StorageClassApi, api: StorageClassApi,
opts?: KubeObjectStoreOptions, opts?: KubeObjectStoreOptions,
) { ) {
super(api, opts); super(dependencies, api, opts);
} }
getPersistentVolumes(storageClass: StorageClass) { getPersistentVolumes(storageClass: StorageClass) {

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert"; import assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import persistentVolumeClaimApiInjectable from "../../../common/k8s-api/endpoints/persistent-volume-claim.api.injectable"; import persistentVolumeClaimApiInjectable from "../../../common/k8s-api/endpoints/persistent-volume-claim.api.injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { PersistentVolumeClaimStore } from "./store"; import { PersistentVolumeClaimStore } from "./store";
@ -16,7 +17,9 @@ const persistentVolumeClaimStoreInjectable = getInjectable({
const api = di.inject(persistentVolumeClaimApiInjectable); const api = di.inject(persistentVolumeClaimApiInjectable);
return new PersistentVolumeClaimStore(api); return new PersistentVolumeClaimStore({
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert"; import assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import persistentVolumeApiInjectable from "../../../common/k8s-api/endpoints/persistent-volume.api.injectable"; import persistentVolumeApiInjectable from "../../../common/k8s-api/endpoints/persistent-volume.api.injectable";
import clusterFrameContextForClusterScopedResourcesInjectable from "../../cluster-frame-context/for-cluster-scoped-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { PersistentVolumeStore } from "./store"; import { PersistentVolumeStore } from "./store";
@ -16,7 +17,9 @@ const persistentVolumeStoreInjectable = getInjectable({
const api = di.inject(persistentVolumeApiInjectable); const api = di.inject(persistentVolumeApiInjectable);
return new PersistentVolumeStore(api); return new PersistentVolumeStore({
context: di.inject(clusterFrameContextForClusterScopedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -8,6 +8,7 @@ import { storesAndApisCanBeCreatedInjectionToken } from "../../../../common/k8s-
import clusterRoleBindingApiInjectable from "../../../../common/k8s-api/endpoints/cluster-role-binding.api.injectable"; import clusterRoleBindingApiInjectable from "../../../../common/k8s-api/endpoints/cluster-role-binding.api.injectable";
import { kubeObjectStoreInjectionToken } from "../../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../../common/k8s-api/api-manager/manager.injectable";
import { ClusterRoleBindingStore } from "./store"; import { ClusterRoleBindingStore } from "./store";
import clusterFrameContextForClusterScopedResourcesInjectable from "../../../cluster-frame-context/for-cluster-scoped-resources.injectable";
const clusterRoleBindingStoreInjectable = getInjectable({ const clusterRoleBindingStoreInjectable = getInjectable({
id: "cluster-role-binding-store", id: "cluster-role-binding-store",
@ -16,7 +17,9 @@ const clusterRoleBindingStoreInjectable = getInjectable({
const api = di.inject(clusterRoleBindingApiInjectable); const api = di.inject(clusterRoleBindingApiInjectable);
return new ClusterRoleBindingStore(api); return new ClusterRoleBindingStore({
context: di.inject(clusterFrameContextForClusterScopedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -8,6 +8,7 @@ import { storesAndApisCanBeCreatedInjectionToken } from "../../../../common/k8s-
import clusterRoleApiInjectable from "../../../../common/k8s-api/endpoints/cluster-role.api.injectable"; import clusterRoleApiInjectable from "../../../../common/k8s-api/endpoints/cluster-role.api.injectable";
import { kubeObjectStoreInjectionToken } from "../../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../../common/k8s-api/api-manager/manager.injectable";
import { ClusterRoleStore } from "./store"; import { ClusterRoleStore } from "./store";
import clusterFrameContextForClusterScopedResourcesInjectable from "../../../cluster-frame-context/for-cluster-scoped-resources.injectable";
const clusterRoleStoreInjectable = getInjectable({ const clusterRoleStoreInjectable = getInjectable({
id: "cluster-role-store", id: "cluster-role-store",
@ -16,7 +17,9 @@ const clusterRoleStoreInjectable = getInjectable({
const api = di.inject(clusterRoleApiInjectable); const api = di.inject(clusterRoleApiInjectable);
return new ClusterRoleStore(api); return new ClusterRoleStore({
context: di.inject(clusterFrameContextForClusterScopedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert"; import assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../../common/k8s-api/api-manager/manager.injectable";
import roleBindingApiInjectable from "../../../../common/k8s-api/endpoints/role-binding.api.injectable"; import roleBindingApiInjectable from "../../../../common/k8s-api/endpoints/role-binding.api.injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../../cluster-frame-context/for-namespaced-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../../stores-apis-can-be-created.injectable";
import { RoleBindingStore } from "./store"; import { RoleBindingStore } from "./store";
@ -16,7 +17,9 @@ const roleBindingStoreInjectable = getInjectable({
const api = di.inject(roleBindingApiInjectable); const api = di.inject(roleBindingApiInjectable);
return new RoleBindingStore(api); return new RoleBindingStore({
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -8,6 +8,7 @@ import roleApiInjectable from "../../../../common/k8s-api/endpoints/role.api.inj
import storesAndApisCanBeCreatedInjectable from "../../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../../stores-apis-can-be-created.injectable";
import { kubeObjectStoreInjectionToken } from "../../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../../common/k8s-api/api-manager/manager.injectable";
import { RoleStore } from "./store"; import { RoleStore } from "./store";
import clusterFrameContextForNamespacedResourcesInjectable from "../../../cluster-frame-context/for-namespaced-resources.injectable";
const roleStoreInjectable = getInjectable({ const roleStoreInjectable = getInjectable({
id: "role-store", id: "role-store",
@ -16,7 +17,9 @@ const roleStoreInjectable = getInjectable({
const api = di.inject(roleApiInjectable); const api = di.inject(roleApiInjectable);
return new RoleStore(api); return new RoleStore({
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -8,6 +8,7 @@ import serviceAccountApiInjectable from "../../../../common/k8s-api/endpoints/se
import storesAndApisCanBeCreatedInjectable from "../../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../../stores-apis-can-be-created.injectable";
import { kubeObjectStoreInjectionToken } from "../../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../../common/k8s-api/api-manager/manager.injectable";
import { ServiceAccountStore } from "./store"; import { ServiceAccountStore } from "./store";
import clusterFrameContextForNamespacedResourcesInjectable from "../../../cluster-frame-context/for-namespaced-resources.injectable";
const serviceAccountStoreInjectable = getInjectable({ const serviceAccountStoreInjectable = getInjectable({
id: "service-account-store", id: "service-account-store",
@ -16,7 +17,9 @@ const serviceAccountStoreInjectable = getInjectable({
const api = di.inject(serviceAccountApiInjectable); const api = di.inject(serviceAccountApiInjectable);
return new ServiceAccountStore(api); return new ServiceAccountStore({
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,
}); });

View File

@ -7,6 +7,7 @@ import assert from "assert";
import getJobsByOwnerInjectable from "../+workloads-jobs/get-jobs-by-owner.injectable"; import getJobsByOwnerInjectable from "../+workloads-jobs/get-jobs-by-owner.injectable";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import cronJobApiInjectable from "../../../common/k8s-api/endpoints/cron-job.api.injectable"; import cronJobApiInjectable from "../../../common/k8s-api/endpoints/cron-job.api.injectable";
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { CronJobStore } from "./store"; import { CronJobStore } from "./store";
@ -19,6 +20,7 @@ const cronJobStoreInjectable = getInjectable({
return new CronJobStore({ return new CronJobStore({
getJobsByOwner: di.inject(getJobsByOwnerInjectable), getJobsByOwner: di.inject(getJobsByOwnerInjectable),
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api); }, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,

View File

@ -3,18 +3,18 @@
* 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 { KubeObjectStoreOptions } from "../../../common/k8s-api/kube-object.store"; import type { KubeObjectStoreDependencies, KubeObjectStoreOptions } from "../../../common/k8s-api/kube-object.store";
import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
import type { CronJob, CronJobApi } from "../../../common/k8s-api/endpoints/cron-job.api"; import type { CronJob, CronJobApi } from "../../../common/k8s-api/endpoints/cron-job.api";
import type { GetJobsByOwner } from "../+workloads-jobs/get-jobs-by-owner.injectable"; import type { GetJobsByOwner } from "../+workloads-jobs/get-jobs-by-owner.injectable";
interface Dependencies { interface Dependencies extends KubeObjectStoreDependencies {
getJobsByOwner: GetJobsByOwner; getJobsByOwner: GetJobsByOwner;
} }
export class CronJobStore extends KubeObjectStore<CronJob, CronJobApi> { export class CronJobStore extends KubeObjectStore<CronJob, CronJobApi> {
constructor(protected readonly dependencies: Dependencies, api: CronJobApi, opts?: KubeObjectStoreOptions) { constructor(protected readonly dependencies: Dependencies, api: CronJobApi, opts?: KubeObjectStoreOptions) {
super(api, opts); super(dependencies, api, opts);
} }
getStatuses(cronJobs?: CronJob[]) { getStatuses(cronJobs?: CronJob[]) {

View File

@ -9,6 +9,7 @@ import daemonSetApiInjectable from "../../../common/k8s-api/endpoints/daemon-set
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/manager.injectable";
import { DaemonSetStore } from "./store"; import { DaemonSetStore } from "./store";
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
const daemonSetStoreInjectable = getInjectable({ const daemonSetStoreInjectable = getInjectable({
id: "daemon-set-store", id: "daemon-set-store",
@ -19,6 +20,7 @@ const daemonSetStoreInjectable = getInjectable({
return new DaemonSetStore({ return new DaemonSetStore({
getPodsByOwnerId: di.inject(getPodsByOwnerIdInjectable), getPodsByOwnerId: di.inject(getPodsByOwnerIdInjectable),
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api); }, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,

View File

@ -6,16 +6,16 @@
import type { GetPodsByOwnerId } from "../+workloads-pods/get-pods-by-owner-id.injectable"; import type { GetPodsByOwnerId } from "../+workloads-pods/get-pods-by-owner-id.injectable";
import type { DaemonSet, DaemonSetApi, Pod } from "../../../common/k8s-api/endpoints"; import type { DaemonSet, DaemonSetApi, Pod } from "../../../common/k8s-api/endpoints";
import { PodStatusPhase } from "../../../common/k8s-api/endpoints"; import { PodStatusPhase } from "../../../common/k8s-api/endpoints";
import type { KubeObjectStoreOptions } from "../../../common/k8s-api/kube-object.store"; import type { KubeObjectStoreDependencies, KubeObjectStoreOptions } from "../../../common/k8s-api/kube-object.store";
import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
export interface DaemonSetStoreDependencies { export interface DaemonSetStoreDependencies extends KubeObjectStoreDependencies {
readonly getPodsByOwnerId: GetPodsByOwnerId; readonly getPodsByOwnerId: GetPodsByOwnerId;
} }
export class DaemonSetStore extends KubeObjectStore<DaemonSet, DaemonSetApi> { export class DaemonSetStore extends KubeObjectStore<DaemonSet, DaemonSetApi> {
constructor(protected readonly dependencies: DaemonSetStoreDependencies, api: DaemonSetApi, opts?: KubeObjectStoreOptions) { constructor(protected readonly dependencies: DaemonSetStoreDependencies, api: DaemonSetApi, opts?: KubeObjectStoreOptions) {
super(api, opts); super(dependencies, api, opts);
} }
getChildPods(daemonSet: DaemonSet): Pod[] { getChildPods(daemonSet: DaemonSet): Pod[] {

View File

@ -9,6 +9,7 @@ import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manag
import { storesAndApisCanBeCreatedInjectionToken } from "../../../common/k8s-api/stores-apis-can-be-created.token"; import { storesAndApisCanBeCreatedInjectionToken } from "../../../common/k8s-api/stores-apis-can-be-created.token";
import deploymentApiInjectable from "../../../common/k8s-api/endpoints/deployment.api.injectable"; import deploymentApiInjectable from "../../../common/k8s-api/endpoints/deployment.api.injectable";
import { DeploymentStore } from "./store"; import { DeploymentStore } from "./store";
import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
const deploymentStoreInjectable = getInjectable({ const deploymentStoreInjectable = getInjectable({
id: "deployment-store", id: "deployment-store",
@ -19,6 +20,7 @@ const deploymentStoreInjectable = getInjectable({
return new DeploymentStore({ return new DeploymentStore({
podStore: di.inject(podStoreInjectable), podStore: di.inject(podStoreInjectable),
context: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
}, api); }, api);
}, },
injectionToken: kubeObjectStoreInjectionToken, injectionToken: kubeObjectStoreInjectionToken,

View File

@ -6,7 +6,7 @@
import type { PodStore } from "../+workloads-pods/store"; import type { PodStore } from "../+workloads-pods/store";
import type { Deployment, DeploymentApi } from "../../../common/k8s-api/endpoints"; import type { Deployment, DeploymentApi } from "../../../common/k8s-api/endpoints";
import { PodStatusPhase } from "../../../common/k8s-api/endpoints"; import { PodStatusPhase } from "../../../common/k8s-api/endpoints";
import type { KubeObjectStoreOptions } from "../../../common/k8s-api/kube-object.store"; import type { KubeObjectStoreDependencies, KubeObjectStoreOptions } from "../../../common/k8s-api/kube-object.store";
import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store";
// This needs to be disables because of https://github.com/microsoft/TypeScript/issues/15300 // This needs to be disables because of https://github.com/microsoft/TypeScript/issues/15300
@ -17,13 +17,13 @@ export type DeploymentStatuses = {
pending: number; pending: number;
}; };
export interface DeploymentStoreDependencies { export interface DeploymentStoreDependencies extends KubeObjectStoreDependencies {
readonly podStore: PodStore; readonly podStore: PodStore;
} }
export class DeploymentStore extends KubeObjectStore<Deployment, DeploymentApi> { export class DeploymentStore extends KubeObjectStore<Deployment, DeploymentApi> {
constructor(protected readonly dependencies: DeploymentStoreDependencies, api: DeploymentApi, opts?: KubeObjectStoreOptions) { constructor(protected readonly dependencies: DeploymentStoreDependencies, api: DeploymentApi, opts?: KubeObjectStoreOptions) {
super(api, opts); super(dependencies, api, opts);
} }
protected sortItems(items: Deployment[]) { protected sortItems(items: Deployment[]) {

View File

@ -12,6 +12,7 @@ import { withInjectables } from "@ogre-tools/injectable-react";
import type { IComputedValue } from "mobx"; import type { IComputedValue } from "mobx";
import workloadsInjectable from "./workloads/workloads.injectable"; import workloadsInjectable from "./workloads/workloads.injectable";
import type { Workload } from "./workloads/workload-injection-token"; import type { Workload } from "./workloads/workload-injection-token";
import { formatKubeApiResource } from "../../../common/rbac";
export interface OverviewStatusesProps {} export interface OverviewStatusesProps {}
@ -24,7 +25,7 @@ const NonInjectedOverviewStatuses = observer(
<div className="OverviewStatuses"> <div className="OverviewStatuses">
<div className="workloads"> <div className="workloads">
{workloads.get().map((workload) => ( {workloads.get().map((workload) => (
<div className="workload" key={workload.resourceName}> <div className="workload" key={formatKubeApiResource(workload.resource)}>
<div className="title"> <div className="title">
<a onClick={workload.open}> <a onClick={workload.open}>
{`${workload.title} (${workload.amountOfItems.get()})`} {`${workload.title} (${workload.amountOfItems.get()})`}

View File

@ -17,7 +17,7 @@ import { NamespaceSelectFilter } from "../+namespaces/namespace-select-filter";
import { Icon } from "../icon"; import { Icon } from "../icon";
import { TooltipPosition } from "../tooltip"; import { TooltipPosition } from "../tooltip";
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import clusterFrameContextInjectable from "../../cluster-frame-context/cluster-frame-context.injectable"; import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable";
import type { ClusterFrameContext } from "../../cluster-frame-context/cluster-frame-context"; import type { ClusterFrameContext } from "../../cluster-frame-context/cluster-frame-context";
import type { SubscribeStores } from "../../kube-watch-api/kube-watch-api"; import type { SubscribeStores } from "../../kube-watch-api/kube-watch-api";
import workloadOverviewDetailsInjectable from "./workload-overview-details/workload-overview-details.injectable"; import workloadOverviewDetailsInjectable from "./workload-overview-details/workload-overview-details.injectable";
@ -123,7 +123,7 @@ class NonInjectedWorkloadsOverview extends React.Component<Dependencies> {
export const WorkloadsOverview = withInjectables<Dependencies>(NonInjectedWorkloadsOverview, { export const WorkloadsOverview = withInjectables<Dependencies>(NonInjectedWorkloadsOverview, {
getProps: (di) => ({ getProps: (di) => ({
detailComponents: di.inject(workloadOverviewDetailsInjectable), detailComponents: di.inject(workloadOverviewDetailsInjectable),
clusterFrameContext: di.inject(clusterFrameContextInjectable), clusterFrameContext: di.inject(clusterFrameContextForNamespacedResourcesInjectable),
subscribeStores: di.inject(subscribeStoresInjectable), subscribeStores: di.inject(subscribeStoresInjectable),
daemonSetStore: di.inject(daemonSetStoreInjectable), daemonSetStore: di.inject(daemonSetStoreInjectable),
podStore: di.inject(podStoreInjectable), podStore: di.inject(podStoreInjectable),

View File

@ -19,17 +19,17 @@ const cronJobsWorkloadInjectable = getInjectable({
const store = di.inject(cronJobsStoreInjectable); const store = di.inject(cronJobsStoreInjectable);
return { return {
resourceName: "cronjobs", resource: {
apiName: "cronjobs",
group: "batch",
},
open: navigate, open: navigate,
amountOfItems: computed( amountOfItems: computed(
() => store.getAllByNs(namespaceStore.contextNamespaces).length, () => store.getAllByNs(namespaceStore.contextNamespaces).length,
), ),
status: computed(() => status: computed(() =>
store.getStatuses(store.getAllByNs(namespaceStore.contextNamespaces)), store.getStatuses(store.getAllByNs(namespaceStore.contextNamespaces)),
), ),
title: ResourceNames.cronjobs, title: ResourceNames.cronjobs,
orderNumber: 70, orderNumber: 70,
}; };

Some files were not shown because too many files have changed in this diff Show More