Skip to content

Commit

Permalink
feat(coral): Allow superadmin access envs and cluster (#2584)
Browse files Browse the repository at this point in the history
* Remove redirect for environments for superadmin

Signed-off-by: Mirjam Aulbach <[email protected]>

* Show additional column for superadmin in kafka environment table

Signed-off-by: Mirjam Aulbach <[email protected]>

* Show additional column for superadmin in connect environment table

Signed-off-by: Mirjam Aulbach <[email protected]>

* Show additional column for superadmin in schema registry environment table

Signed-off-by: Mirjam Aulbach <[email protected]>

* Remove redirect for cluster page for superadmin

Signed-off-by: Mirjam Aulbach <[email protected]>

* Add new property to show edit button for cluster table dependent on permission

Signed-off-by: Mirjam Aulbach <[email protected]>

* Use feature flag instead of prop for isSuperAdmin check

Signed-off-by: Mirjam Aulbach <[email protected]>

---------

Signed-off-by: Mirjam Aulbach <[email protected]>
  • Loading branch information
programmiri authored Aug 30, 2024
1 parent 35804bc commit e588916
Show file tree
Hide file tree
Showing 10 changed files with 313 additions and 15 deletions.
1 change: 1 addition & 0 deletions coral/src/app/features/configuration/clusters/Clusters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ function Clusters() {
? handleShowDeleteModal
: undefined
}
showEdit={permissions.addDeleteEditClusters}
ariaLabel={`Cluster overview, page ${clusters?.currentPage ?? 0} of ${
clusters?.totalPages ?? 0
}`}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,20 +264,28 @@ describe("ClusterTable.tsx", () => {
describe("shows all clusters as a table (user with permissions.addDeleteEditClusters)", () => {
const tableLabel = "Cluster overview";
beforeAll(() => {
Object.defineProperty(window, "location", {
value: {
assign: jest.fn(),
},
writable: true,
});

customRender(
<ClustersTable
clusters={testCluster}
ariaLabel={tableLabel}
handleShowConnectModal={mockHandleShowConnectModal}
handleShowDeleteModal={mockHandleShowDeleteModal}
showEdit={true}
/>,
{ queryClient: true }
);
});

afterAll(cleanup);

it("renders a table with an acessible name", async () => {
it("renders a table with an accessible name", async () => {
const table = screen.getByRole("table", {
name: tableLabel,
});
Expand Down Expand Up @@ -490,6 +498,30 @@ describe("ClusterTable.tsx", () => {
},
});
});

it(`displays an edit button that redirects to Klaw for ${cluster.clusterName}`, async () => {
const table = screen.getByRole("table", {
name: tableLabel,
});
const row = within(table).getByRole("row", {
name: new RegExp(`${cluster.clusterName}`),
});
const menuButton = within(row).getByRole("button", {
name: "Context menu",
});

await userEvent.click(menuButton);

const editButton = screen.getByRole("menuitem", {
name: "Edit",
});

await userEvent.click(editButton);

expect(window.location.assign).toHaveBeenCalledWith(
"http://localhost/modifyCluster?clusterId=1&clusterType=kafka"
);
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,20 @@ import { ClusterDetails } from "src/domain/cluster";
import { clusterTypeToString } from "src/services/formatter/cluster-type-formatter";
import { kafkaFlavorToString } from "src/services/formatter/kafka-flavor-formatter";
import deleteIcon from "@aivenio/aquarium/dist/src/icons/delete";
import editIcon from "@aivenio/aquarium/dist/src/icons/edit";
import camelCase from "lodash/camelCase";

type ClustersTableProps = {
clusters: ClusterDetails[];
ariaLabel: string;
handleShowConnectModal?: ({ show, data }: ClusterConnectModalState) => void;
handleShowDeleteModal?: ({ show, data }: ClusterDeleteModalState) => void;
showEdit?: boolean;
};

interface ClustersTableRow {
id: ClusterDetails["clusterId"];
type: ClusterDetails["clusterType"];
clusterName: ClusterDetails["clusterName"];
bootstrapServers: ClusterDetails["bootstrapServers"];
protocol: ClusterDetails["protocol"];
Expand All @@ -37,11 +41,18 @@ interface ClustersTableRow {
}

const ClustersTable = (props: ClustersTableProps) => {
const { clusters, ariaLabel, handleShowConnectModal, handleShowDeleteModal } =
props;
const {
clusters,
ariaLabel,
showEdit,
handleShowConnectModal,
handleShowDeleteModal,
} = props;

const isAdminUser =
handleShowConnectModal !== undefined && handleShowDeleteModal !== undefined;
handleShowConnectModal !== undefined &&
handleShowDeleteModal !== undefined &&
showEdit === true;

const columns: Array<DataTableColumn<ClustersTableRow>> = [
{
Expand Down Expand Up @@ -129,6 +140,7 @@ const ClustersTable = (props: ClustersTableProps) => {
const rows: ClustersTableRow[] = clusters.map((cluster) => {
return {
id: cluster.clusterId,
type: cluster.clusterType,
clusterName: cluster.clusterName,
bootstrapServers: cluster.bootstrapServers,
protocol: cluster.protocol,
Expand All @@ -155,6 +167,9 @@ const ClustersTable = (props: ClustersTableProps) => {
noWrap={false}
menu={
<DropdownMenu.Items>
<DropdownMenu.Item icon={editIcon} key="edit">
Edit
</DropdownMenu.Item>
<DropdownMenu.Item icon={deleteIcon} key="delete">
Remove
</DropdownMenu.Item>
Expand All @@ -171,6 +186,13 @@ const ClustersTable = (props: ClustersTableProps) => {
},
});
}
if (action === "edit") {
const { id, type } = data;
const typeForUrl = camelCase(type).toLowerCase();
window.location.assign(
`${window.origin}/modifyCluster?clusterId=${id}&clusterType=${typeForUrl}`
);
}
}}
/>
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { createMockEnvironmentDTO } from "src/domain/environment/environment-tes
import { Environment } from "src/domain/environment/environment-types";
import { mockIntersectionObserver } from "src/services/test-utils/mock-intersection-observer";
import { customRender } from "src/services/test-utils/render-with-wrappers";
import { UseAuthContext } from "src/app/context-provider/AuthProvider";
import { testAuthUser } from "src/domain/auth-user/auth-user-test-helper";

const TEST_UPDATE_TIME = "${TEST_UPDATE_TIME}";

Expand Down Expand Up @@ -64,6 +66,14 @@ const tableRowHeader = [
"Status",
];

let mockAuthUserContext: UseAuthContext = {
...testAuthUser,
isSuperAdminUser: false,
};
jest.mock("src/app/context-provider/AuthProvider", () => ({
useAuthContext: () => mockAuthUserContext,
}));

describe("KafkaEnvironmentsTable.tsx", () => {
describe("shows empty state correctly", () => {
afterAll(cleanup);
Expand Down Expand Up @@ -210,4 +220,59 @@ describe("KafkaEnvironmentsTable.tsx", () => {
});
});
});

describe("shows additional colum with edit link for superadmin user", () => {
beforeAll(() => {
mockIntersectionObserver();
});

afterEach(cleanup);

const additionalRowSuperAdmin = "Manage";
const tableRowHeaderSuperAdmin = [
...tableRowHeader,
additionalRowSuperAdmin,
];

it("shows a row with edit link for superadmin user", () => {
mockAuthUserContext = { ...testAuthUser, isSuperAdminUser: true };
customRender(
<KafkaEnvironmentsTable
environments={mockEnvironments}
ariaLabel={"Kafka Environments overview, page 1 of 10"}
/>,
{ queryClient: true }
);

const table = screen.getByRole("table", {
name: "Kafka Environments overview, page 1 of 10",
});

const columns = within(table).getAllByRole("columnheader");

expect(columns).toHaveLength(tableRowHeaderSuperAdmin.length);
expect(columns[tableRowHeaderSuperAdmin.length - 1]).toHaveTextContent(
additionalRowSuperAdmin
);
});

it("does not show the colum for user", () => {
mockAuthUserContext = { ...testAuthUser, isSuperAdminUser: false };
customRender(
<KafkaEnvironmentsTable
environments={mockEnvironments}
ariaLabel={"Kafka Environments overview, page 1 of 10"}
/>,
{ queryClient: true }
);

const table = screen.getByRole("table", {
name: "Kafka Environments overview, page 1 of 10",
});

const columns = within(table).getAllByRole("columnheader");

expect(columns).toHaveLength(tableRowHeader.length);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import {
DataTable,
DataTableColumn,
EmptyState,
Link,
StatusChip,
} from "@aivenio/aquarium";
import EnvironmentStatus from "src/app/features/configuration/environments/components/EnvironmentStatus";
import { Environment } from "src/domain/environment";
import { useAuthContext } from "src/app/context-provider/AuthProvider";

type KafkaEnvironmentsTableProps = {
environments: Environment[];
Expand All @@ -15,6 +17,7 @@ type KafkaEnvironmentsTableProps = {

interface KafkaEnvironmentsTableRow {
id: Environment["id"];
type: Environment["type"];
environmentName: Environment["name"];
clusterName: Environment["clusterName"];
tenantName: Environment["tenantName"];
Expand All @@ -27,6 +30,16 @@ interface KafkaEnvironmentsTableRow {
const KafkaEnvironmentsTable = (props: KafkaEnvironmentsTableProps) => {
const { environments, ariaLabel } = props;

const { isSuperAdminUser } = useAuthContext();

const optionalColumnSuperAdmin: DataTableColumn<KafkaEnvironmentsTableRow> = {
type: "custom",
headerName: "Manage",
UNSAFE_render: ({ type, id }: KafkaEnvironmentsTableRow) => {
return <Link href={`/modifyEnv?envId=${id}&envType=${type}`}>Edit</Link>;
},
};

const columns: Array<DataTableColumn<KafkaEnvironmentsTableRow>> = [
{
type: "text",
Expand Down Expand Up @@ -109,11 +122,13 @@ const KafkaEnvironmentsTable = (props: KafkaEnvironmentsTableProps) => {
);
},
},
...(isSuperAdminUser ? [optionalColumnSuperAdmin] : []),
];

const rows: KafkaEnvironmentsTableRow[] = environments.map((env) => {
return {
id: env.id,
type: env.type,
environmentName: env.name,
clusterName: env.clusterName,
tenantName: env.tenantName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { createMockEnvironmentDTO } from "src/domain/environment/environment-tes
import { Environment } from "src/domain/environment/environment-types";
import { mockIntersectionObserver } from "src/services/test-utils/mock-intersection-observer";
import { customRender } from "src/services/test-utils/render-with-wrappers";
import { UseAuthContext } from "src/app/context-provider/AuthProvider";
import { testAuthUser } from "src/domain/auth-user/auth-user-test-helper";

const TEST_UPDATE_TIME = "14-Sep-2023 12:30:38 UTC";

Expand Down Expand Up @@ -42,6 +44,14 @@ const mockEnvironments: Environment[] = [

const tableRowHeader = ["Environment", "Cluster", "Tenant", "Status"];

let mockAuthUserContext: UseAuthContext = {
...testAuthUser,
isSuperAdminUser: false,
};
jest.mock("src/app/context-provider/AuthProvider", () => ({
useAuthContext: () => mockAuthUserContext,
}));

describe("KafkaConnectEnvironmentsTable.tsx", () => {
describe("shows empty state correctly", () => {
afterAll(cleanup);
Expand Down Expand Up @@ -161,4 +171,58 @@ describe("KafkaConnectEnvironmentsTable.tsx", () => {
});
});
});

describe("shows additional colum with edit link for superadmin user", () => {
beforeAll(() => {
mockIntersectionObserver();
});

afterEach(cleanup);

const additionalRowSuperAdmin = "Manage";
const tableRowHeaderSuperAdmin = [
...tableRowHeader,
additionalRowSuperAdmin,
];

it("shows a row with edit link for superadmin user", () => {
mockAuthUserContext = { ...testAuthUser, isSuperAdminUser: true };
customRender(
<KafkaConnectEnvironmentsTable
environments={mockEnvironments}
ariaLabel={"Kafka Connect Environments overview, page 0 of 0"}
/>,
{ queryClient: true }
);

const table = screen.getByRole("table", {
name: "Kafka Connect Environments overview, page 0 of 0",
});

const columns = within(table).getAllByRole("columnheader");

expect(columns).toHaveLength(tableRowHeaderSuperAdmin.length);
expect(columns[tableRowHeaderSuperAdmin.length - 1]).toHaveTextContent(
additionalRowSuperAdmin
);
});

it("does not show the colum for user", () => {
mockAuthUserContext = { ...testAuthUser, isSuperAdminUser: false };
customRender(
<KafkaConnectEnvironmentsTable
environments={mockEnvironments}
ariaLabel={"Kafka Connect Environments overview, page 0 of 0"}
/>,
{ queryClient: true }
);

const table = screen.getByRole("table", {
name: "Kafka Connect Environments overview, page 0 of 0",
});

const columns = within(table).getAllByRole("columnheader");
expect(columns).toHaveLength(tableRowHeader.length);
});
});
});
Loading

0 comments on commit e588916

Please sign in to comment.