issue 19582 (#19749)

* fixed paginate subgroups + nav

* render matched sub groups and fix pagination when searching
This commit is contained in:
Erik Jan de Wit 2023-04-19 21:35:36 +02:00 committed by GitHub
parent 0ddc71d987
commit 3b65f1163d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -61,6 +61,8 @@ export const GroupPickerDialog = ({
const [max, setMax] = useState(10);
const [first, setFirst] = useState(0);
const [count, setCount] = useState(0);
const currentGroup = () => navigation[navigation.length - 1];
useFetch(
@ -68,13 +70,14 @@ export const GroupPickerDialog = ({
let group;
let groups;
let existingUserGroups;
let count = 0;
if (!groupId) {
groups = await adminClient.groups.find({
first,
max: max + 1,
max: max + (isSearching ? 0 : 1),
search: isSearching ? filter : "",
});
} else {
} else if (!navigation.map(({ id }) => id).includes(groupId)) {
group = await adminClient.groups.findOne({ id: groupId });
if (!group) {
throw new Error(t("common:notFound"));
@ -82,24 +85,32 @@ export const GroupPickerDialog = ({
groups = group.subGroups!;
}
if (isSearching) {
count = (await adminClient.groups.count({ search: filter, top: true }))
.count;
}
if (id) {
existingUserGroups = await adminClient.users.listGroups({
id,
});
}
return { group, groups, existingUserGroups };
return { group, groups, existingUserGroups, count };
},
async ({ group: selectedGroup, groups, existingUserGroups }) => {
async ({ group: selectedGroup, groups, existingUserGroups, count }) => {
setJoinedGroups(existingUserGroups || []);
if (selectedGroup) {
setNavigation([...navigation, selectedGroup]);
}
if (groups) {
groups.forEach((group: SelectableGroup) => {
group.checked = !!selectedRows.find((r) => r.id === group.id);
});
setGroups(groups);
}
setCount(count);
},
[groupId, filter, first, max]
);
@ -111,25 +122,6 @@ export const GroupPickerDialog = ({
].some((group) => group === row?.id);
};
const hasSubgroups = (group: GroupRepresentation) =>
group.subGroups?.length !== 0;
const expandGroup = (
group: GroupRepresentation,
name: string
): GroupRepresentation => {
if (group.name?.includes(name)) {
return group;
}
if (group.subGroups) {
for (const g of group.subGroups) {
const found = expandGroup(g, name);
return found;
}
}
return group;
};
return (
<Modal
variant={isSearching ? ModalVariant.medium : ModalVariant.small}
@ -161,7 +153,10 @@ export const GroupPickerDialog = ({
]}
>
<PaginatingTableToolbar
count={groups.length}
count={
(isSearching ? count : groups.length) -
(groupId || isSearching ? first : 0)
}
first={first}
max={max}
onNextClick={setFirst}
@ -189,6 +184,8 @@ export const GroupPickerDialog = ({
onClick={() => {
setGroupId(undefined);
setNavigation([]);
setFirst(0);
setMax(10);
}}
>
{t("groups")}
@ -203,6 +200,8 @@ export const GroupPickerDialog = ({
onClick={() => {
setGroupId(group.id);
setNavigation([...navigation].slice(0, i));
setFirst(0);
setMax(10);
}}
>
{group.name}
@ -213,7 +212,88 @@ export const GroupPickerDialog = ({
))}
</Breadcrumb>
<DataList aria-label={t("groups")} isCompact>
{groups.slice(0, max).map((group: SelectableGroup) => (
{groups
.slice(groupId ? first : 0, max + (groupId ? first : 0))
.map((group: SelectableGroup) => (
<>
<GroupRow
key={group.id}
group={group}
isRowDisabled={isRowDisabled}
onSelect={setGroupId}
type={type}
isSearching={isSearching}
setIsSearching={setIsSearching}
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
canBrowse={canBrowse}
/>
{isSearching &&
group.subGroups?.length !== 0 &&
group.subGroups!.map((g) => (
<GroupRow
key={g.id}
group={g}
isRowDisabled={isRowDisabled}
onSelect={setGroupId}
type={type}
isSearching={isSearching}
setIsSearching={setIsSearching}
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
canBrowse={canBrowse}
/>
))}
</>
))}
</DataList>
{groups.length === 0 && !isSearching && (
<ListEmptyState
hasIcon={false}
message={t("groups:moveGroupEmpty")}
instructions={t("groups:moveGroupEmptyInstructions")}
/>
)}
{groups.length === 0 && isSearching && (
<ListEmptyState
message={t("common:noSearchResults")}
instructions={t("common:noSearchResultsInstructions")}
/>
)}
</PaginatingTableToolbar>
</Modal>
);
};
type GroupRowProps = {
group: SelectableGroup;
type: "selectOne" | "selectMany";
isRowDisabled: (row?: GroupRepresentation) => boolean;
isSearching: boolean;
setIsSearching: (value: boolean) => void;
onSelect: (groupId: string) => void;
selectedRows: SelectableGroup[];
setSelectedRows: (groups: SelectableGroup[]) => void;
canBrowse: boolean;
};
const GroupRow = ({
group,
type,
isRowDisabled,
isSearching,
setIsSearching,
onSelect,
selectedRows,
setSelectedRows,
canBrowse,
}: GroupRowProps) => {
const { t } = useTranslation();
const hasSubgroups = (group: GroupRepresentation) =>
group.subGroups?.length !== 0;
return (
<DataListItem
className={`join-group-dialog-row-${
isRowDisabled(group) ? "disabled" : ""
@ -222,17 +302,14 @@ export const GroupPickerDialog = ({
key={group.id}
id={group.id}
onClick={(e) => {
const g = isSearching ? expandGroup(group, filter) : group;
if (isRowDisabled(g)) return;
if (isRowDisabled(group)) return;
if (type === "selectOne") {
setGroupId(g.id);
onSelect(group.id!);
} else if (
hasSubgroups(group) &&
(e.target as HTMLInputElement).type !== "checkbox"
) {
setGroupId(
isSearching ? expandGroup(group, filter).id : group.id
);
onSelect(group.id!);
setIsSearching(false);
}
}}
@ -254,14 +331,9 @@ export const GroupPickerDialog = ({
group.checked = checked;
let newSelectedRows: SelectableGroup[] = [];
if (!group.checked) {
newSelectedRows = selectedRows.filter(
(r) => r.id !== group.id
);
newSelectedRows = selectedRows.filter((r) => r.id !== group.id);
} else {
newSelectedRows = [
...selectedRows,
isSearching ? expandGroup(group, filter) : group,
];
newSelectedRows = [...selectedRows, group];
}
setSelectedRows(newSelectedRows);
@ -277,10 +349,7 @@ export const GroupPickerDialog = ({
className="keycloak-groups-group-path"
>
{isSearching ? (
<GroupPath
id={`select-${group.name}`}
group={expandGroup(group, filter)}
/>
<GroupPath id={`select-${group.name}`} group={group} />
) : (
<span id={`select-${group.name}`}>{group.name}</span>
)}
@ -293,35 +362,13 @@ export const GroupPickerDialog = ({
aria-label={t("groupName")}
isPlainButtonAction
>
{((hasSubgroups(group) && canBrowse) ||
type === "selectOne") && (
<Button
isDisabled
variant="link"
aria-label={t("common:select")}
>
{((hasSubgroups(group) && canBrowse) || type === "selectOne") && (
<Button isDisabled variant="link" aria-label={t("common:select")}>
<AngleRightIcon />
</Button>
)}
</DataListAction>
</DataListItemRow>
</DataListItem>
))}
</DataList>
{groups.length === 0 && !isSearching && (
<ListEmptyState
hasIcon={false}
message={t("groups:moveGroupEmpty")}
instructions={t("groups:moveGroupEmptyInstructions")}
/>
)}
{groups.length === 0 && isSearching && (
<ListEmptyState
message={t("common:noSearchResults")}
instructions={t("common:noSearchResultsInstructions")}
/>
)}
</PaginatingTableToolbar>
</Modal>
);
};