-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Active users][Settings][Account settings] Adapt fields and sync data #135
Closed
Closed
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
4e6b910
Functionality for Text inputs with buttons
carma12 0ae1535
Functionality for checkbox list
carma12 1b29f79
Functionality of Selectors
carma12 6fc47f2
Functionality for date-time picker
carma12 e615727
Functionality for Text inputs
carma12 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,164 @@ | ||
import React from "react"; | ||
// PatternFly | ||
import { CalendarMonth, DropdownItem } from "@patternfly/react-core"; | ||
// Layouts | ||
import DataTimePickerLayout from "src/components/layouts/Calendar/DataTimePickerLayout"; | ||
// Components | ||
import CalendarButton from "src/components/layouts/Calendar/CalendarButton"; | ||
// Data types | ||
import { User } from "src/utils/datatypes/globalDataTypes"; | ||
// Utils | ||
import { | ||
getFullDate, | ||
getFullTime, | ||
getLDAPGeneralizedTime, | ||
parseFullDateStringToUTCFormat, | ||
} from "src/utils/utils"; | ||
// ipaObject Utils | ||
import { | ||
IPAParamDefinition, | ||
getParamProperties, | ||
updateIpaObject, | ||
} from "src/utils/ipaObjectUtils"; | ||
import CalendarLayout from "src/components/layouts/Calendar/CalendarLayout"; | ||
|
||
const IpaCalendar = (props: IPAParamDefinition) => { | ||
// Date and time picker (Calendar) | ||
const [isCalendarOpen, setIsCalendarOpen] = React.useState(false); | ||
const [isTimeOpen, setIsTimeOpen] = React.useState(false); | ||
const [valueDate, setValueDate] = React.useState("YYYY-MM-DD"); | ||
const [valueTime, setValueTime] = React.useState("HH:MM"); | ||
const times = Array.from(new Array(10), (_, i) => i + 10); | ||
const defaultTime = "10:00"; | ||
|
||
const { readOnly } = getParamProperties(props); | ||
|
||
// Initialize parameters got from the 'User' object | ||
React.useEffect(() => { | ||
if (props.ipaObject !== undefined) { | ||
// Parse ipaObject into 'User' type to access the 'datetime' parameter | ||
const user = props.ipaObject as unknown as User; | ||
if (user[props.name] && user[props.name][0].__datetime__) { | ||
// Parse to UTC format | ||
const paramUtcDate = parseFullDateStringToUTCFormat( | ||
user[props.name][0].__datetime__ | ||
); | ||
|
||
// Get date | ||
const fullDate = getFullDate(paramUtcDate); | ||
setValueDate(fullDate); | ||
|
||
// Get time | ||
const fullTime = getFullTime(paramUtcDate); | ||
setValueTime(fullTime); | ||
} | ||
} | ||
}, [props.ipaObject]); | ||
|
||
// 'onToggle' calendar function | ||
const onToggleCalendar = () => { | ||
setIsCalendarOpen(!isCalendarOpen); | ||
setIsTimeOpen(false); | ||
}; | ||
|
||
// 'onToggle' time function | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars | ||
const onToggleTime = (_ev: any) => { | ||
setIsTimeOpen(!isTimeOpen); | ||
setIsCalendarOpen(false); | ||
}; | ||
|
||
// On selecting a date from the calendar | ||
const onSelectCalendar = (newValueDate: Date) => { | ||
const newValue = getFullDate(newValueDate); | ||
setValueDate(newValue); | ||
|
||
setIsCalendarOpen(!isCalendarOpen); | ||
// setting default time when it is not picked | ||
let valTime = valueTime; | ||
if (valueTime === "HH:MM") { | ||
setValueTime(defaultTime); | ||
valTime = defaultTime; | ||
} | ||
|
||
// Convert to LDAP format | ||
const newFullDate = new Date(newValue + " " + valTime); | ||
const LDAPDate = getLDAPGeneralizedTime(newFullDate); | ||
|
||
// Update 'ipaObject' with the new date | ||
if (props.ipaObject !== undefined && props.onChange !== undefined) { | ||
updateIpaObject(props.ipaObject, props.onChange, LDAPDate, props.name); | ||
} | ||
}; | ||
|
||
// On selecting a time from the dropdown | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const onSelectTime = (ev: any) => { | ||
const newTime = ev.target.value as string; | ||
|
||
setValueTime(newTime); | ||
setIsTimeOpen(!isTimeOpen); | ||
|
||
const newFullDate = new Date(valueDate + " " + newTime); | ||
const LDAPDate = getLDAPGeneralizedTime(newFullDate); | ||
|
||
// Update 'ipaObject' with the new date | ||
// - Parse to ISO format (to return to the "user_mod" API call) | ||
if (props.ipaObject !== undefined && props.onChange !== undefined) { | ||
updateIpaObject(props.ipaObject, props.onChange, LDAPDate, props.name); | ||
} | ||
}; | ||
|
||
const timeOptions = times.map((time) => ( | ||
<DropdownItem key={time} component="button" value={`${time}:00`}> | ||
{`${time}:00`} | ||
</DropdownItem> | ||
)); | ||
|
||
const calendar = ( | ||
<CalendarMonth | ||
date={new Date(valueDate)} | ||
onChange={onSelectCalendar} | ||
disabled={readOnly} | ||
/> | ||
); | ||
|
||
const time = ( | ||
<DataTimePickerLayout | ||
dropdownOnSelect={onSelectTime} | ||
toggleAriaLabel="Toggle the time picker menu" | ||
toggleIndicator={null} | ||
toggleOnToggle={onToggleTime} | ||
toggleStyle={{ padding: "6px 16px" }} | ||
dropdownIsOpen={isTimeOpen} | ||
dropdownItems={timeOptions} | ||
/> | ||
); | ||
|
||
const calendarButton = ( | ||
<CalendarButton | ||
ariaLabel="Toggle the calendar" | ||
onClick={onToggleCalendar} | ||
/> | ||
); | ||
|
||
return ( | ||
<CalendarLayout | ||
name={props.name} | ||
position="bottom" | ||
bodyContent={calendar} | ||
showClose={false} | ||
isVisible={isCalendarOpen} | ||
hasNoPadding={true} | ||
hasAutoWidth={true} | ||
textInputId="date-time" | ||
textInputAriaLabel="date and time picker" | ||
textInputValue={valueDate + " " + valueTime} | ||
> | ||
{readOnly ? <></> : calendarButton} | ||
{readOnly ? <></> : time} | ||
</CalendarLayout> | ||
); | ||
}; | ||
|
||
export default IpaCalendar; |
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,46 @@ | ||
import React from "react"; | ||
// PatternFly | ||
import { Checkbox } from "@patternfly/react-core"; | ||
// Utils | ||
import { | ||
IPAParamDefinitionCheckbox, | ||
getParamPropertiesCheckBox, | ||
} from "src/utils/ipaObjectUtils"; | ||
|
||
const IpaCheckbox = (props: IPAParamDefinitionCheckbox) => { | ||
const { required, readOnly, onChange, className } = | ||
getParamPropertiesCheckBox(props); | ||
const [isChecked, setIsChecked] = React.useState(false); | ||
|
||
React.useEffect(() => { | ||
if (props.ipaObject !== undefined && props.value !== undefined) { | ||
const checkboxesStateList = props.ipaObject[props.name] as string[]; | ||
if (checkboxesStateList !== undefined) { | ||
const index = checkboxesStateList.indexOf(props.value); | ||
|
||
if (index > -1) { | ||
setIsChecked(true); | ||
} else { | ||
setIsChecked(false); | ||
} | ||
} | ||
} | ||
}, [props.ipaObject]); | ||
|
||
return ( | ||
<Checkbox | ||
id={props.id || ""} | ||
name={props.name} | ||
label={props.value} | ||
onChange={onChange} | ||
isRequired={required} | ||
readOnly={readOnly} | ||
isChecked={isChecked} | ||
aria-label={props.name} | ||
className={className} | ||
isDisabled={readOnly} | ||
/> | ||
); | ||
}; | ||
|
||
export default IpaCheckbox; |
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,35 @@ | ||
import React from "react"; | ||
// PatternFly | ||
import { Select, SelectOption, SelectVariant } from "@patternfly/react-core"; | ||
// Utils | ||
import { | ||
IPAParamDefinitionSelect, | ||
getParamPropertiesSelect, | ||
} from "src/utils/ipaObjectUtils"; | ||
|
||
const IpaSelect = (props: IPAParamDefinitionSelect) => { | ||
const { required, readOnly, value } = getParamPropertiesSelect(props); | ||
|
||
return ( | ||
<Select | ||
id={props.id} | ||
name={props.name} | ||
variant={props.variant || SelectVariant.single} | ||
aria-label={props.name} | ||
onToggle={props.onToggle} | ||
onSelect={props.onSelect} | ||
selections={value?.toString()} | ||
isOpen={props.isOpen} | ||
aria-labelledby={props.ariaLabelledBy || props.id} | ||
readOnly={readOnly} | ||
isDisabled={readOnly} | ||
required={required} | ||
> | ||
{props.elementsOptions.map((option, index) => ( | ||
<SelectOption key={index} value={option} /> | ||
))} | ||
</Select> | ||
); | ||
}; | ||
|
||
export default IpaSelect; |
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
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,93 @@ | ||
import React from "react"; | ||
// Patternfly | ||
import { Flex, FlexItem } from "@patternfly/react-core"; | ||
// Layouts | ||
import SecondaryButton from "../layouts/SecondaryButton"; | ||
// Data types | ||
import { Metadata } from "src/utils/datatypes/globalDataTypes"; | ||
// Fields | ||
import IpaTextInputWithId from "./IpaTextInputWithId"; | ||
// Hooks | ||
import useAlerts from "src/hooks/useAlerts"; | ||
// ipaObject utils | ||
import { getParamProperties } from "src/utils/ipaObjectUtils"; | ||
|
||
interface PropsToTextInputFromList { | ||
name: string; | ||
elementsList: string[]; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
ipaObject: Record<string, any>; | ||
metadata: Metadata; | ||
onOpenModal: () => void; | ||
onRemove: (idx: number) => void; | ||
} | ||
|
||
const IpaTextInputFromList = (props: PropsToTextInputFromList) => { | ||
const [elementsList, setElementsList] = React.useState(props.elementsList); | ||
|
||
// Get 'readOnly' to determine if the field has permissions to be edited | ||
const { readOnly } = getParamProperties({ | ||
name: props.name, | ||
ipaObject: props.ipaObject, | ||
objectName: "user", | ||
metadata: props.metadata, | ||
}); | ||
|
||
// Alerts to show in the UI | ||
const alerts = useAlerts(); | ||
|
||
React.useEffect(() => { | ||
setElementsList(props.elementsList); | ||
}, [props.elementsList]); | ||
|
||
return ( | ||
<> | ||
<alerts.ManagedAlerts /> | ||
<Flex direction={{ default: "column" }} name={props.name}> | ||
{elementsList !== undefined && | ||
elementsList.map((element, idx) => ( | ||
<Flex direction={{ default: "row" }} key={idx} name="value"> | ||
<FlexItem | ||
key={idx} | ||
flex={{ default: "flex_1" }} | ||
className="pf-u-ml-lg" | ||
> | ||
<IpaTextInputWithId | ||
id={props.name + "-" + idx} | ||
value={element} | ||
name={props.name} | ||
ipaObject={props.ipaObject} | ||
objectName="user" | ||
metadata={props.metadata} | ||
idx={idx} | ||
readOnly={true} // This field is always read-only | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very minor issue, but I think you get a build warning when a prop is explicitly set to true or false. A boolean prop is set or it isn't. Again, if it's not generating a warning then don't worry about it, but I've seen this trigger annoying messages. :-) |
||
/> | ||
</FlexItem> | ||
<FlexItem | ||
key={element + "-delete-button"} | ||
order={{ default: "-1" }} | ||
> | ||
<SecondaryButton | ||
name="remove" | ||
onClickHandler={() => props.onRemove(idx)} | ||
isDisabled={readOnly} | ||
> | ||
Delete | ||
</SecondaryButton> | ||
</FlexItem> | ||
</Flex> | ||
))} | ||
</Flex> | ||
<SecondaryButton | ||
classname="pf-u-mt-md" | ||
name="add" | ||
onClickHandler={props.onOpenModal} | ||
isDisabled={readOnly} | ||
> | ||
Add | ||
</SecondaryButton> | ||
</> | ||
); | ||
}; | ||
|
||
export default IpaTextInputFromList; |
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,38 @@ | ||
import React from "react"; | ||
// PatternFly | ||
import { TextInput } from "@patternfly/react-core"; | ||
// Utils | ||
import { | ||
IPAParamDefinitionWithIndex, | ||
convertToString, | ||
getParamPropertiesWithIndex, | ||
} from "src/utils/ipaObjectUtils"; | ||
|
||
const IpaTextInputWithId = (props: IPAParamDefinitionWithIndex) => { | ||
const { required, readOnly, value, idx } = getParamPropertiesWithIndex(props); | ||
|
||
const [paramValue, setParamValue] = React.useState(""); | ||
|
||
React.useEffect(() => { | ||
if (props.value !== undefined) { | ||
setParamValue(props.value); | ||
} else { | ||
setParamValue(convertToString(value)); | ||
} | ||
}, [props.value, value]); | ||
|
||
return ( | ||
<TextInput | ||
key={idx} | ||
id={props.id || props.name} | ||
name={props.name} | ||
value={paramValue} | ||
type="text" | ||
aria-label={props.name} | ||
isRequired={required} | ||
readOnlyVariant={readOnly ? "plain" : undefined} | ||
/> | ||
); | ||
}; | ||
|
||
export default IpaTextInputWithId; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IpaCalendar component should not have any reference to a specific object type (in this case user). The raw value should be obtained the same way as in text input, e.g.:
const { required, readOnly, value, onChange } = getParamProperties(props);
After that you can extract the base64 value and change it into
Date
object. There is also no need to do it in an effect as it is simple conversion of value from props.But the question is whether we should be doing this parsing here. I think that the conversion from base64 to Date or string (depending what we find more useful) should happen in
apiToUser
method inuserUtils
or any similar method that is used in rpc for other object types.The reason is that in
ipaObject
should be of the same type/structure after changing it. Or in other words, it should be possible to set it to the same value and be regarded as a same value. Atm the source is object with base64 string and after modification it is string, thus this doesn't apply.