Fixed feedback discussions (#31409)
see: #24805 Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
This commit is contained in:
parent
6ce89670b5
commit
83f8622d15
5 changed files with 62 additions and 19 deletions
|
@ -25,7 +25,7 @@ export const PageBreadCrumbs = () => {
|
||||||
const crumbs = uniqBy(
|
const crumbs = uniqBy(
|
||||||
useBreadcrumbs(routesWithCrumbs, {
|
useBreadcrumbs(routesWithCrumbs, {
|
||||||
disableDefaults: true,
|
disableDefaults: true,
|
||||||
excludePaths: ["/", `/${realm}`],
|
excludePaths: ["/", `/${realm}`, `/${realm}/page-section`],
|
||||||
}),
|
}),
|
||||||
elementText,
|
elementText,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
import { useAlerts } from "@keycloak/keycloak-ui-shared";
|
||||||
import { ButtonVariant, DropdownItem } from "@patternfly/react-core";
|
import { ButtonVariant, DropdownItem } from "@patternfly/react-core";
|
||||||
|
import { get } from "lodash-es";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import { useAdminClient } from "../admin-client";
|
import { useAdminClient } from "../admin-client";
|
||||||
import { useAlerts } from "@keycloak/keycloak-ui-shared";
|
|
||||||
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
|
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
|
||||||
import { ViewHeader } from "../components/view-header/ViewHeader";
|
import { ViewHeader } from "../components/view-header/ViewHeader";
|
||||||
import { useRealm } from "../context/realm-context/RealmContext";
|
import { useRealm } from "../context/realm-context/RealmContext";
|
||||||
|
@ -10,6 +11,9 @@ import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
||||||
import { PageHandler } from "./PageHandler";
|
import { PageHandler } from "./PageHandler";
|
||||||
import { PAGE_PROVIDER } from "./PageList";
|
import { PAGE_PROVIDER } from "./PageList";
|
||||||
import { PageParams, toPage } from "./routes";
|
import { PageParams, toPage } from "./routes";
|
||||||
|
import { useFetch } from "../utils/useFetch";
|
||||||
|
import ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const { adminClient } = useAdminClient();
|
const { adminClient } = useAdminClient();
|
||||||
|
@ -21,12 +25,19 @@ export default function Page() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { id, providerId } = useParams<PageParams>();
|
const { id, providerId } = useParams<PageParams>();
|
||||||
const { addAlert, addError } = useAlerts();
|
const { addAlert, addError } = useAlerts();
|
||||||
|
const [pageData, setPageData] = useState<ComponentRepresentation>();
|
||||||
|
|
||||||
const page = pages?.find((p) => p.id === providerId);
|
const page = pages?.find((p) => p.id === providerId);
|
||||||
if (!page) {
|
if (!page) {
|
||||||
throw new Error(t("notFound"));
|
throw new Error(t("notFound"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useFetch(
|
||||||
|
async () => adminClient.components.findOne({ id: id! }),
|
||||||
|
setPageData,
|
||||||
|
[id],
|
||||||
|
);
|
||||||
|
|
||||||
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
|
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
|
||||||
titleKey: "itemDeleteConfirmTitle",
|
titleKey: "itemDeleteConfirmTitle",
|
||||||
messageKey: "itemDeleteConfirm",
|
messageKey: "itemDeleteConfirm",
|
||||||
|
@ -48,7 +59,10 @@ export default function Page() {
|
||||||
<>
|
<>
|
||||||
<DeleteConfirm />
|
<DeleteConfirm />
|
||||||
<ViewHeader
|
<ViewHeader
|
||||||
titleKey={id || t("createItem")}
|
titleKey={
|
||||||
|
get(pageData, `config.${page.metadata.displayFields[0]}`)?.[0] ||
|
||||||
|
t("createItem")
|
||||||
|
}
|
||||||
dropdownItems={
|
dropdownItems={
|
||||||
id
|
id
|
||||||
? [
|
? [
|
||||||
|
|
|
@ -70,7 +70,7 @@ export const PageHandler = ({
|
||||||
} else {
|
} else {
|
||||||
await adminClient.components.create(updatedComponent);
|
await adminClient.components.create(updatedComponent);
|
||||||
}
|
}
|
||||||
addAlert("itemSaveSuccessful");
|
addAlert(t("itemSaveSuccessful"));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
addError("itemSaveError", error);
|
addError("itemSaveError", error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation";
|
import ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation";
|
||||||
import type { ComponentQuery } from "@keycloak/keycloak-admin-client/lib/resources/components";
|
import type { ComponentQuery } from "@keycloak/keycloak-admin-client/lib/resources/components";
|
||||||
|
import { useAlerts } from "@keycloak/keycloak-ui-shared";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
ButtonVariant,
|
ButtonVariant,
|
||||||
|
@ -7,30 +8,36 @@ import {
|
||||||
ToolbarItem,
|
ToolbarItem,
|
||||||
} from "@patternfly/react-core";
|
} from "@patternfly/react-core";
|
||||||
import { IRowData } from "@patternfly/react-table";
|
import { IRowData } from "@patternfly/react-table";
|
||||||
|
import { get } from "lodash-es";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link, useNavigate, useParams } from "react-router-dom";
|
import { Link, useNavigate, useParams } from "react-router-dom";
|
||||||
import { useAdminClient } from "../admin-client";
|
import { useAdminClient } from "../admin-client";
|
||||||
import { useAlerts } from "@keycloak/keycloak-ui-shared";
|
|
||||||
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
|
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
|
||||||
import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
|
import { ListEmptyState } from "../components/list-empty-state/ListEmptyState";
|
||||||
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
|
import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable";
|
||||||
import { ViewHeader } from "../components/view-header/ViewHeader";
|
import { ViewHeader } from "../components/view-header/ViewHeader";
|
||||||
import { useRealm } from "../context/realm-context/RealmContext";
|
import { useRealm } from "../context/realm-context/RealmContext";
|
||||||
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
||||||
import { PageListParams, toDetailPage } from "./routes";
|
import { addDetailPage, PageListParams, toDetailPage } from "./routes";
|
||||||
|
|
||||||
export const PAGE_PROVIDER = "org.keycloak.services.ui.extend.UiPageProvider";
|
export const PAGE_PROVIDER = "org.keycloak.services.ui.extend.UiPageProvider";
|
||||||
export const TAB_PROVIDER = "org.keycloak.services.ui.extend.UiTabProvider";
|
export const TAB_PROVIDER = "org.keycloak.services.ui.extend.UiTabProvider";
|
||||||
|
|
||||||
const DetailLink = (obj: ComponentRepresentation) => {
|
type DetailLinkProps = {
|
||||||
|
obj: ComponentRepresentation;
|
||||||
|
field: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const DetailLink = ({ obj, field }: DetailLinkProps) => {
|
||||||
const { realm } = useRealm();
|
const { realm } = useRealm();
|
||||||
|
const value = get(obj, field);
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
key={obj.id}
|
key={value}
|
||||||
to={toDetailPage({ realm, providerId: obj.providerId!, id: obj.id! })}
|
to={toDetailPage({ realm, providerId: obj.providerId!, id: obj.id! })}
|
||||||
>
|
>
|
||||||
{obj.id}
|
{value}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -89,7 +96,7 @@ export default function PageList() {
|
||||||
component={(props) => (
|
component={(props) => (
|
||||||
<Link
|
<Link
|
||||||
{...props}
|
{...props}
|
||||||
to={toDetailPage({ realm: realmName, providerId: page.id })}
|
to={addDetailPage({ realm: realmName, providerId: page.id })}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
@ -109,10 +116,15 @@ export default function PageList() {
|
||||||
searchPlaceholderKey="searchItem"
|
searchPlaceholderKey="searchItem"
|
||||||
loader={loader}
|
loader={loader}
|
||||||
columns={[
|
columns={[
|
||||||
{ name: "id", cellRenderer: DetailLink },
|
...page.metadata.displayFields.map((name: string, index: number) => ({
|
||||||
...page.properties.slice(0, 3).map((p) => ({
|
name: `config.${name}[0]`,
|
||||||
name: `config.${p.name}[0]`,
|
displayKey: page.properties.find((p) => p.name === name)!.label,
|
||||||
displayKey: p.label,
|
cellRenderer:
|
||||||
|
index === 0
|
||||||
|
? (obj: ComponentRepresentation) => (
|
||||||
|
<DetailLink obj={obj} field={`config.${name}`} />
|
||||||
|
)
|
||||||
|
: undefined,
|
||||||
})),
|
})),
|
||||||
]}
|
]}
|
||||||
ariaLabelKey="list"
|
ariaLabelKey="list"
|
||||||
|
@ -123,7 +135,7 @@ export default function PageList() {
|
||||||
instructions={t("noItemsInstructions")}
|
instructions={t("noItemsInstructions")}
|
||||||
primaryActionText={t("createItem")}
|
primaryActionText={t("createItem")}
|
||||||
onPrimaryAction={() =>
|
onPrimaryAction={() =>
|
||||||
navigate(toDetailPage({ realm: realmName, providerId: page.id }))
|
navigate(addDetailPage({ realm: realmName, providerId: page.id }))
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { AppRouteObject } from "../routes";
|
||||||
import { lazy } from "react";
|
import { lazy } from "react";
|
||||||
|
|
||||||
export type PageListParams = { realm?: string; providerId: string };
|
export type PageListParams = { realm?: string; providerId: string };
|
||||||
export type PageParams = { realm: string; providerId: string; id?: string };
|
export type PageParams = { realm: string; providerId: string; id: string };
|
||||||
|
|
||||||
const PageList = lazy(() => import("./PageList"));
|
const PageList = lazy(() => import("./PageList"));
|
||||||
const Page = lazy(() => import("./Page"));
|
const Page = lazy(() => import("./Page"));
|
||||||
|
@ -18,15 +18,28 @@ const PageListRoute: AppRouteObject = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const PageDetailRoute: AppRouteObject = {
|
const PageDetailRoute: AppRouteObject = {
|
||||||
path: "/:realm/page/:providerId/:id?",
|
path: "/:realm/page-section/:providerId/:id",
|
||||||
element: <Page />,
|
element: <Page />,
|
||||||
breadcrumb: (t) => t("page"),
|
breadcrumb: (t) => t("details"),
|
||||||
handle: {
|
handle: {
|
||||||
access: "view-realm",
|
access: "view-realm",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const routes: AppRouteObject[] = [PageListRoute, PageDetailRoute];
|
const AddPageDetailRoute: AppRouteObject = {
|
||||||
|
path: "/:realm/page-section/:providerId/add",
|
||||||
|
element: <Page />,
|
||||||
|
breadcrumb: (t) => t("add"),
|
||||||
|
handle: {
|
||||||
|
access: "view-realm",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const routes: AppRouteObject[] = [
|
||||||
|
PageDetailRoute,
|
||||||
|
AddPageDetailRoute,
|
||||||
|
PageListRoute,
|
||||||
|
];
|
||||||
|
|
||||||
export const toPage = (params: PageListParams): Partial<Path> => ({
|
export const toPage = (params: PageListParams): Partial<Path> => ({
|
||||||
pathname: generatePath(PageListRoute.path, params),
|
pathname: generatePath(PageListRoute.path, params),
|
||||||
|
@ -36,4 +49,8 @@ export const toDetailPage = (params: PageParams): Partial<Path> => ({
|
||||||
pathname: generatePath(PageDetailRoute.path, params),
|
pathname: generatePath(PageDetailRoute.path, params),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const addDetailPage = (params: Partial<PageParams>): Partial<Path> => ({
|
||||||
|
pathname: generatePath(AddPageDetailRoute.path, params),
|
||||||
|
});
|
||||||
|
|
||||||
export default routes;
|
export default routes;
|
||||||
|
|
Loading…
Reference in a new issue