diff --git a/packages/core/src/renderer/components/cluster-settings/cluster-settings-menu-clear-item.injectable.ts b/packages/core/src/renderer/components/cluster-settings/cluster-settings-menu-clear-item.injectable.ts new file mode 100644 index 0000000000..300dab853c --- /dev/null +++ b/packages/core/src/renderer/components/cluster-settings/cluster-settings-menu-clear-item.injectable.ts @@ -0,0 +1,22 @@ +import { getInjectable } from "@ogre-tools/injectable"; +import type { ClusterPreferences } from "../../../common/cluster-types"; +import { clusterIconSettingsMenuInjectionToken } from "./cluster-settings-menu-injection-token"; + +const clusterIconSettingsMenuClearItem = getInjectable({ + id: "cluster-icon-settings-menu-clear-item", + + instantiate: () => ({ + id: "clear-icon-menu-item", + title: "Clear", + disabled: (preferences: ClusterPreferences) => !preferences.icon, + /** + * NOTE: this needs to be `null` rather than `undefined` so that we can + * tell the difference between it not being there and being cleared. + */ + onClick: (preferences: ClusterPreferences) => ({ icon: null }) + }), + + injectionToken: clusterIconSettingsMenuInjectionToken +}) + +export default clusterIconSettingsMenuClearItem; \ No newline at end of file diff --git a/packages/core/src/renderer/components/cluster-settings/cluster-settings-menu-injection-token.ts b/packages/core/src/renderer/components/cluster-settings/cluster-settings-menu-injection-token.ts new file mode 100644 index 0000000000..5024794b87 --- /dev/null +++ b/packages/core/src/renderer/components/cluster-settings/cluster-settings-menu-injection-token.ts @@ -0,0 +1,13 @@ +import { getInjectionToken } from "@ogre-tools/injectable"; +import type { ClusterPreferences } from "../../../common/cluster-types"; + +export type ClusterIconMenuItem = { + id: string, + title: string, + disabled: (preferences: ClusterPreferences) => boolean, + onClick: (preferences: ClusterPreferences) => Partial, +} + +export const clusterIconSettingsMenuInjectionToken = getInjectionToken({ + id: "cluster-icon-settings-menu-injection-token", +}); \ No newline at end of file diff --git a/packages/core/src/renderer/components/cluster-settings/icon-settings.tsx b/packages/core/src/renderer/components/cluster-settings/icon-settings.tsx index f5813368e8..979b246e1d 100644 --- a/packages/core/src/renderer/components/cluster-settings/icon-settings.tsx +++ b/packages/core/src/renderer/components/cluster-settings/icon-settings.tsx @@ -3,106 +3,105 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import React from "react"; -import type { Cluster } from "../../../common/cluster/cluster"; -import { observable } from "mobx"; +import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-for-mobx"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import type { IComputedValue } from "mobx"; import { observer } from "mobx-react"; +import React from "react"; import type { KubernetesCluster } from "../../../common/catalog-entities"; +import type { ClusterPreferences } from "../../../common/cluster-types"; +import type { Cluster } from "../../../common/cluster/cluster"; +import { Avatar } from "../avatar"; import { FilePicker, OverSizeLimitStyle } from "../file-picker"; import { MenuActions, MenuItem } from "../menu"; -import { Avatar } from "../avatar"; -import autoBindReact from "auto-bind/react"; - -enum GeneralInputStatus { - CLEAN = "clean", - ERROR = "error", -} +import type { ShowNotification } from "../notifications"; +import showErrorNotificationInjectable from "../notifications/show-error-notification.injectable"; +import { ClusterIconMenuItem, clusterIconSettingsMenuInjectionToken } from "./cluster-settings-menu-injection-token"; export interface ClusterIconSettingProps { cluster: Cluster; entity: KubernetesCluster; } -@observer -export class ClusterIconSetting extends React.Component { - @observable status = GeneralInputStatus.CLEAN; - @observable errorText?: string; +interface Dependencies { + menuItems: IComputedValue + showErrorNotification: ShowNotification; +} - constructor(props: ClusterIconSettingProps) { - super(props); - autoBindReact(this); - } - private element = React.createRef(); +const NonInjectedClusterIconSetting = observer((props: ClusterIconSettingProps & Dependencies) => { + const element = React.createRef(); + const { cluster, entity } = props; - async onIconPick([file]: File[]) { + const onIconPick = async ([file]: File[]) => { if (!file) { return; } - const { cluster } = this.props; - try { const buf = Buffer.from(await file.arrayBuffer()); cluster.preferences.icon = `data:${file.type};base64,${buf.toString("base64")}`; } catch (e) { - this.errorText = String(e); - this.status = GeneralInputStatus.ERROR; + props.showErrorNotification(String(e)) } } - clearIcon() { - /** - * NOTE: this needs to be `null` rather than `undefined` so that we can - * tell the difference between it not being there and being cleared. - */ - this.props.cluster.preferences.icon = null; - } - - onUploadClick() { - this.element + const onUploadClick = () => { + element .current ?.querySelector("input[type=file]") ?.click(); } - render() { - const { entity } = this.props; - - return ( -
-
-
- - )} - onOverSizeLimit={OverSizeLimitStyle.FILTER} - handler={this.onIconPick} - /> -
- - - Upload Icon - - this.clearIcon()} disabled={!this.props.cluster.preferences.icon}> - Clear - - -
-
- ); + const save = ([kind, value]: [kind: keyof ClusterPreferences, value: any]) => { + cluster.preferences[kind] = value } -} + + return ( +
+
+
+ + )} + onOverSizeLimit={OverSizeLimitStyle.FILTER} + handler={onIconPick} + /> +
+ + + Upload Icon + + {props.menuItems.get().map(item => + save(item.onClick(cluster.preferences))} key={item.id} disabled={item.disabled(cluster.preferences)}>{item.title} + )} + +
+
+ ); +}); + +export const ClusterIconSetting = withInjectables(NonInjectedClusterIconSetting, { + getProps: (di, props) => { + const computedInjectMany = di.inject(computedInjectManyInjectable); + + return { + ...props, + menuItems: computedInjectMany(clusterIconSettingsMenuInjectionToken), + showErrorNotification: di.inject(showErrorNotificationInjectable), + } + } +}); \ No newline at end of file