From a339e79d3ecbd35c12abd3c67717fc5ea466b415 Mon Sep 17 00:00:00 2001 From: Erik Jan de Wit Date: Thu, 3 Oct 2024 09:03:14 +0200 Subject: [PATCH] added exact search option to attributes Signed-off-by: Erik Jan de Wit --- .../src/components/users/UserDataTable.tsx | 49 +++++++++------ .../UserDataTableAttributeSearchForm.tsx | 59 +++++++++++++------ .../users/UserDataTableToolbarItems.tsx | 18 +++--- 3 files changed, 81 insertions(+), 45 deletions(-) diff --git a/js/apps/admin-ui/src/components/users/UserDataTable.tsx b/js/apps/admin-ui/src/components/users/UserDataTable.tsx index 2fc34489cc9..aa3f62477a6 100644 --- a/js/apps/admin-ui/src/components/users/UserDataTable.tsx +++ b/js/apps/admin-ui/src/components/users/UserDataTable.tsx @@ -33,6 +33,8 @@ import { useState } from "react"; import { useTranslation } from "react-i18next"; import { Link, useNavigate } from "react-router-dom"; import { useAdminClient } from "../../admin-client"; +import { fetchRealmInfo } from "../../context/auth/admin-ui-endpoint"; +import { UiRealmInfo } from "../../context/auth/uiRealmInfo"; import { useRealm } from "../../context/realm-context/RealmContext"; import { SearchType } from "../../user/details/SearchFilter"; import { toAddUser } from "../../user/routes/AddUser"; @@ -41,8 +43,11 @@ import { emptyFormatter } from "../../util"; import { useConfirmDialog } from "../confirm-dialog/ConfirmDialog"; import { BruteUser, findUsers } from "../role-mapping/resource"; import { UserDataTableToolbarItems } from "./UserDataTableToolbarItems"; -import { UiRealmInfo } from "../../context/auth/uiRealmInfo"; -import { fetchRealmInfo } from "../../context/auth/admin-ui-endpoint"; + +export type UserFilter = { + exact: boolean; + userAttribute: UserAttribute[]; +}; export type UserAttribute = { name: string; @@ -119,7 +124,10 @@ export function UserDataTable() { const [selectedRows, setSelectedRows] = useState([]); const [searchType, setSearchType] = useState("default"); const [searchDropdownOpen, setSearchDropdownOpen] = useState(false); - const [activeFilters, setActiveFilters] = useState([]); + const [activeFilters, setActiveFilters] = useState({ + exact: false, + userAttribute: [], + }); const [profile, setProfile] = useState({}); const [query, setQuery] = useState(""); @@ -145,10 +153,11 @@ export function UserDataTable() { ); const loader = async (first?: number, max?: number, search?: string) => { - const params: { [name: string]: string | number } = { + const params: { [name: string]: string | number | boolean } = { first: first!, max: max!, q: query!, + exact: activeFilters.exact, }; const searchParam = search || searchUser || ""; @@ -219,17 +228,16 @@ export function UserDataTable() { const listUsers = !uiRealmInfo.userProfileProvidersEnabled; const clearAllFilters = () => { - const filtered = [...activeFilters].filter( - (chip) => chip.name !== chip.name, - ); - setActiveFilters(filtered); + setActiveFilters({ exact: false, userAttribute: [] }); setSearchUser(""); setQuery(""); refresh(); }; - const createQueryString = (filters: UserAttribute[]) => { - return filters.map((filter) => `${filter.name}:${filter.value}`).join(" "); + const createQueryString = (filters: UserFilter) => { + return filters.userAttribute + .map((filter) => `${filter.name}:${filter.value}`) + .join(" "); }; const searchUserWithAttributes = () => { @@ -241,9 +249,9 @@ export function UserDataTable() { const createAttributeSearchChips = () => { return ( - {activeFilters.length > 0 && ( + {activeFilters.userAttribute.length > 0 && ( <> - {Object.values(activeFilters).map((entry) => { + {Object.values(activeFilters.userAttribute).map((entry) => { return ( { event.stopPropagation(); - const filtered = [...activeFilters].filter( + const filtered = [...activeFilters.userAttribute].filter( (chip) => chip.name !== entry.name, ); - const attributes = createQueryString(filtered); + const active = { + userAttribute: filtered, + exact: activeFilters.exact, + }; - setActiveFilters(filtered); - setQuery(attributes); + setActiveFilters(active); + setQuery(createQueryString(active)); refresh(); }} > @@ -304,7 +315,7 @@ export function UserDataTable() { }; const subtoolbar = () => { - if (!activeFilters.length) { + if (!activeFilters.userAttribute.length) { return; } return ( @@ -329,7 +340,9 @@ export function UserDataTable() { void; + activeFilters: UserFilter; + setActiveFilters: (filters: UserFilter) => void; profile: UserProfileConfig; createAttributeSearchChips: () => ReactNode; searchUserWithAttributes: () => void; }; +type UserFilterForm = UserAttribute & { exact: boolean }; + export function UserDataTableAttributeSearchForm({ activeFilters, setActiveFilters, @@ -59,13 +62,16 @@ export function UserDataTableAttributeSearchForm({ setValue, setError, clearErrors, - } = useForm({ + control, + } = useForm({ mode: "onChange", defaultValues, }); const isAttributeKeyDuplicate = () => { - return activeFilters.some((filter) => filter.name === getValues().name); + return activeFilters.userAttribute.some( + (filter) => filter.name === getValues().name, + ); }; const isAttributeNameValid = () => { @@ -76,7 +82,9 @@ export function UserDataTableAttributeSearchForm({ message: t("searchUserByAttributeMissingKeyError"), }); } else if ( - activeFilters.some((filter) => filter.name === getValues().name) + activeFilters.userAttribute.some( + (filter) => filter.name === getValues().name, + ) ) { setError("name", { type: "conflict", @@ -106,13 +114,11 @@ export function UserDataTableAttributeSearchForm({ const addToFilter = () => { if (isAttributeValid()) { - setActiveFilters([ - ...activeFilters, - { - ...getValues(), - }, - ]); - reset(); + setActiveFilters({ + exact: getValues().exact, + userAttribute: [...activeFilters.userAttribute, { ...getValues() }], + }); + reset({ exact: getValues().exact }); } else { if (errors.name?.message) { addAlert(errors.name.message, AlertVariant.danger); @@ -125,10 +131,10 @@ export function UserDataTableAttributeSearchForm({ }; const clearActiveFilters = () => { - const filtered = [...activeFilters].filter( + const filtered = [...activeFilters.userAttribute].filter( (chip) => chip.name !== chip.name, ); - setActiveFilters(filtered); + setActiveFilters({ exact: getValues().exact, userAttribute: filtered }); }; const createAttributeKeyInputField = () => { @@ -244,12 +250,29 @@ export function UserDataTableAttributeSearchForm({ {createAttributeSearchChips()} + +
+ ( + + )} + /> +