Merge pull request #406 from edewit/issue-404
removed bookmarable sub tab
This commit is contained in:
commit
1a9131db7f
12 changed files with 80 additions and 76 deletions
|
@ -21,7 +21,7 @@ export const ClientScopesSection = () => {
|
|||
|
||||
const ClientScopeDetailLink = (clientScope: ClientScopeRepresentation) => (
|
||||
<>
|
||||
<Link key={clientScope.id} to={`${url}/${clientScope.id}`}>
|
||||
<Link key={clientScope.id} to={`${url}/${clientScope.id}/settings`}>
|
||||
{clientScope.name}
|
||||
</Link>
|
||||
</>
|
||||
|
|
|
@ -42,7 +42,7 @@ export const RoleMappingForm = () => {
|
|||
|
||||
const { t } = useTranslation("client-scopes");
|
||||
const { register, handleSubmit, control, errors } = useForm();
|
||||
const { clientScopeId } = useParams<{ clientScopeId: string }>();
|
||||
const { id } = useParams<{ id: string }>();
|
||||
|
||||
const [roleOpen, setRoleOpen] = useState(false);
|
||||
|
||||
|
@ -101,10 +101,7 @@ export const RoleMappingForm = () => {
|
|||
|
||||
const save = async (mapping: ProtocolMapperRepresentation) => {
|
||||
try {
|
||||
await adminClient.clientScopes.addProtocolMapper(
|
||||
{ id: clientScopeId },
|
||||
mapping
|
||||
);
|
||||
await adminClient.clientScopes.addProtocolMapper({ id }, mapping);
|
||||
addAlert(t("mapperCreateSuccess"));
|
||||
} catch (error) {
|
||||
addAlert(t("mapperCreateError", error));
|
||||
|
@ -227,7 +224,7 @@ export const RoleMappingForm = () => {
|
|||
placeholderText={t("selectASourceOfRoles")}
|
||||
isGrouped
|
||||
onFilter={(evt) => {
|
||||
const textInput = evt.target.value;
|
||||
const textInput = evt?.target.value || "";
|
||||
if (textInput === "") {
|
||||
return createSelectGroup(clients);
|
||||
} else {
|
||||
|
|
|
@ -59,7 +59,7 @@ export const MapperList = ({ clientScope, refresh }: MapperListProps) => {
|
|||
const [filter, setFilter] = useState(clientScope.protocolMappers);
|
||||
const toggleAddMapperDialog = (buildIn: boolean) => {
|
||||
if (buildIn) {
|
||||
setFilter(mapperList);
|
||||
setFilter(mapperList || []);
|
||||
} else {
|
||||
setFilter(undefined);
|
||||
}
|
||||
|
@ -123,9 +123,7 @@ export const MapperList = ({ clientScope, refresh }: MapperListProps) => {
|
|||
cells: {
|
||||
name: (
|
||||
<>
|
||||
<Link to={`${url}/${clientScope.id}/${mapper.id}`}>
|
||||
{mapper.name}
|
||||
</Link>
|
||||
<Link to={`${url}/${mapper.id}`}>{mapper.name}</Link>
|
||||
</>
|
||||
),
|
||||
category: mapperType.category,
|
||||
|
|
|
@ -37,8 +37,8 @@ import { convertFormValuesToObject, convertToFormValues } from "../../util";
|
|||
import { FormAccess } from "../../components/form-access/FormAccess";
|
||||
|
||||
type Params = {
|
||||
scopeId: string;
|
||||
id: string;
|
||||
mapperId: string;
|
||||
};
|
||||
|
||||
export const MappingDetails = () => {
|
||||
|
@ -47,7 +47,7 @@ export const MappingDetails = () => {
|
|||
const handleError = useErrorHandler();
|
||||
const { addAlert } = useAlerts();
|
||||
|
||||
const { scopeId, id } = useParams<Params>();
|
||||
const { id, mapperId } = useParams<Params>();
|
||||
const { register, errors, setValue, control, handleSubmit } = useForm();
|
||||
const [mapping, setMapping] = useState<ProtocolMapperRepresentation>();
|
||||
const [typeOpen, setTypeOpen] = useState(false);
|
||||
|
@ -63,10 +63,10 @@ export const MappingDetails = () => {
|
|||
useEffect(() => {
|
||||
return asyncStateFetch(
|
||||
async () => {
|
||||
if (id.match(isGuid)) {
|
||||
if (mapperId.match(isGuid)) {
|
||||
const data = await adminClient.clientScopes.findProtocolMapper({
|
||||
id: scopeId,
|
||||
mapperId: id,
|
||||
id,
|
||||
mapperId,
|
||||
});
|
||||
if (data) {
|
||||
Object.entries(data).map((entry) => {
|
||||
|
@ -83,9 +83,19 @@ export const MappingDetails = () => {
|
|||
mapping: data,
|
||||
};
|
||||
} else {
|
||||
const scope = await adminClient.clientScopes.findOne({ id: scopeId });
|
||||
const scope = await adminClient.clientScopes.findOne({ id });
|
||||
const protocolMappers = serverInfo.protocolMapperTypes![
|
||||
scope.protocol!
|
||||
];
|
||||
const mapping = protocolMappers.find(
|
||||
(mapper) => mapper.id === mapperId
|
||||
)!;
|
||||
return {
|
||||
mapping: { protocol: scope.protocol, protocolMapper: id },
|
||||
mapping: {
|
||||
name: mapping.name,
|
||||
protocol: scope.protocol,
|
||||
protocolMapper: mapperId,
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
|
@ -105,11 +115,11 @@ export const MappingDetails = () => {
|
|||
onConfirm: async () => {
|
||||
try {
|
||||
await adminClient.clientScopes.delClientScopeMappings(
|
||||
{ client: scopeId, id },
|
||||
{ client: id, id: mapperId },
|
||||
[]
|
||||
);
|
||||
addAlert(t("mappingDeletedSuccess"), AlertVariant.success);
|
||||
history.push(`${url}/${scopeId}`);
|
||||
history.push(`${url}/${id}`);
|
||||
} catch (error) {
|
||||
addAlert(t("mappingDeletedError", { error }), AlertVariant.danger);
|
||||
}
|
||||
|
@ -119,15 +129,15 @@ export const MappingDetails = () => {
|
|||
const save = async (formMapping: ProtocolMapperRepresentation) => {
|
||||
const config = convertFormValuesToObject(formMapping.config);
|
||||
const map = { ...mapping, ...formMapping, config };
|
||||
const key = id.match(isGuid) ? "Updated" : "Created";
|
||||
const key = mapperId.match(isGuid) ? "Updated" : "Created";
|
||||
try {
|
||||
if (id.match(isGuid)) {
|
||||
if (mapperId.match(isGuid)) {
|
||||
await adminClient.clientScopes.updateProtocolMapper(
|
||||
{ id: scopeId, mapperId: id },
|
||||
{ id, mapperId },
|
||||
map
|
||||
);
|
||||
} else {
|
||||
await adminClient.clientScopes.addProtocolMapper({ id: scopeId }, map);
|
||||
await adminClient.clientScopes.addProtocolMapper({ id }, map);
|
||||
}
|
||||
addAlert(t(`mapping${key}Success`), AlertVariant.success);
|
||||
} catch (error) {
|
||||
|
@ -140,10 +150,10 @@ export const MappingDetails = () => {
|
|||
<DeleteConfirm />
|
||||
<ViewHeader
|
||||
titleKey={mapping ? mapping.name! : t("addMapper")}
|
||||
subKey={id.match(isGuid) ? id : ""}
|
||||
subKey={mapperId.match(isGuid) ? mapperId : ""}
|
||||
badge={mapping?.protocol}
|
||||
dropdownItems={
|
||||
id.match(isGuid)
|
||||
mapperId.match(isGuid)
|
||||
? [
|
||||
<DropdownItem
|
||||
key="delete"
|
||||
|
@ -163,7 +173,7 @@ export const MappingDetails = () => {
|
|||
role="manage-clients"
|
||||
>
|
||||
<>
|
||||
{!id.match(isGuid) && (
|
||||
{!mapperId.match(isGuid) && (
|
||||
<FormGroup
|
||||
label={t("common:name")}
|
||||
labelIcon={
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
PageSection,
|
||||
Spinner,
|
||||
Tab,
|
||||
Tabs,
|
||||
TabTitleText,
|
||||
} from "@patternfly/react-core";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
@ -113,6 +114,7 @@ export const ClientDetails = () => {
|
|||
const { addAlert } = useAlerts();
|
||||
const [downloadDialogOpen, setDownloadDialogOpen] = useState(false);
|
||||
const toggleDownloadDialog = () => setDownloadDialogOpen(!downloadDialogOpen);
|
||||
const [activeTab2, setActiveTab2] = useState(30);
|
||||
|
||||
const form = useForm<ClientForm>();
|
||||
const publicClient = useWatch({
|
||||
|
@ -121,12 +123,12 @@ export const ClientDetails = () => {
|
|||
defaultValue: false,
|
||||
});
|
||||
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const { clientId } = useParams<{ clientId: string }>();
|
||||
|
||||
const [client, setClient] = useState<ClientRepresentation>();
|
||||
|
||||
const loader = async () => {
|
||||
const roles = await adminClient.clients.listRoles({ id });
|
||||
const roles = await adminClient.clients.listRoles({ id: clientId });
|
||||
return _.sortBy(roles, (role) => role.name?.toUpperCase());
|
||||
};
|
||||
|
||||
|
@ -137,7 +139,7 @@ export const ClientDetails = () => {
|
|||
continueButtonVariant: ButtonVariant.danger,
|
||||
onConfirm: async () => {
|
||||
try {
|
||||
await adminClient.clients.del({ id });
|
||||
await adminClient.clients.del({ id: clientId });
|
||||
addAlert(t("clientDeletedSuccess"), AlertVariant.success);
|
||||
} catch (error) {
|
||||
addAlert(`${t("clientDeleteError")} ${error}`, AlertVariant.danger);
|
||||
|
@ -162,14 +164,14 @@ export const ClientDetails = () => {
|
|||
|
||||
useEffect(() => {
|
||||
return asyncStateFetch(
|
||||
() => adminClient.clients.findOne({ id }),
|
||||
() => adminClient.clients.findOne({ id: clientId }),
|
||||
(fetchedClient) => {
|
||||
setClient(fetchedClient);
|
||||
setupForm(fetchedClient);
|
||||
},
|
||||
handleError
|
||||
);
|
||||
}, [id]);
|
||||
}, [clientId]);
|
||||
|
||||
const save = async () => {
|
||||
if (await form.trigger()) {
|
||||
|
@ -187,7 +189,7 @@ export const ClientDetails = () => {
|
|||
webOrigins,
|
||||
attributes,
|
||||
};
|
||||
await adminClient.clients.update({ id }, newClient);
|
||||
await adminClient.clients.update({ id: clientId }, newClient);
|
||||
setupForm(newClient);
|
||||
setClient(newClient);
|
||||
addAlert(t("clientSaveSuccess"), AlertVariant.success);
|
||||
|
@ -244,7 +246,7 @@ export const ClientDetails = () => {
|
|||
eventKey="credentials"
|
||||
title={<TabTitleText>{t("credentials")}</TabTitleText>}
|
||||
>
|
||||
<Credentials clientId={id} save={save} />
|
||||
<Credentials clientId={clientId} save={save} />
|
||||
</Tab>
|
||||
)}
|
||||
<Tab
|
||||
|
@ -259,22 +261,32 @@ export const ClientDetails = () => {
|
|||
eventKey="clientScopes"
|
||||
title={<TabTitleText>{t("clientScopes")}</TabTitleText>}
|
||||
>
|
||||
<KeycloakTabs paramName="subtab" isSecondary>
|
||||
<Tabs
|
||||
activeKey={activeTab2}
|
||||
isSecondary
|
||||
onSelect={(_, key) => setActiveTab2(key as number)}
|
||||
>
|
||||
<Tab
|
||||
id="setup"
|
||||
eventKey="setup"
|
||||
eventKey={30}
|
||||
title={<TabTitleText>{t("setup")}</TabTitleText>}
|
||||
>
|
||||
<ClientScopes clientId={id} protocol={client!.protocol!} />
|
||||
<ClientScopes
|
||||
clientId={clientId}
|
||||
protocol={client!.protocol!}
|
||||
/>
|
||||
</Tab>
|
||||
<Tab
|
||||
id="evaluate"
|
||||
eventKey="evaluate"
|
||||
eventKey={31}
|
||||
title={<TabTitleText>{t("evaluate")}</TabTitleText>}
|
||||
>
|
||||
<EvaluateScopes clientId={id} protocol={client!.protocol!} />
|
||||
<EvaluateScopes
|
||||
clientId={clientId}
|
||||
protocol={client!.protocol!}
|
||||
/>
|
||||
</Tab>
|
||||
</KeycloakTabs>
|
||||
</Tabs>
|
||||
</Tab>
|
||||
{client!.serviceAccountsEnabled && (
|
||||
<Tab
|
||||
|
@ -282,7 +294,7 @@ export const ClientDetails = () => {
|
|||
eventKey="serviceAccount"
|
||||
title={<TabTitleText>{t("serviceAccount")}</TabTitleText>}
|
||||
>
|
||||
<ServiceAccount clientId={id} />
|
||||
<ServiceAccount clientId={clientId} />
|
||||
</Tab>
|
||||
)}
|
||||
<Tab
|
||||
|
|
|
@ -66,7 +66,7 @@ export const ClientsSection = () => {
|
|||
|
||||
const ClientDetailLink = (client: ClientRepresentation) => (
|
||||
<>
|
||||
<Link key={client.id} to={`${url}/${client.id}`}>
|
||||
<Link key={client.id} to={`${url}/${client.id}/settings`}>
|
||||
{client.clientId}
|
||||
{!client.enabled && (
|
||||
<Badge isRead className="pf-u-ml-sm">
|
||||
|
|
|
@ -44,7 +44,7 @@ export const NewClientForm = () => {
|
|||
try {
|
||||
const newClient = await adminClient.clients.create({ ...client });
|
||||
addAlert(t("createSuccess"), AlertVariant.success);
|
||||
history.push(`/${realm}/clients/${newClient.id}`);
|
||||
history.push(`/${realm}/clients/${newClient.id}/settings`);
|
||||
} catch (error) {
|
||||
addAlert(t("createError", { error }), AlertVariant.danger);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import { MemoryRouter } from "react-router-dom";
|
|||
describe("BreadCrumbs tests", () => {
|
||||
it("couple of crumbs", () => {
|
||||
const crumbs = mount(
|
||||
<MemoryRouter initialEntries={["/master/clients/1234"]}>
|
||||
<MemoryRouter initialEntries={["/master/clients/1234/settings"]}>
|
||||
<PageBreadCrumbs />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
|
|
@ -136,7 +136,7 @@ exports[`BreadCrumbs tests couple of crumbs 1`] = `
|
|||
</AngleRightIcon>
|
||||
</span>
|
||||
<span
|
||||
key="/master/clients/1234"
|
||||
key="/master/clients/1234/settings"
|
||||
>
|
||||
Client details
|
||||
</span>
|
||||
|
|
|
@ -15,8 +15,6 @@ const createUrl = (
|
|||
const value = params[key];
|
||||
if (url.indexOf(key) !== -1) {
|
||||
url = url.replace(new RegExp(`:${key}\\??`), value || "");
|
||||
} else {
|
||||
url += `/${value}`;
|
||||
}
|
||||
}
|
||||
return url;
|
||||
|
@ -37,13 +35,13 @@ export const KeycloakTabs = ({
|
|||
(isValidElement<TabProps>(firstTab) && firstTab.props.eventKey) ||
|
||||
"";
|
||||
|
||||
const pathIndex = match.path.indexOf(paramName) + paramName.length;
|
||||
const path = match.path.substr(0, pathIndex);
|
||||
return (
|
||||
<Tabs
|
||||
activeKey={tab}
|
||||
onSelect={(_, key) =>
|
||||
history.push(
|
||||
createUrl(match.path, { ...params, [paramName]: key as string })
|
||||
)
|
||||
history.push(createUrl(path, { ...params, [paramName]: key as string }))
|
||||
}
|
||||
{...rest}
|
||||
>
|
||||
|
|
|
@ -22,6 +22,15 @@ type RolesListProps = {
|
|||
) => Promise<RoleRepresentation[]>;
|
||||
};
|
||||
|
||||
const RoleLink = ({ role }: { role: RoleRepresentation }) => {
|
||||
const { url } = useRouteMatch();
|
||||
return (
|
||||
<Link key={role.id} to={`${url}/${role.id}/details`}>
|
||||
{role.name}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export const RolesList = ({
|
||||
loader,
|
||||
paginated = true,
|
||||
|
@ -37,9 +46,7 @@ export const RolesList = ({
|
|||
|
||||
const RoleDetailLink = (role: RoleRepresentation) => (
|
||||
<>
|
||||
<Link key={role.id} to={`${url}/${role.id}/details`}>
|
||||
{role.name}
|
||||
</Link>
|
||||
<RoleLink role={role} />
|
||||
</>
|
||||
);
|
||||
|
||||
|
|
|
@ -59,12 +59,6 @@ export const routes: RoutesFn = (t: TFunction) => [
|
|||
breadcrumb: t("clients:importClient"),
|
||||
access: "manage-clients",
|
||||
},
|
||||
{
|
||||
path: "/:realm/clients/:id",
|
||||
component: ClientDetails,
|
||||
breadcrumb: t("clients:clientSettings"),
|
||||
access: "view-clients",
|
||||
},
|
||||
{
|
||||
path: "/:realm/clients/:clientId/roles/add-role",
|
||||
component: RealmRoleTabs,
|
||||
|
@ -84,9 +78,9 @@ export const routes: RoutesFn = (t: TFunction) => [
|
|||
access: "view-realm",
|
||||
},
|
||||
{
|
||||
path: "/:realm/clients/:id/:tab?/:subtab?",
|
||||
path: "/:realm/clients/:clientId/:tab",
|
||||
component: ClientDetails,
|
||||
breadcrumb: null,
|
||||
breadcrumb: t("clients:clientSettings"),
|
||||
access: "view-clients",
|
||||
},
|
||||
{
|
||||
|
@ -96,31 +90,19 @@ export const routes: RoutesFn = (t: TFunction) => [
|
|||
access: "manage-clients",
|
||||
},
|
||||
{
|
||||
path: "/:realm/client-scopes/:id",
|
||||
component: ClientScopeForm,
|
||||
breadcrumb: t("client-scopes:clientScopeDetails"),
|
||||
access: "view-clients",
|
||||
},
|
||||
{
|
||||
path: "/:realm/client-scopes/:id/:tab",
|
||||
component: ClientScopeForm,
|
||||
breadcrumb: null,
|
||||
access: "view-clients",
|
||||
},
|
||||
{
|
||||
path: "/:realm/client-scopes/:scopeId/oidc-role-name-mapper",
|
||||
path: "/:realm/client-scopes/:id/mappers/oidc-role-name-mapper",
|
||||
component: RoleMappingForm,
|
||||
breadcrumb: t("client-scopes:mappingDetails"),
|
||||
access: "view-clients",
|
||||
},
|
||||
{
|
||||
path: "/:realm/client-scopes/:scopeId/:id",
|
||||
path: "/:realm/client-scopes/:id/mappers/:mapperId",
|
||||
component: MappingDetails,
|
||||
breadcrumb: t("client-scopes:mappingDetails"),
|
||||
access: "view-clients",
|
||||
},
|
||||
{
|
||||
path: "/:realm/client-scopes/:id",
|
||||
path: "/:realm/client-scopes/:id/:tab",
|
||||
component: ClientScopeForm,
|
||||
breadcrumb: t("client-scopes:clientScopeDetails"),
|
||||
access: "view-clients",
|
||||
|
|
Loading…
Reference in a new issue