Idp pager UI (#24933)

* Identity Provider Pager (UI) Closes #21074

Signed-off-by: Andreas Kozadinos <koza-sparrow@hotmail.com>

* fixed the PR

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* Update js/apps/admin-ui/src/identity-providers/IdentityProvidersSection.tsx

Co-authored-by: Jon Koops <jonkoops@gmail.com>

* Update js/apps/admin-ui/src/identity-providers/IdentityProvidersSection.tsx

Co-authored-by: Jon Koops <jonkoops@gmail.com>

* Update js/apps/admin-ui/src/identity-providers/ManageOrderDialog.tsx

Co-authored-by: Jon Koops <jonkoops@gmail.com>

---------

Signed-off-by: Andreas Kozadinos <koza-sparrow@hotmail.com>
Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
Co-authored-by: Andreas Kozadinos <koza-sparrow@hotmail.com>
Co-authored-by: Jon Koops <jonkoops@gmail.com>
This commit is contained in:
Erik Jan de Wit 2023-12-11 14:38:20 +01:00 committed by GitHub
parent 0cbdf3b1ee
commit c7be03b103
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 36 deletions

View file

@ -1,4 +1,5 @@
import type IdentityProviderRepresentation from "@keycloak/keycloak-admin-client/lib/defs/identityProviderRepresentation";
import type { IdentityProvidersQuery } from "@keycloak/keycloak-admin-client/lib/resources/identityProviders";
import {
AlertVariant,
Badge,
@ -11,7 +12,6 @@ import {
DropdownToggle,
Gallery,
PageSection,
Spinner,
Split,
SplitItem,
Text,
@ -24,7 +24,6 @@ import { Fragment, useState } from "react";
import { useTranslation } from "react-i18next";
import { Link, useNavigate } from "react-router-dom";
import { IconMapper } from "ui-shared";
import { adminClient } from "../admin-client";
import { useAlerts } from "../components/alert/Alerts";
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
@ -84,26 +83,31 @@ export default function IdentityProvidersSection() {
const [addProviderOpen, setAddProviderOpen] = useState(false);
const [manageDisplayDialog, setManageDisplayDialog] = useState(false);
const [providers, setProviders] =
useState<IdentityProviderRepresentation[]>();
const [hasProviders, setHasProviders] = useState(false);
const [selectedProvider, setSelectedProvider] =
useState<IdentityProviderRepresentation>();
const { addAlert, addError } = useAlerts();
useFetch(
async () => {
const provider = await adminClient.realms.findOne({ realm });
if (!provider) {
throw new Error(t("notFound"));
}
return provider.identityProviders!;
},
async () => adminClient.identityProviders.find({ max: 1 }),
(providers) => {
setProviders(sortBy(providers, ["config.guiOrder", "alias"]));
setHasProviders(providers.length === 1);
},
[key],
);
const loader = async (first?: number, max?: number, search?: string) => {
const params: IdentityProvidersQuery = {
first: first!,
max: max!,
};
if (search) {
params.search = search;
}
const providers = await adminClient.identityProviders.find(params);
return sortBy(providers, ["config.guiOrder", "alias"]);
};
const navigateToCreate = (providerId: string) =>
navigate(
toIdentityProviderCreate({
@ -145,9 +149,6 @@ export default function IdentityProvidersSection() {
await adminClient.identityProviders.del({
alias: selectedProvider!.alias!,
});
setProviders([
...providers!.filter((p) => p.alias !== selectedProvider?.alias),
]);
refresh();
addAlert(t("deletedSuccessIdentityProvider"), AlertVariant.success);
} catch (error) {
@ -156,10 +157,6 @@ export default function IdentityProvidersSection() {
},
});
if (!providers) {
return <Spinner />;
}
return (
<>
<DeleteConfirm />
@ -169,7 +166,6 @@ export default function IdentityProvidersSection() {
setManageDisplayDialog(false);
refresh();
}}
providers={providers.filter((p) => p.enabled)}
/>
)}
<ViewHeader
@ -178,10 +174,10 @@ export default function IdentityProvidersSection() {
helpUrl={helpUrls.identityProvidersUrl}
/>
<PageSection
variant={providers.length === 0 ? "default" : "light"}
className={providers.length === 0 ? "" : "pf-u-p-0"}
variant={!hasProviders ? "default" : "light"}
className={!hasProviders ? "" : "pf-u-p-0"}
>
{providers.length === 0 && (
{!hasProviders && (
<>
<TextContent>
<Text component={TextVariants.p}>{t("getStarted")}</Text>
@ -216,9 +212,11 @@ export default function IdentityProvidersSection() {
))}
</>
)}
{providers.length !== 0 && (
{hasProviders && (
<KeycloakDataTable
loader={providers}
key={key}
loader={loader}
isPaginated
ariaLabelKey="identityProviders"
searchPlaceholderKey="searchForProvider"
toolbarItem={

View file

@ -17,27 +17,24 @@ import {
import { sortBy } from "lodash-es";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { adminClient } from "../admin-client";
import { useAlerts } from "../components/alert/Alerts";
import { KeycloakSpinner } from "../components/keycloak-spinner/KeycloakSpinner";
import { useFetch } from "../utils/useFetch";
type ManageOrderDialogProps = {
providers: IdentityProviderRepresentation[];
onClose: () => void;
};
export const ManageOrderDialog = ({
providers,
onClose,
}: ManageOrderDialogProps) => {
export const ManageOrderDialog = ({ onClose }: ManageOrderDialogProps) => {
const { t } = useTranslation();
const { addAlert, addError } = useAlerts();
const [alias, setAlias] = useState("");
const [liveText, setLiveText] = useState("");
const [order, setOrder] = useState(
providers.map((provider) => provider.alias!),
);
const [providers, setProviders] =
useState<IdentityProviderRepresentation[]>();
const [order, setOrder] = useState<string[]>([]);
const onDragStart = (id: string) => {
setAlias(id);
@ -57,11 +54,24 @@ export const ManageOrderDialog = ({
setOrder(providerOrder);
};
useFetch(
() => adminClient.identityProviders.find(),
(providers) => {
setProviders(sortBy(providers, ["config.guiOrder", "alias"]));
setOrder(providers.map((provider) => provider.alias!));
},
[],
);
if (!providers) {
return <KeycloakSpinner />;
}
return (
<Modal
variant={ModalVariant.small}
title={t("manageDisplayOrder")}
isOpen={true}
isOpen
onClose={onClose}
actions={[
<Button

View file

@ -5,13 +5,25 @@ import type IdentityProviderRepresentation from "../defs/identityProviderReprese
import type { ManagementPermissionReference } from "../defs/managementPermissionReference.js";
import Resource from "./resource.js";
export interface PaginatedQuery {
first?: number;
max?: number;
}
export interface IdentityProvidersQuery extends PaginatedQuery {
search?: string;
}
export class IdentityProviders extends Resource<{ realm?: string }> {
/**
* Identity provider
* https://www.keycloak.org/docs-api/11.0/rest-api/#_identity_providers_resource
*/
public find = this.makeRequest<{}, IdentityProviderRepresentation[]>({
public find = this.makeRequest<
IdentityProvidersQuery,
IdentityProviderRepresentation[]
>({
method: "GET",
path: "/instances",
});