Skip to content
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
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/components/Form/IpaSelect.tsx
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;
11 changes: 10 additions & 1 deletion src/components/UserSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ import {
// Icons
import OutlinedQuestionCircleIcon from "@patternfly/react-icons/dist/esm/icons/outlined-question-circle-icon";
// Data types
import { Metadata, User } from "src/utils/datatypes/globalDataTypes";
import {
IDPServer,
Metadata,
RadiusServer,
User,
} from "src/utils/datatypes/globalDataTypes";
// Layouts
import ToolbarLayout from "src/components/layouts/ToolbarLayout";
import TitleLayout from "src/components/layouts/TitleLayout";
Expand Down Expand Up @@ -53,6 +58,8 @@ export interface PropsToUserSettings {
isDataLoading?: boolean;
modifiedValues: () => Partial<User>;
onResetValues: () => void;
radiusProxyData?: RadiusServer[];
idpData?: IDPServer[];
from: "active-users" | "stage-users" | "preserved-users";
}

Expand Down Expand Up @@ -251,6 +258,8 @@ const UserSettings = (props: PropsToUserSettings) => {
onUserChange={props.onUserChange}
metadata={props.metadata}
onRefresh={props.onRefresh}
radiusProxyConf={props.radiusProxyData || []}
idpConf={props.idpData || []}
/>
<TitleLayout
key={2}
Expand Down
140 changes: 77 additions & 63 deletions src/components/UsersSections/UsersAccountSettings.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
// PatternFly
import {
Flex,
FlexItem,
Form,
FormGroup,
TextInput,
Select,
SelectVariant,
SelectOption,
DropdownItem,
CalendarMonth,
Button,
} from "@patternfly/react-core";
// Data types
import { IDPServer, Metadata, User } from "src/utils/datatypes/globalDataTypes";
import {
IDPServer,
Metadata,
RadiusServer,
User,
} from "src/utils/datatypes/globalDataTypes";
// Layouts
import SecondaryButton from "src/components/layouts/SecondaryButton";
import DataTimePickerLayout from "src/components/layouts/Calendar/DataTimePickerLayout";
Expand All @@ -40,12 +42,15 @@ import useAlerts from "src/hooks/useAlerts";
import DeletionConfirmationModal from "../modals/DeletionConfirmationModal";
// Form
import IpaCheckbox from "../Form/IpaCheckbox";
import IpaSelect from "../Form/IpaSelect";

interface PropsToUsersAccountSettings {
user: Partial<User>;
onUserChange: (element: Partial<User>) => void;
metadata: Metadata;
onRefresh: () => void;
radiusProxyConf: RadiusServer[];
idpConf: IDPServer[];
}

// Generic data to pass to the Textbox adder
Expand Down Expand Up @@ -197,6 +202,59 @@ const UsersAccountSettings = (props: PropsToUsersAccountSettings) => {
</Button>,
];

// Dropdown 'Radius proxy configuration'
const [isRadiusConfOpen, setIsRadiusConfOpen] = useState(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of this logic could be generalized and be part of IpaSelect - thus reusable for other parts. The only specific part is translation of radius proxy objects into list of strings. The same applies for idp config.

const [radiusConfSelected, setRadiusConfSelected] = useState(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "selected" state is not needed as the value is already part of user/ipaObject.

ipaObject.ipatokenradiusconfiglink
);
const [radiusConfOptions, setRadiusConfOptions] = useState<string[]>([]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't need to be a state. And the conversion from radiusProxyConf doesn't need to be in an effect -> simplification.

const radiusConfOnToggle = (isOpen: boolean) => {
setIsRadiusConfOpen(isOpen);
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const radiusConfOnSelect = (selection: any) => {
setRadiusConfSelected(selection.target.textContent as string);
updateIpaObject(
selection.target.textContent as string,
"ipatokenradiusconfiglink"
);
setIsRadiusConfOpen(false);
};

useEffect(() => {
const radiusProxyList: string[] = [];
props.radiusProxyConf.map((item) => {
const itemString = item.cn.toString();
radiusProxyList.push(itemString);
});
setRadiusConfOptions(radiusProxyList);
}, [props.radiusProxyConf]);

// Dropdown 'External IdP configuration'
const [isIdpConfOpen, setIsIdpConfOpen] = useState(false);
const [idpConfSelected, setIdpConfSelected] = useState("");
const [idpConfOptions, setIdpConfOptions] = useState<string[]>([]);

const idpConfOnToggle = (isOpen: boolean) => {
setIsIdpConfOpen(isOpen);
};

const idpConfOnSelect = (selection: any) => {
setIdpConfSelected(selection.target.textContent as string);
updateIpaObject(selection.target.textContent as string, "ipaidpconfiglink");
setIsIdpConfOpen(false);
};

useEffect(() => {
const idpList: string[] = [];
props.idpConf.map((item) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be an additional "empty" item which allows users to remove radius proxy or display nothing when a user doesn't have a proxy defined.

Atm, after adding a radius proxy to IPA, this control shows that the users have it even though they don't.

const itemString = item.cn.toString();
idpList.push(itemString);
});
setIdpConfOptions(idpList);
}, [props.idpConf]);

// TODO: This state variables should update the user data via the IPA API (`user_mod`)
const [userLogin] = useState(props.user.uid);
const [password] = useState("");
Expand Down Expand Up @@ -553,38 +611,6 @@ const UsersAccountSettings = (props: PropsToUsersAccountSettings) => {
/>
);

// Dropdown 'Radius proxy configuration'
const [isRadiusConfOpen, setIsRadiusConfOpen] = useState(false);
const [radiusConfSelected, setRadiusConfSelected] = useState("");
const radiusConfOptions = [
{ value: "Option 1", disabled: false },
{ value: "Option 2", disabled: false },
{ value: "Option 3", disabled: false },
];
const radiusConfOnToggle = (isOpen: boolean) => {
setIsRadiusConfOpen(isOpen);
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const radiusConfOnSelect = (selection: any) => {
setRadiusConfSelected(selection.target.textContent);
setIsRadiusConfOpen(false);
};

// Dropdown 'External IdP configuration'
const [isIdpConfOpen, setIsIdpConfOpen] = useState(false);
const [idpConfSelected, setIdpConfSelected] = useState("");
const [idpConfOptions] = useState<IDPServer[]>([]);

const idpConfOnToggle = (isOpen: boolean) => {
setIsIdpConfOpen(isOpen);
};

const idpConfOnSelect = (selection: any) => {
setIdpConfSelected(selection.target.textContent);
setIsIdpConfOpen(false);
};

// Messages for the popover
const certificateMappingDataMessage = () => (
<div>
Expand Down Expand Up @@ -846,26 +872,18 @@ const UsersAccountSettings = (props: PropsToUsersAccountSettings) => {
label="Radius proxy configuration"
fieldId="radius-proxy-configuration"
>
<Select
<IpaSelect
id="radius-proxy-configuration"
name="ipatokenradiusconfiglink"
variant={SelectVariant.single}
placeholderText=" "
aria-label="Select Input with descriptions"
onToggle={radiusConfOnToggle}
onSelect={radiusConfOnSelect}
selections={radiusConfSelected}
elementsOptions={radiusConfOptions}
isOpen={isRadiusConfOpen}
aria-labelledby="radius-proxy-conf"
>
{radiusConfOptions.map((option, index) => (
<SelectOption
isDisabled={option.disabled}
key={index}
value={option.value}
/>
))}
</Select>
ipaObject={ipaObject}
objectName="user"
metadata={props.metadata}
value={radiusConfSelected}
/>
</FormGroup>
<FormGroup
label="Radius proxy username"
Expand All @@ -884,22 +902,18 @@ const UsersAccountSettings = (props: PropsToUsersAccountSettings) => {
label="External IdP configuration"
fieldId="external-idp-configuration"
>
<Select
<IpaSelect
id="external-idp-configuration"
name="ipaidpconfiglink"
variant={SelectVariant.single}
placeholderText=" "
aria-label="Select Input with descriptions"
onToggle={idpConfOnToggle}
onSelect={idpConfOnSelect}
selections={idpConfSelected}
elementsOptions={idpConfOptions}
isOpen={isIdpConfOpen}
aria-labelledby="external-idp-conf"
>
{idpConfOptions.map((option, index) => (
<SelectOption key={index} value={option.cn} />
))}
</Select>
ipaObject={ipaObject}
objectName="user"
metadata={props.metadata}
value={idpConfSelected}
/>
</FormGroup>
<FormGroup
label="External IdP user identifier"
Expand Down
Loading