1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Remove usages of legacy global clusterRoleBindingStore

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-12-22 12:04:47 -05:00
parent d122e68dc2
commit 4a60a91ffd
11 changed files with 226 additions and 90 deletions

View File

@ -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";

View File

@ -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<ClusterRoleBinding> {
}
interface Dependencies {
openConfirmDialog: OpenConfirmDialog;
openClusterRoleBindingDialog: OpenClusterRoleBindingDialog;
clusterRoleBindingStore: ClusterRoleBindingStore;
}
@observer
@ -47,7 +51,7 @@ class NonInjectedClusterRoleBindingDetails extends React.Component<ClusterRoleBi
}
removeSelectedSubjects() {
const { object: clusterRoleBinding, openConfirmDialog } = this.props;
const { object: clusterRoleBinding, openConfirmDialog, clusterRoleBindingStore } = this.props;
const { selectedSubjects } = this;
openConfirmDialog({
@ -65,7 +69,7 @@ class NonInjectedClusterRoleBindingDetails extends React.Component<ClusterRoleBi
render() {
const { selectedSubjects } = this;
const { object: clusterRoleBinding } = this.props;
const { object: clusterRoleBinding, openClusterRoleBindingDialog } = this.props;
if (!clusterRoleBinding) {
return null;
@ -121,7 +125,7 @@ class NonInjectedClusterRoleBindingDetails extends React.Component<ClusterRoleBi
)}
<AddRemoveButtons
onAdd={() => 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<Dependencies, ClusterRo
getProps: (di, props) => ({
...props,
openConfirmDialog: di.inject(openConfirmDialogInjectable),
openClusterRoleBindingDialog: di.inject(openClusterRoleBindingDialogInjectable),
clusterRoleBindingStore: di.inject(clusterRoleBindingStoreInjectable),
}),
});

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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<ClusterRoleBindingDialogState>({
isOpen: false,
}),
});
export default clusterRoleBindingDialogStateInjectable;

View File

@ -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<DialogProps> {
}
interface DialogState {
isOpen: boolean;
data?: ClusterRoleBinding;
interface Dependencies {
state: IObservableValue<ClusterRoleBindingDialogState>;
editBindingNameState: IObservableValue<string>;
clusterRoleStore: ClusterRoleStore;
serviceAccountStore: ServiceAccountStore;
clusterRoleBindingStore: ClusterRoleBindingStore;
closeClusterRoleBindingDialog: CloseClusterRoleBindingDialog;
openClusterRoleBindingDialog: OpenClusterRoleBindingDialog;
showDetails: ShowDetails;
}
const dialogState = observable.object<DialogState>({
isOpen: false,
});
@observer
export class ClusterRoleBindingDialog extends React.Component<ClusterRoleBindingDialogProps> {
constructor(props: ClusterRoleBindingDialogProps) {
class NonInjectedClusterRoleBindingDialog extends React.Component<ClusterRoleBindingDialogProps & Dependencies> {
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<ClusterRoleBinding
}
get clusterRoleBinding() {
return dialogState.data;
return this.props.state.get().clusterRoleBinding;
}
get isEditing() {
@ -87,7 +85,6 @@ export class ClusterRoleBindingDialog extends React.Component<ClusterRoleBinding
}
@observable selectedRoleRef: ClusterRole | undefined = undefined;
@observable bindingName = "";
selectedAccounts = new ObservableHashSet<ServiceAccount>([], sa => sa.metadata.uid);
selectedUsers = observable.set<string>([]);
selectedGroups = observable.set<string>([]);
@ -121,16 +118,15 @@ export class ClusterRoleBindingDialog extends React.Component<ClusterRoleBinding
return this.reset();
}
this.selectedRoleRef = clusterRoleStore
this.selectedRoleRef = this.props.clusterRoleStore
.items
.find(item => 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<ClusterRoleBinding
reset = action(() => {
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<ClusterRoleBinding
try {
const { selfLink } = this.isEditing
? await clusterRoleBindingStore.updateSubjects(clusterRoleBinding, selectedBindings)
: await clusterRoleBindingStore.create({ name: bindingName }, {
: await clusterRoleBindingStore.create({ name: editBindingNameState.get() }, {
subjects: selectedBindings,
roleRef: {
name: selectedRoleRef.getName(),
@ -164,7 +165,7 @@ export class ClusterRoleBindingDialog extends React.Component<ClusterRoleBinding
});
showDetails(selfLink);
ClusterRoleBindingDialog.close();
closeClusterRoleBindingDialog();
} catch (err) {
Notifications.checkedError(err, `Unknown error occured while ${this.isEditing ? "editing the" : "creating a"} ClusterRoleBinding`);
}
@ -198,9 +199,10 @@ export class ClusterRoleBindingDialog extends React.Component<ClusterRoleBinding
)}
onChange={option => {
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<ClusterRoleBinding
<Input
placeholder="Name of ClusterRoleBinding ..."
disabled={this.isEditing}
value={this.bindingName}
onChange={val => this.bindingName = val}
value={this.props.editBindingNameState.get()}
onChange={val => this.props.editBindingNameState.set(val)}
/>
<SubTitle title="Binding targets" />
@ -252,16 +254,24 @@ export class ClusterRoleBindingDialog extends React.Component<ClusterRoleBinding
}
render() {
const { ...dialogProps } = this.props;
const {
closeClusterRoleBindingDialog,
openClusterRoleBindingDialog,
clusterRoleStore,
editBindingNameState,
serviceAccountStore,
state,
...dialogProps
} = this.props;
const [action, nextLabel] = this.isEditing ? ["Edit", "Update"] : ["Add", "Create"];
const disableNext = !this.selectedRoleRef || !this.selectedBindings.length || !this.bindingName;
const disableNext = !this.selectedRoleRef || !this.selectedBindings.length || !editBindingNameState.get();
return (
<Dialog
{...dialogProps}
className="AddClusterRoleBindingDialog"
isOpen={dialogState.isOpen}
close={ClusterRoleBindingDialog.close}
isOpen={state.get().isOpen}
close={closeClusterRoleBindingDialog}
onClose={this.reset}
onOpen={this.onOpen}
>
@ -271,7 +281,7 @@ export class ClusterRoleBindingDialog extends React.Component<ClusterRoleBinding
{`${action} ClusterRoleBinding`}
</h5>
)}
done={ClusterRoleBindingDialog.close}
done={closeClusterRoleBindingDialog}
>
<WizardStep
nextLabel={nextLabel}
@ -285,3 +295,17 @@ export class ClusterRoleBindingDialog extends React.Component<ClusterRoleBinding
);
}
}
export const ClusterRoleBindingDialog = withInjectables<Dependencies, ClusterRoleBindingDialogProps>(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),
}),
});

View File

@ -4,4 +4,4 @@
*/
export * from "./view";
export * from "./details";
export * from "./dialog";
export * from "./dialog/view";

View File

@ -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);

View File

@ -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<Dependencies> {
render() {
const {
clusterRoleBindingStore,
clusterRoleStore,
serviceAccountStore,
} = this.props;
return (
<SiblingsInTabLayout>
<KubeObjectListLayout
@ -66,3 +82,12 @@ export class ClusterRoleBindings extends React.Component {
);
}
}
export const ClusterRoleBindings = withInjectables<Dependencies>(NonInjectedClusterRoleBindings, {
getProps: (di, props) => ({
...props,
clusterRoleBindingStore: di.inject(clusterRoleBindingStoreInjectable),
clusterRoleStore: di.inject(clusterRoleStoreInjectable),
serviceAccountStore: di.inject(serviceAccountStoreInjectable),
}),
});