Skip to content

Commit

Permalink
🪟 🔧 [Form Migration][Part 1] New react-hook-form components for `<C…
Browse files Browse the repository at this point in the history
…onnectionTransformationPage />` and refactored the old ones (#7967)
  • Loading branch information
dizel852 committed Aug 2, 2023
1 parent 9c26d03 commit 9886059
Show file tree
Hide file tree
Showing 23 changed files with 519 additions and 104 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
@use "scss/colors";
@use "scss/variables";

.container {
margin-bottom: variables.$spacing-xl;
}

.list {
background-color: colors.$grey-50;
border-radius: variables.$border-radius-xs;
overflow: hidden;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React from "react";
import { FormattedMessage } from "react-intl";

import { Box } from "components/ui/Box";
import { FlexContainer } from "components/ui/Flex";
import { Modal, ModalProps } from "components/ui/Modal";

import { ConnectionFormMode } from "hooks/services/ConnectionForm/ConnectionFormService";
Expand Down Expand Up @@ -65,7 +67,7 @@ export const ArrayOfObjectsEditor = <T extends ItemBase = ItemBase>({

return (
<>
<div className={styles.container}>
<Box mb="xl">
<EditorHeader
itemsCount={items.length}
onAddItem={onAddItem}
Expand All @@ -75,7 +77,7 @@ export const ArrayOfObjectsEditor = <T extends ItemBase = ItemBase>({
disabled={disabled}
/>
{items.length ? (
<div className={styles.list}>
<FlexContainer direction="column" gap="xs" className={styles.list}>
{items.map((item, index) => (
<EditorRow
key={`form-item-${index}`}
Expand All @@ -87,9 +89,9 @@ export const ArrayOfObjectsEditor = <T extends ItemBase = ItemBase>({
disabled={disabled}
/>
))}
</div>
</FlexContainer>
) : null}
</div>
</Box>
{mode !== "readonly" && isEditable && renderEditModal()}
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from "react";
import { FieldArrayWithId } from "react-hook-form";

import { Box } from "components/ui/Box";
import { FlexContainer } from "components/ui/Flex";

import styles from "./ArrayOfObjectsEditor.module.scss";
import { EditorHeader } from "./components/EditorHeader";
import { EditorRow } from "./components/EditorRow";

export interface ArrayOfObjectsHookFormEditorProps<T> {
fields: T[];
mainTitle?: React.ReactNode;
addButtonText?: React.ReactNode;
renderItemName?: (item: T, index: number) => React.ReactNode | undefined;
renderItemDescription?: (item: T, index: number) => React.ReactNode | undefined;
onAddItem: () => void;
onStartEdit: (n: number) => void;
onRemove: (index: number) => void;
}

/**
* The component is used to render a list of react-hook-form FieldArray items with the ability to add, edit and remove items.
* It's a react-hook-form version of the ArrayOfObjectsEditor component and will replace it in the future.
* @see ArrayOfObjectsEditor
* @param fields
* @param mainTitle
* @param addButtonText
* @param onAddItem
* @param renderItemName
* @param renderItemDescription
* @param onStartEdit
* @param onRemove
* @param mode
* @constructor
*/
export const ArrayOfObjectsHookFormEditor = <T extends FieldArrayWithId>({
fields,
mainTitle,
addButtonText,
onAddItem,
renderItemName,
renderItemDescription,
onStartEdit,
onRemove,
}: ArrayOfObjectsHookFormEditorProps<T>) => (
<Box mb="xl">
<EditorHeader
mainTitle={mainTitle}
itemsCount={fields.length}
addButtonText={addButtonText}
onAddItem={onAddItem}
/>
{fields.length ? (
<FlexContainer direction="column" gap="xs" className={styles.list}>
{fields.map((field, index) => (
<EditorRow
key={field.id}
name={renderItemName?.(field, index)}
description={renderItemDescription?.(field, index)}
id={index}
onEdit={onStartEdit}
onRemove={onRemove}
/>
))}
</FlexContainer>
) : null}
</Box>
);

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
import React from "react";
import { FormattedMessage } from "react-intl";

import { Box } from "components/ui/Box";
import { Button } from "components/ui/Button";
import { FlexContainer } from "components/ui/Flex";
import { Text } from "components/ui/Text";

import { ConnectionFormMode } from "hooks/services/ConnectionForm/ConnectionFormService";

import styles from "./EditorHeader.module.scss";

interface EditorHeaderProps {
mainTitle?: React.ReactNode;
addButtonText?: React.ReactNode;
itemsCount: number;
onAddItem: () => void;
/**
* seems like "mode" and "disabled" props can be removed since we can control fields enable/disable states on higher levels
* TODO: remove during ArrayOfObjectsEditor refactoring and CreateConnectionForm migration
*/
mode?: ConnectionFormMode;
disabled?: boolean;
}

const EditorHeader: React.FC<EditorHeaderProps> = ({
export const EditorHeader: React.FC<EditorHeaderProps> = ({
itemsCount,
onAddItem,
mainTitle,
Expand All @@ -25,15 +30,17 @@ const EditorHeader: React.FC<EditorHeaderProps> = ({
disabled,
}) => {
return (
<div className={styles.editorHeader}>
{mainTitle || <FormattedMessage id="form.items" values={{ count: itemsCount }} />}
{mode !== "readonly" && (
<Button variant="secondary" type="button" onClick={onAddItem} data-testid="addItemButton" disabled={disabled}>
{addButtonText || <FormattedMessage id="form.addItems" />}
</Button>
)}
</div>
<Box mt="sm" mb="md">
<FlexContainer justifyContent="space-between" alignItems="center">
<Text color="darkBlue" size="lg" bold>
{mainTitle || <FormattedMessage id="form.items" values={{ count: itemsCount }} />}
</Text>
{mode !== "readonly" && (
<Button variant="secondary" type="button" onClick={onAddItem} data-testid="addItemButton" disabled={disabled}>
{addButtonText || <FormattedMessage id="form.addItems" />}
</Button>
)}
</FlexContainer>
</Box>
);
};

export { EditorHeader };
Original file line number Diff line number Diff line change
@@ -1,30 +1,18 @@
@use "scss/colors";
@use "scss/variables";

.container + .container {
.container {
border-top: 1px solid colors.$foreground;
background-color: colors.$grey-50;
}

.body {
display: flex;
justify-content: space-between;
align-items: center;
flex-direction: row;
color: colors.$dark-blue;
font-weight: 400;
font-size: variables.$font-size-sm;
line-height: 1.4;
padding: variables.$spacing-xs variables.$spacing-xs variables.$spacing-xs variables.$spacing-md;
gap: variables.$spacing-xs;
padding: variables.$spacing-xs variables.$spacing-md;
}

.name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.actions {
display: flex;
flex-direction: row;
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from "react";
import { useIntl } from "react-intl";

import { CrossIcon } from "components/icons/CrossIcon";
import { PencilIcon } from "components/icons/PencilIcon";
import { Button } from "components/ui/Button";
import { FlexContainer } from "components/ui/Flex";
import { Icon } from "components/ui/Icon";
import { Text } from "components/ui/Text";
import { Tooltip } from "components/ui/Tooltip";

import styles from "./EditorRow.module.scss";
Expand All @@ -21,17 +22,19 @@ export const EditorRow: React.FC<EditorRowProps> = ({ name, id, description, onE
const { formatMessage } = useIntl();

const body = (
<div className={styles.body}>
<div className={styles.name}>{name || id}</div>
<div className={styles.actions}>
<FlexContainer justifyContent="space-between" alignItems="center" gap="xs" className={styles.body}>
<Text size="sm" className={styles.name}>
{name || id}
</Text>
<FlexContainer gap="none">
<Button
size="xs"
type="button"
variant="clear"
arial-label={formatMessage({ id: "form.edit" })}
onClick={() => onEdit(id)}
disabled={disabled}
icon={<PencilIcon />}
icon={<Icon type="pencil" />}
/>
<Button
size="xs"
Expand All @@ -40,10 +43,10 @@ export const EditorRow: React.FC<EditorRowProps> = ({ name, id, description, onE
aria-label={formatMessage({ id: "form.delete" })}
onClick={() => onRemove(id)}
disabled={disabled}
icon={<CrossIcon />}
icon={<Icon type="cross" />}
/>
</div>
</div>
</FlexContainer>
</FlexContainer>
);

return (
Expand Down
6 changes: 2 additions & 4 deletions airbyte-webapp/src/components/ArrayOfObjectsEditor/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
import { ArrayOfObjectsEditor } from "./ArrayOfObjectsEditor";

export default ArrayOfObjectsEditor;
export { ArrayOfObjectsEditor };
export { ArrayOfObjectsEditor } from "./ArrayOfObjectsEditor";
export { ArrayOfObjectsHookFormEditor } from "./ArrayOfObjectsHookFormEditor";
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,27 @@
@use "scss/variables";

.container {
margin-bottom: 6px;
}
margin-bottom: variables.$spacing-sm;

.label {
padding-left: variables.$spacing-md;
font-size: variables.$font-size-lg;
color: colors.$dark-blue;
cursor: pointer;
}
.label {
font-size: variables.$font-size-lg;
color: colors.$dark-blue;
cursor: pointer;

.disabled {
color: colors.$grey-300;
cursor: auto;
}
&--disabled {
color: colors.$grey;
cursor: auto;
}
}

.message {
padding-left: variables.$spacing-sm;
color: colors.$grey-300;
font-size: variables.$font-size-md;
.message {
padding-left: variables.$spacing-sm;
color: colors.$grey;
font-size: variables.$font-size-md;

& a {
text-decoration: underline;
color: colors.$blue;
& a {
text-decoration: underline;
color: colors.$blue;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@ import { FlexContainer } from "components/ui/Flex";
import { RadioButton } from "components/ui/RadioButton";

import styles from "./LabeledRadioButton.module.scss";
type IProps = {

export interface LabeledRadioButtonProps extends React.InputHTMLAttributes<HTMLInputElement> {
message?: React.ReactNode;
label?: React.ReactNode;
className?: string;
} & React.InputHTMLAttributes<HTMLInputElement>;
}

const LabeledRadioButton: React.FC<IProps> = (props) => (
<FlexContainer className={classNames(props.className, styles.container)} alignItems="center" gap="none">
export const LabeledRadioButton = React.forwardRef<HTMLDivElement, LabeledRadioButtonProps>((props, ref) => (
<FlexContainer ref={ref} alignItems="center" gap="sm" className={classNames(styles.container, props.className)}>
<RadioButton {...props} id={`radiobutton-${props.id || props.name}`} disabled={props.disabled} />
<label
className={classNames(styles.label, { [styles.disabled]: props.disabled })}
className={classNames(styles.label, { [styles["label--disabled"]]: props.disabled })}
htmlFor={`radiobutton-${props.id || props.name}`}
>
{props.label}
<span className={styles.message}>{props.message}</span>
</label>
</FlexContainer>
);
));

export default LabeledRadioButton;
LabeledRadioButton.displayName = "LabeledRadioButton";
6 changes: 2 additions & 4 deletions airbyte-webapp/src/components/LabeledRadioButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
import LabeledRadioButton from "./LabeledRadioButton";

export default LabeledRadioButton;
export { LabeledRadioButton };
export { LabeledRadioButton } from "./LabeledRadioButton";
export type { LabeledRadioButtonProps } from "./LabeledRadioButton";
Loading

0 comments on commit 9886059

Please sign in to comment.