From d6f59a1ecb73b5a7d53bca5e10804c9547b3f086 Mon Sep 17 00:00:00 2001 From: Carla Martinez Date: Tue, 21 Nov 2023 15:27:51 +0100 Subject: [PATCH] Add 'Delete' option The 'Delete' option allows to remove a given user from its 'Settings' page. The solution has been adapted to the three user pages (Active, Stage, and Preserved). Signed-off-by: Carla Martinez --- src/components/UserSettings.tsx | 44 +++++++++++++- src/components/modals/DeleteUsers.tsx | 50 ++++++++-------- src/components/tables/UsersDisplayTable.tsx | 64 ++++++++++++--------- src/utils/ipaObjectUtils.ts | 18 +++--- 4 files changed, 113 insertions(+), 63 deletions(-) diff --git a/src/components/UserSettings.tsx b/src/components/UserSettings.tsx index 5e6d4a69..8fab032f 100644 --- a/src/components/UserSettings.tsx +++ b/src/components/UserSettings.tsx @@ -49,6 +49,7 @@ import { import useAlerts from "src/hooks/useAlerts"; // Modals import DisableEnableUsers from "./modals/DisableEnableUsers"; +import DeleteUsers from "./modals/DeleteUsers"; export interface PropsToUserSettings { originalUser: Partial; @@ -115,10 +116,16 @@ const UserSettings = (props: PropsToUserSettings) => { setIsDisableEnableModalOpen(false); }; + // 'Delete' modal + const [isDeleteModalOpen, setIsDeleteModalOpen] = React.useState(false); + const onCloseDeleteModal = () => { + setIsDeleteModalOpen(false); + }; + // Kebab const [isKebabOpen, setIsKebabOpen] = useState(false); - const dropdownItems = [ + const activeDropdownItems = [ Reset password, { > Disable , - Delete, + setIsDeleteModalOpen(true)}> + Delete + , Unlock , @@ -145,6 +154,21 @@ const UserSettings = (props: PropsToUserSettings) => { New certificate, ]; + const stageDropdownItems = [ + Activate, + setIsDeleteModalOpen(true)}> + Delete + , + ]; + + const preservedDropdownItems = [ + Stage, + Restore, + setIsDeleteModalOpen(true)}> + Delete + , + ]; + const onKebabToggle = (isOpen: boolean) => { setIsKebabOpen(isOpen); }; @@ -224,7 +248,13 @@ const UserSettings = (props: PropsToUserSettings) => { idKebab="toggle-action-buttons" isKebabOpen={isKebabOpen} isPlain={true} - dropdownItems={dropdownItems} + dropdownItems={ + props.from === "active-users" + ? activeDropdownItems + : props.from === "stage-users" + ? stageDropdownItems + : preservedDropdownItems + } /> ), }, @@ -395,6 +425,14 @@ const UserSettings = (props: PropsToUserSettings) => { singleUser={true} onRefresh={props.onRefresh} /> + ); }; diff --git a/src/components/modals/DeleteUsers.tsx b/src/components/modals/DeleteUsers.tsx index 62c67d63..06486e7e 100644 --- a/src/components/modals/DeleteUsers.tsx +++ b/src/components/modals/DeleteUsers.tsx @@ -30,6 +30,9 @@ import ErrorModal from "./ErrorModal"; import { ErrorData } from "src/utils/datatypes/globalDataTypes"; // Hooks import useAlerts from "src/hooks/useAlerts"; +// Routing +import { useNavigate } from "react-router-dom"; +import { URL_PREFIX } from "src/navigation/NavRoutes"; interface ButtonsData { updateIsDeleteButtonDisabled?: (value: boolean) => void; @@ -46,25 +49,20 @@ export interface PropsToDeleteUsers { from: "active-users" | "stage-users" | "preserved-users"; handleModalToggle: () => void; selectedUsersData: SelectedUsersData; - buttonsData: ButtonsData; - // NOTE: 'onRefresh' is handled as { (User) => void | undefined } as a temporal solution - // until the C.L. is adapted in 'stage-' and 'preserved users' (otherwise - // the operation will fail for those components) - onRefresh?: () => void; - // NOTE: 'onOpenAddModal' is handled as { () => void | undefined } as a temporal solution - // until the C.L. is adapted in 'stage-' and 'preserved users' (otherwise - // the operation will fail for those components) + buttonsData?: ButtonsData; + onRefresh: () => void; onOpenDeleteModal?: () => void; - // NOTE: 'onCloseAddModal' is handled as { () => void | undefined } as a temporal solution - // until the C.L. is adapted in 'stage-' and 'preserved users' (otherwise - // the operation will fail for those components) onCloseDeleteModal?: () => void; + fromSettings?: boolean | false; } const DeleteUsers = (props: PropsToDeleteUsers) => { // Set dispatch (Redux) const dispatch = useAppDispatch(); + // Redirect + const navigate = useNavigate(); + // Alerts const alerts = useAlerts(); @@ -248,18 +246,18 @@ const DeleteUsers = (props: PropsToDeleteUsers) => { props.selectedUsersData.updateSelectedUsers([]); // Disable 'Delete' button - if ( - props.from === "active-users" && - props.buttonsData.updateIsDeleteButtonDisabled !== undefined - ) { - props.buttonsData.updateIsDeleteButtonDisabled(true); + if (props.buttonsData !== undefined) { + if ( + props.from === "active-users" && + props.buttonsData.updateIsDeleteButtonDisabled !== undefined + ) { + props.buttonsData.updateIsDeleteButtonDisabled(true); + } + props.buttonsData.updateIsDeletion(true); } - props.buttonsData.updateIsDeletion(true); // Refresh data - if (props.onRefresh !== undefined) { - props.onRefresh(); - } + props.onRefresh(); // Show alert: success if (isDeleteChecked) { @@ -275,7 +273,9 @@ const DeleteUsers = (props: PropsToDeleteUsers) => { "success" ); } - + // Redirect to main page + navigate(URL_PREFIX + "/active-users"); + // Close modal closeModal(); } } else if (error) { @@ -295,7 +295,7 @@ const DeleteUsers = (props: PropsToDeleteUsers) => { onClick={() => { deleteUsers(props.selectedUsersData.selectedUsers); }} - form="active-users-remove-users-modal" + form="remove-users-modal" spinnerAriaValueText="Deleting" spinnerAriaLabel="Deleting" isLoading={spinning} @@ -325,7 +325,7 @@ const DeleteUsers = (props: PropsToDeleteUsers) => { modalPosition="top" offPosition="76px" title={title} - formId="active-users-remove-users-modal" + formId="remove-users-modal" fields={fields} show={props.show} onClose={closeModal} @@ -341,7 +341,7 @@ const DeleteUsers = (props: PropsToDeleteUsers) => { onClick={() => { deleteUsers(props.selectedUsersData.selectedUsers); }} - form="active-users-remove-users-modal" + form="remove-users-modal" spinnerAriaValueText="Preserving" spinnerAriaLabel="Preserving" isLoading={spinning} @@ -360,7 +360,7 @@ const DeleteUsers = (props: PropsToDeleteUsers) => { modalPosition="top" offPosition="76px" title={title} - formId="active-users-remove-users-modal" + formId="remove-users-modal" fields={fields} show={props.show} onClose={closeModal} diff --git a/src/components/tables/UsersDisplayTable.tsx b/src/components/tables/UsersDisplayTable.tsx index 926c3776..51d3ae07 100644 --- a/src/components/tables/UsersDisplayTable.tsx +++ b/src/components/tables/UsersDisplayTable.tsx @@ -33,35 +33,45 @@ const UsersDisplayTable = (props: PropsToDisplayUsersTable) => { // Given userIds, retrieve full user info to display into table const usersToDisplay: User[] = []; - switch (props.from) { - case "active-users": - activeUsersListCopy.map((user) => { - props.usersToDisplay.map((selected) => { - if (user.uid[0] === selected[0]) { - usersToDisplay.push(user); - } + const [usersToDisplayList, setUsersToDisplayList] = React.useState( + [] + ); + + // Given its `uids`, get full user info to display + React.useEffect(() => { + switch (props.from) { + case "active-users": + activeUsersListCopy.map((user) => { + props.usersToDisplay.map((selected) => { + if (user.uid[0] === selected[0] || user.uid[0] === selected) { + usersToDisplay.push(user); + } + }); }); - }); - break; - case "stage-users": - stageUsersListCopy.map((user) => { - props.usersToDisplay.map((selected) => { - if (user.uid === selected) { - usersToDisplay.push(user); - } + setUsersToDisplayList(usersToDisplay); + break; + case "stage-users": + stageUsersListCopy.map((user) => { + props.usersToDisplay.map((selected) => { + if (user.uid === selected || user.uid[0] === selected) { + usersToDisplay.push(user); + } + }); }); - }); - break; - case "preserved-users": - preservedUsersListCopy.map((user) => { - props.usersToDisplay.map((selected) => { - if (user.uid === selected) { - usersToDisplay.push(user); - } + setUsersToDisplayList(usersToDisplay); + break; + case "preserved-users": + preservedUsersListCopy.map((user) => { + props.usersToDisplay.map((selected) => { + if (user.uid === selected || user.uid[0] === selected) { + usersToDisplay.push(user); + } + }); }); - }); - break; - } + setUsersToDisplayList(usersToDisplay); + break; + } + }, [props.usersToDisplay]); // Define column names const columnNames = { @@ -83,7 +93,7 @@ const UsersDisplayTable = (props: PropsToDisplayUsersTable) => { ); - const body = usersToDisplay.map((user) => ( + const body = usersToDisplayList.map((user) => ( {user.uid} {user.givenname} diff --git a/src/utils/ipaObjectUtils.ts b/src/utils/ipaObjectUtils.ts index 8a81d4ba..6f5ec989 100644 --- a/src/utils/ipaObjectUtils.ts +++ b/src/utils/ipaObjectUtils.ts @@ -174,14 +174,16 @@ export function convertApiObj( dateValues: Set ) { const obj = {}; - for (const [key, value] of Object.entries(apiRecord)) { - if (simpleValues.has(key)) { - obj[key] = convertToString(value as BasicType); - } else if (dateValues.has(key)) { - // TODO convert to Datetime object - obj[key] = value; - } else { - obj[key] = value; + if (apiRecord !== undefined) { + for (const [key, value] of Object.entries(apiRecord)) { + if (simpleValues.has(key)) { + obj[key] = convertToString(value as BasicType); + } else if (dateValues.has(key)) { + // TODO convert to Datetime object + obj[key] = value; + } else { + obj[key] = value; + } } } return obj;