Fix being able to view clusters outside the current workspace (#2355)

This commit is contained in:
Sebastian Malton authored and GitHub committed 2021-04-14 09:49:14 -04:00
1 parent da6b5d6bde
commit b6c3ce7d28
36 files changed
+583 -240

No files matched your search

+1 -2
View File
@@ -56,8 +56,7 @@ export async function bootstrap(App: AppComponent) {
// preload common stores
await Promise.all([
userStore.load(),
workspaceStore.load(),
clusterStore.load(),
clusterStore.load().then(() => workspaceStore.load()),
extensionsStore.load(),
filesystemProvisionerStore.load(),
themeStore.init(),
@@ -45,7 +45,7 @@ export class AddCluster extends React.Component {
@observable showSettings = false;
componentDidMount() {
clusterStore.setActive(null);
workspaceStore.currentWorkspace.clearActiveCluster();
this.setKubeConfig(userStore.kubeConfigPath);
appEventBus.emit({ name: "cluster-add", action: "start" });
}
@@ -181,13 +181,11 @@ export class AddCluster extends React.Component {
});
runInAction(() => {
clusterStore.addClusters(...newClusters);
const [cluster, ...rest] = clusterStore.addClusters(...newClusters);
if (newClusters.length === 1) {
const clusterId = newClusters[0].id;
clusterStore.setActive(clusterId);
navigate(clusterViewURL({ params: { clusterId } }));
if (rest.length === 0) {
workspaceStore.getById(cluster.workspace).setActiveCluster(cluster);
navigate(clusterViewURL({ params: { clusterId: cluster.id } }));
} else {
if (newClusters.length > 1) {
Notifications.ok(
@@ -1,7 +1,7 @@
import { navigate } from "../../navigation";
import { commandRegistry } from "../../../extensions/registries/command-registry";
import { clusterSettingsURL } from "./cluster-settings.route";
import { clusterStore } from "../../../common/cluster-store";
import { getHostedClusterId } from "../../../common/cluster-store";
commandRegistry.add({
id: "cluster.viewCurrentClusterSettings",
@@ -9,7 +9,7 @@ commandRegistry.add({
scope: "global",
action: () => navigate(clusterSettingsURL({
params: {
clusterId: clusterStore.active.id
clusterId: getHostedClusterId(),
}
})),
isActive: (context) => !!context.cluster
@@ -16,6 +16,7 @@ import { PageLayout } from "../layout/page-layout";
import { requestMain } from "../../../common/ipc";
import { clusterActivateHandler, clusterRefreshHandler } from "../../../common/cluster-ipc";
import { navigation } from "../../navigation";
import { workspaceStore } from "../../../common/workspace-store";
interface Props extends RouteComponentProps<IClusterSettingsRouteParams> {
}
@@ -39,7 +40,9 @@ export class ClusterSettings extends React.Component<Props> {
reaction(() => this.cluster, this.refreshCluster, {
fireImmediately: true,
}),
reaction(() => this.clusterId, clusterId => clusterStore.setActive(clusterId), {
reaction(() => this.cluster, cluster => {
workspaceStore.getById(cluster.workspace).setActiveCluster(cluster);
}, {
fireImmediately: true,
})
]);
@@ -5,7 +5,7 @@ import { reaction } from "mobx";
import { disposeOnUnmount, observer } from "mobx-react";
import { nodesStore } from "../+nodes/nodes.store";
import { podsStore } from "../+workloads-pods/pods.store";
import { clusterStore, getHostedCluster } from "../../../common/cluster-store";
import { getHostedCluster } from "../../../common/cluster-store";
import { interval } from "../../utils";
import { TabLayout } from "../layout/tab-layout";
import { Spinner } from "../spinner";
@@ -66,7 +66,7 @@ export class ClusterOverview extends React.Component {
render() {
const isLoaded = nodesStore.isLoaded && podsStore.isLoaded;
const isMetricsHidden = clusterStore.isMetricHidden(ResourceType.Cluster);
const isMetricsHidden = getHostedCluster().isMetricHidden(ResourceType.Cluster);
return (
<TabLayout>
@@ -1,38 +1,58 @@
import "./landing-page.scss";
import React from "react";
import { computed, observable } from "mobx";
import { observer } from "mobx-react";
import { computed, reaction } from "mobx";
import { disposeOnUnmount, observer } from "mobx-react";
import { clusterStore } from "../../../common/cluster-store";
import { workspaceStore } from "../../../common/workspace-store";
import { WorkspaceId, workspaceStore } from "../../../common/workspace-store";
import { WorkspaceOverview } from "./workspace-overview";
import { PageLayout } from "../layout/page-layout";
import { Notifications } from "../notifications";
import { Icon } from "../icon";
import { createStorage } from "../../utils";
@observer
export class LandingPage extends React.Component {
@observable showHint = true;
private static storage = createStorage<WorkspaceId[]>("seen_workspaces", []);
@computed
get clusters() {
return clusterStore.getByWorkspaceId(workspaceStore.currentWorkspaceId);
@computed get workspace() {
return workspaceStore.currentWorkspace;
}
componentDidMount() {
const noClustersInScope = !this.clusters.length;
const showStartupHint = this.showHint;
// ignore workspaces that don't exist
const seenWorkspaces = new Set(
LandingPage
.storage
.get()
.filter(id => workspaceStore.getById(id))
);
if (showStartupHint && noClustersInScope) {
Notifications.info(<><b>Welcome!</b><p>Get started by associating one or more clusters to Lens</p></>, {
timeout: 30_000,
id: "landing-welcome"
});
}
disposeOnUnmount(this, [
reaction(() => this.workspace, workspace => {
const showWelcomeNotification = !(
seenWorkspaces.has(workspace.id)
|| workspace.isManaged
|| clusterStore.getByWorkspaceId(workspace.id).length
);
if (showWelcomeNotification) {
Notifications.info(<><b>Welcome!</b><p>Get started by associating one or more clusters to Lens</p></>, {
timeout: 30_000,
id: "landing-welcome"
});
}
seenWorkspaces.add(workspace.id);
LandingPage.storage.set(Array.from(seenWorkspaces));
}, {
fireImmediately: true,
}),
]);
}
render() {
const showBackButton = this.clusters.length > 0;
const header = <><Icon svg="logo-lens" big /> <h2>{workspaceStore.currentWorkspace.name}</h2></>;
const showBackButton = Boolean(this.workspace.activeClusterId);
const header = <><Icon svg="logo-lens" big /> <h2>{this.workspace.name}</h2></>;
return (
<PageLayout className="LandingOverview flex" header={header} provideBackButtonNavigation={showBackButton} showOnTop={true}>
@@ -15,7 +15,7 @@ import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
import { getBackendServiceNamePort } from "../../api/endpoints/ingress.api";
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
import { clusterStore } from "../../../common/cluster-store";
import { getHostedCluster } from "../../../common/cluster-store";
interface Props extends KubeObjectDetailsProps<Ingress> {
}
@@ -101,6 +101,7 @@ export class IngressDetails extends React.Component<Props> {
if (!ingress) {
return null;
}
const { spec, status } = ingress;
const ingressPoints = status?.loadBalancer?.ingress;
const { metrics } = ingressStore;
@@ -108,8 +109,7 @@ export class IngressDetails extends React.Component<Props> {
"Network",
"Duration",
];
const isMetricHidden = clusterStore.isMetricHidden(ResourceType.Ingress);
const isMetricHidden = getHostedCluster().isMetricHidden(ResourceType.Ingress);
const { serviceName, servicePort } = ingress.getServiceNamePort();
return (
@@ -18,7 +18,7 @@ import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { KubeEventDetails } from "../+events/kube-event-details";
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
import { clusterStore } from "../../../common/cluster-store";
import { getHostedCluster } from "../../../common/cluster-store";
interface Props extends KubeObjectDetailsProps<Node> {
}
@@ -54,7 +54,7 @@ export class NodeDetails extends React.Component<Props> {
"Disk",
"Pods",
];
const isMetricHidden = clusterStore.isMetricHidden(ResourceType.Node);
const isMetricHidden = getHostedCluster().isMetricHidden(ResourceType.Node);
return (
<div className="NodeDetails">
@@ -15,7 +15,7 @@ import { getDetailsUrl, KubeObjectDetailsProps, KubeObjectMeta } from "../kube-o
import { PersistentVolumeClaim } from "../../api/endpoints";
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
import { clusterStore } from "../../../common/cluster-store";
import { getHostedCluster } from "../../../common/cluster-store";
interface Props extends KubeObjectDetailsProps<PersistentVolumeClaim> {
}
@@ -43,7 +43,7 @@ export class PersistentVolumeClaimDetails extends React.Component<Props> {
const metricTabs = [
"Disk"
];
const isMetricHidden = clusterStore.isMetricHidden(ResourceType.VolumeClaim);
const isMetricHidden = getHostedCluster().isMetricHidden(ResourceType.VolumeClaim);
return (
<div className="PersistentVolumeClaimDetails">
@@ -19,7 +19,7 @@ import { PodDetailsList } from "../+workloads-pods/pod-details-list";
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
import { clusterStore } from "../../../common/cluster-store";
import { getHostedCluster } from "../../../common/cluster-store";
interface Props extends KubeObjectDetailsProps<DaemonSet> {
}
@@ -49,7 +49,7 @@ export class DaemonSetDetails extends React.Component<Props> {
const nodeSelector = daemonSet.getNodeSelectors();
const childPods = daemonSetStore.getChildPods(daemonSet);
const metrics = daemonSetStore.metrics;
const isMetricHidden = clusterStore.isMetricHidden(ResourceType.DaemonSet);
const isMetricHidden = getHostedCluster().isMetricHidden(ResourceType.DaemonSet);
return (
<div className="DaemonSetDetails">
@@ -20,7 +20,7 @@ import { PodDetailsList } from "../+workloads-pods/pod-details-list";
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
import { clusterStore } from "../../../common/cluster-store";
import { getHostedCluster } from "../../../common/cluster-store";
interface Props extends KubeObjectDetailsProps<Deployment> {
}
@@ -49,7 +49,7 @@ export class DeploymentDetails extends React.Component<Props> {
const selectors = deployment.getSelectors();
const childPods = deploymentStore.getChildPods(deployment);
const metrics = deploymentStore.metrics;
const isMetricHidden = clusterStore.isMetricHidden(ResourceType.Deployment);
const isMetricHidden = getHostedCluster().isMetricHidden(ResourceType.Deployment);
return (
<div className="DeploymentDetails">
@@ -12,7 +12,7 @@ import { ResourceMetrics } from "../resource-metrics";
import { IMetrics } from "../../api/endpoints/metrics.api";
import { ContainerCharts } from "./container-charts";
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
import { clusterStore } from "../../../common/cluster-store";
import { getHostedCluster } from "../../../common/cluster-store";
interface Props {
pod: Pod;
@@ -65,7 +65,7 @@ export class PodDetailsContainer extends React.Component<Props> {
"Memory",
"Filesystem",
];
const isMetricHidden = clusterStore.isMetricHidden(ResourceType.Container);
const isMetricHidden = getHostedCluster().isMetricHidden(ResourceType.Container);
return (
<div className="PodDetailsContainer">
@@ -23,7 +23,7 @@ import { PodCharts, podMetricTabs } from "./pod-charts";
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
import { clusterStore } from "../../../common/cluster-store";
import { getHostedCluster } from "../../../common/cluster-store";
interface Props extends KubeObjectDetailsProps<Pod> {
}
@@ -68,7 +68,7 @@ export class PodDetails extends React.Component<Props> {
const nodeSelector = pod.getNodeSelectors();
const volumes = pod.getVolumes();
const metrics = podsStore.metrics;
const isMetricHidden = clusterStore.isMetricHidden(ResourceType.Pod);
const isMetricHidden = getHostedCluster().isMetricHidden(ResourceType.Pod);
return (
<div className="PodDetails">
@@ -18,7 +18,7 @@ import { PodDetailsList } from "../+workloads-pods/pod-details-list";
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
import { clusterStore } from "../../../common/cluster-store";
import { getHostedCluster } from "../../../common/cluster-store";
interface Props extends KubeObjectDetailsProps<ReplicaSet> {
}
@@ -49,7 +49,7 @@ export class ReplicaSetDetails extends React.Component<Props> {
const nodeSelector = replicaSet.getNodeSelectors();
const images = replicaSet.getImages();
const childPods = replicaSetStore.getChildPods(replicaSet);
const isMetricHidden = clusterStore.isMetricHidden(ResourceType.ReplicaSet);
const isMetricHidden = getHostedCluster().isMetricHidden(ResourceType.ReplicaSet);
return (
<div className="ReplicaSetDetails">
@@ -19,7 +19,7 @@ import { PodDetailsList } from "../+workloads-pods/pod-details-list";
import { KubeObjectMeta } from "../kube-object/kube-object-meta";
import { kubeObjectDetailRegistry } from "../../api/kube-object-detail-registry";
import { ResourceType } from "../+cluster-settings/components/cluster-metrics-setting";
import { clusterStore } from "../../../common/cluster-store";
import { getHostedCluster } from "../../../common/cluster-store";
interface Props extends KubeObjectDetailsProps<StatefulSet> {
}
@@ -48,7 +48,7 @@ export class StatefulSetDetails extends React.Component<Props> {
const nodeSelector = statefulSet.getNodeSelectors();
const childPods = statefulSetStore.getChildPods(statefulSet);
const metrics = statefulSetStore.metrics;
const isMetricHidden = clusterStore.isMetricHidden(ResourceType.StatefulSet);
const isMetricHidden = getHostedCluster().isMetricHidden(ResourceType.StatefulSet);
return (
<div className="StatefulSetDetails">
@@ -7,7 +7,6 @@ import { Input, InputValidator } from "../input";
import { navigate } from "../../navigation";
import { CommandOverlay } from "../command-palette/command-container";
import { landingURL } from "../+landing-page";
import { clusterStore } from "../../../common/cluster-store";
const uniqueWorkspaceName: InputValidator = {
condition: ({ required }) => required,
@@ -31,7 +30,6 @@ export class AddWorkspace extends React.Component {
}
workspaceStore.setActive(workspace.id);
clusterStore.setActive(null);
navigate(landingURL());
CommandOverlay.close();
}
@@ -3,7 +3,7 @@ import { observer } from "mobx-react";
import { computed} from "mobx";
import { WorkspaceStore, workspaceStore } from "../../../common/workspace-store";
import { commandRegistry } from "../../../extensions/registries/command-registry";
import { Select } from "../select";
import { Select, SelectOption } from "../select";
import { navigate } from "../../navigation";
import { CommandOverlay } from "../command-palette/command-container";
import { AddWorkspace } from "./add-workspace";
@@ -20,8 +20,8 @@ export class ChooseWorkspace extends React.Component {
private static editActionId = "__edit__";
@computed get options() {
const options = workspaceStore.enabledWorkspacesList.map((workspace) => {
return { value: workspace.id, label: workspace.name };
const options: SelectOption<string | symbol>[] = workspaceStore.enabledWorkspacesList.map((workspace) => {
return { value: workspace.id, label: workspace.name, isDisabled: workspaceStore.isActive(workspace) };
});
options.push({ value: ChooseWorkspace.overviewActionId, label: "Show current workspace overview ..." });
@@ -39,42 +39,30 @@ export class ChooseWorkspace extends React.Component {
return options;
}
onChange(id: string) {
if (id === ChooseWorkspace.overviewActionId) {
navigate(landingURL()); // overview of active workspace. TODO: change name from landing
CommandOverlay.close();
onChange(idOrAction: string): void {
switch (idOrAction) {
case ChooseWorkspace.overviewActionId:
navigate(landingURL()); // overview of active workspace. TODO: change name from landing
return;
return CommandOverlay.close();
case ChooseWorkspace.addActionId:
return CommandOverlay.open(<AddWorkspace />);
case ChooseWorkspace.removeActionId:
return CommandOverlay.open(<RemoveWorkspace />);
case ChooseWorkspace.editActionId:
return CommandOverlay.open(<EditWorkspace />);
default: // assume id
workspaceStore.setActive(idOrAction);
const clusterId = workspaceStore.getById(idOrAction).activeClusterId;
if (clusterId) {
navigate(clusterViewURL({ params: { clusterId } }));
} else {
navigate(landingURL());
}
CommandOverlay.close();
}
if (id === ChooseWorkspace.addActionId) {
CommandOverlay.open(<AddWorkspace />);
return;
}
if (id === ChooseWorkspace.removeActionId) {
CommandOverlay.open(<RemoveWorkspace />);
return;
}
if (id === ChooseWorkspace.editActionId) {
CommandOverlay.open(<EditWorkspace />);
return;
}
workspaceStore.setActive(id);
const clusterId = workspaceStore.getById(id).lastActiveClusterId;
if (clusterId) {
navigate(clusterViewURL({ params: { clusterId } }));
} else {
navigate(landingURL());
}
CommandOverlay.close();
}
render() {
@@ -9,7 +9,8 @@ import { cssNames, IClassName } from "../../utils";
import { Badge } from "../badge";
import { Tooltip } from "../tooltip";
import { subscribeToBroadcast } from "../../../common/ipc";
import { observable } from "mobx";
import { computed, observable } from "mobx";
import { workspaceStore } from "../../../common/workspace-store";
interface Props extends DOMAttributes<HTMLElement> {
cluster: Cluster;
@@ -18,7 +19,6 @@ interface Props extends DOMAttributes<HTMLElement> {
showErrors?: boolean;
showTooltip?: boolean;
interactive?: boolean;
isActive?: boolean;
options?: HashiconParams;
}
@@ -33,8 +33,16 @@ export class ClusterIcon extends React.Component<Props> {
@observable eventCount = 0;
get eventCountBroadcast() {
return `cluster-warning-event-count:${this.props.cluster.id}`;
@computed get eventCountBroadcast() {
const { cluster } = this.props;
return `cluster-warning-event-count:${cluster.id}`;
}
@computed get isActive() {
const { cluster } = this.props;
return workspaceStore.getById(cluster.workspace).activeClusterId === cluster.id;
}
componentDidMount() {
@@ -48,8 +56,9 @@ export class ClusterIcon extends React.Component<Props> {
}
render() {
const { isActive } = this;
const {
cluster, showErrors, showTooltip, errorClass, options, interactive, isActive,
cluster, showErrors, showTooltip, errorClass, options, interactive,
children, ...elemProps
} = this.props;
const { name, preferences, id: clusterId, online } = cluster;
@@ -10,6 +10,7 @@ import { ConfirmDialog } from "../confirm-dialog";
import { Cluster } from "../../../main/cluster";
import { Tooltip } from "../../components//tooltip";
import { IpcRendererNavigationEvents } from "../../navigation/events";
import { workspaceStore } from "../../../common/workspace-store";
const navigate = (route: string) =>
broadcastMessage(IpcRendererNavigationEvents.NAVIGATE_IN_APP, route);
@@ -24,8 +25,10 @@ export const ClusterActions = (cluster: Cluster) => ({
params: { clusterId: cluster.id }
})),
disconnect: async () => {
clusterStore.deactivate(cluster.id);
navigate(landingURL());
if (workspaceStore.tryClearAsActiveCluster(cluster)) {
navigate(landingURL());
}
await requestMain(clusterDisconnectHandler, cluster.id);
},
remove: () => {
@@ -38,7 +41,6 @@ export const ClusterActions = (cluster: Cluster) => ({
label: "Remove"
},
ok: () => {
clusterStore.deactivate(cluster.id);
clusterStore.removeById(cluster.id);
navigate(landingURL());
},
@@ -17,6 +17,7 @@ import { hasLoadedView, initView, lensViews, refreshViews } from "./lens-views";
import { globalPageRegistry } from "../../../extensions/registries/page-registry";
import { Extensions, extensionsRoute } from "../+extensions";
import { getMatchedClusterId } from "../../navigation";
import { workspaceStore } from "../../../common/workspace-store";
@observer
export class ClusterManager extends React.Component {
@@ -44,12 +45,12 @@ export class ClusterManager extends React.Component {
}
get startUrl() {
const { activeClusterId } = clusterStore;
const { currentWorkspace } = workspaceStore;
if (activeClusterId) {
if (currentWorkspace.activeClusterId) {
return clusterViewURL({
params: {
clusterId: activeClusterId
clusterId: currentWorkspace.activeClusterId
}
});
}
@@ -8,6 +8,7 @@ import { ClusterStatus } from "./cluster-status";
import { hasLoadedView } from "./lens-views";
import { Cluster } from "../../../main/cluster";
import { clusterStore } from "../../../common/cluster-store";
import { workspaceStore } from "../../../common/workspace-store";
interface Props extends RouteComponentProps<IClusterViewRouteParams> {
}
@@ -24,7 +25,9 @@ export class ClusterView extends React.Component<Props> {
async componentDidMount() {
disposeOnUnmount(this, [
reaction(() => this.clusterId, clusterId => clusterStore.setActive(clusterId), {
reaction(() => this.cluster, cluster => {
workspaceStore.getById(cluster.workspace).setActiveCluster(cluster);
}, {
fireImmediately: true,
})
]);
@@ -30,6 +30,10 @@ interface Props {
export class ClustersMenu extends React.Component<Props> {
@observable workspaceMenuVisible = false;
get workspace() {
return workspaceStore.currentWorkspace;
}
showCluster = (clusterId: ClusterId) => {
navigate(clusterViewURL({ params: { clusterId } }));
};
@@ -77,9 +81,7 @@ export class ClustersMenu extends React.Component<Props> {
render() {
const { className } = this.props;
const workspace = workspaceStore.getById(workspaceStore.currentWorkspaceId);
const clusters = clusterStore.getByWorkspaceId(workspace.id).filter(cluster => cluster.enabled);
const activeClusterId = clusterStore.activeCluster;
const clusters = clusterStore.getByWorkspaceId(this.workspace.id).filter(cluster => cluster.enabled);
return (
<div className={cssNames("ClustersMenu flex column", className)}>
@@ -88,26 +90,21 @@ export class ClustersMenu extends React.Component<Props> {
<Droppable droppableId="cluster-menu" type="CLUSTER">
{({ innerRef, droppableProps, placeholder }: DroppableProvided) => (
<div ref={innerRef} {...droppableProps}>
{clusters.map((cluster, index) => {
const isActive = cluster.id === activeClusterId;
return (
<Draggable draggableId={cluster.id} index={index} key={cluster.id}>
{({ draggableProps, dragHandleProps, innerRef }: DraggableProvided) => (
<div ref={innerRef} {...draggableProps} {...dragHandleProps}>
<ClusterIcon
key={cluster.id}
showErrors={true}
cluster={cluster}
isActive={isActive}
onClick={() => this.showCluster(cluster.id)}
onContextMenu={() => this.showContextMenu(cluster)}
/>
</div>
)}
</Draggable>
);
})}
{clusters.map((cluster, index) => (
<Draggable draggableId={cluster.id} index={index} key={cluster.id}>
{({ draggableProps, dragHandleProps, innerRef }: DraggableProvided) => (
<div ref={innerRef} {...draggableProps} {...dragHandleProps}>
<ClusterIcon
key={cluster.id}
showErrors={true}
cluster={cluster}
onClick={() => this.showCluster(cluster.id)}
onContextMenu={() => this.showContextMenu(cluster)}
/>
</div>
)}
</Draggable>
))}
{placeholder}
</div>
)}
@@ -8,7 +8,6 @@ import { EventEmitter } from "../../../common/event-emitter";
import { subscribeToBroadcast } from "../../../common/ipc";
import { CommandDialog } from "./command-dialog";
import { CommandRegistration, commandRegistry } from "../../../extensions/registries/command-registry";
import { clusterStore } from "../../../common/cluster-store";
import { workspaceStore } from "../../../common/workspace-store";
export type CommandDialogEvent = {
@@ -49,7 +48,7 @@ export class CommandContainer extends React.Component<{ clusterId?: string }> {
private runCommand(command: CommandRegistration) {
command.action({
cluster: clusterStore.active,
cluster: workspaceStore.currentWorkspace.activeCluster,
workspace: workspaceStore.currentWorkspace
});
}
@@ -4,7 +4,6 @@ import { computed, observable, toJS } from "mobx";
import { observer } from "mobx-react";
import React from "react";
import { commandRegistry } from "../../../extensions/registries/command-registry";
import { clusterStore } from "../../../common/cluster-store";
import { workspaceStore } from "../../../common/workspace-store";
import { CommandOverlay } from "./command-container";
import { broadcastMessage } from "../../../common/ipc";
@@ -16,30 +15,31 @@ export class CommandDialog extends React.Component {
@observable menuIsOpen = true;
@computed get options() {
const context = {
cluster: clusterStore.active,
workspace: workspaceStore.currentWorkspace
};
const activeCluster = workspaceStore.currentWorkspace.activeCluster;
return commandRegistry.getItems().filter((command) => {
if (command.scope === "cluster" && !clusterStore.active) {
return false;
}
return commandRegistry.getItems()
.filter(command => {
if (command.scope === "cluster" && !activeCluster) {
return false;
}
if (!command.isActive) {
return true;
}
if (!command.isActive) {
return true;
}
try {
return command.isActive(context);
} catch(e) {
console.error(e);
try {
return command.isActive({
cluster: activeCluster,
workspace: workspaceStore.currentWorkspace
});
} catch(e) {
console.error(e);
return false;
}
}).map((command) => {
return { value: command.id, label: command.title };
}).sort((a, b) => a.label > b.label ? 1 : -1);
return false;
}
})
.map(({ id, title }) => ({ value: id, label: title }))
.sort((a, b) => a.label > b.label ? 1 : -1);
}
private onChange(value: string) {
@@ -49,6 +49,7 @@ export class CommandDialog extends React.Component {
return;
}
const activeCluster = workspaceStore.currentWorkspace.activeCluster;
const action = toJS(command.action);
try {
@@ -56,16 +57,16 @@ export class CommandDialog extends React.Component {
if (command.scope === "global") {
action({
cluster: clusterStore.active,
cluster: activeCluster,
workspace: workspaceStore.currentWorkspace
});
} else if(clusterStore.active) {
} else if(activeCluster) {
navigate(clusterViewURL({
params: {
clusterId: clusterStore.active.id
clusterId: activeCluster.id
}
}));
broadcastMessage(`command-palette:run-action:${clusterStore.active.id}`, command.id);
broadcastMessage(`command-palette:run-action:${activeCluster.id}`, command.id);
}
} catch(error) {
console.error("[COMMAND-DIALOG] failed to execute command", command.id, error);
+8 -1
View File
@@ -8,6 +8,7 @@ import { invalidKubeconfigHandler } from "./invalid-kubeconfig-handler";
import { clusterStore } from "../../common/cluster-store";
import { navigate } from "../navigation";
import { clusterSettingsURL } from "../components/+cluster-settings";
import logger from "../../main/logger";
function sendToBackchannel(backchannel: string, notificationId: string, data: BackchannelArg): void {
notificationsStore.remove(notificationId);
@@ -59,6 +60,12 @@ const listNamespacesForbiddenHandlerDisplayedAt = new Map<string, number>();
const intervalBetweenNotifications = 1000 * 60; // 60s
function ListNamespacesForbiddenHandler(event: IpcRendererEvent, ...[clusterId]: ListNamespaceForbiddenArgs): void {
const cluster = clusterStore.getById(clusterId);
if (!cluster) {
return void logger.warn("[ListNamespacesForbiddenHandler]: received event but was given an unknown cluster ID", { clusterId });
}
const lastDisplayedAt = listNamespacesForbiddenHandlerDisplayedAt.get(clusterId);
const wasDisplayed = Boolean(lastDisplayedAt);
const now = Date.now();
@@ -76,7 +83,7 @@ function ListNamespacesForbiddenHandler(event: IpcRendererEvent, ...[clusterId]:
(
<div className="flex column gaps">
<b>Add Accessible Namespaces</b>
<p>Cluster <b>{clusterStore.active.name}</b> does not have permissions to list namespaces. Please add the namespaces you have access to.</p>
<p>Cluster <b>{cluster.name}</b> does not have permissions to list namespaces. Please add the namespaces you have access to.</p>
<div className="flex gaps row align-left box grow">
<Button active outlined label="Go to Accessible Namespaces Settings" onClick={()=> {
navigate(clusterSettingsURL({ params: { clusterId }, fragment: "accessible-namespaces" }));