Turn on strict mode in tsconfig.json, some helpful lints, and required cleanup where strictness necessitates it (#5195)

* Turn on strict mode in tsconfig.json

- Add route, clusterRoute, and payloadValidatedClusterRoute helper
  functions to improve types with backend routes

- Turn on the following new lints:
  - react/jsx-first-prop-new-line
  - react/jsx-wrap-multilines
  - react/jsx-one-expression-per-line
  - react/jsx-max-props-per-line
  - react/jsx-indent
  - react/jsx-indent-props

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix build

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Replace KubeObject scope strings with enum

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Revert package.json version changes

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* revert move hostedCluster(Id)

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* change some type param names to be not single letters

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* remove copy-extension-themes

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* add new make clean action

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix build to not use webpack for generating types

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix kube-object-menu.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix select.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix catalog.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* revert move fileNameMigration to index

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix ref logic error

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix log-resource-selector.test.tsx tests

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix dock-store.test.ts test by overriding createStorage to not touch file system

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix cluster.test.ts tests

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix kube=api.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fixed hotbar-store.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix kubeconfig-manager.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix cluster-role-bindings/__tests__/dialog.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix role-bindings/__tests__/dialog.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix pods.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix delete-cluster-dialog.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix daemonset.store.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix replicaset.store.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix statefulsets/dialog/dialog.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix replicasets/scale-dialog/dialog.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix deployments.store.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix deployments/scale/dialog.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix cronjob.store.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix stateful-set.api.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix deployment.api.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix api-manager.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix statefulset.store.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix job.store.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix pods.store.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix scroll-spy.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix hotbar-remove-command.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix catalog-entity-registry.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix welcome.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix verify-that-all-routes-have-route-component.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix pod-tolerations.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* better fix for previous 3 fixes, plus also select.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix kube-object-menu.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix app-paths.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix dock-tabs.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix isReactNode typing

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix sub-title.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix drawer.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix list-layout.tsx and header.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix error-boundary.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix upgrade-chart/store.ts and dock-tab.store.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix install-chart/store.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix edit-resource/store.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix create-resource/store.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix namespace-select.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix namespace-select-filter.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix crd-list.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix wrong types for extensions

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix circular dependency

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix circular dependency on catalogCategoryRegistry

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix api-kube

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix type errors, most <Select /> errors

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fixing more type errors

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* some more fixing type errors

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* convert all KubeApis to injectable with legacy global backups

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* factor out into a common file all the exports

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* convert all KubeObjectStores to injectable with legacy global backups

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix lint

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* remove unused legacy KubeApi globals

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix bad previous commit

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* more crash fixing

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* try and fix behavioural tests

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix sidebar-and-tab-navigation-for-core.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix sidebar-and-tab-navigation-for-extensions.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix navigation-using-application-menu.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix catalog.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Make ThemeStore non-singleton and fix navigation-to-terminal-preferences.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* extensions.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix catalog-entity-registry.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix navigation-using-application-menu.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix log-resource-selector.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix dock-tabs.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix delete-cluster-dialog.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix navigation-to-kubernetes-preferences.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix navigation-to-editor-preferences.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix navigation-to-proxy-preferences.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix navigation-using-application-menu.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix navigation-to-application-preferences.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix dock-store.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix select.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix role-bindings/__tests__/dialog.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix hotbar-remove-command.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix cluster-role-bindings/__tests__/dialog.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix navigation-to-extension-specific-preferences.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix navigation-to-telemetry-preferences.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix closing-preferences.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix navigation-to-editor-preferences.test.ts

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix navigation-to-proxy-preferences.test.ts

- Fix other type errors too

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* final tweaks

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add more tsconfig files, fix bug in <Catalog>

- Make all of history, navigation injectable

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix type errors

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Convert all of kube-details-params/ and navigate/ to injectable

- This fixes a runtime error that was encountered during testing

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix runtime errors on renderer

- remove all static uses of `createPageParam` (and then removed the
  legacy global)
- Made LensRendererExtension and LensMainExtension just used
  dependencies and not the getLegacyDi
- Fixed circular dep in extension-loader

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Move registerStore calls to after injectMany

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* replace all the rest of the legacy uses of apiManager

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix stack overflow and cycles in DI

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix NamespaceSelectFilter not opening

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix WizardStep and AddNamespaceDialog

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix KubeApi's not being registered

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* cleanup WindowManager

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Proper fix for Wizard, fix NamespaceStore.subscribe

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Rewrite withTooltip to be more type correct

- Fixes mobx related "too many recursive actions" error

- Change all the uses of withTooltips to be functional components

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add e2e test to cover kube api registration

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* cleanup internal-commands

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* remove cast in <Animate>

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix command-palette e2e test

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix type error after rebase

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix test name

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix lint

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix code to help CodeQL scanner

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* update intree extension lock files

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix build-extensions picking wrong @types/react

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix tests from rebase

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix type error

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Make KubeconfigSyncManager more injectable

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix crash in test mode for Dialog

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* make Select snapshots deterministic

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix new type error

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix kube-object.store.test.ts typing

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix merge build issues

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix snapshots after merge

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix lint after merge

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* reexport BaseKubeJsonApiObjectMetadata

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix typo in terminalSpawningPool

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* remove duplicate license header

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix typo to waitUntilDefined

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* remove iter use from getLegacyGlobalDiForExtensionApi

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* remove complex createStorage override

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* override logger with mocks only when needed for tests

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* remove specialized overrideStore flags for getDiForUnitTesting

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* remove unnecessary | undefined types from the exactOptionalFieldTypes experiment

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* use more descriptive name for local test mocks

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* remove unnecessary addition to 'make clean' target

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* remove oddity of KubeObjectStore.getById(undefined) being allowed

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* rename KubeObject.getDescriptor in favour of name without fundemental JS meaning

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Simplify legacyRegisterApi when working in behaviour unit tests

- Don't emit within main environment as there should be no auto
  registering there

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* change confusing variable name in ReactiveDuration

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* make visitor pattern more explicit for Entity contextMenuOpen

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* toggleDetails -> toggleKubeDetailsPane is more specific

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* remove outdated comment

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix bug where LensExtension dependencies are not set

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix tests from the revert of react 18

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix more tests from merge

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix typings with new is-compatible-extension tests

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* more type fixing

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Revert in-tree extension versions

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Improve name of guarding injectable for stores and apis

- New name better implies that it is just a guard state and does not do
  anything

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Add helper for <Select>.isMulti for storing in a Set<Value>

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* fix is-compatible-extension.test.ts types

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton authored and GitHub committed 2022-05-16 07:17:57 -04:00
1 parent 381d77c633
commit dfcb7c3330
1062 files changed
+26512 -28689

No files matched your search

@@ -5,16 +5,15 @@
import userEvent from "@testing-library/user-event";
import React from "react";
import { clusterRolesStore } from "../../+cluster-roles/store";
import { ClusterRole } from "../../../../../common/k8s-api/endpoints";
import { RoleBindingDialog } from "../dialog";
import { getDiForUnitTesting } from "../../../../getDiForUnitTesting";
import type { DiRender } from "../../../test-utils/renderFor";
import { renderFor } from "../../../test-utils/renderFor";
import directoryForUserDataInjectable
from "../../../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
jest.mock("../../+cluster-roles/store");
import directoryForUserDataInjectable from "../../../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import clusterRoleStoreInjectable from "../../+cluster-roles/store.injectable";
import storesAndApisCanBeCreatedInjectable from "../../../../stores-apis-can-be-created.injectable";
import ipcRendererInjectable from "../../../../app-paths/get-value-from-registered-channel/ipc-renderer/ipc-renderer.injectable";
describe("RoleBindingDialog tests", () => {
let render: DiRender;
@@ -22,21 +21,31 @@ describe("RoleBindingDialog tests", () => {
beforeEach(async () => {
const di = getDiForUnitTesting({ doGeneralOverrides: true });
di.override(storesAndApisCanBeCreatedInjectable, () => true);
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
di.override(ipcRendererInjectable, () => ({
on: jest.fn(),
invoke: jest.fn(), // TODO: replace with proper mocking via the IPC bridge
} as never));
await di.runSetups();
render = renderFor(di);
(clusterRolesStore as any).items = [new ClusterRole({
apiVersion: "rbac.authorization.k8s.io/v1",
kind: "ClusterRole",
metadata: {
name: "foobar",
resourceVersion: "1",
uid: "1",
},
})];
const store = di.inject(clusterRoleStoreInjectable);
store.items.replace([
new ClusterRole({
apiVersion: "rbac.authorization.k8s.io/v1",
kind: "ClusterRole",
metadata: {
name: "foobar",
resourceVersion: "1",
uid: "1",
selfLink: "/apis/rbac.authorization.k8s.io/v1/clusterroles/foobar",
},
}),
]);
});
afterEach(() => {
@@ -8,7 +8,7 @@ import "./details.scss";
import { reaction } from "mobx";
import { disposeOnUnmount, observer } from "mobx-react";
import React from "react";
import type { RoleBinding, RoleBindingSubject } from "../../../../common/k8s-api/endpoints";
import type { RoleBinding } from "../../../../common/k8s-api/endpoints";
import { prevDefault } from "../../../utils";
import { AddRemoveButtons } from "../../add-remove-buttons";
import { DrawerTitle } from "../../drawer";
@@ -16,9 +16,9 @@ import type { KubeObjectDetailsProps } from "../../kube-object-details";
import { KubeObjectMeta } from "../../kube-object-meta";
import { Table, TableCell, TableHead, TableRow } from "../../table";
import { RoleBindingDialog } from "./dialog";
import { roleBindingsStore } from "./store";
import { roleBindingStore } from "./legacy-store";
import { ObservableHashSet } from "../../../../common/utils/hash-set";
import { hashRoleBindingSubject } from "./hashers";
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";
@@ -32,7 +32,7 @@ interface Dependencies {
@observer
class NonInjectedRoleBindingDetails extends React.Component<RoleBindingDetailsProps & Dependencies> {
selectedSubjects = new ObservableHashSet<RoleBindingSubject>([], hashRoleBindingSubject);
private readonly selectedSubjects = new ObservableHashSet([], hashSubject);
async componentDidMount() {
disposeOnUnmount(this, [
@@ -47,10 +47,14 @@ class NonInjectedRoleBindingDetails extends React.Component<RoleBindingDetailsPr
const { selectedSubjects } = this;
openConfirmDialog({
ok: () => roleBindingsStore.removeSubjects(roleBinding, selectedSubjects.toJSON()),
ok: () => roleBindingStore.removeSubjects(roleBinding, selectedSubjects.toJSON()),
labelOk: `Remove`,
message: (
<p>Remove selected bindings for <b>{roleBinding.getName()}</b>?</p>
<p>
Remove selected bindings for
<b>{roleBinding.getName()}</b>
?
</p>
),
});
};
@@ -116,7 +120,7 @@ class NonInjectedRoleBindingDetails extends React.Component<RoleBindingDetailsPr
<AddRemoveButtons
onAdd={() => RoleBindingDialog.open(roleBinding)}
onRemove={selectedSubjects.size ? this.removeSelectedSubjects : null}
onRemove={selectedSubjects.size ? this.removeSelectedSubjects : undefined}
addTooltip={`Edit bindings of ${roleRef.name}`}
removeTooltip={`Remove selected bindings from ${roleRef.name}`}
/>
@@ -9,10 +9,10 @@ import { computed, observable, makeObservable, action } from "mobx";
import { observer } from "mobx-react";
import React from "react";
import { rolesStore } from "../+roles/store";
import { serviceAccountsStore } from "../+service-accounts/store";
import { roleStore } from "../+roles/legacy-store";
import { serviceAccountStore } from "../+service-accounts/legacy-store";
import { NamespaceSelect } from "../../+namespaces/namespace-select";
import type { ClusterRole, Role, RoleBinding, RoleBindingSubject, ServiceAccount } from "../../../../common/k8s-api/endpoints";
import type { ClusterRole, Role, RoleBinding, ServiceAccount } from "../../../../common/k8s-api/endpoints";
import { roleApi } from "../../../../common/k8s-api/endpoints";
import type { DialogProps } from "../../dialog";
import { Dialog } from "../../dialog";
@@ -22,12 +22,13 @@ import { showDetails } from "../../kube-detail-params";
import { SubTitle } from "../../layout/sub-title";
import { Notifications } from "../../notifications";
import type { SelectOption } from "../../select";
import { Select } from "../../select";
import { onMultiSelectFor, Select } from "../../select";
import { Wizard, WizardStep } from "../../wizard";
import { roleBindingsStore } from "./store";
import { clusterRolesStore } from "../+cluster-roles/store";
import { roleBindingStore } from "./legacy-store";
import { clusterRoleStore } from "../+cluster-roles/legacy-store";
import { Input } from "../../input";
import { ObservableHashSet, nFircate } from "../../../utils";
import type { Subject } from "../../../../common/k8s-api/endpoints/types/subject";
export interface RoleBindingDialogProps extends Partial<DialogProps> {
}
@@ -58,7 +59,7 @@ export class RoleBindingDialog extends React.Component<RoleBindingDialogProps> {
RoleBindingDialog.state.data = undefined;
}
get roleBinding(): RoleBinding {
get roleBinding() {
return RoleBindingDialog.state.data;
}
@@ -66,26 +67,26 @@ export class RoleBindingDialog extends React.Component<RoleBindingDialogProps> {
return !!this.roleBinding;
}
@observable.ref selectedRoleRef: Role | ClusterRole | undefined = undefined;
@observable.ref selectedRoleRef: Role | ClusterRole | null | undefined = null;
@observable bindingName = "";
@observable bindingNamespace = "";
@observable bindingNamespace: string | null = null;
selectedAccounts = new ObservableHashSet<ServiceAccount>([], sa => sa.metadata.uid);
selectedUsers = observable.set<string>([]);
selectedGroups = observable.set<string>([]);
@computed get selectedBindings(): RoleBindingSubject[] {
const serviceAccounts = Array.from(this.selectedAccounts, sa => ({
@computed get selectedBindings(): Subject[] {
const serviceAccounts: Subject[] = Array.from(this.selectedAccounts, sa => ({
name: sa.getName(),
kind: "ServiceAccount" as const,
kind: "ServiceAccount",
namespace: sa.getNs(),
}));
const users = Array.from(this.selectedUsers, user => ({
const users: Subject[] = Array.from(this.selectedUsers, user => ({
name: user,
kind: "User" as const,
kind: "User",
}));
const groups = Array.from(this.selectedGroups, group => ({
const groups: Subject[] = Array.from(this.selectedGroups, group => ({
name: group,
kind: "Group" as const,
kind: "Group",
}));
return [
@@ -96,27 +97,25 @@ export class RoleBindingDialog extends React.Component<RoleBindingDialogProps> {
}
@computed get roleRefOptions(): SelectOption<Role | ClusterRole>[] {
const roles = rolesStore.items
.filter(role => role.getNs() === this.bindingNamespace)
.map(value => ({ value, label: value.getName() }));
const clusterRoles = clusterRolesStore.items
.map(value => ({ value, label: value.getName() }));
const roles = roleStore.items
.filter(role => role.getNs() === this.bindingNamespace);
const clusterRoles = clusterRoleStore.items;
return [
...roles,
...clusterRoles,
];
}
@computed get serviceAccountOptions(): SelectOption<ServiceAccount>[] {
return serviceAccountsStore.items.map(account => ({
value: account,
label: `${account.getName()} (${account.getNs()})`,
].map(r => ({
value: r,
label: r.getName(),
}));
}
@computed get selectedServiceAccountOptions(): SelectOption<ServiceAccount>[] {
return this.serviceAccountOptions.filter(({ value }) => this.selectedAccounts.has(value));
@computed get serviceAccountOptions(): SelectOption<ServiceAccount>[] {
return serviceAccountStore.items.map(serviceAccount => ({
value: serviceAccount,
label: `${serviceAccount.getName()} (${serviceAccount.getNs()})`,
isSelected: this.selectedAccounts.has(serviceAccount),
}));
}
onOpen = action(() => {
@@ -126,9 +125,13 @@ export class RoleBindingDialog extends React.Component<RoleBindingDialogProps> {
return this.reset();
}
this.selectedRoleRef = (binding.roleRef.kind === roleApi.kind ? rolesStore : clusterRolesStore)
.items
.find(item => item.getName() === binding.roleRef.name);
const findByRoleRefName = (item: Role | ClusterRole) => item.getName() === binding.roleRef.name;
this.selectedRoleRef = (
binding.roleRef.kind === roleApi.kind
? roleStore.items.find(findByRoleRefName)
: clusterRoleStore.items.find(findByRoleRefName)
);
this.bindingName = binding.getName();
this.bindingNamespace = binding.getNs();
@@ -137,7 +140,7 @@ export class RoleBindingDialog extends React.Component<RoleBindingDialogProps> {
const accountNames = new Set(saSubjects.map(acc => acc.name));
this.selectedAccounts.replace(
serviceAccountsStore.items
serviceAccountStore.items
.filter(sa => accountNames.has(sa.getName())),
);
this.selectedUsers.replace(uSubjects.map(user => user.name));
@@ -145,7 +148,7 @@ export class RoleBindingDialog extends React.Component<RoleBindingDialogProps> {
});
reset = action(() => {
this.selectedRoleRef = undefined;
this.selectedRoleRef = null;
this.bindingName = "";
this.bindingNamespace = "";
this.selectedAccounts.clear();
@@ -154,12 +157,19 @@ export class RoleBindingDialog extends React.Component<RoleBindingDialogProps> {
});
createBindings = async () => {
const { selectedRoleRef, bindingNamespace: namespace, selectedBindings } = this;
const { selectedRoleRef, bindingNamespace, selectedBindings, roleBinding, bindingName } = this;
if (!selectedRoleRef || !roleBinding || !bindingNamespace || !bindingName) {
return;
}
try {
const roleBinding = this.isEditing
? await roleBindingsStore.updateSubjects(this.roleBinding, selectedBindings)
: await roleBindingsStore.create({ name: this.bindingName, namespace }, {
const newRoleBinding = this.isEditing
? await roleBindingStore.updateSubjects(roleBinding, selectedBindings)
: await roleBindingStore.create({
name: bindingName,
namespace: bindingNamespace,
}, {
subjects: selectedBindings,
roleRef: {
name: selectedRoleRef.getName(),
@@ -167,10 +177,10 @@ export class RoleBindingDialog extends React.Component<RoleBindingDialogProps> {
},
});
showDetails(roleBinding.selfLink);
showDetails(newRoleBinding.selfLink);
RoleBindingDialog.close();
} catch (err) {
Notifications.error(err);
Notifications.checkedError(err, `Unknown error occured while ${this.isEditing ? "editing" : "creating"} role bindings.`);
}
};
@@ -184,7 +194,7 @@ export class RoleBindingDialog extends React.Component<RoleBindingDialogProps> {
isDisabled={this.isEditing}
value={this.bindingNamespace}
autoFocus={!this.isEditing}
onChange={({ value }) => this.bindingNamespace = value}
onChange={opt => this.bindingNamespace = opt?.value ?? null}
/>
<SubTitle title="Role Reference" />
@@ -195,12 +205,12 @@ export class RoleBindingDialog extends React.Component<RoleBindingDialogProps> {
isDisabled={this.isEditing}
options={this.roleRefOptions}
value={this.selectedRoleRef}
onChange={({ value }) => {
if (!this.selectedRoleRef || this.bindingName === this.selectedRoleRef.getName()) {
this.bindingName = value.getName();
}
onChange={option => {
this.selectedRoleRef = option?.value;
this.selectedRoleRef = value;
if (!this.selectedRoleRef || this.bindingName === this.selectedRoleRef.getName()) {
this.bindingName = option?.value.getName() ?? "";
}
}}
/>
@@ -235,19 +245,14 @@ export class RoleBindingDialog extends React.Component<RoleBindingDialogProps> {
isMulti
themeName="light"
placeholder="Select service accounts ..."
autoConvertOptions={false}
options={this.serviceAccountOptions}
value={this.selectedServiceAccountOptions}
formatOptionLabel={({ value }: SelectOption<ServiceAccount>) => (
<><Icon small material="account_box" /> {value.getName()} ({value.getNs()})</>
formatOptionLabel={option => (
<>
<Icon small material="account_box" />
{` ${option.label}`}
</>
)}
onChange={(selected: SelectOption<ServiceAccount>[] | null) => {
if (selected) {
this.selectedAccounts.replace(selected.map(opt => opt.value));
} else {
this.selectedAccounts.clear();
}
}}
onChange={onMultiSelectFor(this.selectedAccounts)}
maxMenuHeight={200}
/>
</>
@@ -269,7 +274,11 @@ export class RoleBindingDialog extends React.Component<RoleBindingDialogProps> {
onOpen={this.onOpen}
>
<Wizard
header={<h5>{action} RoleBinding</h5>}
header={(
<h5>
{`${action} RoleBinding`}
</h5>
)}
done={RoleBindingDialog.close}
>
<WizardStep
@@ -1,16 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { MD5 } from "crypto-js";
import type { RoleBindingSubject } from "../../../../common/k8s-api/endpoints";
export function hashRoleBindingSubject(subject: RoleBindingSubject): string {
return MD5(JSON.stringify([
["kind", subject.kind],
["name", subject.name],
["namespace", subject.namespace],
["apiGroup", subject.apiGroup],
])).toString();
}
@@ -0,0 +1,12 @@
/**
* 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 roleBindingStoreInjectable from "./store.injectable";
/**
* @deprecated use `di.inject(roleBindingStoreInjectable)` instead
*/
export const roleBindingStore = asLegacyGlobalForExtensionApi(roleBindingStoreInjectable);
@@ -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 assert from "assert";
import { kubeObjectStoreInjectionToken } from "../../../../common/k8s-api/api-manager/manager.injectable";
import roleBindingApiInjectable from "../../../../common/k8s-api/endpoints/role-binding.api.injectable";
import storesAndApisCanBeCreatedInjectable from "../../../stores-apis-can-be-created.injectable";
import { RoleBindingStore } from "./store";
const roleBindingStoreInjectable = getInjectable({
id: "role-binding-store",
instantiate: (di) => {
assert(di.inject(storesAndApisCanBeCreatedInjectable), "roleBindingStore is only available in certain environments");
const api = di.inject(roleBindingApiInjectable);
return new RoleBindingStore(api);
},
injectionToken: kubeObjectStoreInjectionToken,
});
export default roleBindingStoreInjectable;
@@ -3,16 +3,13 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { apiManager } from "../../../../common/k8s-api/api-manager";
import type { RoleBinding, RoleBindingSubject } from "../../../../common/k8s-api/endpoints";
import { roleBindingApi } from "../../../../common/k8s-api/endpoints";
import type { RoleBinding, RoleBindingApi, RoleBindingData } from "../../../../common/k8s-api/endpoints";
import type { Subject } from "../../../../common/k8s-api/endpoints/types/subject";
import { KubeObjectStore } from "../../../../common/k8s-api/kube-object.store";
import { HashSet } from "../../../utils";
import { hashRoleBindingSubject } from "./hashers";
export class RoleBindingsStore extends KubeObjectStore<RoleBinding> {
api = roleBindingApi;
import { hashSubject } from "../hashers";
export class RoleBindingStore extends KubeObjectStore<RoleBinding, RoleBindingApi, RoleBindingData> {
protected sortItems(items: RoleBinding[]) {
return super.sortItems(items, [
roleBinding => roleBinding.kind,
@@ -20,19 +17,15 @@ export class RoleBindingsStore extends KubeObjectStore<RoleBinding> {
]);
}
protected async createItem(params: { name: string; namespace: string }, data?: Partial<RoleBinding>) {
return roleBindingApi.create(params, data);
}
async updateSubjects(roleBinding: RoleBinding, subjects: RoleBindingSubject[]) {
async updateSubjects(roleBinding: RoleBinding, subjects: Subject[]) {
return this.update(roleBinding, {
roleRef: roleBinding.roleRef,
subjects,
});
}
async removeSubjects(roleBinding: RoleBinding, subjectsToRemove: Iterable<RoleBindingSubject>) {
const currentSubjects = new HashSet(roleBinding.getSubjects(), hashRoleBindingSubject);
async removeSubjects(roleBinding: RoleBinding, subjectsToRemove: Iterable<Subject>) {
const currentSubjects = new HashSet(roleBinding.getSubjects(), hashSubject);
for (const subject of subjectsToRemove) {
currentSubjects.delete(subject);
@@ -41,7 +34,3 @@ export class RoleBindingsStore extends KubeObjectStore<RoleBinding> {
return this.updateSubjects(roleBinding, currentSubjects.toJSON());
}
}
export const roleBindingsStore = new RoleBindingsStore();
apiManager.registerStore(roleBindingsStore);
@@ -9,10 +9,10 @@ import React from "react";
import { KubeObjectListLayout } from "../../kube-object-list-layout";
import { KubeObjectStatusIcon } from "../../kube-object-status-icon";
import { RoleBindingDialog } from "./dialog";
import { roleBindingsStore } from "./store";
import { rolesStore } from "../+roles/store";
import { clusterRolesStore } from "../+cluster-roles/store";
import { serviceAccountsStore } from "../+service-accounts/store";
import { roleBindingStore } from "./legacy-store";
import { roleStore } from "../+roles/legacy-store";
import { clusterRoleStore } from "../+cluster-roles/legacy-store";
import { serviceAccountStore } from "../+service-accounts/legacy-store";
import { SiblingsInTabLayout } from "../../layout/siblings-in-tab-layout";
import { KubeObjectAge } from "../../kube-object/age";
@@ -32,8 +32,8 @@ export class RoleBindings extends React.Component {
isConfigurable
tableId="access_role_bindings"
className="RoleBindings"
store={roleBindingsStore}
dependentStores={[rolesStore, clusterRolesStore, serviceAccountsStore]}
store={roleBindingStore}
dependentStores={[roleStore, clusterRoleStore, serviceAccountStore]}
sortingCallbacks={{
[columnId.name]: binding => binding.getName(),
[columnId.namespace]: binding => binding.getNs(),