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 { Cluster } from "../../main/cluster";
|
||||||
import type { Workspace } from "../../common/workspace-store";
|
import type { Workspace } from "../../common/workspace-store";
|
||||||
import { BaseRegistry } from "./base-registry";
|
import { BaseRegistry } from "./base-registry";
|
||||||
|
import { action } from "mobx";
|
||||||
|
import { LensExtension } from "../lens-extension";
|
||||||
|
|
||||||
export type CommandContext = {
|
export type CommandContext = {
|
||||||
cluster?: Cluster;
|
cluster?: Cluster;
|
||||||
@ -18,6 +20,18 @@ export interface CommandRegistration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class CommandRegistry extends BaseRegistry<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();
|
export const commandRegistry = new CommandRegistry();
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import { InstalledExtension, extensionDiscovery } from "../extensions/extension-
|
|||||||
import type { LensExtensionId } from "../extensions/lens-extension";
|
import type { LensExtensionId } from "../extensions/lens-extension";
|
||||||
import { installDeveloperTools } from "./developer-tools";
|
import { installDeveloperTools } from "./developer-tools";
|
||||||
import { filesystemProvisionerStore } from "./extension-filesystem";
|
import { filesystemProvisionerStore } from "./extension-filesystem";
|
||||||
|
import { bindBroadcastHandlers } from "../common/ipc";
|
||||||
|
|
||||||
const workingDir = path.join(app.getPath("appData"), appName);
|
const workingDir = path.join(app.getPath("appData"), appName);
|
||||||
let proxyPort: number;
|
let proxyPort: number;
|
||||||
@ -63,6 +64,8 @@ app.on("ready", async () => {
|
|||||||
logger.info(`🚀 Starting Lens from "${workingDir}"`);
|
logger.info(`🚀 Starting Lens from "${workingDir}"`);
|
||||||
await shellSync();
|
await shellSync();
|
||||||
|
|
||||||
|
bindBroadcastHandlers();
|
||||||
|
|
||||||
powerMonitor.on("shutdown", () => {
|
powerMonitor.on("shutdown", () => {
|
||||||
app.exit();
|
app.exit();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { Link } from "react-router-dom";
|
|
||||||
import { workspacesURL } from "../../+workspaces";
|
|
||||||
import { workspaceStore } from "../../../../common/workspace-store";
|
import { workspaceStore } from "../../../../common/workspace-store";
|
||||||
import { Cluster } from "../../../../main/cluster";
|
import { Cluster } from "../../../../main/cluster";
|
||||||
import { Select } from "../../../components/select";
|
import { Select } from "../../../components/select";
|
||||||
@ -18,10 +16,7 @@ export class ClusterWorkspaceSetting extends React.Component<Props> {
|
|||||||
<>
|
<>
|
||||||
<SubTitle title="Cluster Workspace"/>
|
<SubTitle title="Cluster Workspace"/>
|
||||||
<p>
|
<p>
|
||||||
Define cluster{" "}
|
Define cluster workspace.
|
||||||
<Link to={workspacesURL()}>
|
|
||||||
workspace
|
|
||||||
</Link>.
|
|
||||||
</p>
|
</p>
|
||||||
<Select
|
<Select
|
||||||
value={this.props.cluster.workspace}
|
value={this.props.cluster.workspace}
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import type { RouteProps } from "react-router";
|
import type { RouteProps } from "react-router";
|
||||||
import { buildURL, IURLParams } from "../../../common/utils/buildUrl";
|
import { buildURL, IURLParams } from "../../../common/utils/buildUrl";
|
||||||
import { KubeResource } from "../../../common/rbac";
|
import { isAllowedResource, KubeResource } from "../../../common/rbac";
|
||||||
import { Workloads } from "./workloads";
|
import { Workloads } from "./workloads";
|
||||||
|
import { navigate } from "../../navigation";
|
||||||
|
import { commandRegistry } from "../../../extensions/registries/command-registry";
|
||||||
|
|
||||||
export const workloadsRoute: RouteProps = {
|
export const workloadsRoute: RouteProps = {
|
||||||
get path() {
|
get path() {
|
||||||
@ -80,3 +82,31 @@ export const workloadURL: Partial<Record<KubeResource, ReturnType<typeof buildUR
|
|||||||
"jobs": jobsURL,
|
"jobs": jobsURL,
|
||||||
"cronjobs": cronJobsURL,
|
"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({
|
commandRegistry.add({
|
||||||
id: "workspace.removeWorkspace",
|
id: "workspace.removeWorkspace",
|
||||||
title: "Workspace: Remove ...",
|
title: "Workspace: Remove workspace ...",
|
||||||
scope: "global",
|
scope: "global",
|
||||||
action: () => openCommandDialog(<RemoveWorkspace />)
|
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 React from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { computed} from "mobx";
|
import { computed} from "mobx";
|
||||||
@ -65,7 +64,7 @@ export class ChooseWorkspace extends React.Component {
|
|||||||
|
|
||||||
commandRegistry.add({
|
commandRegistry.add({
|
||||||
id: "workspace.chooseWorkspace",
|
id: "workspace.chooseWorkspace",
|
||||||
title: "Workspace: Choose...",
|
title: "Workspace: Switch to workspace ...",
|
||||||
scope: "global",
|
scope: "global",
|
||||||
action: () => openCommandDialog(<ChooseWorkspace />)
|
action: () => openCommandDialog(<ChooseWorkspace />)
|
||||||
});
|
});
|
||||||
|
|||||||
@ -173,6 +173,8 @@ export class App extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const cluster = getHostedCluster();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Router history={history}>
|
<Router history={history}>
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
@ -204,7 +206,7 @@ export class App extends React.Component {
|
|||||||
<StatefulSetScaleDialog/>
|
<StatefulSetScaleDialog/>
|
||||||
<ReplicaSetScaleDialog/>
|
<ReplicaSetScaleDialog/>
|
||||||
<CronJobTriggerDialog/>
|
<CronJobTriggerDialog/>
|
||||||
<CommandContainer listenPaletteOpen={false} />
|
<CommandContainer cluster={cluster} />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -22,6 +22,10 @@ import { ConfirmDialog } from "../confirm-dialog";
|
|||||||
import { clusterViewURL } from "./cluster-view.route";
|
import { clusterViewURL } from "./cluster-view.route";
|
||||||
import { getExtensionPageUrl, globalPageMenuRegistry, globalPageRegistry } from "../../../extensions/registries";
|
import { getExtensionPageUrl, globalPageMenuRegistry, globalPageRegistry } from "../../../extensions/registries";
|
||||||
import { clusterDisconnectHandler } from "../../../common/cluster-ipc";
|
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 {
|
interface Props {
|
||||||
className?: IClassName;
|
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 { EventEmitter } from "../../../common/event-emitter";
|
||||||
import { subscribeToBroadcast } from "../../../common/ipc";
|
import { subscribeToBroadcast } from "../../../common/ipc";
|
||||||
import { CommandDialog } from "./command-dialog";
|
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 = {
|
export type CommandDialogEvent = {
|
||||||
component: React.ReactElement
|
component: React.ReactElement
|
||||||
@ -23,7 +27,7 @@ export function closeCommandDialog() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class CommandContainer extends React.Component<{listenPaletteOpen: boolean}> {
|
export class CommandContainer extends React.Component<{cluster?: Cluster}> {
|
||||||
@observable visible = false;
|
@observable visible = false;
|
||||||
@observable commandComponent: React.ReactElement;
|
@observable commandComponent: React.ReactElement;
|
||||||
|
|
||||||
@ -39,22 +43,49 @@ export class CommandContainer extends React.Component<{listenPaletteOpen: boolea
|
|||||||
this.commandComponent = null;
|
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() {
|
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", () => {
|
subscribeToBroadcast("command-palette:open", () => {
|
||||||
openCommandDialog(<CommandDialog />);
|
openCommandDialog(<CommandDialog />);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
window.addEventListener("keyup", (e) => this.escHandler(e), true);
|
window.addEventListener("keyup", (e) => this.escHandler(e), true);
|
||||||
commandDialogBus.addListener((event) => {
|
commandDialogBus.addListener((event) => {
|
||||||
console.log(event);
|
|
||||||
this.commandComponent = event.component;
|
this.commandComponent = event.component;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Dialog isOpen={!!this.commandComponent} animated={false}>
|
<Dialog isOpen={!!this.commandComponent} animated={false} onClose={() => this.commandComponent = null}>
|
||||||
<div id="command-container">
|
<div id="command-container">
|
||||||
{this.commandComponent}
|
{this.commandComponent}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -7,15 +7,37 @@ import { commandRegistry } from "../../../extensions/registries/command-registry
|
|||||||
import { clusterStore } from "../../../common/cluster-store";
|
import { clusterStore } from "../../../common/cluster-store";
|
||||||
import { workspaceStore } from "../../../common/workspace-store";
|
import { workspaceStore } from "../../../common/workspace-store";
|
||||||
import { closeCommandDialog } from "./command-container";
|
import { closeCommandDialog } from "./command-container";
|
||||||
|
import { broadcastMessage } from "../../../common/ipc";
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class CommandDialog extends React.Component {
|
export class CommandDialog extends React.Component {
|
||||||
@observable menuIsOpen = true;
|
@observable menuIsOpen = true;
|
||||||
|
|
||||||
@computed get options() {
|
@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 };
|
return { value: command.id, label: command.title };
|
||||||
});
|
}).sort((a, b) => a.label > b.label ? 1 : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onChange(value: string) {
|
private onChange(value: string) {
|
||||||
@ -29,10 +51,15 @@ export class CommandDialog extends React.Component {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
closeCommandDialog();
|
closeCommandDialog();
|
||||||
action({
|
|
||||||
cluster: clusterStore.active,
|
if (command.scope === "global") {
|
||||||
workspace: workspaceStore.currentWorkspace
|
action({
|
||||||
});
|
cluster: clusterStore.active,
|
||||||
|
workspace: workspaceStore.currentWorkspace
|
||||||
|
});
|
||||||
|
} else if(clusterStore.active) {
|
||||||
|
broadcastMessage(`command-palette:run-action:${clusterStore.active.id}`, command.id);
|
||||||
|
}
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
console.error("failed to execute command", command.id, 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 { createTerminalTab, isTerminalTab } from "./terminal.store";
|
||||||
import { UpgradeChart } from "./upgrade-chart";
|
import { UpgradeChart } from "./upgrade-chart";
|
||||||
import { isUpgradeChartTab } from "./upgrade-chart.store";
|
import { isUpgradeChartTab } from "./upgrade-chart.store";
|
||||||
|
import { commandRegistry } from "../../../extensions/registries/command-registry";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: string;
|
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>
|
</ErrorBoundary>
|
||||||
<Notifications/>
|
<Notifications/>
|
||||||
<ConfirmDialog/>
|
<ConfirmDialog/>
|
||||||
<CommandContainer listenPaletteOpen={true} />
|
<CommandContainer />
|
||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user