Merge pull request #406 from edewit/issue-404

removed bookmarable sub tab
This commit is contained in:
mfrances17 2021-03-03 09:28:50 -05:00 committed by GitHub
commit 1a9131db7f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 80 additions and 76 deletions

View file

@ -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>
</>

View file

@ -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 {

View file

@ -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,

View file

@ -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={

View file

@ -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

View file

@ -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">

View file

@ -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);
}

View file

@ -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>
);

View file

@ -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>

View file

@ -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}
>

View file

@ -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} />
</>
);

View file

@ -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",