initial version of the client settings page (#89)
* initial version of the client settings page * fix test * fixed spelling * merge errors * fix merge error * renamed Step1 and Step2
This commit is contained in:
parent
c656d6acee
commit
0f1d93d672
12 changed files with 1710 additions and 55 deletions
|
@ -22,6 +22,7 @@ import { UserFederationSection } from "./user-federation/UserFederationSection";
|
||||||
|
|
||||||
import { PageNotFoundSection } from "./PageNotFoundSection";
|
import { PageNotFoundSection } from "./PageNotFoundSection";
|
||||||
import { RealmContextProvider } from "./components/realm-context/RealmContext";
|
import { RealmContextProvider } from "./components/realm-context/RealmContext";
|
||||||
|
import { ClientSettings } from "./clients/ClientSettings";
|
||||||
|
|
||||||
export const App = () => {
|
export const App = () => {
|
||||||
return (
|
return (
|
||||||
|
@ -33,6 +34,11 @@ export const App = () => {
|
||||||
<Route exact path="/add-realm" component={NewRealmForm}></Route>
|
<Route exact path="/add-realm" component={NewRealmForm}></Route>
|
||||||
|
|
||||||
<Route exact path="/clients" component={ClientsSection}></Route>
|
<Route exact path="/clients" component={ClientsSection}></Route>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
path="/client-settings"
|
||||||
|
component={ClientSettings}
|
||||||
|
></Route>
|
||||||
<Route exact path="/add-client" component={NewClientForm}></Route>
|
<Route exact path="/add-client" component={NewClientForm}></Route>
|
||||||
<Route exact path="/import-client" component={ImportForm}></Route>
|
<Route exact path="/import-client" component={ImportForm}></Route>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { useContext } from "react";
|
import React, { useContext } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
|
@ -41,11 +42,11 @@ export const ClientList = ({ baseUrl, clients }: ClientListProps) => {
|
||||||
const field = data!.toString();
|
const field = data!.toString();
|
||||||
const value = convertClientId(field);
|
const value = convertClientId(field);
|
||||||
return field.indexOf("true") !== -1 ? (
|
return field.indexOf("true") !== -1 ? (
|
||||||
<>{value}</>
|
<Link to="client-settings">{value}</Link>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<Link to="client-settings">
|
||||||
{value} <Badge isRead>Disabled</Badge>
|
{value} <Badge isRead>Disabled</Badge>
|
||||||
</>
|
</Link>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -60,12 +61,18 @@ export const ClientList = ({ baseUrl, clients }: ClientListProps) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* eslint-disable no-template-curly-in-string */
|
/* eslint-disable no-template-curly-in-string */
|
||||||
const replaceBaseUrl = (r: ClientRepresentation) =>
|
const replaceBaseUrl = (r: ClientRepresentation) => {
|
||||||
r.rootUrl &&
|
if (r.rootUrl) {
|
||||||
|
if (!r.rootUrl.startsWith("http") || r.rootUrl.indexOf("$") !== -1) {
|
||||||
|
r.rootUrl =
|
||||||
r.rootUrl
|
r.rootUrl
|
||||||
.replace("${authBaseUrl}", baseUrl)
|
.replace("${authBaseUrl}", baseUrl)
|
||||||
.replace("${authAdminUrl}", baseUrl) +
|
.replace("${authAdminUrl}", baseUrl) +
|
||||||
(r.baseUrl ? r.baseUrl.substr(1) : "");
|
(r.baseUrl ? r.baseUrl.substr(1) : "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r.rootUrl;
|
||||||
|
};
|
||||||
|
|
||||||
const data = clients!
|
const data = clients!
|
||||||
.map((r) => {
|
.map((r) => {
|
||||||
|
@ -120,7 +127,7 @@ export const ClientList = ({ baseUrl, clients }: ClientListProps) => {
|
||||||
httpClient.doDelete(
|
httpClient.doDelete(
|
||||||
`/admin/realms/${realm}/clients/${data[rowId].client.id}`
|
`/admin/realms/${realm}/clients/${data[rowId].client.id}`
|
||||||
);
|
);
|
||||||
add(t("clientDeletedSucess"), AlertVariant.success);
|
add(t("clientDeletedSuccess"), AlertVariant.success);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
add(`${t("clientDeleteError")} ${error}`, AlertVariant.danger);
|
add(`${t("clientDeleteError")} ${error}`, AlertVariant.danger);
|
||||||
}
|
}
|
||||||
|
|
137
src/clients/ClientSettings.tsx
Normal file
137
src/clients/ClientSettings.tsx
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
import React, { useState, FormEvent } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import {
|
||||||
|
FormGroup,
|
||||||
|
TextInput,
|
||||||
|
Form,
|
||||||
|
Dropdown,
|
||||||
|
DropdownToggle,
|
||||||
|
DropdownItem,
|
||||||
|
Switch,
|
||||||
|
TextArea,
|
||||||
|
PageSection,
|
||||||
|
} from "@patternfly/react-core";
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
|
||||||
|
import { ScrollForm } from "../components/scroll-form/ScrollForm";
|
||||||
|
import { ClientDescription } from "./ClientDescription";
|
||||||
|
import { ClientRepresentation } from "./models/client-model";
|
||||||
|
import { CapabilityConfig } from "./add/CapabilityConfig";
|
||||||
|
|
||||||
|
type ClientSettingsProps = {
|
||||||
|
client: ClientRepresentation;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ClientSettings = ({ client: clientInit }: ClientSettingsProps) => {
|
||||||
|
const { t } = useTranslation("clients");
|
||||||
|
const [client, setClient] = useState({ ...clientInit });
|
||||||
|
const form = useForm();
|
||||||
|
const onChange = (
|
||||||
|
value: string | boolean,
|
||||||
|
event: FormEvent<HTMLInputElement>
|
||||||
|
) => {
|
||||||
|
const target = event.target;
|
||||||
|
const name = (target as HTMLInputElement).name;
|
||||||
|
|
||||||
|
setClient({
|
||||||
|
...client,
|
||||||
|
[name]: value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<PageSection>
|
||||||
|
<ScrollForm
|
||||||
|
sections={[
|
||||||
|
t("capabilityConfig"),
|
||||||
|
t("generalSettings"),
|
||||||
|
t("accessSettings"),
|
||||||
|
t("loginSettings"),
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Form isHorizontal>
|
||||||
|
<CapabilityConfig form={form} />
|
||||||
|
</Form>
|
||||||
|
<Form isHorizontal>
|
||||||
|
<ClientDescription register={form.register} />
|
||||||
|
</Form>
|
||||||
|
<Form isHorizontal>
|
||||||
|
<FormGroup label={t("rootUrl")} fieldId="kc-root-url">
|
||||||
|
<TextInput
|
||||||
|
type="text"
|
||||||
|
id="kc-root-url"
|
||||||
|
name="rootUrl"
|
||||||
|
value={client.rootUrl}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup label={t("validRedirectUri")} fieldId="kc-redirect">
|
||||||
|
<TextInput
|
||||||
|
type="text"
|
||||||
|
id="kc-redirect"
|
||||||
|
name="redirectUris"
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup label={t("homeURL")} fieldId="kc-home-url">
|
||||||
|
<TextInput
|
||||||
|
type="text"
|
||||||
|
id="kc-home-url"
|
||||||
|
name="baseUrl"
|
||||||
|
value={client.baseUrl}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</Form>
|
||||||
|
<Form isHorizontal>
|
||||||
|
<FormGroup label={t("loginTheme")} fieldId="kc-login-theme">
|
||||||
|
<Dropdown
|
||||||
|
id="kc-login-theme"
|
||||||
|
toggle={
|
||||||
|
<DropdownToggle id="toggle-id" onToggle={() => {}}>
|
||||||
|
{t("loginTheme")}
|
||||||
|
</DropdownToggle>
|
||||||
|
}
|
||||||
|
dropdownItems={[
|
||||||
|
<DropdownItem key="link">Link</DropdownItem>,
|
||||||
|
<DropdownItem key="action" component="button" />,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup label={t("consentRequired")} fieldId="kc-consent">
|
||||||
|
<Switch
|
||||||
|
id="kc-consent"
|
||||||
|
name="consentRequired"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={client.consentRequired}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("displayOnClient")}
|
||||||
|
fieldId="kc-display-on-client"
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
id="kc-display-on-client"
|
||||||
|
name="alwaysDisplayInConsole"
|
||||||
|
label={t("common:on")}
|
||||||
|
labelOff={t("common:off")}
|
||||||
|
isChecked={client.alwaysDisplayInConsole}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup
|
||||||
|
label={t("consentScreenText")}
|
||||||
|
fieldId="kc-consent-screen-text"
|
||||||
|
>
|
||||||
|
<TextArea
|
||||||
|
id="kc-consent-screen-text"
|
||||||
|
name="consentText"
|
||||||
|
//value={client.protocolMappers![0].consentText}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</Form>
|
||||||
|
</ScrollForm>
|
||||||
|
</PageSection>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,17 +1,15 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { MemoryRouter } from "react-router-dom";
|
||||||
import { render } from "@testing-library/react";
|
import { render } from "@testing-library/react";
|
||||||
|
|
||||||
import clientMock from "./mock-clients.json";
|
import clientMock from "./mock-clients.json";
|
||||||
import { I18nextProvider } from "react-i18next";
|
|
||||||
import i18n from "../../i18n";
|
|
||||||
import { ClientList } from "../ClientList";
|
import { ClientList } from "../ClientList";
|
||||||
|
|
||||||
test("renders ClientList", () => {
|
test("renders ClientList", () => {
|
||||||
const { getByText } = render(
|
const container = render(
|
||||||
<I18nextProvider i18n={i18n}>
|
<MemoryRouter>
|
||||||
<ClientList clients={clientMock} baseUrl="http://blog.nerdin.ch" />
|
<ClientList clients={clientMock} baseUrl="http://blog.nerdin.ch" />
|
||||||
</I18nextProvider>
|
</MemoryRouter>
|
||||||
);
|
);
|
||||||
const headerElement = getByText(/Client ID/i);
|
expect(container).toMatchSnapshot();
|
||||||
expect(headerElement).toBeInTheDocument();
|
|
||||||
});
|
});
|
||||||
|
|
1509
src/clients/__tests__/__snapshots__/ClientList.test.tsx.snap
Normal file
1509
src/clients/__tests__/__snapshots__/ClientList.test.tsx.snap
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import {
|
import {
|
||||||
FormGroup,
|
FormGroup,
|
||||||
Switch,
|
Switch,
|
||||||
|
@ -8,13 +9,12 @@ import {
|
||||||
Form,
|
Form,
|
||||||
} from "@patternfly/react-core";
|
} from "@patternfly/react-core";
|
||||||
import { UseFormMethods, Controller } from "react-hook-form";
|
import { UseFormMethods, Controller } from "react-hook-form";
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
|
|
||||||
type Step2Props = {
|
type CapabilityConfigProps = {
|
||||||
form: UseFormMethods;
|
form: UseFormMethods;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Step2 = ({ form }: Step2Props) => {
|
export const CapabilityConfig = ({ form }: CapabilityConfigProps) => {
|
||||||
const { t } = useTranslation("clients");
|
const { t } = useTranslation("clients");
|
||||||
return (
|
return (
|
||||||
<Form isHorizontal>
|
<Form isHorizontal>
|
||||||
|
@ -34,13 +34,13 @@ export const Step2 = ({ form }: Step2Props) => {
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup label={t("authentication")} fieldId="kc-authorisation">
|
<FormGroup label={t("clientAuthorization")} fieldId="kc-authorization">
|
||||||
<Controller
|
<Controller
|
||||||
name="authorizationServicesEnabled"
|
name="authorizationServicesEnabled"
|
||||||
control={form.control}
|
control={form.control}
|
||||||
render={({ onChange, value }) => (
|
render={({ onChange, value }) => (
|
||||||
<Switch
|
<Switch
|
||||||
id="kc-authorisation"
|
id="kc-authorization"
|
||||||
name="authorizationServicesEnabled"
|
name="authorizationServicesEnabled"
|
||||||
label={t("common:on")}
|
label={t("common:on")}
|
||||||
labelOff={t("common:off")}
|
labelOff={t("common:off")}
|
||||||
|
@ -59,7 +59,6 @@ export const Step2 = ({ form }: Step2Props) => {
|
||||||
render={({ onChange, value }) => (
|
render={({ onChange, value }) => (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={t("standardFlow")}
|
label={t("standardFlow")}
|
||||||
aria-label={t("enableStandardFlow")}
|
|
||||||
id="kc-flow-standard"
|
id="kc-flow-standard"
|
||||||
name="standardFlowEnabled"
|
name="standardFlowEnabled"
|
||||||
isChecked={value}
|
isChecked={value}
|
||||||
|
@ -75,7 +74,6 @@ export const Step2 = ({ form }: Step2Props) => {
|
||||||
render={({ onChange, value }) => (
|
render={({ onChange, value }) => (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={t("directAccess")}
|
label={t("directAccess")}
|
||||||
aria-label={t("enableDirectAccess")}
|
|
||||||
id="kc-flow-direct"
|
id="kc-flow-direct"
|
||||||
name="directAccessGrantsEnabled"
|
name="directAccessGrantsEnabled"
|
||||||
isChecked={value}
|
isChecked={value}
|
||||||
|
@ -90,9 +88,8 @@ export const Step2 = ({ form }: Step2Props) => {
|
||||||
control={form.control}
|
control={form.control}
|
||||||
render={({ onChange, value }) => (
|
render={({ onChange, value }) => (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={t("implicidFlow")}
|
label={t("implicitFlow")}
|
||||||
aria-label={t("enableImplicidFlow")}
|
id="kc-flow-implicit"
|
||||||
id="kc-flow-implicid"
|
|
||||||
name="implicitFlowEnabled"
|
name="implicitFlowEnabled"
|
||||||
isChecked={value}
|
isChecked={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
@ -107,7 +104,6 @@ export const Step2 = ({ form }: Step2Props) => {
|
||||||
render={({ onChange, value }) => (
|
render={({ onChange, value }) => (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={t("serviceAccount")}
|
label={t("serviceAccount")}
|
||||||
aria-label={t("enableServiceAccount")}
|
|
||||||
id="kc-flow-service-account"
|
id="kc-flow-service-account"
|
||||||
name="serviceAccountsEnabled"
|
name="serviceAccountsEnabled"
|
||||||
isChecked={value}
|
isChecked={value}
|
|
@ -14,11 +14,11 @@ import { sortProvider } from "../../util";
|
||||||
import { ServerInfoRepresentation } from "../models/server-info";
|
import { ServerInfoRepresentation } from "../models/server-info";
|
||||||
import { ClientDescription } from "../ClientDescription";
|
import { ClientDescription } from "../ClientDescription";
|
||||||
|
|
||||||
type Step1Props = {
|
type GeneralSettingsProps = {
|
||||||
form: UseFormMethods;
|
form: UseFormMethods;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Step1 = ({ form }: Step1Props) => {
|
export const GeneralSettings = ({ form }: GeneralSettingsProps) => {
|
||||||
const httpClient = useContext(HttpClientContext)!;
|
const httpClient = useContext(HttpClientContext)!;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { errors, control, register } = form;
|
const { errors, control, register } = form;
|
|
@ -15,8 +15,8 @@ import { useTranslation } from "react-i18next";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
|
||||||
import { HttpClientContext } from "../../http-service/HttpClientContext";
|
import { HttpClientContext } from "../../http-service/HttpClientContext";
|
||||||
import { Step1 } from "./Step1";
|
import { GeneralSettings } from "./GeneralSettings";
|
||||||
import { Step2 } from "./Step2";
|
import { CapabilityConfig } from "./CapabilityConfig";
|
||||||
import { ClientRepresentation } from "../models/client-model";
|
import { ClientRepresentation } from "../models/client-model";
|
||||||
import { useAlerts } from "../../components/alert/Alerts";
|
import { useAlerts } from "../../components/alert/Alerts";
|
||||||
import { RealmContext } from "../../components/realm-context/RealmContext";
|
import { RealmContext } from "../../components/realm-context/RealmContext";
|
||||||
|
@ -110,11 +110,11 @@ export const NewClientForm = () => {
|
||||||
steps={[
|
steps={[
|
||||||
{
|
{
|
||||||
name: t("generalSettings"),
|
name: t("generalSettings"),
|
||||||
component: <Step1 form={methods} />,
|
component: <GeneralSettings form={methods} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: t("capabilityConfig"),
|
name: t("capabilityConfig"),
|
||||||
component: <Step2 form={methods} />,
|
component: <CapabilityConfig form={methods} />,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
footer={<Footer />}
|
footer={<Footer />}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
{
|
{
|
||||||
"clients": {
|
"clients": {
|
||||||
|
"clientAuthorization": "Client authorization",
|
||||||
|
"implicitFlow": "Implicit flow",
|
||||||
"createClient": "Create client",
|
"createClient": "Create client",
|
||||||
"importClient": "Import client",
|
"importClient": "Import client",
|
||||||
"clientID": "Client ID",
|
"clientID": "Client ID",
|
||||||
|
@ -12,19 +14,23 @@
|
||||||
"capabilityConfig": "Capability config",
|
"capabilityConfig": "Capability config",
|
||||||
"clientsExplain": "Clients are applications and services that can request authentication of a user",
|
"clientsExplain": "Clients are applications and services that can request authentication of a user",
|
||||||
"clientImportError": "Could not import client",
|
"clientImportError": "Could not import client",
|
||||||
"clientImportSuccess": "Client imported succeful",
|
"clientImportSuccess": "Client imported successful",
|
||||||
"clientDeletedSucess": "The client has been deleted",
|
"clientDeletedSuccess": "The client has been deleted",
|
||||||
"clientDeleteError": "Could not delete client:",
|
"clientDeleteError": "Could not delete client:",
|
||||||
"clientAuthentication": "Client authentication",
|
"clientAuthentication": "Client authentication",
|
||||||
"authentication": "Authentication",
|
"authentication": "Authentication",
|
||||||
"authenticationFlow": "Authentication flow",
|
"authenticationFlow": "Authentication flow",
|
||||||
"standardFlow": "Standard flow",
|
"standardFlow": "Standard flow",
|
||||||
"enableStandardFlow": "Enable standard flow",
|
|
||||||
"directAccess": "Direct access",
|
"directAccess": "Direct access",
|
||||||
"enableDirectAccess": "Enable direct access",
|
|
||||||
"implicidFlow": "Implicid flow",
|
|
||||||
"enableImplicidFlow": "Enable implicid flow",
|
|
||||||
"serviceAccount": "Service account",
|
"serviceAccount": "Service account",
|
||||||
"enableServiceAccount": "Enable service account"
|
"enableServiceAccount": "Enable service account",
|
||||||
|
"displayOnClient": "Display client on screen",
|
||||||
|
"consentScreenText": "Client consent screen text",
|
||||||
|
"loginSettings": "Login settings",
|
||||||
|
"accessSettings": "Access settings",
|
||||||
|
"rootUrl": "Root URL",
|
||||||
|
"validRedirectUri": "Valid redirect URIs",
|
||||||
|
"loginTheme": "Login theme",
|
||||||
|
"consentRequired": "Consent required"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { Children, useEffect, useState } from "react";
|
import React, { Children, useEffect, useState } from "react";
|
||||||
import { Form, Grid, GridItem, Title } from "@patternfly/react-core";
|
import { Grid, GridItem, Title } from "@patternfly/react-core";
|
||||||
|
|
||||||
import { FormPanel } from "./FormPanel";
|
import { FormPanel } from "./FormPanel";
|
||||||
import style from "./scroll-form.module.css";
|
import style from "./scroll-form.module.css";
|
||||||
|
@ -70,13 +70,11 @@ export const ScrollForm = ({ sections, children }: ScrollFormProps) => {
|
||||||
<>
|
<>
|
||||||
<Grid hasGutter>
|
<Grid hasGutter>
|
||||||
<GridItem span={8}>
|
<GridItem span={8}>
|
||||||
<Form>
|
|
||||||
{sections.map((cat, index) => (
|
{sections.map((cat, index) => (
|
||||||
<FormPanel id={cat} key={cat} title={cat}>
|
<FormPanel id={cat} key={cat} title={cat}>
|
||||||
{nodes[index]}
|
{nodes[index]}
|
||||||
</FormPanel>
|
</FormPanel>
|
||||||
))}
|
))}
|
||||||
</Form>
|
|
||||||
</GridItem>
|
</GridItem>
|
||||||
<GridItem span={4}>
|
<GridItem span={4}>
|
||||||
<Nav />
|
<Nav />
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
padding: 24px;
|
padding-top: 24px;
|
||||||
border-style: solid;
|
padding-bottom: 48px;
|
||||||
border-color: var(--pf-global--BorderColor--100);
|
|
||||||
border-width: var(--pf-global--BorderWidth--sm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
padding-bottom: 8px;
|
padding-bottom: 24px;
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
.sticky {
|
.sticky {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50px;
|
top: 100px;
|
||||||
}
|
}
|
Loading…
Reference in a new issue