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
new file mode 100644
index 0000000000..132f338685
--- /dev/null
+++ b/src/renderer/components/+user-management/+cluster-role-bindings/__tests__/dialog.test.tsx
@@ -0,0 +1,62 @@
+/**
+ * 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 { render } from "@testing-library/react";
+import React from "react";
+import { ClusterRoleBindingDialog } from "../dialog";
+import { clusterRolesStore } from "../../+cluster-roles/store";
+import { ClusterRole } from "../../../../../common/k8s-api/endpoints";
+import userEvent from "@testing-library/user-event";
+
+jest.mock("../../+cluster-roles/store");
+
+describe("ClusterRoleBindingDialog tests", () => {
+ beforeEach(() => {
+ (clusterRolesStore as any).items = [new ClusterRole({
+ apiVersion: "rbac.authorization.k8s.io/v1",
+ kind: "ClusterRole",
+ metadata: {
+ name: "foobar",
+ resourceVersion: "1",
+ uid: "1",
+ },
+ })];
+ });
+
+ afterEach(() => {
+ ClusterRoleBindingDialog.close();
+ jest.resetAllMocks();
+ });
+
+ it("should render without any errors", () => {
+ const { container } = render();
+
+ expect(container).toBeInstanceOf(HTMLElement);
+ });
+
+ it("clusterrole select should be searchable", async () => {
+ ClusterRoleBindingDialog.open();
+ const res = render();
+
+ userEvent.keyboard("a");
+ await res.findAllByText("foobar");
+ });
+});
diff --git a/src/renderer/components/+user-management/+cluster-role-bindings/dialog.tsx b/src/renderer/components/+user-management/+cluster-role-bindings/dialog.tsx
index cac74775e8..7b494af70d 100644
--- a/src/renderer/components/+user-management/+cluster-role-bindings/dialog.tsx
+++ b/src/renderer/components/+user-management/+cluster-role-bindings/dialog.tsx
@@ -37,9 +37,9 @@ import { Select, SelectOption } from "../../select";
import { Wizard, WizardStep } from "../../wizard";
import { clusterRoleBindingsStore } from "./store";
import { clusterRolesStore } from "../+cluster-roles/store";
-import { getRoleRefSelectOption, ServiceAccountOption } from "../select-options";
import { ObservableHashSet, nFircate } from "../../../utils";
import { Input } from "../../input";
+import { TooltipPosition } from "../../tooltip";
interface Props extends Partial {
}
@@ -114,24 +114,21 @@ export class ClusterRoleBindingDialog extends React.Component {
}
@computed get clusterRoleRefoptions(): SelectOption[] {
- return clusterRolesStore.items.map(getRoleRefSelectOption);
+ return clusterRolesStore.items.map(value => ({
+ value,
+ label: value.getName(),
+ }));
}
- @computed get serviceAccountOptions(): ServiceAccountOption[] {
- return serviceAccountsStore.items.map(account => {
- const name = account.getName();
- const namespace = account.getNs();
-
- return {
- value: `${account.getName()}%${account.getNs()}`,
- account,
- label: <> {name} ({namespace})>,
- };
- });
+ @computed get serviceAccountOptions(): SelectOption[] {
+ return serviceAccountsStore.items.map(account => ({
+ value: account,
+ label: `${account.getName()} (${account.getNs()})`,
+ }));
}
- @computed get selectedServiceAccountOptions(): ServiceAccountOption[] {
- return this.serviceAccountOptions.filter(({ account }) => this.selectedAccounts.has(account));
+ @computed get selectedServiceAccountOptions(): SelectOption[] {
+ return this.serviceAccountOptions.filter(({ value }) => this.selectedAccounts.has(value));
}
@action
@@ -198,6 +195,21 @@ export class ClusterRoleBindingDialog extends React.Component {
isDisabled={this.isEditing}
options={this.clusterRoleRefoptions}
value={this.selectedRoleRef}
+ autoFocus={!this.isEditing}
+ formatOptionLabel={({ value }: SelectOption) => (
+ <>
+
+ {" "}
+ {value.getName()}
+ >
+ )}
onChange={({ value }: SelectOption ) => {
if (!this.selectedRoleRef || this.bindingName === this.selectedRoleRef.getName()) {
this.bindingName = value.getName();
@@ -241,9 +253,12 @@ export class ClusterRoleBindingDialog extends React.Component {
autoConvertOptions={false}
options={this.serviceAccountOptions}
value={this.selectedServiceAccountOptions}
- onChange={(selected: ServiceAccountOption[] | null) => {
+ formatOptionLabel={({ value }: SelectOption) => (
+ <> {value.getName()} ({value.getNs()})>
+ )}
+ onChange={(selected: SelectOption[] | null) => {
if (selected) {
- this.selectedAccounts.replace(selected.map(opt => opt.account));
+ this.selectedAccounts.replace(selected.map(opt => opt.value));
} else {
this.selectedAccounts.clear();
}
diff --git a/src/renderer/components/+user-management/select-options.tsx b/src/renderer/components/+user-management/+role-bindings/__tests__/dialog.test.tsx
similarity index 52%
rename from src/renderer/components/+user-management/select-options.tsx
rename to src/renderer/components/+user-management/+role-bindings/__tests__/dialog.test.tsx
index 16608f9f07..6b663e7b86 100644
--- a/src/renderer/components/+user-management/select-options.tsx
+++ b/src/renderer/components/+user-management/+role-bindings/__tests__/dialog.test.tsx
@@ -19,31 +19,44 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+import { render } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
import React from "react";
-import type { ServiceAccount } from "../../../common/k8s-api/endpoints";
-import type { KubeObject } from "../../../common/k8s-api/kube-object";
-import { Icon } from "../icon";
-import type { SelectOption } from "../select";
-import { TooltipPosition } from "../tooltip";
+import { rolesStore } from "../../+roles/store";
+import { Role } from "../../../../../common/k8s-api/endpoints";
+import { RoleBindingDialog } from "../dialog";
-export type ServiceAccountOption = SelectOption & { account: ServiceAccount };
+jest.mock("../../+roles/store");
-export function getRoleRefSelectOption(item: T): SelectOption {
- return {
- value: item,
- label: (
- <>
-
- {" "}
- {item.getName()}
- >
- ),
- };
-}
+describe("RoleBindingDialog tests", () => {
+ beforeEach(() => {
+ (rolesStore as any).items = [new Role({
+ apiVersion: "rbac.authorization.k8s.io/v1",
+ kind: "Role",
+ metadata: {
+ name: "foobar",
+ resourceVersion: "1",
+ uid: "1",
+ },
+ })];
+ });
+
+ afterEach(() => {
+ RoleBindingDialog.close();
+ jest.resetAllMocks();
+ });
+
+ it("should render without any errors", () => {
+ const { container } = render();
+
+ expect(container).toBeInstanceOf(HTMLElement);
+ });
+
+ it("role select should be searchable", async () => {
+ RoleBindingDialog.open();
+ const res = render();
+
+ userEvent.keyboard("a");
+ await res.findAllByText("foobar");
+ });
+});
diff --git a/src/renderer/components/+user-management/+role-bindings/dialog.tsx b/src/renderer/components/+user-management/+role-bindings/dialog.tsx
index 8da322297c..a04a888bfe 100644
--- a/src/renderer/components/+user-management/+role-bindings/dialog.tsx
+++ b/src/renderer/components/+user-management/+role-bindings/dialog.tsx
@@ -40,7 +40,6 @@ import { Wizard, WizardStep } from "../../wizard";
import { roleBindingsStore } from "./store";
import { clusterRolesStore } from "../+cluster-roles/store";
import { Input } from "../../input";
-import { getRoleRefSelectOption, ServiceAccountOption } from "../select-options";
import { ObservableHashSet, nFircate } from "../../../utils";
interface Props extends Partial {
@@ -112,9 +111,9 @@ export class RoleBindingDialog extends React.Component {
@computed get roleRefOptions(): SelectOption[] {
const roles = rolesStore.items
.filter(role => role.getNs() === this.bindingNamespace)
- .map(getRoleRefSelectOption);
+ .map(value => ({ value, label: value.getName() }));
const clusterRoles = clusterRolesStore.items
- .map(getRoleRefSelectOption);
+ .map(value => ({ value, label: value.getName() }));
return [
...roles,
@@ -122,21 +121,15 @@ export class RoleBindingDialog extends React.Component {
];
}
- @computed get serviceAccountOptions(): ServiceAccountOption[] {
- return serviceAccountsStore.items.map(account => {
- const name = account.getName();
- const namespace = account.getNs();
-
- return {
- value: `${account.getName()}%${account.getNs()}`,
- account,
- label: <> {name} ({namespace})>,
- };
- });
+ @computed get serviceAccountOptions(): SelectOption[] {
+ return serviceAccountsStore.items.map(account => ({
+ value: account,
+ label: `${account.getName()} (${account.getNs()})`,
+ }));
}
- @computed get selectedServiceAccountOptions(): ServiceAccountOption[] {
- return this.serviceAccountOptions.filter(({ account }) => this.selectedAccounts.has(account));
+ @computed get selectedServiceAccountOptions(): SelectOption[] {
+ return this.serviceAccountOptions.filter(({ value }) => this.selectedAccounts.has(value));
}
@action
@@ -204,6 +197,7 @@ export class RoleBindingDialog extends React.Component {
themeName="light"
isDisabled={this.isEditing}
value={this.bindingNamespace}
+ autoFocus={!this.isEditing}
onChange={({ value }) => this.bindingNamespace = value}
/>
@@ -256,9 +250,12 @@ export class RoleBindingDialog extends React.Component {
autoConvertOptions={false}
options={this.serviceAccountOptions}
value={this.selectedServiceAccountOptions}
- onChange={(selected: ServiceAccountOption[] | null) => {
+ formatOptionLabel={({ value }: SelectOption) => (
+ <> {value.getName()} ({value.getNs()})>
+ )}
+ onChange={(selected: SelectOption[] | null) => {
if (selected) {
- this.selectedAccounts.replace(selected.map(opt => opt.account));
+ this.selectedAccounts.replace(selected.map(opt => opt.value));
} else {
this.selectedAccounts.clear();
}