Skip to content

Commit

Permalink
feat: [WD-16894] Add bulk deletion of TLS Users
Browse files Browse the repository at this point in the history
Signed-off-by: Nkeiruka <[email protected]>
  • Loading branch information
Kxiru committed Dec 9, 2024
1 parent b452c41 commit 8ed4442
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 34 deletions.
17 changes: 9 additions & 8 deletions src/api/auth-identities.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,24 @@ export const updateIdentities = (
});
};

export const deleteOIDCIdentity = (identity: LxdIdentity) => {
export const deleteIdentity = (identity: LxdIdentity) => {
return new Promise((resolve, reject) => {
fetch(`/1.0/auth/identities/oidc/${identity.id}`, {
method: "DELETE",
})
fetch(
`/1.0/auth/identities/${identity.authentication_method}/${identity.id}`,
{
method: "DELETE",
},
)
.then(handleResponse)
.then(resolve)
.catch(reject);
});
};

export const deleteOIDCIdentities = (
identities: LxdIdentity[],
): Promise<void> => {
export const deleteIdentities = (identities: LxdIdentity[]): Promise<void> => {
return new Promise((resolve, reject) => {
void Promise.allSettled(
identities.map((identity) => deleteOIDCIdentity(identity)),
identities.map((identity) => deleteIdentity(identity)),
)
.then(handleSettledResult)
.then(resolve)
Expand Down
6 changes: 4 additions & 2 deletions src/components/ResourceLabel.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { FC } from "react";
import ResourceIcon, { ResourceIconType } from "./ResourceIcon";
import classNames from "classnames";

interface Props {
type: ResourceIconType;
value: string;
bold?: boolean;
fullWidth?: boolean;
}

const ResourceLabel: FC<Props> = ({ type, value, bold }) => {
const ResourceLabel: FC<Props> = ({ type, value, bold, fullWidth }) => {
const ValueWrapper = bold ? "strong" : "span";
return (
<span className="resource-label u-truncate">
<span className={classNames("resource-label", { "u-truncate": fullWidth })}>
<ResourceIcon type={type} />
<ValueWrapper>{value}</ValueWrapper>
</span>
Expand Down
39 changes: 27 additions & 12 deletions src/pages/permissions/PermissionIdentities.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import Tag from "components/Tag";
import BulkDeleteIdentitiesBtn from "./actions/BulkDeleteIdentitiesBtn";
import DeleteIdentityBtn from "./actions/DeleteIdentityBtn";
import { useSupportedFeatures } from "context/useSupportedFeatures";
import ResourceLabel from "components/ResourceLabel";

const PermissionIdentities: FC = () => {
const notify = useNotify();
Expand Down Expand Up @@ -114,9 +115,11 @@ const PermissionIdentities: FC = () => {

const rows = filteredIdentities.map((identity) => {
const isLoggedInIdentity = settings?.auth_user_name === identity.id;
const isTlsIdentity = identity.authentication_method === "tls";
const isUnrestrictedIdentity =
identity.type === "Client certificate (unrestricted)";

return {
name: isTlsIdentity ? "" : identity.id,
name: isUnrestrictedIdentity ? "" : identity.id,
key: identity.id,
className: "u-row",
columns: [
Expand Down Expand Up @@ -144,7 +147,17 @@ const PermissionIdentities: FC = () => {
"aria-label": "Auth method",
},
{
content: identity.type,
content: (
<ResourceLabel
type={
identity.authentication_method == "tls"
? "certificate"
: "oidc-identity"
}
value={identity.type}
fullWidth={true}
/>
),
role: "cell",
"aria-label": "Type",
className: "u-truncate",
Expand All @@ -157,7 +170,7 @@ const PermissionIdentities: FC = () => {
"aria-label": "Groups for this identity",
},
{
content: !isTlsIdentity && (
content: !isUnrestrictedIdentity && (
<>
<Button
appearance="base"
Expand Down Expand Up @@ -198,10 +211,10 @@ const PermissionIdentities: FC = () => {
defaultSort: "name",
});

// NOTE: tls user group membership cannot be modified, this will be supported in the future
const nonTlsUsers = identities.filter((identity) => {
const isTlsIdentity = identity.authentication_method === "tls";
return !isTlsIdentity;
const restrictedIdentities = identities.filter((identity) => {
const isUnrestrictedIdentity =
identity.type === "Client certificate (unrestricted)";
return !isUnrestrictedIdentity;
});

if (isLoading) {
Expand All @@ -218,11 +231,11 @@ const PermissionIdentities: FC = () => {
if (selectedIdentityIds.length > 0) {
return (
<SelectedTableNotification
totalCount={nonTlsUsers.length ?? 0}
itemName="OIDC identity"
totalCount={restrictedIdentities.length ?? 0}
itemName="identity"
selectedNames={selectedIdentityIds}
setSelectedNames={setSelectedIdentityIds}
filteredNames={nonTlsUsers.map((item) => item.id)}
filteredNames={restrictedIdentities.map((item) => item.id)}
hideActions={!!panelParams.panel}
/>
);
Expand Down Expand Up @@ -294,7 +307,9 @@ const PermissionIdentities: FC = () => {
selectedNames={selectedIdentityIds}
setSelectedNames={setSelectedIdentityIds}
processingNames={[]}
filteredNames={nonTlsUsers.map((identity) => identity.id)}
filteredNames={restrictedIdentities.map(
(identity) => identity.id,
)}
disableSelect={!!panelParams.panel}
/>
</TablePagination>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/permissions/actions/BulkDeleteIdentitiesBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
useNotify,
} from "@canonical/react-components";
import { LxdIdentity } from "types/permissions";
import { deleteOIDCIdentities } from "api/auth-identities";
import { deleteIdentities } from "api/auth-identities";
import { useQueryClient } from "@tanstack/react-query";
import { useToastNotification } from "context/toastNotificationProvider";
import { queryKeys } from "util/queryKeys";
Expand All @@ -27,7 +27,7 @@ const BulkDeleteIdentitiesBtn: FC<Props & ButtonProps> = ({
const successMessage = `${identities.length} ${pluralize("identity", identities.length)} successfully deleted`;

const handleDelete = () => {
deleteOIDCIdentities(identities)
deleteIdentities(identities)
.then(() => {
void queryClient.invalidateQueries({
predicate: (query) => {
Expand Down
11 changes: 7 additions & 4 deletions src/pages/permissions/actions/DeleteIdentityBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import { useToastNotification } from "context/toastNotificationProvider";
import { LxdIdentity } from "types/permissions";
import ItemName from "components/ItemName";
import { deleteOIDCIdentity } from "api/auth-identities";
import { deleteIdentity } from "api/auth-identities";
import ResourceLabel from "components/ResourceLabel";

interface Props {
Expand All @@ -20,9 +20,11 @@ const DeleteIdentityBtn: FC<Props> = ({ identity }) => {
const queryClient = useQueryClient();
const notify = useNotify();
const toastNotify = useToastNotification();
const identityIconType =
identity.authentication_method == "tls" ? "certificate" : "oidc-identity";

const handleDelete = () => {
deleteOIDCIdentity(identity)
deleteIdentity(identity)
.then(() => {
void queryClient.invalidateQueries({
predicate: (query) => {
Expand All @@ -33,7 +35,8 @@ const DeleteIdentityBtn: FC<Props> = ({ identity }) => {
});
toastNotify.success(
<>
Identity <ResourceLabel type={"idp-group"} value={identity.name} />{" "}
Identity{" "}
<ResourceLabel type={identityIconType} value={identity.name} />{" "}
deleted.
</>,
);
Expand All @@ -43,7 +46,7 @@ const DeleteIdentityBtn: FC<Props> = ({ identity }) => {
notify.failure(
`Identity deletion failed`,
e,
<ResourceLabel type={"idp-group"} value={identity.name} />,
<ResourceLabel type={identityIconType} value={identity.name} />,
);
});
};
Expand Down
8 changes: 4 additions & 4 deletions src/pages/permissions/panels/EditIdentitiesForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ const EditIdentitiesForm: FC<Props> = ({
notify.failure("Loading details failed", error);
}

const nonTlsIdentities = identities.filter(
(identity) => identity.authentication_method !== "tls",
const fineGrainedIdentities = identities.filter(
(identity) => identity.type !== "Client certificate (unrestricted)",
);

const toggleRow = (id: string) => {
Expand Down Expand Up @@ -104,7 +104,7 @@ const EditIdentitiesForm: FC<Props> = ({
},
];

const filteredIdentities = nonTlsIdentities.filter((identity) => {
const filteredIdentities = fineGrainedIdentities.filter((identity) => {
if (filter) {
return identity.name.toLowerCase().includes(filter.toLowerCase());
}
Expand Down Expand Up @@ -168,7 +168,7 @@ const EditIdentitiesForm: FC<Props> = ({
.map((identity) => identity.id)}
setSelectedNames={bulkSelect}
processingNames={[]}
filteredNames={nonTlsIdentities.map((identity) => identity.id)}
filteredNames={fineGrainedIdentities.map((identity) => identity.id)}
indeterminateNames={[]}
onToggleRow={toggleRow}
hideContextualMenu
Expand Down
4 changes: 2 additions & 2 deletions src/util/instanceBulkActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ export const pluralize = (item: string, count: number): string => {
return item;
}

if (item.includes("identity")) {
return item.replace("identity", "identities");
if (item.toLowerCase().includes("identity")) {
return item.toLowerCase().replace("identity", "identities");
}

return `${item}s`;
Expand Down

0 comments on commit 8ed4442

Please sign in to comment.