import { AlertVariant, Badge, Button, ButtonVariant, PageSection, Tab, TabTitleText, ToolbarItem, } from "@patternfly/react-core"; import { cellWidth, IRowData, TableText } from "@patternfly/react-table"; import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation"; import type { ClientQuery } from "@keycloak/keycloak-admin-client/lib/resources/clients"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import { Link, useHistory } from "react-router-dom"; import { useAlerts } from "../components/alert/Alerts"; import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog"; import { formattedLinkTableCell } from "../components/external-link/FormattedLink"; import { Action, KeycloakDataTable, } from "../components/table-toolbar/KeycloakDataTable"; import { ViewHeader } from "../components/view-header/ViewHeader"; import { useAdminClient } from "../context/auth/AdminClient"; import { useRealm } from "../context/realm-context/RealmContext"; import { addTrailingSlash, emptyFormatter, exportClient } from "../util"; import { InitialAccessTokenList } from "./initial-access/InitialAccessTokenList"; import { toAddClient } from "./routes/AddClient"; import { toClient } from "./routes/Client"; import { toImportClient } from "./routes/ImportClient"; import { isRealmClient, getProtocolName } from "./utils"; import helpUrls from "../help-urls"; import { useAccess } from "../context/access/Access"; import { routableTab, RoutableTabs, } from "../components/routable-tabs/RoutableTabs"; import { ClientsTab, toClients } from "./routes/Clients"; export default function ClientsSection() { const { t } = useTranslation("clients"); const { addAlert, addError } = useAlerts(); const { adminClient } = useAdminClient(); const { realm } = useRealm(); const history = useHistory(); const [key, setKey] = useState(0); const refresh = () => setKey(new Date().getTime()); const [selectedClient, setSelectedClient] = useState(); const { hasAccess } = useAccess(); const isManager = hasAccess("manage-clients"); const loader = async (first?: number, max?: number, search?: string) => { const params: ClientQuery = { first: first!, max: max!, }; if (search) { params.clientId = search; params.search = true; } return await adminClient.clients.find({ ...params }); }; const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({ titleKey: t("clientDelete", { clientId: selectedClient?.clientId }), messageKey: "clients:clientDeleteConfirm", continueButtonLabel: "common:delete", continueButtonVariant: ButtonVariant.danger, onConfirm: async () => { try { await adminClient.clients.del({ id: selectedClient!.id!, }); addAlert(t("clientDeletedSuccess"), AlertVariant.success); refresh(); } catch (error) { addError("clients:clientDeleteError", error); } }, }); const ClientDetailLink = (client: ClientRepresentation) => ( {client.clientId} {!client.enabled && ( {t("common:disabled")} )} ); const ClientDescription = (client: ClientRepresentation) => ( {emptyFormatter()(client.description)} ); const ToolbarItems = () => { if (!isManager) return ; return ( <> ); }; const route = (tab: ClientsTab) => routableTab({ to: toClients({ realm, tab }), history, }); return ( <> {t("clientsList")}} {...route("list")} > } actionResolver={(rowData: IRowData) => { const client: ClientRepresentation = rowData.data; const actions: Action[] = [ { title: t("common:export"), onClick() { exportClient(client); }, }, ]; if ( !isRealmClient(client) && (isManager || client.access?.configure) ) { actions.push({ title: t("common:delete"), onClick() { setSelectedClient(client); toggleDeleteDialog(); }, }); } return actions; }} columns={[ { name: "clientId", displayKey: "common:clientId", cellRenderer: ClientDetailLink, }, { name: "protocol", displayKey: "common:type", cellRenderer: (client) => getProtocolName(t, client.protocol ?? "openid-connect"), }, { name: "description", displayKey: "common:description", transforms: [cellWidth(20)], cellRenderer: ClientDescription, }, { name: "baseUrl", displayKey: "clients:homeURL", cellFormatters: [formattedLinkTableCell(), emptyFormatter()], cellRenderer: (client) => { if (client.rootUrl) { if ( !client.rootUrl.startsWith("http") || client.rootUrl.includes("$") ) { return ( client.rootUrl .replace( "${authBaseUrl}", addTrailingSlash(adminClient.baseUrl) ) .replace( "${authAdminUrl}", addTrailingSlash(adminClient.baseUrl) ) + (client.baseUrl ? client.baseUrl.substring(1) : "") ); } } return client.baseUrl; }, }, ]} /> {t("initialAccessToken")}} {...route("initial-access-token")} > ); }