diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e3c8105..2a8a28db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [0.14.0] + +- Fixes an issue where the delete button (for login methods) would be visible when there is only one login method +- Modifies Modal message when deleting a login method +- Fixes search issues on User Management tab +- Fixes search issues on Tenant Management tab + ## [0.13.0] - Adds support for SAML metadata diff --git a/src/ui/components/search/index.tsx b/src/ui/components/search/index.tsx index 7141786f..65d6309b 100644 --- a/src/ui/components/search/index.tsx +++ b/src/ui/components/search/index.tsx @@ -37,6 +37,7 @@ type SearchType = { type searchProp = { onSearch: (paginationToken?: string, search?: object) => Promise; loading: boolean; + searchRef?: React.RefObject<{ getSearchQuery: () => Record }>; }; type action = "chn" | "del"; @@ -67,6 +68,40 @@ const tagToImg = (tag: string) => { } }; +const generateSearchQuery = (searches: SearchType[]) => { + const tempQueryMap: Record = {}; + searches.forEach((el) => { + let value = el.value.trim(); + + if (el.tag === "phone") { + try { + const parsed = parsePhoneNumber(value); + + if (parsed !== undefined) { + value = parsed.format("E.164"); + } + } catch (e) { + let temp = value; + + if (!temp.startsWith("+")) { + temp = "+" + temp; + } + + temp = temp.replace(/[()\s]/g, ""); + value = temp; + } + } + + if (el.tag in tempQueryMap) { + const temp = tempQueryMap[el.tag] + ";" + value; + tempQueryMap[el.tag] = temp; + } else { + tempQueryMap[el.tag] = value; + } + }); + return tempQueryMap; +}; + const Search: React.FC = (props: searchProp) => { const [active, setActive] = useState(false); const [searches, setSearches] = useState([]); @@ -92,42 +127,20 @@ const Search: React.FC = (props: searchProp) => { if (props.loading) { return; } - - const tempQueryMap: Record = {}; - searches.forEach((el) => { - let value = el.value.trim(); - - if (el.tag === "phone") { - try { - const parsed = parsePhoneNumber(value); - - if (parsed !== undefined) { - value = parsed.format("E.164"); - } - } catch (e) { - let temp = value; - - if (!temp.startsWith("+")) { - temp = "+" + temp; - } - - temp = temp.replace(/[()\s]/g, ""); - value = temp; - } - } - - if (el.tag in tempQueryMap) { - const temp = tempQueryMap[el.tag] + ";" + value; - tempQueryMap[el.tag] = temp; - } else { - tempQueryMap[el.tag] = value; - } - }); + const tempQueryMap = generateSearchQuery(searches); await props.onSearch(undefined, tempQueryMap); }, [searches] ); + useEffect(() => { + if (props.searchRef) { + props.searchRef.current = { + getSearchQuery: () => generateSearchQuery(searches), + }; + } + }, [props.searchRef, searches]); + // useEffect to call everytime searches change useEffect(() => { getSearchResult(searches).catch(console.error); diff --git a/src/ui/components/userDetail/loginMethods/LoginMethods.tsx b/src/ui/components/userDetail/loginMethods/LoginMethods.tsx index 281df337..e14b7f46 100644 --- a/src/ui/components/userDetail/loginMethods/LoginMethods.tsx +++ b/src/ui/components/userDetail/loginMethods/LoginMethods.tsx @@ -134,6 +134,7 @@ type MethodProps = { updateContext: (val: LoginMethod, ind: number) => void; index: number; showUnlink: boolean; + showDelete: boolean; }; const Methods: React.FC = ({ @@ -146,6 +147,7 @@ const Methods: React.FC = ({ updateContext, index, showUnlink, + showDelete, }) => { const { sendUserEmailVerification: sendUserEmailVerificationApi } = useVerifyUserTokenService(); const { showModal, showToast } = useContext(PopupContentContext); @@ -252,6 +254,7 @@ const Methods: React.FC = ({ onDelete={onDeleteCallback} onUnlink={onUnlinkCallback} showUnlink={showUnlink} + showDelete={showDelete} /> )} {isEditing && ( @@ -462,6 +465,7 @@ export const LoginMethods: React.FC = ({ refetchAllData, refet showUnlink={ methods.length > 1 || (userDetail.details.isPrimaryUser === true && methods.length === 1) } + showDelete={methods.length > 1} /> ))} diff --git a/src/ui/components/userDetail/loginMethods/components/dropDown.tsx b/src/ui/components/userDetail/loginMethods/components/dropDown.tsx index 39327ee7..3ef1d9d1 100644 --- a/src/ui/components/userDetail/loginMethods/components/dropDown.tsx +++ b/src/ui/components/userDetail/loginMethods/components/dropDown.tsx @@ -7,9 +7,10 @@ type DropDOwnProps = { onUnlink: () => void | null; onDelete: () => void | null; showUnlink: boolean; + showDelete: boolean; }; -export const DropDown = ({ onEdit, onUnlink, onDelete, showUnlink }: DropDOwnProps) => { +export const DropDown = ({ onEdit, onUnlink, onDelete, showUnlink, showDelete }: DropDOwnProps) => { const [open, setOpen] = useState(false); const [hover, setHover] = useState(false); const ref = useRef(null); @@ -47,13 +48,15 @@ export const DropDown = ({ onEdit, onUnlink, onDelete, showUnlink }: DropDOwnPro Unlink )} -
close(onDelete)}> - {" "} - Delete -
+ {showDelete && ( +
close(onDelete)}> + {" "} + Delete +
+ )} ); diff --git a/src/ui/components/userDetail/userDetailForm.tsx b/src/ui/components/userDetail/userDetailForm.tsx index 0068ec12..c6262fe3 100644 --- a/src/ui/components/userDetail/userDetailForm.tsx +++ b/src/ui/components/userDetail/userDetailForm.tsx @@ -513,10 +513,11 @@ export const UserDeleteConfirmation: FC = ({ user, return (

- To delete the user, please confirm by typing the {inputType}: {informationToEnter} below + To delete the {loginMethod ? "login method" : "user"}, please confirm by typing the {inputType}:{" "} + {informationToEnter} below

{""}

-

This will also delete any accounts linked to this user

+ {!loginMethod &&

This will also delete any accounts linked to this user

}
), - header:

Delete User?

, + header:

Delete {loginMethod ? "login method" : "user"}?

, closeCallbackRef: closeConfirmDeleteRef, } as LayoutModalProps; }; diff --git a/src/ui/pages/tenants/index.tsx b/src/ui/pages/tenants/index.tsx index 60bed65b..dcac4379 100644 --- a/src/ui/pages/tenants/index.tsx +++ b/src/ui/pages/tenants/index.tsx @@ -72,6 +72,11 @@ const TenantList = ({ void getTenants(); }, []); + useEffect(() => { + // When user changes the search query, we reset the pagination to the first page + setCurrentActivePage(1); + }, [searchQuery]); + return (

Tenant Management

diff --git a/src/ui/pages/usersList/UsersList.tsx b/src/ui/pages/usersList/UsersList.tsx index 8131e121..9eb879ad 100644 --- a/src/ui/pages/usersList/UsersList.tsx +++ b/src/ui/pages/usersList/UsersList.tsx @@ -80,6 +80,7 @@ export const UsersList: React.FC = ({ const [isSearch, setIsSearch] = useState(false); const [showCreateUserDialog, setShowCreateUserDialog] = useState(false); const [paginationTokenByOffset, setPaginationTokenByOffset] = useState({}); + const searchRef = useRef<{ getSearchQuery: () => Record }>(null); const { fetchUsers } = useFetchUsersService(); const { fetchCount } = useFetchCount(); @@ -215,7 +216,11 @@ export const UsersList: React.FC = ({ const loadCount = async () => { setLoading(true); const tenantId = getSelectedTenant(); - const [countResult] = await Promise.all([fetchCount(tenantId).catch(() => undefined), loadUsers()]); + const searchQueryMap = searchRef?.current?.getSearchQuery(); + const [countResult] = await Promise.all([ + fetchCount(tenantId).catch(() => undefined), + loadUsers(undefined, searchQueryMap), + ]); if (countResult) { setCount(countResult.count); } @@ -295,6 +300,7 @@ export const UsersList: React.FC = ({ )}