forked from freeipa/freeipa-webui
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The 'General' section from 'Sudo rules' > 'Settings' should show information about the rule name, sudo order, and description (if any). At the same time, it should include the action buttons functionality ('Refresh', 'Revert', and 'Save'). Signed-off-by: Carla Martinez <[email protected]>
- Loading branch information
Showing
8 changed files
with
519 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import React from "react"; | ||
// PatternFly | ||
import { | ||
HelperText, | ||
HelperTextItem, | ||
NumberInput, | ||
} from "@patternfly/react-core"; | ||
// IPA Object | ||
import { | ||
getParamProperties, | ||
IPAParamDefinition, | ||
} from "src/utils/ipaObjectUtils"; | ||
|
||
/** | ||
* Interface for the IPA Number Input | ||
* @param {string} className - The class name for the input (Optional. Default: "") | ||
* @param {number} numCharsShown - The number of characters shown in the input (Optional. Default: 1) | ||
* @param {number} minValue - The minimum value allowed (Optional) | ||
* @param {number} maxValue - The maximum value allowed (Optional) | ||
* @param {IPAParamDefinition} IPAParamDefinition - IPA Object parameters | ||
* @returns {React.ReactNode} The IPA Number Input component | ||
* | ||
*/ | ||
|
||
interface IPAParamDefinitionNumberInput extends IPAParamDefinition { | ||
className?: string; | ||
numCharsShown?: number; | ||
minValue?: number; | ||
maxValue?: number; | ||
} | ||
|
||
const IpaNumberInput = (props: IPAParamDefinitionNumberInput) => { | ||
const { readOnly, value, onChange } = getParamProperties(props); | ||
|
||
const numberValue = value as number; | ||
|
||
const [isError, setIsError] = React.useState(false); | ||
const [errorMessage, setErrorMessage] = React.useState(""); | ||
|
||
const normalizeBetween = (value, min, max) => { | ||
if (min !== undefined && max !== undefined) { | ||
return Math.max(Math.min(value, max), min); | ||
} else if (value <= min) { | ||
return min; | ||
} else if (value >= max) { | ||
return max; | ||
} | ||
return value; | ||
}; | ||
|
||
const onMinus = () => { | ||
const newValue = normalizeBetween( | ||
(value as number) - 1, | ||
props.minValue, | ||
props.maxValue | ||
); | ||
onChange(newValue); | ||
}; | ||
|
||
const onChangeHandler = (event: React.FormEvent<HTMLInputElement>) => { | ||
const value = (event.target as HTMLInputElement).value; | ||
onChange(value === "" ? value : +value); | ||
|
||
// Return to max and min values if the input is beyond those values | ||
if (props.minValue && +value < props.minValue) { | ||
onChange(props.minValue); | ||
} else if (props.maxValue && +value > props.maxValue) { | ||
onChange(props.maxValue); | ||
} | ||
|
||
// Show error message if other characters are entered | ||
if (isNaN(+value) || /[a-zA-Z]/.test(value)) { | ||
onChange(value as string); | ||
setIsError(true); | ||
setErrorMessage("Only numbers are allowed."); | ||
return; | ||
} | ||
}; | ||
|
||
const onBlur = (event: React.FocusEvent<HTMLInputElement>) => { | ||
const blurVal = +event.target.value; | ||
|
||
if (props.minValue && blurVal < props.minValue) { | ||
onChange(props.minValue); | ||
} else if (props.maxValue && blurVal > props.maxValue) { | ||
onChange(props.maxValue); | ||
} | ||
}; | ||
|
||
const onPlus = () => { | ||
const newValue = normalizeBetween( | ||
(value as number) + 1, | ||
props.minValue, | ||
props.maxValue | ||
); | ||
onChange(newValue); | ||
}; | ||
|
||
return ( | ||
<> | ||
<NumberInput | ||
value={numberValue} | ||
onMinus={onMinus} | ||
onChange={onChangeHandler} | ||
min={props.minValue} | ||
max={props.maxValue} | ||
onBlur={onBlur} | ||
onPlus={onPlus} | ||
inputName="input" | ||
inputAriaLabel="number input" | ||
minusBtnAriaLabel="minus" | ||
plusBtnAriaLabel="plus" | ||
isDisabled={readOnly} | ||
widthChars={props.numCharsShown || 1} | ||
className={props.className || ""} | ||
/> | ||
{isError && ( | ||
<HelperText> | ||
<HelperTextItem>{errorMessage}</HelperTextItem> | ||
</HelperText> | ||
)} | ||
</> | ||
); | ||
}; | ||
|
||
export default IpaNumberInput; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import React from "react"; | ||
// PatternFly | ||
import { Form, FormGroup } from "@patternfly/react-core"; | ||
// Ipa Components | ||
import IpaTextInput from "../Form/IpaTextInput"; | ||
import IpaTextArea from "../Form/IpaTextArea"; | ||
import IpaNumberInput from "../Form/IpaNumberInput"; | ||
// Data types | ||
import { Metadata } from "src/utils/datatypes/globalDataTypes"; | ||
|
||
interface PropsToSudoRuleGeneral { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
ipaObject: Record<string, any>; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
recordOnChange: (ipaObject: Record<string, any>) => void; | ||
metadata: Metadata; | ||
} | ||
|
||
const SudoRuleGeneral = (props: PropsToSudoRuleGeneral) => { | ||
return ( | ||
<Form className="pf-v5-u-mt-sm pf-v5-u-mb-lg pf-v5-u-mr-md" isHorizontal> | ||
<FormGroup label="Rule name" fieldId="rule-name"> | ||
<IpaTextInput | ||
name="cn" | ||
aria-label="rule name" | ||
ipaObject={props.ipaObject} | ||
onChange={props.recordOnChange} | ||
objectName="sudorule" | ||
metadata={props.metadata} | ||
/> | ||
</FormGroup> | ||
<FormGroup label="Sudo order" fieldId="sudo-order"> | ||
<IpaNumberInput | ||
name="sudoorder" | ||
aria-label="sudo order" | ||
ipaObject={props.ipaObject} | ||
onChange={props.recordOnChange} | ||
objectName="sudorule" | ||
metadata={props.metadata} | ||
numCharsShown={15} | ||
minValue={0} | ||
maxValue={2147483647} | ||
/> | ||
</FormGroup> | ||
<FormGroup label="Description" fieldId="description"> | ||
<IpaTextArea | ||
name="description" | ||
ipaObject={props.ipaObject} | ||
onChange={props.recordOnChange} | ||
objectName="sudorule" | ||
metadata={props.metadata} | ||
/> | ||
</FormGroup> | ||
</Form> | ||
); | ||
}; | ||
|
||
export default SudoRuleGeneral; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import React from "react"; | ||
// PatternFly | ||
import { | ||
JumpLinks, | ||
JumpLinksItem, | ||
Sidebar, | ||
SidebarContent, | ||
SidebarPanel, | ||
TextVariants, | ||
} from "@patternfly/react-core"; | ||
import HelpTextWithIconLayout from "./HelpTextWithIconLayout"; | ||
// Icons | ||
import OutlinedQuestionCircleIcon from "@patternfly/react-icons/dist/esm/icons/outlined-question-circle-icon"; | ||
|
||
interface SidebarLayoutProps { | ||
itemNames: string[]; | ||
children: React.ReactNode; | ||
} | ||
|
||
const SidebarLayout = (props: SidebarLayoutProps) => { | ||
// Utility functions | ||
const parseNameToId = (name: string) => { | ||
return name.toLowerCase().replace(/ /g, "-"); | ||
}; | ||
|
||
// Render component | ||
return ( | ||
<> | ||
<Sidebar isPanelRight> | ||
<SidebarPanel variant="sticky"> | ||
<HelpTextWithIconLayout | ||
textComponent={TextVariants.p} | ||
textClassName="pf-v5-u-mb-md" | ||
subTextComponent={TextVariants.a} | ||
subTextIsVisitedLink={true} | ||
textContent="Help" | ||
icon={ | ||
<OutlinedQuestionCircleIcon className="pf-v5-u-primary-color-100 pf-v5-u-mr-sm" /> | ||
} | ||
/> | ||
<JumpLinks | ||
isVertical | ||
label="Jump to section" | ||
scrollableSelector="#settings-page" | ||
offset={220} // for masthead | ||
expandable={{ default: "expandable", md: "nonExpandable" }} | ||
> | ||
{props.itemNames.map((item, index) => ( | ||
<JumpLinksItem key={index} href={"#" + parseNameToId(item)}> | ||
{item} | ||
</JumpLinksItem> | ||
))} | ||
</JumpLinks> | ||
</SidebarPanel> | ||
<SidebarContent className="pf-v5-u-mr-xl"> | ||
{props.children} | ||
</SidebarContent> | ||
</Sidebar> | ||
</> | ||
); | ||
}; | ||
|
||
export default SidebarLayout; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.