diff --git a/src/renderer/components/+user-management/+cluster-role-bindings/__tests__/dialog.test.tsx b/src/renderer/components/+user-management/+cluster-role-bindings/__tests__/dialog.test.tsx index 1bbcf98a56..b37f8a5be9 100644 --- a/src/renderer/components/+user-management/+cluster-role-bindings/__tests__/dialog.test.tsx +++ b/src/renderer/components/+user-management/+cluster-role-bindings/__tests__/dialog.test.tsx @@ -4,7 +4,7 @@ */ import React from "react"; -import { ClusterRoleBindingDialog } from "../dialog"; +import { ClusterRoleBindingDialog } from "../dialog/view"; import { ClusterRole } from "../../../../../common/k8s-api/endpoints"; import userEvent from "@testing-library/user-event"; import { getDiForUnitTesting } from "../../../../getDiForUnitTesting"; diff --git a/src/renderer/components/+user-management/+cluster-role-bindings/details.tsx b/src/renderer/components/+user-management/+cluster-role-bindings/details.tsx index d78bae4fb1..87de375bed 100644 --- a/src/renderer/components/+user-management/+cluster-role-bindings/details.tsx +++ b/src/renderer/components/+user-management/+cluster-role-bindings/details.tsx @@ -15,18 +15,22 @@ import { AddRemoveButtons } from "../../add-remove-buttons"; import { DrawerTitle } from "../../drawer"; import type { KubeObjectDetailsProps } from "../../kube-object-details"; import { Table, TableCell, TableHead, TableRow } from "../../table"; -import { ClusterRoleBindingDialog } from "./dialog"; -import { clusterRoleBindingStore } from "./legacy-store"; import { hashSubject } from "../hashers"; import type { OpenConfirmDialog } from "../../confirm-dialog/open.injectable"; import { withInjectables } from "@ogre-tools/injectable-react"; import openConfirmDialogInjectable from "../../confirm-dialog/open.injectable"; +import type { ClusterRoleBindingStore } from "./store"; +import type { OpenClusterRoleBindingDialog } from "./dialog/open.injectable"; +import openClusterRoleBindingDialogInjectable from "./dialog/open.injectable"; +import clusterRoleBindingStoreInjectable from "./store.injectable"; export interface ClusterRoleBindingDetailsProps extends KubeObjectDetailsProps { } interface Dependencies { openConfirmDialog: OpenConfirmDialog; + openClusterRoleBindingDialog: OpenClusterRoleBindingDialog; + clusterRoleBindingStore: ClusterRoleBindingStore; } @observer @@ -47,7 +51,7 @@ class NonInjectedClusterRoleBindingDetails extends React.Component ClusterRoleBindingDialog.open(clusterRoleBinding)} + onAdd={() => openClusterRoleBindingDialog(clusterRoleBinding)} onRemove={selectedSubjects.size ? this.removeSelectedSubjects : undefined} addTooltip={`Add bindings to ${roleRef.name}`} removeTooltip={`Remove selected bindings from ${roleRef.name}`} @@ -135,5 +139,7 @@ export const ClusterRoleBindingDetails = withInjectables ({ ...props, openConfirmDialog: di.inject(openConfirmDialogInjectable), + openClusterRoleBindingDialog: di.inject(openClusterRoleBindingDialogInjectable), + clusterRoleBindingStore: di.inject(clusterRoleBindingStoreInjectable), }), }); diff --git a/src/renderer/components/+user-management/+cluster-role-bindings/dialog/close.injectable.ts b/src/renderer/components/+user-management/+cluster-role-bindings/dialog/close.injectable.ts new file mode 100644 index 0000000000..32971c37d7 --- /dev/null +++ b/src/renderer/components/+user-management/+cluster-role-bindings/dialog/close.injectable.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { action } from "mobx"; +import editClusterRoleBindingNameStateInjectable from "./edit-name-state.injectable"; +import clusterRoleBindingDialogStateInjectable from "./state.injectable"; + +export type CloseClusterRoleBindingDialog = () => void; + +const closeClusterRoleBindingDialogInjectable = getInjectable({ + id: "close-cluster-role-binding-dialog", + instantiate: (di): CloseClusterRoleBindingDialog => { + const state = di.inject(clusterRoleBindingDialogStateInjectable); + const editNameState = di.inject(editClusterRoleBindingNameStateInjectable); + + return action(() => { + state.set({ + isOpen: false, + }); + editNameState.set(""); + }); + }, +}); + +export default closeClusterRoleBindingDialogInjectable; diff --git a/src/renderer/components/+user-management/+cluster-role-bindings/dialog/edit-name-state.injectable.ts b/src/renderer/components/+user-management/+cluster-role-bindings/dialog/edit-name-state.injectable.ts new file mode 100644 index 0000000000..b5a3b768ad --- /dev/null +++ b/src/renderer/components/+user-management/+cluster-role-bindings/dialog/edit-name-state.injectable.ts @@ -0,0 +1,13 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { observable } from "mobx"; + +const editClusterRoleBindingNameStateInjectable = getInjectable({ + id: "edit-cluster-role-binding-name-state", + instantiate: () => observable.box(""), +}); + +export default editClusterRoleBindingNameStateInjectable; diff --git a/src/renderer/components/+user-management/+cluster-role-bindings/dialog/open.injectable.ts b/src/renderer/components/+user-management/+cluster-role-bindings/dialog/open.injectable.ts new file mode 100644 index 0000000000..44fff0ba43 --- /dev/null +++ b/src/renderer/components/+user-management/+cluster-role-bindings/dialog/open.injectable.ts @@ -0,0 +1,29 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { action } from "mobx"; +import type { ClusterRoleBinding } from "../../../../../common/k8s-api/endpoints"; +import editClusterRoleBindingNameStateInjectable from "./edit-name-state.injectable"; +import clusterRoleBindingDialogStateInjectable from "./state.injectable"; + +export type OpenClusterRoleBindingDialog = (clusterRoleBinding?: ClusterRoleBinding) => void; + +const openClusterRoleBindingDialogInjectable = getInjectable({ + id: "open-cluster-role-binding-dialog", + instantiate: (di): OpenClusterRoleBindingDialog => { + const state = di.inject(clusterRoleBindingDialogStateInjectable); + const editNameState = di.inject(editClusterRoleBindingNameStateInjectable); + + return action((clusterRoleBinding) => { + state.set({ + isOpen: true, + clusterRoleBinding, + }); + editNameState.set(clusterRoleBinding?.getName() ?? ""); + }); + }, +}); + +export default openClusterRoleBindingDialogInjectable; diff --git a/src/renderer/components/+user-management/+cluster-role-bindings/dialog/state.injectable.ts b/src/renderer/components/+user-management/+cluster-role-bindings/dialog/state.injectable.ts new file mode 100644 index 0000000000..6fe2444e33 --- /dev/null +++ b/src/renderer/components/+user-management/+cluster-role-bindings/dialog/state.injectable.ts @@ -0,0 +1,24 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { observable } from "mobx"; +import type { ClusterRoleBinding } from "../../../../../common/k8s-api/endpoints"; + +export type ClusterRoleBindingDialogState = { + isOpen: false; + clusterRoleBinding?: undefined; +} | { + isOpen: true; + clusterRoleBinding: ClusterRoleBinding | undefined; +}; + +const clusterRoleBindingDialogStateInjectable = getInjectable({ + id: "cluster-role-binding-dialog-state", + instantiate: () => observable.box({ + isOpen: false, + }), +}); + +export default clusterRoleBindingDialogStateInjectable; diff --git a/src/renderer/components/+user-management/+cluster-role-bindings/dialog.scss b/src/renderer/components/+user-management/+cluster-role-bindings/dialog/view.scss similarity index 100% rename from src/renderer/components/+user-management/+cluster-role-bindings/dialog.scss rename to src/renderer/components/+user-management/+cluster-role-bindings/dialog/view.scss diff --git a/src/renderer/components/+user-management/+cluster-role-bindings/dialog.tsx b/src/renderer/components/+user-management/+cluster-role-bindings/dialog/view.tsx similarity index 54% rename from src/renderer/components/+user-management/+cluster-role-bindings/dialog.tsx rename to src/renderer/components/+user-management/+cluster-role-bindings/dialog/view.tsx index 4afa930059..c3f2821d98 100644 --- a/src/renderer/components/+user-management/+cluster-role-bindings/dialog.tsx +++ b/src/renderer/components/+user-management/+cluster-role-bindings/dialog/view.tsx @@ -3,75 +3,73 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import "./dialog.scss"; +import "./view.scss"; -import { action, computed, makeObservable, observable, reaction } from "mobx"; -import { disposeOnUnmount, observer } from "mobx-react"; +import type { IObservableValue } from "mobx"; +import { action, computed, makeObservable, observable } from "mobx"; +import { observer } from "mobx-react"; import React from "react"; -import { serviceAccountStore } from "../+service-accounts/legacy-store"; -import type { ClusterRole, ClusterRoleBinding, ServiceAccount } from "../../../../common/k8s-api/endpoints"; -import type { DialogProps } from "../../dialog"; -import { Dialog } from "../../dialog"; -import { EditableList } from "../../editable-list"; -import { Icon } from "../../icon"; -import { showDetails } from "../../kube-detail-params"; -import { SubTitle } from "../../layout/sub-title"; -import { Notifications } from "../../notifications"; -import { onMultiSelectFor, Select } from "../../select"; -import { Wizard, WizardStep } from "../../wizard"; -import { clusterRoleBindingStore } from "./legacy-store"; -import { clusterRoleStore } from "../+cluster-roles/legacy-store"; -import { ObservableHashSet, nFircate } from "../../../utils"; -import { Input } from "../../input"; -import { TooltipPosition } from "../../tooltip"; -import type { Subject } from "../../../../common/k8s-api/endpoints/types/subject"; +import type { ClusterRole, ServiceAccount } from "../../../../../common/k8s-api/endpoints"; +import type { DialogProps } from "../../../dialog"; +import { Dialog } from "../../../dialog"; +import { EditableList } from "../../../editable-list"; +import { Icon } from "../../../icon"; +import { SubTitle } from "../../../layout/sub-title"; +import { Notifications } from "../../../notifications"; +import { onMultiSelectFor, Select } from "../../../select"; +import { Wizard, WizardStep } from "../../../wizard"; +import { ObservableHashSet, nFircate } from "../../../../utils"; +import { Input } from "../../../input"; +import { TooltipPosition } from "../../../tooltip"; +import type { Subject } from "../../../../../common/k8s-api/endpoints/types/subject"; +import type { ClusterRoleBindingDialogState } from "./state.injectable"; +import type { ClusterRoleStore } from "../../+cluster-roles/store"; +import type { ServiceAccountStore } from "../../+service-accounts/store"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import clusterRoleStoreInjectable from "../../+cluster-roles/store.injectable"; +import editClusterRoleBindingNameStateInjectable from "./edit-name-state.injectable"; +import serviceAccountStoreInjectable from "../../+service-accounts/store.injectable"; +import clusterRoleBindingDialogStateInjectable from "./state.injectable"; +import type { CloseClusterRoleBindingDialog } from "./close.injectable"; +import type { OpenClusterRoleBindingDialog } from "./open.injectable"; +import openClusterRoleBindingDialogInjectable from "./open.injectable"; +import closeClusterRoleBindingDialogInjectable from "./close.injectable"; +import type { ShowDetails } from "../../../kube-detail-params/show-details.injectable"; +import type { ClusterRoleBindingStore } from "../store"; +import clusterRoleBindingStoreInjectable from "../store.injectable"; +import showDetailsInjectable from "../../../kube-detail-params/show-details.injectable"; export interface ClusterRoleBindingDialogProps extends Partial { } -interface DialogState { - isOpen: boolean; - data?: ClusterRoleBinding; +interface Dependencies { + state: IObservableValue; + editBindingNameState: IObservableValue; + clusterRoleStore: ClusterRoleStore; + serviceAccountStore: ServiceAccountStore; + clusterRoleBindingStore: ClusterRoleBindingStore; + closeClusterRoleBindingDialog: CloseClusterRoleBindingDialog; + openClusterRoleBindingDialog: OpenClusterRoleBindingDialog; + showDetails: ShowDetails; } -const dialogState = observable.object({ - isOpen: false, -}); - @observer -export class ClusterRoleBindingDialog extends React.Component { - constructor(props: ClusterRoleBindingDialogProps) { +class NonInjectedClusterRoleBindingDialog extends React.Component { + constructor(props: ClusterRoleBindingDialogProps & Dependencies) { super(props); makeObservable(this); } - componentDidMount() { - disposeOnUnmount(this, [ - reaction(() => this.isEditing, () => { - this.bindingName = dialogState.data?.getName() ?? ""; - }), - ]); - } - - static open(roleBinding?: ClusterRoleBinding) { - dialogState.isOpen = true; - dialogState.data = roleBinding; - } - - static close() { - dialogState.isOpen = false; - } - @computed get clusterRoleOptions() { - return clusterRoleStore.items.map(clusterRole => ({ + return this.props.clusterRoleStore.items.map(clusterRole => ({ value: clusterRole, label: clusterRole.getName(), })); } @computed get serviceAccountOptions() { - return serviceAccountStore.items.map(serviceAccount => ({ + return this.props.serviceAccountStore.items.map(serviceAccount => ({ value: serviceAccount, label: `${serviceAccount.getName()} (${serviceAccount.getNs()})`, isSelected: this.selectedAccounts.has(serviceAccount), @@ -79,7 +77,7 @@ export class ClusterRoleBindingDialog extends React.Component([], sa => sa.metadata.uid); selectedUsers = observable.set([]); selectedGroups = observable.set([]); @@ -121,16 +118,15 @@ export class ClusterRoleBindingDialog extends React.Component item.getName() === binding.roleRef.name); - this.bindingName = binding.getName(); const [saSubjects, uSubjects, gSubjects] = nFircate(binding.getSubjects(), "kind", ["ServiceAccount", "User", "Group"]); const accountNames = new Set(saSubjects.map(acc => acc.name)); this.selectedAccounts.replace( - serviceAccountStore.items + this.props.serviceAccountStore.items .filter(sa => accountNames.has(sa.getName())), ); this.selectedUsers.replace(uSubjects.map(user => user.name)); @@ -139,14 +135,19 @@ export class ClusterRoleBindingDialog extends React.Component { this.selectedRoleRef = undefined; - this.bindingName = ""; this.selectedAccounts.clear(); this.selectedUsers.clear(); this.selectedGroups.clear(); }); createBindings = async () => { - const { selectedRoleRef, selectedBindings, bindingName, clusterRoleBinding } = this; + const { + closeClusterRoleBindingDialog, + clusterRoleBindingStore, + editBindingNameState, + showDetails, + } = this.props; + const { selectedRoleRef, selectedBindings, clusterRoleBinding } = this; if (!clusterRoleBinding || !selectedRoleRef) { return; @@ -155,7 +156,7 @@ export class ClusterRoleBindingDialog extends React.Component { this.selectedRoleRef = option?.value; + const bindingName = this.props.editBindingNameState.get(); - if (!this.selectedRoleRef || this.bindingName === this.selectedRoleRef.getName()) { - this.bindingName = option?.value?.getName() ?? ""; + if (!this.selectedRoleRef || bindingName === this.selectedRoleRef.getName()) { + this.props.editBindingNameState.set(option?.value?.getName() ?? ""); } }} /> @@ -209,8 +211,8 @@ export class ClusterRoleBindingDialog extends React.Component this.bindingName = val} + value={this.props.editBindingNameState.get()} + onChange={val => this.props.editBindingNameState.set(val)} /> @@ -252,16 +254,24 @@ export class ClusterRoleBindingDialog extends React.Component @@ -271,7 +281,7 @@ export class ClusterRoleBindingDialog extends React.Component )} - done={ClusterRoleBindingDialog.close} + done={closeClusterRoleBindingDialog} > (NonInjectedClusterRoleBindingDialog, { + getProps: (di, props) => ({ + ...props, + clusterRoleStore: di.inject(clusterRoleStoreInjectable), + editBindingNameState: di.inject(editClusterRoleBindingNameStateInjectable), + serviceAccountStore: di.inject(serviceAccountStoreInjectable), + state: di.inject(clusterRoleBindingDialogStateInjectable), + clusterRoleBindingStore: di.inject(clusterRoleBindingStoreInjectable), + openClusterRoleBindingDialog: di.inject(openClusterRoleBindingDialogInjectable), + closeClusterRoleBindingDialog: di.inject(closeClusterRoleBindingDialogInjectable), + showDetails: di.inject(showDetailsInjectable), + }), +}); diff --git a/src/renderer/components/+user-management/+cluster-role-bindings/index.ts b/src/renderer/components/+user-management/+cluster-role-bindings/index.ts index 0dd1376b97..59d5a476cb 100644 --- a/src/renderer/components/+user-management/+cluster-role-bindings/index.ts +++ b/src/renderer/components/+user-management/+cluster-role-bindings/index.ts @@ -4,4 +4,4 @@ */ export * from "./view"; export * from "./details"; -export * from "./dialog"; +export * from "./dialog/view"; diff --git a/src/renderer/components/+user-management/+cluster-role-bindings/legacy-store.ts b/src/renderer/components/+user-management/+cluster-role-bindings/legacy-store.ts deleted file mode 100644 index 6eb3bf50d4..0000000000 --- a/src/renderer/components/+user-management/+cluster-role-bindings/legacy-store.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { asLegacyGlobalForExtensionApi } from "../../../../extensions/as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; -import clusterRoleBindingStoreInjectable from "./store.injectable"; - -/** - * @deprecated use `di.inject(clusterRoleBindingStoreInjectable)` instead - */ -export const clusterRoleBindingStore = asLegacyGlobalForExtensionApi(clusterRoleBindingStoreInjectable); diff --git a/src/renderer/components/+user-management/+cluster-role-bindings/view.tsx b/src/renderer/components/+user-management/+cluster-role-bindings/view.tsx index 4daf4c001f..7803227dd7 100644 --- a/src/renderer/components/+user-management/+cluster-role-bindings/view.tsx +++ b/src/renderer/components/+user-management/+cluster-role-bindings/view.tsx @@ -9,12 +9,16 @@ import { observer } from "mobx-react"; import React from "react"; import { KubeObjectListLayout } from "../../kube-object-list-layout"; import { KubeObjectStatusIcon } from "../../kube-object-status-icon"; -import { ClusterRoleBindingDialog } from "./dialog"; -import { clusterRoleBindingStore } from "./legacy-store"; -import { clusterRoleStore } from "../+cluster-roles/legacy-store"; -import { serviceAccountStore } from "../+service-accounts/legacy-store"; +import { ClusterRoleBindingDialog } from "./dialog/view"; import { SiblingsInTabLayout } from "../../layout/siblings-in-tab-layout"; import { KubeObjectAge } from "../../kube-object/age"; +import type { ClusterRoleBindingStore } from "./store"; +import { withInjectables } from "@ogre-tools/injectable-react"; +import clusterRoleBindingStoreInjectable from "./store.injectable"; +import type { ClusterRoleStore } from "../+cluster-roles/store"; +import type { ServiceAccountStore } from "../+service-accounts/store"; +import clusterRoleStoreInjectable from "../+cluster-roles/store.injectable"; +import serviceAccountStoreInjectable from "../+service-accounts/store.injectable"; enum columnId { name = "name", @@ -23,9 +27,21 @@ enum columnId { age = "age", } +interface Dependencies { + clusterRoleBindingStore: ClusterRoleBindingStore; + clusterRoleStore: ClusterRoleStore; + serviceAccountStore: ServiceAccountStore; +} + @observer -export class ClusterRoleBindings extends React.Component { +class NonInjectedClusterRoleBindings extends React.Component { render() { + const { + clusterRoleBindingStore, + clusterRoleStore, + serviceAccountStore, + } = this.props; + return ( (NonInjectedClusterRoleBindings, { + getProps: (di, props) => ({ + ...props, + clusterRoleBindingStore: di.inject(clusterRoleBindingStoreInjectable), + clusterRoleStore: di.inject(clusterRoleStoreInjectable), + serviceAccountStore: di.inject(serviceAccountStoreInjectable), + }), +});