Skip to content

Commit

Permalink
Migrate radio buttons to Ant Design (#5681)
Browse files Browse the repository at this point in the history
  • Loading branch information
jpople authored Jan 20, 2025
1 parent fdd8b4b commit 43d6ad1
Show file tree
Hide file tree
Showing 10 changed files with 186 additions and 171 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ Changes can also be flagged with a GitHub label for tracking purposes. The URL o
### Changed
- Updated UI colors to new brand. Update logo, homepage cards. [#5668](https://github.com/ethyca/fides/pull/5668)

### Developer Experience
- Migrated radio buttons and groups to Ant Design [#5681](https://github.com/ethyca/fides/pull/5681)



## [2.53.0](https://github.com/ethyca/fides/compare/2.52.0...2.53.0)
Expand Down
11 changes: 4 additions & 7 deletions clients/admin-ui/cypress/e2e/consent-settings.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,8 @@ describe("Consent settings", () => {
cy.getByTestId("consent-configuration");
cy.getByTestId("setting-Global Privacy Platform").within(() => {
cy.get("p").contains("GPP status Enabled");
cy.getByTestId("option-national").should(
"not.have.attr",
"data-checked",
);
cy.getByTestId("option-state").should("have.attr", "data-checked");
cy.getByTestId("option-national").should("not.have.attr", "checked");
cy.getByTestId("option-state").should("have.attr", "checked");
cy.getByTestId("input-gpp.mspa_covered_transactions").should(
"not.have.attr",
"data-checked",
Expand All @@ -78,8 +75,8 @@ describe("Consent settings", () => {
cy.visit(GLOBAL_CONSENT_CONFIG_ROUTE);
cy.getByTestId("setting-Global Privacy Platform").within(() => {
cy.get("p").contains("GPP status Enabled");
cy.getByTestId("option-national").should("have.attr", "data-checked");
cy.getByTestId("option-state").should("not.have.attr", "data-checked");
cy.getByTestId("option-national").should("have.attr", "checked");
cy.getByTestId("option-state").should("not.have.attr", "checked");
cy.getByTestId("input-gpp.mspa_covered_transactions").should(
"have.attr",
"data-checked",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {
AntButton as Button,
AntFlex as Flex,
AntRadio as Radio,
ChevronDownIcon,
ConfirmationModal,
HStack,
Expand All @@ -15,8 +17,6 @@ import {
PopoverHeader,
PopoverTrigger,
Portal,
Radio,
RadioGroup,
Skeleton,
Text,
theme,
Expand Down Expand Up @@ -310,48 +310,39 @@ export const CustomReportTemplates = ({
<Skeleton width="100%" height={theme.space[4]} />
</VStack>
) : (
<RadioGroup
onChange={handleSelection}
<Radio.Group
onChange={(e) => handleSelection(e.target.value)}
value={selectedReportId}
display="flex"
flexDirection="column"
gap={2}
colorScheme="minos"
className="flex flex-col gap-2"
>
{searchResults?.map((customReport) => (
<HStack
<Flex
key={customReport.id}
justifyContent={
className={
userCanDeleteReports
? "space-between"
: "flex-start"
? "justify-between"
: "justify-start"
}
min-height={theme.space[6]}
color="gray.700"
>
<Radio
name="custom-report-id"
value={customReport.id}
name="custom-report-id"
data-testid="custom-report-item"
>
<Text fontSize="sm">{customReport.name}</Text>
</Radio>
{userCanDeleteReports && (
<IconButton
variant="ghost"
size="xs"
aria-label={`delete ${CUSTOM_REPORT_TITLE}`}
<Button
type="text"
size="small"
icon={<TrashCanOutlineIcon fontSize={16} />}
onClick={() => {
setReportToDelete(customReport);
}}
onClick={() => setReportToDelete(customReport)}
data-testid="delete-report-button"
color="gray.700"
/>
)}
</HStack>
</Flex>
))}
</RadioGroup>
</Radio.Group>
))}
</PopoverBody>
<PopoverFooter border="none" px={6} pb={4} pt={4}>
Expand Down
113 changes: 113 additions & 0 deletions clients/admin-ui/src/features/common/form/ControlledRadioGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import type { AntRadioGroupProps as RadioGroupProps } from "fidesui";
import {
AntFlex as Flex,
AntRadio as Radio,
FormControl,
Grid,
RadioChangeEvent,
Text,
} from "fidesui";
import { useField } from "formik";

import type { StringField } from "~/features/common/form/inputs";
import { ErrorMessage, Label, Option } from "~/features/common/form/inputs";
import QuestionTooltip from "~/features/common/QuestionTooltip";

interface ControlledRadioGroupProps extends RadioGroupProps {
label?: string;
options: Option[];
layout?: "inline" | "stacked";
defaultFirstSelected?: boolean;
}

const ControlledRadioGroup = ({
label,
options,
layout,
defaultFirstSelected = true,
...props
}: ControlledRadioGroupProps & StringField) => {
const [initialField, meta] = useField(props);
const field = { ...initialField, value: initialField.value ?? "" };
const isInvalid = !!(meta.touched && meta.error);
const defaultSelected = defaultFirstSelected ? options[0] : undefined;
const selected =
options.find((o) => o.value === field.value) ?? defaultSelected;

const handleChange = (e: RadioChangeEvent) => {
field.onChange(props.name)(e.target.value);
};

if (layout === "stacked") {
return (
<FormControl isInvalid={isInvalid}>
<Flex className="w-fit">
{label ? <Label>{label}</Label> : null}
<Radio.Group
onChange={handleChange}
value={selected?.value}
data-testid={`input-${field.name}`}
>
<Flex className="flex-col gap-3">
{options.map(
({ value, label: optionLabel, tooltip: optionTooltip }) => (
<Radio
key={value}
value={value}
data-testid={`option-${value}`}
>
<Flex className="items-center gap-2">
<Text fontSize="sm" fontWeight="medium">
{optionLabel}
</Text>
{optionTooltip ? (
<QuestionTooltip label={optionTooltip} />
) : null}
</Flex>
</Radio>
),
)}
</Flex>
</Radio.Group>
</Flex>
<ErrorMessage
isInvalid={isInvalid}
message={meta.error}
fieldName={field.name}
/>
</FormControl>
);
}

return (
<FormControl isInvalid={isInvalid}>
<Grid templateColumns="1fr 3fr">
<Label>{label}</Label>
<Radio.Group
onChange={handleChange}
value={selected?.value}
data-testid={`input-${field.name}`}
>
<Flex>
{options.map((o) => (
<Radio
key={o.value}
value={o.value}
data-testid={`option-${o.value}`}
>
{o.label}
</Radio>
))}
</Flex>
</Radio.Group>
</Grid>
<ErrorMessage
isInvalid={isInvalid}
message={meta.error}
fieldName={field.name}
/>
</FormControl>
);
};

export default ControlledRadioGroup;
103 changes: 0 additions & 103 deletions clients/admin-ui/src/features/common/form/inputs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ import {
NumberInput,
NumberInputField,
NumberInputStepper,
Radio,
RadioGroup,
Stack,
Text,
Textarea,
TextareaProps,
Expand Down Expand Up @@ -365,106 +362,6 @@ export const CustomTextArea = ({
);
};

interface CustomRadioGroupProps {
label?: string;
options: Option[];
variant?: "inline" | "stacked";
defaultFirstSelected?: boolean;
}
export const CustomRadioGroup = ({
label,
options,
variant,
defaultFirstSelected = true,
...props
}: CustomRadioGroupProps & StringField) => {
const [initialField, meta] = useField(props);
const field = { ...initialField, value: initialField.value ?? "" };
const isInvalid = !!(meta.touched && meta.error);
const defaultSelected = defaultFirstSelected ? options[0] : undefined;
const selected =
options.find((o) => o.value === field.value) ?? defaultSelected;

const handleChange = (o: string) => {
field.onChange(props.name)(o);
};

if (variant === "stacked") {
return (
<FormControl isInvalid={isInvalid}>
<Stack width="fit-content">
{label ? (
<Label htmlFor={props.id || props.name}>{label}</Label>
) : null}
<RadioGroup
onChange={handleChange}
value={selected?.value}
data-testid={`input-${field.name}`}
colorScheme="complimentary"
>
<Stack direction="column" spacing={3}>
{options.map(
({ value, label: optionLabel, tooltip: optionTooltip }) => (
<Radio
key={value}
value={value}
data-testid={`option-${value}`}
>
<HStack alignItems="center" spacing={2}>
<Text fontSize="sm" fontWeight="medium">
{optionLabel}
</Text>
{optionTooltip ? (
<QuestionTooltip label={optionTooltip} />
) : null}
</HStack>
</Radio>
),
)}
</Stack>
</RadioGroup>
</Stack>
<ErrorMessage
isInvalid={isInvalid}
message={meta.error}
fieldName={field.name}
/>
</FormControl>
);
}

return (
<FormControl isInvalid={isInvalid}>
<Grid templateColumns="1fr 3fr">
<Label htmlFor={props.id || props.name}>{label}</Label>
<RadioGroup
onChange={handleChange}
value={selected?.value}
data-testid={`input-${field.name}`}
colorScheme="primary"
>
<Stack direction="row">
{options.map((o) => (
<Radio
key={o.value}
value={o.value}
data-testid={`option-${o.value}`}
>
{o.label}
</Radio>
))}
</Stack>
</RadioGroup>
</Grid>
<ErrorMessage
isInvalid={isInvalid}
message={meta.error}
fieldName={field.name}
/>
</FormControl>
);
};

interface CustomNumberInputProps {
label: string;
tooltip?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@ import { ReactNode } from "react";

import { useAppSelector } from "~/app/hooks";
import { useFeatures } from "~/features/common/features";
import {
CustomCheckbox,
CustomRadioGroup,
CustomSwitch,
} from "~/features/common/form/inputs";
import ControlledRadioGroup from "~/features/common/form/ControlledRadioGroup";
import { CustomCheckbox, CustomSwitch } from "~/features/common/form/inputs";
import { selectGppSettings } from "~/features/privacy-requests";
import { GPPApplicationConfigResponse, GPPUSApproach } from "~/types/api";

Expand Down Expand Up @@ -44,9 +41,9 @@ const GppConfiguration = () => {
{isEnabled ? (
<>
<Section title="GPP U.S.">
<CustomRadioGroup
<ControlledRadioGroup
name="gpp.us_approach"
variant="stacked"
layout="stacked"
defaultFirstSelected={false}
options={[
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { AntFlex as Flex } from "fidesui";

import { MonitorSystemAggregate } from "../../types";
// import { MonitorSystemAggregate } from "../../types";

interface DiscoveredSystemActionsCellProps {
system: MonitorSystemAggregate;
}
// interface DiscoveredSystemActionsCellProps {
// system: MonitorSystemAggregate;
// }

export const DiscoveredSystemActionsCell = ({
system,
}: DiscoveredSystemActionsCellProps) => {
console.log(system);
return <Flex> </Flex>;
};
export const DiscoveredSystemActionsCell = () =>
// {
// system,
// }: DiscoveredSystemActionsCellProps,
{
// console.log(system);
return <Flex> </Flex>;
};
Loading

0 comments on commit 43d6ad1

Please sign in to comment.