No longer fetch the resources eager, but on row click (#4185)

This commit is contained in:
Erik Jan de Wit 2023-01-13 13:07:13 +01:00 committed by GitHub
parent 69344da121
commit 467da39668
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 70 additions and 40 deletions

View file

@ -1,7 +1,7 @@
import { useTranslation } from "react-i18next";
import { Alert, AlertVariant } from "@patternfly/react-core";
import type { ExpandableScopeRepresentation } from "./Scopes";
import type { PermissionScopeRepresentation } from "./Scopes";
import { useAlerts } from "../../components/alert/Alerts";
import { ConfirmDialogModal } from "../../components/confirm-dialog/ConfirmDialog";
import { useAdminClient } from "../../context/auth/AdminClient";
@ -10,7 +10,7 @@ import type ScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/s
type DeleteScopeDialogProps = {
clientId: string;
selectedScope:
| ExpandableScopeRepresentation
| PermissionScopeRepresentation
| ScopeRepresentation
| undefined;
refresh: () => void;

View file

@ -39,8 +39,13 @@ type ScopesProps = {
clientId: string;
};
export type ExpandableScopeRepresentation = ScopeRepresentation & {
export type PermissionScopeRepresentation = ScopeRepresentation & {
permissions?: PolicyRepresentation[];
isLoaded: boolean;
};
type ExpandableRow = {
id: string;
isExpanded: boolean;
};
@ -51,9 +56,10 @@ export const AuthorizationScopes = ({ clientId }: ScopesProps) => {
const { realm } = useRealm();
const [deleteDialog, toggleDeleteDialog] = useToggle();
const [scopes, setScopes] = useState<ExpandableScopeRepresentation[]>();
const [scopes, setScopes] = useState<PermissionScopeRepresentation[]>();
const [selectedScope, setSelectedScope] =
useState<ExpandableScopeRepresentation>();
useState<PermissionScopeRepresentation>();
const [collapsed, setCollapsed] = useState<ExpandableRow[]>([]);
const [key, setKey] = useState(0);
const refresh = () => setKey(key + 1);
@ -78,39 +84,68 @@ export const AuthorizationScopes = ({ clientId }: ScopesProps) => {
return await Promise.all(
scopes.map(async (scope) => {
const options = { id: clientId, scopeId: scope.id! };
const [resources, permissions] = await Promise.all([
adminClient.clients.listAllResourcesByScope(options),
adminClient.clients.listAllPermissionsByScope(options),
]);
const permissions =
await adminClient.clients.listAllPermissionsByScope(options);
return {
...scope,
resources,
permissions,
isExpanded: false,
isLoaded: false,
};
})
);
},
setScopes,
(scopes) => {
setScopes(scopes);
setCollapsed(scopes.map((s) => ({ id: s.id!, isExpanded: false })));
},
[key, search, first, max]
);
const ResourceRenderer = ({
row,
}: {
row: ExpandableScopeRepresentation;
}) => (
<>
{row.resources?.[0]?.name ? row.resources[0]?.name : "—"}{" "}
<MoreLabel array={row.resources} />
</>
const getScope = (id: string) => scopes?.find((scope) => scope.id === id)!;
const isExpanded = (id: string | undefined) =>
collapsed.find((c) => c.id === id)?.isExpanded || false;
useFetch(
async () => {
const newlyOpened = collapsed
.filter((row) => row.isExpanded)
.map(({ id }) => getScope(id))
.filter((s) => !s.isLoaded);
return await Promise.all(
newlyOpened.map(async (scope) => ({
...scope,
resources: await adminClient.clients.listAllResourcesByScope({
id: clientId,
scopeId: scope.id!,
}),
isLoaded: true,
}))
);
},
(resourcesScopes) => {
let result = [...(scopes || [])];
resourcesScopes.forEach((resourceScope) => {
const index = scopes?.findIndex(
(scope) => resourceScope.id === scope.id
)!;
result = [
...result.slice(0, index),
resourceScope,
...result.slice(index + 1),
];
});
setScopes(result);
},
[collapsed]
);
const PermissionsRenderer = ({
row,
}: {
row: ExpandableScopeRepresentation;
row: PermissionScopeRepresentation;
}) => (
<>
{row.permissions?.[0]?.name ? row.permissions[0]?.name : "—"}{" "}
@ -166,29 +201,24 @@ export const AuthorizationScopes = ({ clientId }: ScopesProps) => {
<Tr>
<Th />
<Th>{t("common:name")}</Th>
<Th>{t("resources")}</Th>
<Th>{t("common:permissions")}</Th>
<Th />
<Th />
</Tr>
</Thead>
{scopes.map((scope, rowIndex) => (
<Tbody key={scope.id} isExpanded={scope.isExpanded}>
<Tbody key={scope.id} isExpanded={isExpanded(scope.id)}>
<Tr>
<Td
expand={{
rowIndex,
isExpanded: scope.isExpanded,
onToggle: (_, rowIndex) => {
const rows = scopes.map((resource, index) =>
index === rowIndex
? {
...resource,
isExpanded: !resource.isExpanded,
}
: resource
);
setScopes(rows);
isExpanded: isExpanded(scope.id),
onToggle: (_event, index, isExpanded) => {
setCollapsed([
...collapsed.slice(0, index),
{ id: scope.id!, isExpanded },
...collapsed.slice(index + 1),
]);
},
}}
/>
@ -203,9 +233,6 @@ export const AuthorizationScopes = ({ clientId }: ScopesProps) => {
{scope.name}
</Link>
</Td>
<Td>
<ResourceRenderer row={scope} />
</Td>
<Td>
<PermissionsRenderer row={scope} />
</Td>
@ -242,11 +269,14 @@ export const AuthorizationScopes = ({ clientId }: ScopesProps) => {
}}
/>
</Tr>
<Tr key={`child-${scope.id}`} isExpanded={scope.isExpanded}>
<Tr
key={`child-${scope.id}`}
isExpanded={isExpanded(scope.id)}
>
<Td />
<Td colSpan={4}>
<ExpandableRowContent>
{scope.isExpanded && (
{isExpanded(scope.id) && (
<DescriptionList
isHorizontal
className="keycloak_resource_details"