Merge remote-tracking branch 'origin/master' into eliminate-gst-from-app-paths

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
Janne Savolainen committed 2022-01-11 13:56:23 +02:00
commit 8d87bd0985
80 files changed
+1822 -1271

No files matched your search

@@ -21,68 +21,100 @@
import "./command-container.scss";
import { observer } from "mobx-react";
import { disposeOnUnmount, observer } from "mobx-react";
import React from "react";
import { Dialog } from "../dialog";
import { ipcRendererOn } from "../../../common/ipc";
import { CommandDialog } from "./command-dialog";
import type { ClusterId } from "../../../common/cluster-types";
import commandOverlayInjectable, { CommandOverlay } from "./command-overlay.injectable";
import { isMac } from "../../../common/vars";
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
import { CommandRegistration, CommandRegistry } from "../../../extensions/registries/command-registry";
import { CommandOverlay } from "./command-overlay";
import { broadcastMessage, ipcRendererOn } from "../../../common/ipc";
import { getMatchedClusterId } from "../../navigation";
import type { Disposer } from "../../utils";
import { withInjectables } from "@ogre-tools/injectable-react";
import windowAddEventListenerInjectable from "../../window/event-listener.injectable";
export interface CommandContainerProps {
clusterId?: ClusterId;
}
interface Dependencies {
addWindowEventListener: <K extends keyof WindowEventMap>(type: K, listener: (this: Window, ev: WindowEventMap[K]) => any, options?: boolean | AddEventListenerOptions) => Disposer;
commandOverlay: CommandOverlay,
}
@observer
export class CommandContainer extends React.Component<CommandContainerProps> {
class NonInjectedCommandContainer extends React.Component<CommandContainerProps & Dependencies> {
private escHandler(event: KeyboardEvent) {
const { commandOverlay } = this.props;
if (event.key === "Escape") {
event.stopPropagation();
CommandOverlay.close();
commandOverlay.close();
}
}
private findCommandById(commandId: string) {
return CommandRegistry.getInstance().getItems().find((command) => command.id === commandId);
}
handleCommandPalette = () => {
const { commandOverlay } = this.props;
const clusterIsActive = getMatchedClusterId() !== undefined;
private runCommand(command: CommandRegistration) {
command.action({
entity: catalogEntityRegistry.activeEntity,
});
if (clusterIsActive) {
broadcastMessage(`command-palette:${catalogEntityRegistry.activeEntity.getId()}:open`);
} else {
commandOverlay.open(<CommandDialog />);
}
};
onKeyboardShortcut(action: () => void) {
return ({ key, shiftKey, ctrlKey, altKey, metaKey }: KeyboardEvent) => {
const ctrlOrCmd = isMac ? metaKey && !ctrlKey : !metaKey && ctrlKey;
if (key === "p" && shiftKey && ctrlOrCmd && !altKey) {
action();
}
};
}
componentDidMount() {
if (this.props.clusterId) {
ipcRendererOn(`command-palette:run-action:${this.props.clusterId}`, (event, commandId: string) => {
const command = this.findCommandById(commandId);
const { clusterId, addWindowEventListener, commandOverlay } = this.props;
if (command) {
this.runCommand(command);
}
});
} else {
ipcRendererOn("command-palette:open", () => {
CommandOverlay.open(<CommandDialog />);
});
}
window.addEventListener("keyup", (e) => this.escHandler(e), true);
const action = clusterId
? () => commandOverlay.open(<CommandDialog />)
: this.handleCommandPalette;
const ipcChannel = clusterId
? `command-palette:${clusterId}:open`
: "command-palette:open";
disposeOnUnmount(this, [
ipcRendererOn(ipcChannel, action),
addWindowEventListener("keydown", this.onKeyboardShortcut(action)),
addWindowEventListener("keyup", (e) => this.escHandler(e), true),
]);
}
render() {
const { commandOverlay } = this.props;
return (
<Dialog
isOpen={CommandOverlay.isOpen}
isOpen={commandOverlay.isOpen}
animated={true}
onClose={CommandOverlay.close}
onClose={commandOverlay.close}
modal={false}
>
<div id="command-container">
{CommandOverlay.component}
{commandOverlay.component}
</div>
</Dialog>
);
}
}
export const CommandContainer = withInjectables<Dependencies, CommandContainerProps>(NonInjectedCommandContainer, {
getProps: (di, props) => ({
addWindowEventListener: di.inject(windowAddEventListenerInjectable),
commandOverlay: di.inject(commandOverlayInjectable),
...props,
}),
});
@@ -21,108 +21,107 @@
import { Select } from "../select";
import { computed, makeObservable, observable } from "mobx";
import type { IComputedValue } from "mobx";
import { observer } from "mobx-react";
import React from "react";
import { CommandRegistry } from "../../../extensions/registries/command-registry";
import { CommandOverlay } from "./command-overlay";
import { broadcastMessage } from "../../../common/ipc";
import { navigate } from "../../navigation";
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
import React, { useState } from "react";
import commandOverlayInjectable from "./command-overlay.injectable";
import type { CatalogEntity } from "../../../common/catalog";
import { clusterViewURL } from "../../../common/routes";
import { navigate } from "../../navigation";
import { broadcastMessage } from "../../../common/ipc";
import { IpcRendererNavigationEvents } from "../../navigation/events";
import type { RegisteredCommand } from "./registered-commands/commands";
import { iter } from "../../utils";
import { orderBy } from "lodash";
import { withInjectables } from "@ogre-tools/injectable-react";
import registeredCommandsInjectable from "./registered-commands/registered-commands.injectable";
import { catalogEntityRegistry } from "../../api/catalog-entity-registry";
@observer
export class CommandDialog extends React.Component {
@observable menuIsOpen = true;
@observable searchValue: any = undefined;
interface Dependencies {
commands: IComputedValue<Map<string, RegisteredCommand>>;
activeEntity?: CatalogEntity;
closeCommandOverlay: () => void;
}
constructor(props: {}) {
super(props);
makeObservable(this);
}
const NonInjectedCommandDialog = observer(({ commands, activeEntity, closeCommandOverlay }: Dependencies) => {
const [searchValue, setSearchValue] = useState("");
@computed get activeEntity(): CatalogEntity | undefined {
return catalogEntityRegistry.activeEntity;
}
@computed get options() {
const registry = CommandRegistry.getInstance();
const context = {
entity: this.activeEntity,
};
return registry.getItems().filter((command) => {
if (command.scope === "entity" && !this.activeEntity) {
return false;
}
try {
return command.isActive?.(context) ?? true;
} catch(e) {
console.error(e);
}
return false;
})
.map((command) => ({
value: command.id,
label: command.title,
}))
.sort((a, b) => a.label > b.label ? 1 : -1);
}
private onChange(value: string) {
const registry = CommandRegistry.getInstance();
const command = registry.getItems().find((cmd) => cmd.id === value);
const executeAction = (commandId: string) => {
const command = commands.get().get(commandId);
if (!command) {
return;
}
try {
CommandOverlay.close();
closeCommandOverlay();
command.action({
entity: activeEntity,
navigate: (url, opts = {}) => {
const { forceRootFrame = false } = opts;
if (command.scope === "global") {
command.action({
entity: this.activeEntity,
});
} else if(this.activeEntity) {
navigate(clusterViewURL({
params: {
clusterId: this.activeEntity.metadata.uid,
},
}));
broadcastMessage(`command-palette:run-action:${this.activeEntity.metadata.uid}`, command.id);
}
} catch(error) {
if (forceRootFrame) {
broadcastMessage(IpcRendererNavigationEvents.NAVIGATE_IN_APP, url);
} else {
navigate(url);
}
},
});
} catch (error) {
console.error("[COMMAND-DIALOG] failed to execute command", command.id, error);
}
}
};
render() {
return (
<Select
menuPortalTarget={null}
onChange={v => this.onChange(v.value)}
components={{
DropdownIndicator: null,
IndicatorSeparator: null,
}}
menuIsOpen={this.menuIsOpen}
options={this.options}
autoFocus={true}
escapeClearsValue={false}
data-test-id="command-palette-search"
placeholder="Type a command or search&hellip;"
onInputChange={(newValue, { action }) => {
if (action === "input-change") {
this.searchValue = newValue;
}
}}
inputValue={this.searchValue}
/>
);
}
}
const context = {
entity: activeEntity,
};
const activeCommands = iter.filter(commands.get().values(), command => {
try {
return command.isActive(context);
} catch (error) {
console.error(`[COMMAND-DIALOG]: isActive for ${command.id} threw an error, defaulting to false`, error);
}
return false;
});
const options = Array.from(activeCommands, ({ id, title }) => ({
value: id,
label: typeof title === "function"
? title(context)
: title,
}));
// Make sure the options are in the correct order
orderBy(options, "label", "asc");
return (
<Select
menuPortalTarget={null}
onChange={v => executeAction(v.value)}
components={{
DropdownIndicator: null,
IndicatorSeparator: null,
}}
menuIsOpen
options={options}
autoFocus={true}
escapeClearsValue={false}
data-test-id="command-palette-search"
placeholder="Type a command or search&hellip;"
onInputChange={(newValue, { action }) => {
if (action === "input-change") {
setSearchValue(newValue);
}
}}
inputValue={searchValue}
/>
);
});
export const CommandDialog = withInjectables<Dependencies>(NonInjectedCommandDialog, {
getProps: di => ({
commands: di.inject(registeredCommandsInjectable),
// TODO: replace with injection
activeEntity: catalogEntityRegistry.activeEntity,
closeCommandOverlay: di.inject(commandOverlayInjectable).close,
}),
});
@@ -19,29 +19,37 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
import { observable } from "mobx";
import React from "react";
export class CommandOverlay {
static #component = observable.box<React.ReactElement | null>(null, { deep: false });
#component = observable.box<React.ReactElement | null>(null, { deep: false });
static get isOpen(): boolean {
return Boolean(CommandOverlay.#component.get());
get isOpen(): boolean {
return Boolean(this.#component.get());
}
static open(component: React.ReactElement) {
open = (component: React.ReactElement) => {
if (!React.isValidElement(component)) {
throw new TypeError("CommandOverlay.open must be passed a valid ReactElement");
}
CommandOverlay.#component.set(component);
}
this.#component.set(component);
};
static close() {
CommandOverlay.#component.set(null);
}
close = () => {
this.#component.set(null);
};
static get component(): React.ReactElement | null {
return CommandOverlay.#component.get();
get component(): React.ReactElement | null {
return this.#component.get();
}
}
const commandOverlayInjectable = getInjectable({
instantiate: () => new CommandOverlay(),
lifecycle: lifecycleEnum.singleton,
});
export default commandOverlayInjectable;
@@ -21,4 +21,4 @@
export * from "./command-container";
export * from "./command-dialog";
export * from "./command-overlay";
export * from "./command-overlay.injectable";
@@ -0,0 +1,73 @@
/**
* Copyright (c) 2021 OpenLens Authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import type { CatalogEntity } from "../../../../common/catalog";
/**
* The context given to commands when executed
*/
export interface CommandContext {
entity?: CatalogEntity;
}
export interface CommandActionNavigateOptions {
/**
* If `true` then the navigate will only navigate on the root frame and not
* within a cluster
* @default false
*/
forceRootFrame?: boolean;
}
export interface CommandActionContext extends CommandContext {
navigate: (url: string, opts?: CommandActionNavigateOptions) => void;
}
export interface CommandRegistration {
/**
* The ID of the command, must be globally unique
*/
id: string;
/**
* The display name of the command in the command pallet
*/
title: string | ((context: CommandContext) => string);
/**
* @deprecated use `isActive` instead since there is always an entity active
*/
scope?: "global" | "entity";
/**
* The function to run when this command is selected
*/
action: (context: CommandActionContext) => void;
/**
* A function that determines if the command is active.
*
* @default () => true
*/
isActive?: (context: CommandContext) => boolean;
}
export type RegisteredCommand = Required<Omit<CommandRegistration, "scope">>;
@@ -0,0 +1,235 @@
/**
* Copyright (c) 2021 OpenLens Authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import React from "react";
import * as routes from "../../../../common/routes";
import { EntitySettingRegistry, RegisteredEntitySetting } from "../../../../extensions/registries";
import { HotbarAddCommand } from "../../hotbar/hotbar-add-command";
import { HotbarRemoveCommand } from "../../hotbar/hotbar-remove-command";
import { HotbarSwitchCommand } from "../../hotbar/hotbar-switch-command";
import { HotbarRenameCommand } from "../../hotbar/hotbar-rename-command";
import { ActivateEntityCommand } from "../../activate-entity-command";
import type { CommandContext, CommandRegistration } from "./commands";
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
import commandOverlayInjectable from "../command-overlay.injectable";
import createTerminalTabInjectable
from "../../dock/create-terminal-tab/create-terminal-tab.injectable";
import type { DockTabCreate } from "../../dock/dock-store/dock.store";
export function isKubernetesClusterActive(context: CommandContext): boolean {
return context.entity?.kind === "KubernetesCluster";
}
interface Dependencies {
openCommandDialog: (component: React.ReactElement) => void;
getEntitySettingItems: (kind: string, apiVersion: string, source?: string) => RegisteredEntitySetting[];
createTerminalTab: () => DockTabCreate
}
function getInternalCommands({ openCommandDialog, getEntitySettingItems, createTerminalTab }: Dependencies): CommandRegistration[] {
return [
{
id: "app.showPreferences",
title: "Preferences: Open",
action: ({ navigate }) => navigate(routes.preferencesURL(), {
forceRootFrame: true,
}),
},
{
id: "cluster.viewHelmCharts",
title: "Cluster: View Helm Charts",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.helmChartsURL()),
},
{
id: "cluster.viewHelmReleases",
title: "Cluster: View Helm Releases",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.releaseURL()),
},
{
id: "cluster.viewConfigMaps",
title: "Cluster: View ConfigMaps",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.configMapsURL()),
},
{
id: "cluster.viewSecrets",
title: "Cluster: View Secrets",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.secretsURL()),
},
{
id: "cluster.viewResourceQuotas",
title: "Cluster: View ResourceQuotas",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.resourceQuotaURL()),
},
{
id: "cluster.viewLimitRanges",
title: "Cluster: View LimitRanges",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.limitRangeURL()),
},
{
id: "cluster.viewHorizontalPodAutoscalers",
title: "Cluster: View HorizontalPodAutoscalers (HPA)",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.hpaURL()),
},
{
id: "cluster.viewPodDisruptionBudget",
title: "Cluster: View PodDisruptionBudgets",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.pdbURL()),
},
{
id: "cluster.viewServices",
title: "Cluster: View Services",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.servicesURL()),
},
{
id: "cluster.viewEndpoints",
title: "Cluster: View Endpoints",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.endpointURL()),
},
{
id: "cluster.viewIngresses",
title: "Cluster: View Ingresses",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.ingressURL()),
},
{
id: "cluster.viewNetworkPolicies",
title: "Cluster: View NetworkPolicies",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.networkPoliciesURL()),
},
{
id: "cluster.viewNodes",
title: "Cluster: View Nodes",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.nodesURL()),
},
{
id: "cluster.viewPods",
title: "Cluster: View Pods",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.podsURL()),
},
{
id: "cluster.viewDeployments",
title: "Cluster: View Deployments",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.deploymentsURL()),
},
{
id: "cluster.viewDaemonSets",
title: "Cluster: View DaemonSets",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.daemonSetsURL()),
},
{
id: "cluster.viewStatefulSets",
title: "Cluster: View StatefulSets",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.statefulSetsURL()),
},
{
id: "cluster.viewJobs",
title: "Cluster: View Jobs",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.jobsURL()),
},
{
id: "cluster.viewCronJobs",
title: "Cluster: View CronJobs",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.cronJobsURL()),
},
{
id: "cluster.viewCustomResourceDefinitions",
title: "Cluster: View Custom Resource Definitions",
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(routes.crdURL()),
},
{
id: "entity.viewSettings",
title: ({ entity }) => `${entity.kind}/${entity.getName()}: View Settings`,
action: ({ entity, navigate }) => navigate(`/entity/${entity.getId()}/settings`, {
forceRootFrame: true,
}),
isActive: ({ entity }) => {
if (!entity) {
return false;
}
return getEntitySettingItems(entity.kind, entity.apiVersion, entity.metadata.source).length > 0;
},
},
{
id: "cluster.openTerminal",
title: "Cluster: Open terminal",
action: () => createTerminalTab(),
isActive: isKubernetesClusterActive,
},
{
id: "hotbar.switchHotbar",
title: "Hotbar: Switch ...",
action: () => openCommandDialog(<HotbarSwitchCommand />),
},
{
id: "hotbar.addHotbar",
title: "Hotbar: Add Hotbar ...",
action: () => openCommandDialog(<HotbarAddCommand />),
},
{
id: "hotbar.removeHotbar",
title: "Hotbar: Remove Hotbar ...",
action: () => openCommandDialog(<HotbarRemoveCommand />),
},
{
id: "hotbar.renameHotbar",
title: "Hotbar: Rename Hotbar ...",
action: () => openCommandDialog(<HotbarRenameCommand />),
},
{
id: "catalog.searchEntities",
title: "Catalog: Activate Entity ...",
action: () => openCommandDialog(<ActivateEntityCommand />),
},
];
}
const internalCommandsInjectable = getInjectable({
instantiate: (di) => getInternalCommands({
openCommandDialog: di.inject(commandOverlayInjectable).open,
getEntitySettingItems: EntitySettingRegistry
.getInstance()
.getItemsForKind,
createTerminalTab: di.inject(createTerminalTabInjectable),
}),
lifecycle: lifecycleEnum.singleton,
});
export default internalCommandsInjectable;
@@ -0,0 +1,69 @@
/**
* Copyright (c) 2021 OpenLens Authors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
import { computed, IComputedValue } from "mobx";
import type { CustomResourceDefinition } from "../../../../common/k8s-api/endpoints";
import customResourceDefinitionsInjectable from "../../+custom-resources/custom-resources.injectable";
import type { LensRendererExtension } from "../../../../extensions/lens-renderer-extension";
import rendererExtensionsInjectable from "../../../../extensions/renderer-extensions.injectable";
import type { CommandRegistration, RegisteredCommand } from "./commands";
import internalCommandsInjectable, { isKubernetesClusterActive } from "./internal-commands.injectable";
interface Dependencies {
extensions: IComputedValue<LensRendererExtension[]>;
customResourceDefinitions: IComputedValue<CustomResourceDefinition[]>;
internalCommands: CommandRegistration[];
}
const instantiateRegisteredCommands = ({ extensions, customResourceDefinitions, internalCommands }: Dependencies) => computed(() => {
const result = new Map<string, RegisteredCommand>();
const commands = [
...internalCommands,
...extensions.get().flatMap(e => e.commands),
...customResourceDefinitions.get().map((command): CommandRegistration => ({
id: `cluster.view.${command.getResourceKind()}`,
title: `Cluster: View ${command.getResourceKind()}`,
isActive: isKubernetesClusterActive,
action: ({ navigate }) => navigate(command.getResourceUrl()),
})),
];
for (const { scope, isActive = () => true, ...command } of commands) {
if (!result.has(command.id)) {
result.set(command.id, { ...command, isActive });
}
}
return result;
});
const registeredCommandsInjectable = getInjectable({
instantiate: (di) => instantiateRegisteredCommands({
extensions: di.inject(rendererExtensionsInjectable),
customResourceDefinitions: di.inject(customResourceDefinitionsInjectable),
internalCommands: di.inject(internalCommandsInjectable),
}),
lifecycle: lifecycleEnum.singleton,
});
export default registeredCommandsInjectable;