mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
tweak
Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
parent
3f158f4a4b
commit
c1a3f6f280
@ -3,6 +3,8 @@
|
||||
import type { Cluster } from "../../main/cluster";
|
||||
import type { Workspace } from "../../common/workspace-store";
|
||||
import { BaseRegistry } from "./base-registry";
|
||||
import { action } from "mobx";
|
||||
import { LensExtension } from "../lens-extension";
|
||||
|
||||
export type CommandContext = {
|
||||
cluster?: Cluster;
|
||||
@ -18,6 +20,18 @@ export interface CommandRegistration {
|
||||
}
|
||||
|
||||
export class CommandRegistry extends BaseRegistry<CommandRegistration> {
|
||||
@action
|
||||
add(items: CommandRegistration | CommandRegistration[], extension?: LensExtension) {
|
||||
const itemArray = [items].flat() as CommandRegistration[];
|
||||
|
||||
const newIds = itemArray.map((item) => item.id);
|
||||
const currentIds = this.getItems().map((item) => item.id);
|
||||
|
||||
const filteredIds = newIds.filter((id) => !currentIds.includes(id));
|
||||
const filteredItems = itemArray.filter((item) => filteredIds.includes(item.id));
|
||||
|
||||
return super.add(filteredItems, extension);
|
||||
}
|
||||
}
|
||||
|
||||
export const commandRegistry = new CommandRegistry();
|
||||
|
||||
@ -26,6 +26,7 @@ import { InstalledExtension, extensionDiscovery } from "../extensions/extension-
|
||||
import type { LensExtensionId } from "../extensions/lens-extension";
|
||||
import { installDeveloperTools } from "./developer-tools";
|
||||
import { filesystemProvisionerStore } from "./extension-filesystem";
|
||||
import { bindBroadcastHandlers } from "../common/ipc";
|
||||
|
||||
const workingDir = path.join(app.getPath("appData"), appName);
|
||||
let proxyPort: number;
|
||||
@ -63,6 +64,8 @@ app.on("ready", async () => {
|
||||
logger.info(`🚀 Starting Lens from "${workingDir}"`);
|
||||
await shellSync();
|
||||
|
||||
bindBroadcastHandlers();
|
||||
|
||||
powerMonitor.on("shutdown", () => {
|
||||
app.exit();
|
||||
});
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { workspacesURL } from "../../+workspaces";
|
||||
import { workspaceStore } from "../../../../common/workspace-store";
|
||||
import { Cluster } from "../../../../main/cluster";
|
||||
import { Select } from "../../../components/select";
|
||||
@ -18,10 +16,7 @@ export class ClusterWorkspaceSetting extends React.Component<Props> {
|
||||
<>
|
||||
<SubTitle title="Cluster Workspace"/>
|
||||
<p>
|
||||
Define cluster{" "}
|
||||
<Link to={workspacesURL()}>
|
||||
workspace
|
||||
</Link>.
|
||||
Define cluster workspace.
|
||||
</p>
|
||||
<Select
|
||||
value={this.props.cluster.workspace}
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import type { RouteProps } from "react-router";
|
||||
import { buildURL, IURLParams } from "../../../common/utils/buildUrl";
|
||||
import { KubeResource } from "../../../common/rbac";
|
||||
import { isAllowedResource, KubeResource } from "../../../common/rbac";
|
||||
import { Workloads } from "./workloads";
|
||||
import { navigate } from "../../navigation";
|
||||
import { commandRegistry } from "../../../extensions/registries/command-registry";
|
||||
|
||||
export const workloadsRoute: RouteProps = {
|
||||
get path() {
|
||||
@ -80,3 +82,31 @@ export const workloadURL: Partial<Record<KubeResource, ReturnType<typeof buildUR
|
||||
"jobs": jobsURL,
|
||||
"cronjobs": cronJobsURL,
|
||||
};
|
||||
|
||||
commandRegistry.add({
|
||||
id: "cluster.viewPods",
|
||||
title: "Cluster: View Pods",
|
||||
scope: "cluster",
|
||||
action: () => navigate(podsURL())
|
||||
});
|
||||
|
||||
commandRegistry.add({
|
||||
id: "cluster.viewDeployments",
|
||||
title: "Cluster: View Deployments",
|
||||
scope: "cluster",
|
||||
action: () => navigate(deploymentsURL())
|
||||
});
|
||||
|
||||
commandRegistry.add({
|
||||
id: "cluster.viewDaemonSets",
|
||||
title: "Cluster: View DaemonSets",
|
||||
scope: "cluster",
|
||||
action: () => navigate(daemonSetsURL())
|
||||
});
|
||||
|
||||
commandRegistry.add({
|
||||
id: "cluster.viewStatefulSets",
|
||||
title: "Cluster: View StatefulSets",
|
||||
scope: "cluster",
|
||||
action: () => navigate(statefulSetsURL())
|
||||
});
|
||||
|
||||
@ -65,7 +65,7 @@ export class RemoveWorkspace extends React.Component {
|
||||
|
||||
commandRegistry.add({
|
||||
id: "workspace.removeWorkspace",
|
||||
title: "Workspace: Remove ...",
|
||||
title: "Workspace: Remove workspace ...",
|
||||
scope: "global",
|
||||
action: () => openCommandDialog(<RemoveWorkspace />)
|
||||
});
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
.Workspaces {
|
||||
.workspace {
|
||||
--flex-gap: #{$padding};
|
||||
padding: $padding / 2;
|
||||
|
||||
&.default {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
> .description {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,3 @@
|
||||
import "./workspaces.scss";
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { computed} from "mobx";
|
||||
@ -65,7 +64,7 @@ export class ChooseWorkspace extends React.Component {
|
||||
|
||||
commandRegistry.add({
|
||||
id: "workspace.chooseWorkspace",
|
||||
title: "Workspace: Choose...",
|
||||
title: "Workspace: Switch to workspace ...",
|
||||
scope: "global",
|
||||
action: () => openCommandDialog(<ChooseWorkspace />)
|
||||
});
|
||||
|
||||
@ -173,6 +173,8 @@ export class App extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const cluster = getHostedCluster();
|
||||
|
||||
return (
|
||||
<Router history={history}>
|
||||
<ErrorBoundary>
|
||||
@ -204,7 +206,7 @@ export class App extends React.Component {
|
||||
<StatefulSetScaleDialog/>
|
||||
<ReplicaSetScaleDialog/>
|
||||
<CronJobTriggerDialog/>
|
||||
<CommandContainer listenPaletteOpen={false} />
|
||||
<CommandContainer cluster={cluster} />
|
||||
</ErrorBoundary>
|
||||
</Router>
|
||||
);
|
||||
|
||||
@ -22,6 +22,10 @@ import { ConfirmDialog } from "../confirm-dialog";
|
||||
import { clusterViewURL } from "./cluster-view.route";
|
||||
import { getExtensionPageUrl, globalPageMenuRegistry, globalPageRegistry } from "../../../extensions/registries";
|
||||
import { clusterDisconnectHandler } from "../../../common/cluster-ipc";
|
||||
import { commandRegistry } from "../../../extensions/registries/command-registry";
|
||||
import { closeCommandDialog, openCommandDialog } from "../command-palette/command-container";
|
||||
import { computed } from "mobx";
|
||||
import { Select } from "../select";
|
||||
|
||||
interface Props {
|
||||
className?: IClassName;
|
||||
@ -178,3 +182,41 @@ export class ClustersMenu extends React.Component<Props> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@observer
|
||||
export class ChooseCluster extends React.Component {
|
||||
@computed get options() {
|
||||
const clusters = clusterStore.getByWorkspaceId(workspaceStore.currentWorkspaceId).filter(cluster => cluster.enabled);
|
||||
const options = clusters.map((cluster) => {
|
||||
return { value: cluster.id, label: cluster.name };
|
||||
});
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
onChange(clusterId: string) {
|
||||
navigate(clusterViewURL({ params: { clusterId } }));
|
||||
closeCommandDialog();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Select
|
||||
onChange={(v) => this.onChange(v.value)}
|
||||
components={{ DropdownIndicator: null, IndicatorSeparator: null }}
|
||||
menuIsOpen={true}
|
||||
options={this.options}
|
||||
autoFocus={true}
|
||||
escapeClearsValue={false}
|
||||
placeholder="Switch to cluster" />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
commandRegistry.add({
|
||||
id: "workspace.chooseCluster",
|
||||
title: "Workspace: Switch to cluster ...",
|
||||
scope: "global",
|
||||
action: () => openCommandDialog(<ChooseCluster />)
|
||||
});
|
||||
|
||||
@ -7,6 +7,10 @@ import { Dialog } from "../dialog";
|
||||
import { EventEmitter } from "../../../common/event-emitter";
|
||||
import { subscribeToBroadcast } from "../../../common/ipc";
|
||||
import { CommandDialog } from "./command-dialog";
|
||||
import { CommandRegistration, commandRegistry } from "../../../extensions/registries/command-registry";
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
import { workspaceStore } from "../../../common/workspace-store";
|
||||
import { Cluster } from "../../../main/cluster";
|
||||
|
||||
export type CommandDialogEvent = {
|
||||
component: React.ReactElement
|
||||
@ -23,7 +27,7 @@ export function closeCommandDialog() {
|
||||
}
|
||||
|
||||
@observer
|
||||
export class CommandContainer extends React.Component<{listenPaletteOpen: boolean}> {
|
||||
export class CommandContainer extends React.Component<{cluster?: Cluster}> {
|
||||
@observable visible = false;
|
||||
@observable commandComponent: React.ReactElement;
|
||||
|
||||
@ -39,22 +43,49 @@ export class CommandContainer extends React.Component<{listenPaletteOpen: boolea
|
||||
this.commandComponent = null;
|
||||
}
|
||||
|
||||
private findCommandById(commandId: string) {
|
||||
return commandRegistry.getItems().find((command) => command.id === commandId);
|
||||
}
|
||||
|
||||
private runCommand(command: CommandRegistration) {
|
||||
command.action({
|
||||
cluster: clusterStore.active,
|
||||
workspace: workspaceStore.currentWorkspace
|
||||
});
|
||||
}
|
||||
|
||||
onClusterAction(commandId: string) {
|
||||
const command = this.findCommandById(commandId);
|
||||
|
||||
if (command) {
|
||||
this.runCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.listenPaletteOpen) {
|
||||
if (this.props.cluster) {
|
||||
subscribeToBroadcast(`command-palette:run-action:${this.props.cluster.id}`, (event, commandId: string) => {
|
||||
console.log("run-action", commandId);
|
||||
const command = this.findCommandById(commandId);
|
||||
|
||||
if (command) {
|
||||
this.runCommand(command);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
subscribeToBroadcast("command-palette:open", () => {
|
||||
openCommandDialog(<CommandDialog />);
|
||||
});
|
||||
}
|
||||
window.addEventListener("keyup", (e) => this.escHandler(e), true);
|
||||
commandDialogBus.addListener((event) => {
|
||||
console.log(event);
|
||||
this.commandComponent = event.component;
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Dialog isOpen={!!this.commandComponent} animated={false}>
|
||||
<Dialog isOpen={!!this.commandComponent} animated={false} onClose={() => this.commandComponent = null}>
|
||||
<div id="command-container">
|
||||
{this.commandComponent}
|
||||
</div>
|
||||
|
||||
@ -7,15 +7,37 @@ import { commandRegistry } from "../../../extensions/registries/command-registry
|
||||
import { clusterStore } from "../../../common/cluster-store";
|
||||
import { workspaceStore } from "../../../common/workspace-store";
|
||||
import { closeCommandDialog } from "./command-container";
|
||||
import { broadcastMessage } from "../../../common/ipc";
|
||||
|
||||
@observer
|
||||
export class CommandDialog extends React.Component {
|
||||
@observable menuIsOpen = true;
|
||||
|
||||
@computed get options() {
|
||||
return commandRegistry.getItems().map((command) => {
|
||||
const context = {
|
||||
cluster: clusterStore.active,
|
||||
workspace: workspaceStore.currentWorkspace
|
||||
};
|
||||
|
||||
return commandRegistry.getItems().filter((command) => {
|
||||
if (command.scope === "cluster" && !clusterStore.active) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!command.isActive) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
return command.isActive(context);
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
|
||||
return false;
|
||||
}
|
||||
}).map((command) => {
|
||||
return { value: command.id, label: command.title };
|
||||
});
|
||||
}).sort((a, b) => a.label > b.label ? 1 : -1);
|
||||
}
|
||||
|
||||
private onChange(value: string) {
|
||||
@ -29,10 +51,15 @@ export class CommandDialog extends React.Component {
|
||||
|
||||
try {
|
||||
closeCommandDialog();
|
||||
action({
|
||||
cluster: clusterStore.active,
|
||||
workspace: workspaceStore.currentWorkspace
|
||||
});
|
||||
|
||||
if (command.scope === "global") {
|
||||
action({
|
||||
cluster: clusterStore.active,
|
||||
workspace: workspaceStore.currentWorkspace
|
||||
});
|
||||
} else if(clusterStore.active) {
|
||||
broadcastMessage(`command-palette:run-action:${clusterStore.active.id}`, command.id);
|
||||
}
|
||||
} catch(error) {
|
||||
console.error("failed to execute command", command.id, error);
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ import { TerminalWindow } from "./terminal-window";
|
||||
import { createTerminalTab, isTerminalTab } from "./terminal.store";
|
||||
import { UpgradeChart } from "./upgrade-chart";
|
||||
import { isUpgradeChartTab } from "./upgrade-chart.store";
|
||||
import { commandRegistry } from "../../../extensions/registries/command-registry";
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
@ -131,3 +132,11 @@ export class Dock extends React.Component<Props> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
commandRegistry.add({
|
||||
id: "cluster.openTerminal",
|
||||
title: "Cluster: Open terminal",
|
||||
scope: "cluster",
|
||||
action: () => createTerminalTab(),
|
||||
isActive: (context) => !!context.cluster
|
||||
});
|
||||
|
||||
@ -38,7 +38,7 @@ export class LensApp extends React.Component {
|
||||
</ErrorBoundary>
|
||||
<Notifications/>
|
||||
<ConfirmDialog/>
|
||||
<CommandContainer listenPaletteOpen={true} />
|
||||
<CommandContainer />
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user