WIP role attributes
fix storybook demos add attributes tab to realm roles section use TableComposable fix formatting css updates fix up styling of role attributes table fix check-types erros logic from call with Jeff clean up, format, make eslint proud delete roledetails call with Erik add delete function and css changes fix storybook demos and format make key input disabled once new attribute is created minus icon gray address PR feedback from Sarah set add and save buttons to disabled when new input field is empty fix save/add fix onChange formState rebase with resolved conflicts fix formatting remove !important Update RealmRolesSection.css Update src/realm-roles/RoleAttributes.tsx Co-authored-by: Erik Jan de Wit <erikjan.dewit@gmail.com> address PR feedback from Sarah and Erik fix paths and use error msg from response remove log stmt fix lint remove minLength
This commit is contained in:
parent
5d7d2b5636
commit
8ef7bd7ddb
10 changed files with 163 additions and 413 deletions
|
@ -1,140 +0,0 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { useHistory, useParams } from "react-router-dom";
|
||||
import {
|
||||
ActionGroup,
|
||||
AlertVariant,
|
||||
Button,
|
||||
FormGroup,
|
||||
PageSection,
|
||||
Tab,
|
||||
Tabs,
|
||||
TabTitleText,
|
||||
TextArea,
|
||||
TextInput,
|
||||
ValidatedOptions,
|
||||
} from "@patternfly/react-core";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { FormAccess } from "../components/form-access/FormAccess";
|
||||
|
||||
import { useAlerts } from "../components/alert/Alerts";
|
||||
import { ViewHeader } from "../components/view-header/ViewHeader";
|
||||
|
||||
import { useAdminClient } from "../context/auth/AdminClient";
|
||||
import RoleRepresentation from "keycloak-admin/lib/defs/roleRepresentation";
|
||||
import { RoleAttributes } from "./RoleAttributes";
|
||||
|
||||
export const RolesForm = () => {
|
||||
const { t } = useTranslation("roles");
|
||||
const { register, handleSubmit, errors, control, setValue } = useForm<
|
||||
RoleRepresentation
|
||||
>();
|
||||
const history = useHistory();
|
||||
const [name, setName] = useState("");
|
||||
const [activeTab, setActiveTab] = useState(0);
|
||||
|
||||
const adminClient = useAdminClient();
|
||||
const form = useForm();
|
||||
|
||||
|
||||
const { id } = useParams<{ id: string }>();
|
||||
|
||||
const { addAlert } = useAlerts();
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const fetchedRole = await adminClient.roles.findOneById({ id });
|
||||
setName(fetchedRole.name!);
|
||||
setupForm(fetchedRole);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
const setupForm = (role: RoleRepresentation) => {
|
||||
Object.entries(role).map((entry) => {
|
||||
setValue(entry[0], entry[1]);
|
||||
});
|
||||
};
|
||||
|
||||
const save = async (role: RoleRepresentation) => {
|
||||
try {
|
||||
await adminClient.roles.updateById({ id }, role);
|
||||
setupForm(role as RoleRepresentation);
|
||||
addAlert(t("roleSaveSuccess"), AlertVariant.success);
|
||||
} catch (error) {
|
||||
addAlert(`${t("roleSaveError")} '${error}'`, AlertVariant.danger);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewHeader titleKey={name} subKey="" />
|
||||
|
||||
<PageSection variant="light">
|
||||
<Tabs
|
||||
activeKey={activeTab}
|
||||
onSelect={(_, key) => setActiveTab(key as number)}
|
||||
isBox
|
||||
>
|
||||
<Tab eventKey={0} title={<TabTitleText>{t("details")}</TabTitleText>}>
|
||||
<FormAccess
|
||||
isHorizontal
|
||||
onSubmit={handleSubmit(save)}
|
||||
role="manage-realm"
|
||||
className="pf-u-mt-lg"
|
||||
>
|
||||
<FormGroup
|
||||
label={t("roleName")}
|
||||
fieldId="kc-name"
|
||||
isRequired
|
||||
validated={errors.name ? "error" : "default"}
|
||||
helperTextInvalid={t("common:required")}
|
||||
>
|
||||
{name ? (
|
||||
<TextInput
|
||||
ref={register({ required: true })}
|
||||
type="text"
|
||||
id="kc-name"
|
||||
name="name"
|
||||
isReadOnly
|
||||
/>
|
||||
) : undefined}
|
||||
</FormGroup>
|
||||
<FormGroup label={t("description")} fieldId="kc-description">
|
||||
<Controller
|
||||
name="description"
|
||||
defaultValue=""
|
||||
control={control}
|
||||
rules={{ maxLength: 255 }}
|
||||
render={({ onChange, value }) => (
|
||||
<TextArea
|
||||
type="text"
|
||||
validated={
|
||||
errors.description
|
||||
? ValidatedOptions.error
|
||||
: ValidatedOptions.default
|
||||
}
|
||||
id="kc-role-description"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
<ActionGroup>
|
||||
<Button variant="primary" type="submit">
|
||||
{t("common:save")}
|
||||
</Button>
|
||||
<Button variant="link" onClick={() => history.push("/roles/")}>
|
||||
{t("common:reload")}
|
||||
</Button>
|
||||
</ActionGroup>
|
||||
</FormAccess>
|
||||
</Tab>
|
||||
<Tab eventKey={1} title={<TabTitleText>{t("attributes")}</TabTitleText>}>
|
||||
<RoleAttributes form={form} />
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</PageSection>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -1,48 +1,31 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { useHistory, useParams } from "react-router-dom";
|
||||
import React from "react";
|
||||
import {
|
||||
ActionGroup,
|
||||
AlertVariant,
|
||||
Button,
|
||||
ButtonVariant,
|
||||
DropdownItem,
|
||||
FormGroup,
|
||||
PageSection,
|
||||
Tab,
|
||||
Tabs,
|
||||
TabTitleText,
|
||||
TextArea,
|
||||
TextInput,
|
||||
ValidatedOptions,
|
||||
} from "@patternfly/react-core";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { SubmitHandler, useForm, UseFormMethods } from "react-hook-form";
|
||||
import { SubmitHandler, UseFormMethods } from "react-hook-form";
|
||||
|
||||
import RoleRepresentation from "keycloak-admin/lib/defs/roleRepresentation";
|
||||
import { FormAccess } from "../components/form-access/FormAccess";
|
||||
|
||||
import { useAlerts } from "../components/alert/Alerts";
|
||||
import { ViewHeader } from "../components/view-header/ViewHeader";
|
||||
|
||||
import { useAdminClient, asyncStateFetch } from "../context/auth/AdminClient";
|
||||
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
|
||||
import { RoleAttributes } from "./RoleAttributes";
|
||||
import { useRealm } from "../context/realm-context/RealmContext";
|
||||
|
||||
type RoleFormType = {
|
||||
form?: UseFormMethods;
|
||||
save?: SubmitHandler<RoleRepresentation>;
|
||||
editMode?: boolean;
|
||||
export type RealmRoleFormProps = {
|
||||
form: UseFormMethods;
|
||||
save: SubmitHandler<RoleRepresentation>;
|
||||
editMode: boolean;
|
||||
};
|
||||
|
||||
export const RoleForm = ({ form, save, editMode }: RoleFormType) => {
|
||||
export const RealmRoleForm = ({ form, save, editMode }: RealmRoleFormProps) => {
|
||||
const { t } = useTranslation("roles");
|
||||
const history = useHistory();
|
||||
const { realm } = useRealm();
|
||||
|
||||
return (
|
||||
<FormAccess
|
||||
isHorizontal
|
||||
onSubmit={form!.handleSubmit(save!)}
|
||||
onSubmit={form.handleSubmit(save)}
|
||||
role="manage-realm"
|
||||
className="pf-u-mt-lg"
|
||||
>
|
||||
|
@ -50,11 +33,11 @@ export const RoleForm = ({ form, save, editMode }: RoleFormType) => {
|
|||
label={t("roleName")}
|
||||
fieldId="kc-name"
|
||||
isRequired
|
||||
validated={form!.errors.name ? "error" : "default"}
|
||||
validated={form.errors.name ? "error" : "default"}
|
||||
helperTextInvalid={t("common:required")}
|
||||
>
|
||||
<TextInput
|
||||
ref={form!.register({ required: true })}
|
||||
ref={form.register({ required: !editMode })}
|
||||
type="text"
|
||||
id="kc-name"
|
||||
name="name"
|
||||
|
@ -65,15 +48,15 @@ export const RoleForm = ({ form, save, editMode }: RoleFormType) => {
|
|||
label={t("description")}
|
||||
fieldId="kc-description"
|
||||
validated={
|
||||
form!.errors.description
|
||||
form.errors.description
|
||||
? ValidatedOptions.error
|
||||
: ValidatedOptions.default
|
||||
}
|
||||
helperTextInvalid={form!.errors.description?.message}
|
||||
helperTextInvalid={form.errors.description?.message}
|
||||
>
|
||||
<TextArea
|
||||
name="description"
|
||||
ref={form!.register({
|
||||
ref={form.register({
|
||||
maxLength: {
|
||||
value: 255,
|
||||
message: t("common:maxLength", { length: 255 }),
|
||||
|
@ -81,7 +64,7 @@ export const RoleForm = ({ form, save, editMode }: RoleFormType) => {
|
|||
})}
|
||||
type="text"
|
||||
validated={
|
||||
form!.errors.description
|
||||
form.errors.description
|
||||
? ValidatedOptions.error
|
||||
: ValidatedOptions.default
|
||||
}
|
||||
|
@ -92,131 +75,10 @@ export const RoleForm = ({ form, save, editMode }: RoleFormType) => {
|
|||
<Button variant="primary" type="submit">
|
||||
{t("common:save")}
|
||||
</Button>
|
||||
<Button variant="link" onClick={() => history.push(`/${realm}/roles`)}>
|
||||
<Button variant="link">
|
||||
{editMode ? t("common:reload") : t("common:cancel")}
|
||||
</Button>
|
||||
</ActionGroup>
|
||||
</FormAccess>
|
||||
);
|
||||
};
|
||||
|
||||
export const RealmRolesForm = () => {
|
||||
const { t } = useTranslation("roles");
|
||||
const form = useForm<RoleRepresentation>();
|
||||
const adminClient = useAdminClient();
|
||||
const { addAlert } = useAlerts();
|
||||
const history = useHistory();
|
||||
const { realm } = useRealm();
|
||||
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const [name, setName] = useState("");
|
||||
const [activeTab, setActiveTab] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
return asyncStateFetch(
|
||||
async () => {
|
||||
if (id) {
|
||||
const role = await adminClient.roles.findOneById({ id });
|
||||
return { role, name: role.name };
|
||||
} else {
|
||||
return { name: t("createRole") };
|
||||
}
|
||||
},
|
||||
({ role, name }) => {
|
||||
setName(name!);
|
||||
if (role) {
|
||||
setupForm(role);
|
||||
}
|
||||
}
|
||||
);
|
||||
}, []);
|
||||
|
||||
const setupForm = (role: RoleRepresentation) => {
|
||||
Object.entries(role).map((entry) => {
|
||||
form.setValue(entry[0], entry[1]);
|
||||
});
|
||||
};
|
||||
|
||||
const save = async (role: RoleRepresentation) => {
|
||||
try {
|
||||
if (id) {
|
||||
await adminClient.roles.updateById({ id }, role);
|
||||
} else {
|
||||
await adminClient.roles.create(role);
|
||||
const createdRole = await adminClient.roles.findOneByName({
|
||||
name: role.name!,
|
||||
});
|
||||
history.push(`/${realm}/roles/${createdRole.id}`);
|
||||
}
|
||||
addAlert(t(id ? "roleSaveSuccess" : "roleCreated"), AlertVariant.success);
|
||||
} catch (error) {
|
||||
addAlert(
|
||||
t((id ? "roleSave" : "roleCreate") + "Error", { error }),
|
||||
AlertVariant.danger
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
|
||||
titleKey: "roles:roleDeleteConfirm",
|
||||
messageKey: t("roles:roleDeleteConfirmDialog", { name }),
|
||||
continueButtonLabel: "common:delete",
|
||||
continueButtonVariant: ButtonVariant.danger,
|
||||
onConfirm: async () => {
|
||||
try {
|
||||
await adminClient.roles.delById({ id });
|
||||
addAlert(t("roleDeletedSuccess"), AlertVariant.success);
|
||||
history.push(`/${realm}/roles`);
|
||||
} catch (error) {
|
||||
addAlert(`${t("roleDeleteError")} ${error}`, AlertVariant.danger);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<DeleteConfirm />
|
||||
<ViewHeader
|
||||
titleKey={name}
|
||||
subKey={id ? "" : "roles:roleCreateExplain"}
|
||||
dropdownItems={
|
||||
id
|
||||
? [
|
||||
<DropdownItem
|
||||
key="action"
|
||||
component="button"
|
||||
onClick={() => toggleDeleteDialog()}
|
||||
>
|
||||
{t("deleteRole")}
|
||||
</DropdownItem>,
|
||||
]
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
|
||||
<PageSection variant="light">
|
||||
{id && (
|
||||
<Tabs
|
||||
activeKey={activeTab}
|
||||
onSelect={(_, key) => setActiveTab(key as number)}
|
||||
isBox
|
||||
>
|
||||
<Tab
|
||||
eventKey={0}
|
||||
title={<TabTitleText>{t("details")}</TabTitleText>}
|
||||
>
|
||||
<RoleForm form={form} save={save} editMode={true} />
|
||||
</Tab>
|
||||
<Tab
|
||||
eventKey={1}
|
||||
title={<TabTitleText>{t("attributes")}</TabTitleText>}
|
||||
>
|
||||
<RoleAttributes />
|
||||
</Tab>
|
||||
</Tabs>
|
||||
)}
|
||||
{!id && <RoleForm form={form} save={save} editMode={false} />}
|
||||
</PageSection>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,31 +1,52 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { useHistory, useParams } from "react-router-dom";
|
||||
import {
|
||||
ActionGroup,
|
||||
AlertVariant,
|
||||
Button,
|
||||
FormGroup,
|
||||
ButtonVariant,
|
||||
DropdownItem,
|
||||
PageSection,
|
||||
Tab,
|
||||
Tabs,
|
||||
TabTitleText,
|
||||
TextArea,
|
||||
TextInput,
|
||||
ValidatedOptions,
|
||||
} from "@patternfly/react-core";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { FormAccess } from "../components/form-access/FormAccess";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
import { useAlerts } from "../components/alert/Alerts";
|
||||
import { useAdminClient, asyncStateFetch } from "../context/auth/AdminClient";
|
||||
import { useAdminClient } from "../context/auth/AdminClient";
|
||||
import RoleRepresentation from "keycloak-admin/lib/defs/roleRepresentation";
|
||||
import { RoleAttributes } from "./RoleAttributes";
|
||||
import "./RealmRolesSection.css";
|
||||
import { KeyValueType, RoleAttributes } from "./RoleAttributes";
|
||||
import { ViewHeader } from "../components/view-header/ViewHeader";
|
||||
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
|
||||
import { RealmRoleForm } from "./RealmRoleForm";
|
||||
import { useRealm } from "../context/realm-context/RealmContext";
|
||||
|
||||
export const RolesTabs = () => {
|
||||
const arrayToAttributes = (attributeArray: KeyValueType[]) => {
|
||||
const initValue: { [index: string]: string[] } = {};
|
||||
return attributeArray.reduce((acc, attribute) => {
|
||||
acc[attribute.key] = [attribute.value];
|
||||
return acc;
|
||||
}, initValue);
|
||||
};
|
||||
|
||||
const attributesToArray = (attributes: { [key: string]: string }): any => {
|
||||
if (!attributes || Object.keys(attributes).length == 0) {
|
||||
return [
|
||||
{
|
||||
key: "",
|
||||
value: "",
|
||||
},
|
||||
];
|
||||
}
|
||||
return Object.keys(attributes).map((key) => ({
|
||||
key: key,
|
||||
value: attributes[key],
|
||||
}));
|
||||
};
|
||||
|
||||
export const RealmRoleTabs = () => {
|
||||
const { t } = useTranslation("roles");
|
||||
const { errors, control, setValue } = useForm<RoleRepresentation>();
|
||||
const form = useForm<RoleRepresentation>({ mode: "onChange" });
|
||||
const history = useHistory();
|
||||
const [name, setName] = useState("");
|
||||
const adminClient = useAdminClient();
|
||||
|
@ -37,116 +58,114 @@ export const RolesTabs = () => {
|
|||
const { addAlert } = useAlerts();
|
||||
|
||||
useEffect(() => {
|
||||
return asyncStateFetch(
|
||||
() => adminClient.roles.findOneById({ id }),
|
||||
(fetchedRole) => {
|
||||
(async () => {
|
||||
if (id) {
|
||||
const fetchedRole = await adminClient.roles.findOneById({ id });
|
||||
setName(fetchedRole.name!);
|
||||
setupForm(fetchedRole);
|
||||
} else {
|
||||
setName(t("createRole"));
|
||||
}
|
||||
);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
const setupForm = (role: RoleRepresentation) => {
|
||||
Object.entries(role).map((entry) => {
|
||||
setValue(entry[0], entry[1]);
|
||||
if (entry[0] === "attributes") {
|
||||
form.setValue(entry[0], attributesToArray(entry[1]));
|
||||
} else {
|
||||
form.setValue(entry[0], entry[1]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const save = async (role: RoleRepresentation) => {
|
||||
try {
|
||||
await adminClient.roles.updateById({ id }, role);
|
||||
setupForm(role as RoleRepresentation);
|
||||
addAlert(t("roleSaveSuccess"), AlertVariant.success);
|
||||
if (id) {
|
||||
if (role.attributes) {
|
||||
// react-hook-form will use `KeyValueType[]` here we convert it back into an indexed property of string[]
|
||||
role.attributes = arrayToAttributes(
|
||||
(role.attributes as unknown) as KeyValueType[]
|
||||
);
|
||||
}
|
||||
await adminClient.roles.updateById({ id }, role);
|
||||
} else {
|
||||
await adminClient.roles.create(role);
|
||||
const createdRole = await adminClient.roles.findOneByName({
|
||||
name: role.name!,
|
||||
});
|
||||
history.push(`/${realm}/roles/${createdRole.id}`);
|
||||
}
|
||||
addAlert(t(id ? "roleSaveSuccess" : "roleCreated"), AlertVariant.success);
|
||||
} catch (error) {
|
||||
addAlert(`${t("roleSaveError")} '${error}'`, AlertVariant.danger);
|
||||
addAlert(
|
||||
t((id ? "roleSave" : "roleCreate") + "Error", {
|
||||
error: error.response.data?.errorMessage || error,
|
||||
}),
|
||||
AlertVariant.danger
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const form = useForm<RoleRepresentation>();
|
||||
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
|
||||
titleKey: "roles:roleDeleteConfirm",
|
||||
messageKey: t("roles:roleDeleteConfirmDialog", { name }),
|
||||
continueButtonLabel: "common:delete",
|
||||
continueButtonVariant: ButtonVariant.danger,
|
||||
onConfirm: async () => {
|
||||
try {
|
||||
await adminClient.roles.delById({ id });
|
||||
addAlert(t("roleDeletedSuccess"), AlertVariant.success);
|
||||
history.replace(`/${realm}/roles`);
|
||||
} catch (error) {
|
||||
addAlert(`${t("roleDeleteError")} ${error}`, AlertVariant.danger);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tabs
|
||||
activeKey={activeTab}
|
||||
onSelect={(_, key) => setActiveTab(key as number)}
|
||||
isBox
|
||||
>
|
||||
<Tab eventKey={0} title={<TabTitleText>{t("details")}</TabTitleText>}>
|
||||
<FormAccess
|
||||
isHorizontal
|
||||
onSubmit={form.handleSubmit(save)}
|
||||
role="manage-realm"
|
||||
className="pf-u-mt-lg"
|
||||
<DeleteConfirm />
|
||||
<ViewHeader
|
||||
titleKey={name}
|
||||
subKey={id ? "" : "roles:roleCreateExplain"}
|
||||
dropdownItems={
|
||||
id
|
||||
? [
|
||||
<DropdownItem
|
||||
key="action"
|
||||
component="button"
|
||||
onClick={() => toggleDeleteDialog()}
|
||||
>
|
||||
{t("deleteRole")}
|
||||
</DropdownItem>,
|
||||
]
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
<PageSection variant="light">
|
||||
{id && (
|
||||
<Tabs
|
||||
activeKey={activeTab}
|
||||
onSelect={(_, key) => setActiveTab(key as number)}
|
||||
isBox
|
||||
>
|
||||
<FormGroup
|
||||
label={t("roleName")}
|
||||
fieldId="kc-name"
|
||||
isRequired
|
||||
validated={errors.name ? "error" : "default"}
|
||||
helperTextInvalid={t("common:required")}
|
||||
<Tab
|
||||
eventKey={0}
|
||||
title={<TabTitleText>{t("details")}</TabTitleText>}
|
||||
>
|
||||
{name ? (
|
||||
<TextInput
|
||||
ref={form.register({ required: true })}
|
||||
type="text"
|
||||
id="kc-name"
|
||||
name="name"
|
||||
isReadOnly
|
||||
/>
|
||||
) : undefined}
|
||||
</FormGroup>
|
||||
<FormGroup label={t("description")} fieldId="kc-description">
|
||||
<Controller
|
||||
name="description"
|
||||
defaultValue=""
|
||||
control={control}
|
||||
rules={{ maxLength: 255 }}
|
||||
render={({ onChange, value }) => (
|
||||
<TextArea
|
||||
type="text"
|
||||
validated={
|
||||
errors.description
|
||||
? ValidatedOptions.error
|
||||
: ValidatedOptions.default
|
||||
}
|
||||
id="kc-role-description"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</FormGroup>
|
||||
<ActionGroup>
|
||||
<Button variant="primary" type="submit">
|
||||
{t("common:save")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="link"
|
||||
onClick={() => history.push(`/${realm}/roles`)}
|
||||
>
|
||||
{t("common:reload")}
|
||||
</Button>
|
||||
</ActionGroup>
|
||||
</FormAccess>
|
||||
</Tab>
|
||||
<Tab
|
||||
eventKey={1}
|
||||
title={<TabTitleText>{t("attributes")}</TabTitleText>}
|
||||
>
|
||||
<RoleAttributes />
|
||||
<ActionGroup className="kc-role-attributes__action-group">
|
||||
<Button variant="primary" type="submit">
|
||||
{t("common:save")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="link"
|
||||
onClick={() => history.push(`/${realm}/roles`)}
|
||||
<RealmRoleForm form={form} save={save} editMode={true} />
|
||||
</Tab>
|
||||
<Tab
|
||||
eventKey={1}
|
||||
title={<TabTitleText>{t("attributes")}</TabTitleText>}
|
||||
>
|
||||
{t("common:reload")}
|
||||
</Button>
|
||||
</ActionGroup>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
<RoleAttributes form={form} save={save} />
|
||||
</Tab>
|
||||
</Tabs>
|
||||
)}
|
||||
{!id && <RealmRoleForm form={form} save={save} editMode={false} />}
|
||||
</PageSection>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -9,9 +9,16 @@
|
|||
margin-left: calc(var(--pf-global--spacer--md) * -1);
|
||||
}
|
||||
|
||||
.pf-c-button.kc-role-attributes__minus-icon {
|
||||
/* shift the button left to adjust for table cell padding */
|
||||
margin-left: calc(var(--pf-global--spacer--md) * -1);
|
||||
color: var(--pf-c-button--m-plain--Color);
|
||||
}
|
||||
|
||||
.kc-role-attributes__action-group {
|
||||
/* subtract the padding at the bottom of the table from the action group margin */
|
||||
--pf-c-form__group--m-action--MarginTop: calc(
|
||||
var(--pf-global--spacer--2xl) - var(--pf-global--spacer--sm)
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,11 @@
|
|||
{
|
||||
"name":"Admin",
|
||||
"composite":true,
|
||||
"description": "Lorem ipsum dolor sit amet"
|
||||
"description": "Lorem ipsum dolor sit amet",
|
||||
"attributes": {
|
||||
"key input 1": "value input 1",
|
||||
"key input 2": "value input 2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name":"Author",
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
{
|
||||
"roles": {
|
||||
"attributes": "Attributes",
|
||||
<<<<<<< HEAD
|
||||
"addAttributeText": "Add an attribute",
|
||||
=======
|
||||
>>>>>>> add role attributes, WIP
|
||||
"deleteAttributeText": "Delete an attribute",
|
||||
"title": "Realm roles",
|
||||
"createRole": "Create role",
|
||||
"importRole": "Import role",
|
||||
|
|
|
@ -11,7 +11,6 @@ import { EventsSection } from "./events/EventsSection";
|
|||
import { GroupsSection } from "./groups/GroupsSection";
|
||||
import { IdentityProvidersSection } from "./identity-providers/IdentityProvidersSection";
|
||||
import { PageNotFoundSection } from "./PageNotFoundSection";
|
||||
import { RealmRolesForm } from "./realm-roles/RealmRoleForm";
|
||||
import { RealmRolesSection } from "./realm-roles/RealmRolesSection";
|
||||
import { RealmSettingsSection } from "./realm-settings/RealmSettingsSection";
|
||||
import { NewRealmForm } from "./realm/add/NewRealmForm";
|
||||
|
@ -24,6 +23,7 @@ import { UserFederationKerberosSettings } from "./user-federation/UserFederation
|
|||
import { UserFederationLdapSettings } from "./user-federation/UserFederationLdapSettings";
|
||||
import { RoleMappingForm } from "./client-scopes/add/RoleMappingForm";
|
||||
import { BreadcrumbsRoute } from "use-react-router-breadcrumbs";
|
||||
import { RealmRoleTabs } from "./realm-roles/RealmRoleTabs";
|
||||
|
||||
export type RouteDef = BreadcrumbsRoute & {
|
||||
component: () => JSX.Element;
|
||||
|
@ -107,13 +107,13 @@ export const routes: RoutesFn = (t) => [
|
|||
},
|
||||
{
|
||||
path: "/:realm/roles/add-role",
|
||||
component: RealmRolesForm,
|
||||
component: RealmRoleTabs,
|
||||
breadcrumb: t("roles:createRole"),
|
||||
access: "manage-realm",
|
||||
},
|
||||
{
|
||||
path: "/:realm/roles/:id",
|
||||
component: RealmRolesForm,
|
||||
component: RealmRoleTabs,
|
||||
breadcrumb: t("roles:roleDetails"),
|
||||
access: "view-realm",
|
||||
},
|
||||
|
|
|
@ -3,19 +3,19 @@ import { Meta } from "@storybook/react";
|
|||
import { MockAdminClient } from "./MockAdminClient";
|
||||
import { MemoryRouter, Route } from "react-router-dom";
|
||||
import rolesMock from "../realm-roles/__tests__/mock-roles.json";
|
||||
import { RolesTabs } from "../realm-roles/RealmRoleTabs";
|
||||
import { RealmRoleTabs } from "../realm-roles/RealmRoleTabs";
|
||||
|
||||
export default {
|
||||
title: "Roles tabs",
|
||||
component: RolesTabs,
|
||||
component: RealmRoleTabs,
|
||||
} as Meta;
|
||||
|
||||
export const RoleTabsExample = () => {
|
||||
export const RolesTabsExample = () => {
|
||||
return (
|
||||
<MockAdminClient mock={{ roles: { findOneById: () => rolesMock[0] } }}>
|
||||
<MemoryRouter initialEntries={["/roles/1"]}>
|
||||
<Route path="/roles/:id">
|
||||
<RolesTabs />
|
||||
<RealmRoleTabs />
|
||||
</Route>
|
||||
</MemoryRouter>
|
||||
</MockAdminClient>
|
||||
|
|
|
@ -3,18 +3,18 @@ import { Page } from "@patternfly/react-core";
|
|||
import { Meta } from "@storybook/react";
|
||||
|
||||
import { MockAdminClient } from "./MockAdminClient";
|
||||
import { RealmRolesForm } from "../realm-roles/RealmRoleForm";
|
||||
import { RealmRoleTabs } from "../realm-roles/RealmRoleTabs";
|
||||
|
||||
export default {
|
||||
title: "New role form",
|
||||
component: RealmRolesForm,
|
||||
component: RealmRoleTabs,
|
||||
} as Meta;
|
||||
|
||||
export const View = () => {
|
||||
return (
|
||||
<Page>
|
||||
<MockAdminClient>
|
||||
<RealmRolesForm />
|
||||
<RealmRoleTabs />
|
||||
</MockAdminClient>
|
||||
</Page>
|
||||
);
|
||||
|
|
|
@ -19351,9 +19351,9 @@ use-latest@^1.0.0:
|
|||
dependencies:
|
||||
use-isomorphic-layout-effect "^1.0.0"
|
||||
|
||||
use-react-router-breadcrumbs@^1.0.4:
|
||||
use-react-router-breadcrumbs@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/use-react-router-breadcrumbs/-/use-react-router-breadcrumbs-1.0.5.tgz#3b39a2c2a6ab72544c2fc8984f6825d0f1122877"
|
||||
resolved "https://registry.npmjs.org/use-react-router-breadcrumbs/-/use-react-router-breadcrumbs-1.0.5.tgz#3b39a2c2a6ab72544c2fc8984f6825d0f1122877"
|
||||
integrity sha512-NDMgWr5MdksqnATRvp84RtZ0ABfuztlsgR4VWlsBV0D3TVV6xhbmkhTdV3cWnyRIZqNlMXZhwJhyRHoC6fbAsQ==
|
||||
|
||||
use-sidecar@^1.0.1:
|
||||
|
|
Loading…
Reference in a new issue