Fix roles pagination+filter out duplicates from associated roles list (#460)
* realm roles UX review progress wip * filter realm roles on Enter key press, add filter functionality * clean up * filterChips logic now in table toolbar * fix lint and format * save with erik * remove filter chips functionality * fix check-types * fix realm roles cypress test * format * wip pagination * rebase * fix roles pagination * format * add back save * remove duplicates in associated roles table, can now paginate modal * remove logs * PR feedback from Erik * rebase and fix pagination/search * remove slice * pagination in modal and associated roles tab * show client roles * lint and format * remove unused variable * address tbody console warning, clean up log stmts * clean up log stmts * fix ts error in AliasRenderer * fix lint * lint * PR feedback from Erik * resolve conflicts and format * comment
This commit is contained in:
parent
c503663e4e
commit
a0faba0f97
7 changed files with 48 additions and 37 deletions
|
@ -159,17 +159,21 @@ export const AttributesForm = ({
|
|||
)}
|
||||
</Tr>
|
||||
))}
|
||||
<Button
|
||||
aria-label={t("roles:addAttributeText")}
|
||||
id="plus-icon"
|
||||
variant="link"
|
||||
className="kc-attributes__plus-icon"
|
||||
onClick={() => append({ key: "", value: "" })}
|
||||
icon={<PlusCircleIcon />}
|
||||
isDisabled={!watchLast}
|
||||
>
|
||||
{t("roles:addAttributeText")}
|
||||
</Button>
|
||||
<Tr>
|
||||
<Td>
|
||||
<Button
|
||||
aria-label={t("roles:addAttributeText")}
|
||||
id="plus-icon"
|
||||
variant="link"
|
||||
className="kc-attributes__plus-icon"
|
||||
onClick={() => append({ key: "", value: "" })}
|
||||
icon={<PlusCircleIcon />}
|
||||
isDisabled={!watchLast}
|
||||
>
|
||||
{t("roles:addAttributeText")}
|
||||
</Button>
|
||||
</Td>
|
||||
</Tr>
|
||||
</Tbody>
|
||||
</TableComposable>
|
||||
<ActionGroup className="kc-attributes__action-group">
|
||||
|
|
|
@ -16,7 +16,6 @@ import { Spinner } from "@patternfly/react-core";
|
|||
import _ from "lodash";
|
||||
|
||||
import { PaginatingTableToolbar } from "./PaginatingTableToolbar";
|
||||
import { TableToolbar } from "./TableToolbar";
|
||||
import { asyncStateFetch } from "../../context/auth/AdminClient";
|
||||
import { ListEmptyState } from "../list-empty-state/ListEmptyState";
|
||||
|
||||
|
@ -56,11 +55,7 @@ function DataTable<T>({
|
|||
}
|
||||
canSelectAll={canSelectAll}
|
||||
cells={columns.map((column) => {
|
||||
return {
|
||||
...column,
|
||||
title: t(column.displayKey || column.name),
|
||||
transforms: column.transforms,
|
||||
};
|
||||
return { ...column, title: t(column.displayKey || column.name) };
|
||||
})}
|
||||
rows={rows}
|
||||
actions={actions}
|
||||
|
|
|
@ -20,9 +20,11 @@ export const AliasRendererComponent = ({
|
|||
const [containerName, setContainerName] = useState<string>("");
|
||||
|
||||
useEffect(() => {
|
||||
adminClient.clients
|
||||
.findOne({ id: containerId! })
|
||||
.then((client) => setContainerName(client.clientId! as string));
|
||||
if (filterType === "clients") {
|
||||
adminClient.clients
|
||||
.findOne({ id: containerId! })
|
||||
.then((client) => setContainerName(client.clientId! as string));
|
||||
}
|
||||
}, [containerId]);
|
||||
|
||||
if (filterType === "roles" || !containerName) {
|
||||
|
|
|
@ -44,14 +44,20 @@ export const AssociatedRolesModal = (props: AssociatedRolesModalProps) => {
|
|||
};
|
||||
|
||||
const loader = async () => {
|
||||
const allRoles = await adminClient.roles.find();
|
||||
const roles = await adminClient.roles.find();
|
||||
const existingAdditionalRoles = await adminClient.roles.getCompositeRoles({
|
||||
id,
|
||||
});
|
||||
const allRoles = [...roles, ...existingAdditionalRoles];
|
||||
|
||||
return alphabetize(allRoles).filter((role: RoleRepresentation) => {
|
||||
const filterDupes = allRoles.filter(
|
||||
(thing, index, self) =>
|
||||
index === self.findIndex((t) => t.name === thing.name)
|
||||
);
|
||||
|
||||
return alphabetize(filterDupes).filter((role: RoleRepresentation) => {
|
||||
return (
|
||||
existingAdditionalRoles.find(
|
||||
props.existingCompositeRoles.find(
|
||||
(existing: RoleRepresentation) => existing.name === role.name
|
||||
) === undefined && role.name !== name
|
||||
);
|
||||
|
|
|
@ -22,7 +22,6 @@ import { RoleFormType } from "./RealmRoleTabs";
|
|||
import ClientRepresentation from "keycloak-admin/lib/defs/clientRepresentation";
|
||||
import { AliasRendererComponent } from "./AliasRendererComponent";
|
||||
import _ from "lodash";
|
||||
import { cellWidth } from "@patternfly/react-table";
|
||||
|
||||
type AssociatedRolesTabProps = {
|
||||
additionalRoles: RoleRepresentation[];
|
||||
|
@ -47,6 +46,7 @@ export const AssociatedRolesTab = ({
|
|||
|
||||
const [selectedRows, setSelectedRows] = useState<RoleRepresentation[]>([]);
|
||||
const [isInheritedHidden, setIsInheritedHidden] = useState(false);
|
||||
const [allRoles, setAllRoles] = useState<RoleRepresentation[]>([]);
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
|
@ -85,12 +85,12 @@ export const AssociatedRolesTab = ({
|
|||
return newRoles;
|
||||
};
|
||||
|
||||
const alphabetize = (rolesList: RoleRepresentation[]) => {
|
||||
return _.sortBy(rolesList, (role) => role.name?.toUpperCase());
|
||||
};
|
||||
|
||||
const loader = async () => {
|
||||
const alphabetize = (rolesList: RoleRepresentation[]) => {
|
||||
return _.sortBy(rolesList, (role) => role.name?.toUpperCase());
|
||||
};
|
||||
if (isInheritedHidden) {
|
||||
setAllRoles(additionalRoles);
|
||||
return alphabetize(additionalRoles);
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,13 @@ export const AssociatedRolesTab = ({
|
|||
);
|
||||
|
||||
return fetchedRoles.then((results: RoleRepresentation[]) => {
|
||||
return alphabetize(results);
|
||||
const filterDupes = results.filter(
|
||||
(thing, index, self) =>
|
||||
index === self.findIndex((t) => t.name === thing.name)
|
||||
);
|
||||
setAllRoles(filterDupes);
|
||||
|
||||
return alphabetize(filterDupes);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -136,11 +142,12 @@ export const AssociatedRolesTab = ({
|
|||
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
|
||||
titleKey: "roles:roleRemoveAssociatedRoleConfirm",
|
||||
messageKey: t("roles:roleRemoveAssociatedText"),
|
||||
continueButtonLabel: t("common:remove"),
|
||||
continueButtonLabel: "common:delete",
|
||||
continueButtonVariant: ButtonVariant.danger,
|
||||
onConfirm: async () => {
|
||||
try {
|
||||
await adminClient.roles.delCompositeRoles({ id }, selectedRows);
|
||||
onRemove(selectedRows);
|
||||
setSelectedRows([]);
|
||||
|
||||
addAlert(t("associatedRolesRemoved"), AlertVariant.success);
|
||||
|
@ -158,11 +165,11 @@ export const AssociatedRolesTab = ({
|
|||
messageKey: t("roles:removeAllAssociatedRolesConfirmDialog", {
|
||||
name: parentRole?.name || t("createRole"),
|
||||
}),
|
||||
continueButtonLabel: "common:remove",
|
||||
continueButtonLabel: "common:delete",
|
||||
continueButtonVariant: ButtonVariant.danger,
|
||||
onConfirm: async () => {
|
||||
try {
|
||||
if (selectedRows.length === additionalRoles.length) {
|
||||
if (selectedRows.length === allRoles.length) {
|
||||
onRemove(selectedRows);
|
||||
const loc = url.replace(/\/AssociatedRoles/g, "/details");
|
||||
history.push(loc);
|
||||
|
@ -170,6 +177,7 @@ export const AssociatedRolesTab = ({
|
|||
onRemove(selectedRows);
|
||||
await adminClient.roles.delCompositeRoles({ id }, selectedRows);
|
||||
addAlert(t("associatedRolesRemoved"), AlertVariant.success);
|
||||
refresh();
|
||||
} catch (error) {
|
||||
addAlert(`${t("roleDeleteError")} ${error}`, AlertVariant.danger);
|
||||
}
|
||||
|
@ -246,20 +254,17 @@ export const AssociatedRolesTab = ({
|
|||
displayKey: "roles:roleName",
|
||||
cellRenderer: AliasRenderer,
|
||||
cellFormatters: [formattedLinkTableCell(), emptyFormatter()],
|
||||
transforms: [cellWidth(40)],
|
||||
},
|
||||
{
|
||||
name: "containerId",
|
||||
displayKey: "roles:inheritedFrom",
|
||||
cellRenderer: InheritedRoleName,
|
||||
cellFormatters: [emptyFormatter()],
|
||||
transforms: [cellWidth(30)],
|
||||
},
|
||||
{
|
||||
name: "description",
|
||||
displayKey: "common:description",
|
||||
cellFormatters: [emptyFormatter()],
|
||||
transforms: [cellWidth(30)],
|
||||
},
|
||||
]}
|
||||
emptyState={
|
||||
|
|
|
@ -57,6 +57,7 @@ export const RealmRoleTabs = () => {
|
|||
const [additionalRoles, setAdditionalRoles] = useState<RoleRepresentation[]>(
|
||||
[]
|
||||
);
|
||||
|
||||
const { addAlert } = useAlerts();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
@ -321,7 +322,6 @@ export const RealmRoleTabs = () => {
|
|||
addComposites={addComposites}
|
||||
parentRole={role!}
|
||||
onRemove={() => refresh()}
|
||||
// client={client!}
|
||||
/>
|
||||
</Tab>
|
||||
) : null}
|
||||
|
|
|
@ -61,7 +61,6 @@ export const UserForm = ({
|
|||
const setupForm = (user: UserRepresentation) => {
|
||||
reset();
|
||||
Object.entries(user).map((entry) => {
|
||||
console.log(entry[0], entry[1]);
|
||||
if (entry[0] == "createdTimestamp") {
|
||||
setTimestamp(entry[1]);
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue