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:
parent
0cbdf3b1ee
commit
c7be03b103
3 changed files with 56 additions and 36 deletions
|
@ -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={
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue