Skip to content

Commit

Permalink
🪟🧹 Connector builder: Fast fields performance improvements (#20957)
Browse files Browse the repository at this point in the history
* improve some types

* improve further

* clean up a bit more

* refactor loading state

* move loading state up

* remove isLoading references

* remove unused props and make fetch connector error work

* remove special component for name

* remove top level state for unifinished flows

* start removing uiwidget

* Update airbyte-webapp/src/views/Connector/ConnectorCard/ConnectorCard.module.scss

Co-authored-by: Tim Roes <tim@airbyte.io>

* remove undefined option for selected id

* remove unused prop

* fix types

* remove uiwidget state

* clean up

* adjust comment

* handle errors in a nice way

* do not respect default on oneOf fields

* rename to formblock

* reduce re-renders

* pass error to secure inputs

* simplify and improve styling

* align top

* code review

* remove comment

* review comments

* rename file

* be strict about boolean values

* add example

* track form error in error boundary

* review comments

* handle unexpected cases better

* speed up some bits

* more changes

* enrich error with connector id

* 🪟🎉 Add copy stream button (#20577)

* add copy stream button

* review comments

* rename prop

* 🪟🎉 Connector builder: Integrate connector form for test input (#20385)

* move connector builder components into the same shared components/connectorBuilder directory

* move diff over from poc branch

* save current progress

* add modal for adding streams

* focus stream after adding and reset button style

* add reset confirm modal and select view on add

* style global config and streams buttons

* styling improvements

* handle long stream names better

* pull in connector manifest schema directly

* add box shadows to resizable panels

* upgrade orval and use connector manifest schema directly

* remove airbyte protocol from connector builder api spec

* generate python models from openapi change

* fix position of yaml toggle

* handle no stream case with better looking message

* group global fields into single object and fix console error

* confirmation modal on toggling dirty form + cleanup

* fix connector name display

* undo change to manifest schema

* remove commented code

* remove unnecessary change

* fix spacing

* use shadow mixin for connector img

* add comment about connector img

* change onSubmit to no-op

* remove console log

* clean up styling

* simplify sidebar to remove StreamSelectButton component

* swap colors of toggle

* move FormikPatch to src/core/form

* move types up to connectorBuilder/ level

* use grid display for ui yaml toggle button

* use spread instead of setting array index directly

* add intl in missing places

* pull connector manifest schema in through separate openapi spec

* use correct intl string id

* throttle setting json manifest in yaml editor

* use  button prop instead of manually styling

* consolidate AddStreamButton styles

* fix sidebar flex styles

* use specific flex properties instead of flex

* clean up download and reset button styles

* use row-reverse for yaml editor download button

* fix stream selector styles to remove margins

* give connector setup guide panel same corner and shadow styles

* remove blur from page display

* set view to stream when selected in test panel

* add placeholder when stream name is empty

* switch to index-based stream selection to preserve testing panel selected stream on rename

* handle empty name in stream selector

* make connector form work in connector builder

* fix small stuff

* add warning label

* review comments

* adjust translation

Co-authored-by: lmossman <lake@airbyte.io>

* use request_body_json instead of request_body_data

* 🪟 🎨 Move `Add` button into the line of Connector Builder key value list fields (#20699)

* move add button into line

* add stories for empty with control, and content + control

* change button name to Control

* 🪟🎉 Connector builder: Allow defining inputs (#20431)

* move connector builder components into the same shared components/connectorBuilder directory

* move diff over from poc branch

* save current progress

* add modal for adding streams

* focus stream after adding and reset button style

* add reset confirm modal and select view on add

* style global config and streams buttons

* styling improvements

* handle long stream names better

* pull in connector manifest schema directly

* add box shadows to resizable panels

* upgrade orval and use connector manifest schema directly

* remove airbyte protocol from connector builder api spec

* generate python models from openapi change

* fix position of yaml toggle

* handle no stream case with better looking message

* group global fields into single object and fix console error

* confirmation modal on toggling dirty form + cleanup

* fix connector name display

* undo change to manifest schema

* remove commented code

* remove unnecessary change

* fix spacing

* use shadow mixin for connector img

* add comment about connector img

* change onSubmit to no-op

* remove console log

* clean up styling

* simplify sidebar to remove StreamSelectButton component

* swap colors of toggle

* move FormikPatch to src/core/form

* move types up to connectorBuilder/ level

* use grid display for ui yaml toggle button

* use spread instead of setting array index directly

* add intl in missing places

* pull connector manifest schema in through separate openapi spec

* use correct intl string id

* throttle setting json manifest in yaml editor

* use  button prop instead of manually styling

* consolidate AddStreamButton styles

* fix sidebar flex styles

* use specific flex properties instead of flex

* clean up download and reset button styles

* use row-reverse for yaml editor download button

* fix stream selector styles to remove margins

* give connector setup guide panel same corner and shadow styles

* remove blur from page display

* set view to stream when selected in test panel

* add placeholder when stream name is empty

* switch to index-based stream selection to preserve testing panel selected stream on rename

* handle empty name in stream selector

* make connector form work in connector builder

* wip

* fix small stuff

* add basic input UI

* user inputs

* make most of inputs configuration work

* fix a bunch of stuff

* handle unknown config types

* add warning label

* fix label

* fix some styling

* review comments

* improve state management and error handling

* handle stored form values that don't contain new fields properly

* Update airbyte-webapp/src/locales/en.json

Co-authored-by: Lake Mossman <lake@airbyte.io>

* Update airbyte-webapp/src/components/connectorBuilder/Builder/InputsView.tsx

Co-authored-by: Lake Mossman <lake@airbyte.io>

* inputs editing weirdness

* input form reset

* using the Label component

* 🪟🎉 Connector builder authentication (#20645)

* allow auth configuration

* check for conflicts with the inferred inputs

* fix invisible inputs

* reduce redundancy and hide advanced input options for inferred inputs

* unnecessary validation

* typo

* unnecessary effect hook

* build spec even for invalid forms but do not update stream list

* fix keys

* 🪟🎉 Connector builder: Session token and oauth authentication (#20712)

* session token and oauth authentication

* fill in session token variable

* typos

* make sure validation error does not go away

* 🪟🎉 Connector builder: Always validate inputs form (#20664)

* validate user input outside of form

* review comments

Co-authored-by: lmossman <lake@airbyte.io>

Co-authored-by: lmossman <lake@airbyte.io>

* fix merge conflict with dropdown prop being renamed to control

* [Connector Builder] Add paginator (#20698)

* move connector builder components into the same shared components/connectorBuilder directory

* move diff over from poc branch

* save current progress

* add modal for adding streams

* focus stream after adding and reset button style

* add reset confirm modal and select view on add

* style global config and streams buttons

* styling improvements

* handle long stream names better

* pull in connector manifest schema directly

* add box shadows to resizable panels

* upgrade orval and use connector manifest schema directly

* remove airbyte protocol from connector builder api spec

* generate python models from openapi change

* fix position of yaml toggle

* handle no stream case with better looking message

* group global fields into single object and fix console error

* confirmation modal on toggling dirty form + cleanup

* fix connector name display

* undo change to manifest schema

* remove commented code

* remove unnecessary change

* fix spacing

* use shadow mixin for connector img

* add comment about connector img

* change onSubmit to no-op

* remove console log

* clean up styling

* simplify sidebar to remove StreamSelectButton component

* swap colors of toggle

* move FormikPatch to src/core/form

* move types up to connectorBuilder/ level

* use grid display for ui yaml toggle button

* use spread instead of setting array index directly

* add intl in missing places

* pull connector manifest schema in through separate openapi spec

* use correct intl string id

* throttle setting json manifest in yaml editor

* use  button prop instead of manually styling

* consolidate AddStreamButton styles

* fix sidebar flex styles

* use specific flex properties instead of flex

* clean up download and reset button styles

* use row-reverse for yaml editor download button

* fix stream selector styles to remove margins

* give connector setup guide panel same corner and shadow styles

* remove blur from page display

* set view to stream when selected in test panel

* add placeholder when stream name is empty

* switch to index-based stream selection to preserve testing panel selected stream on rename

* handle empty name in stream selector

* make connector form work in connector builder

* wip

* fix small stuff

* add basic input UI

* user inputs

* make most of inputs configuration work

* fix a bunch of stuff

* handle unknown config types

* add warning label

* fix label

* fix some styling

* review comments

* improve state management and error handling

* allow auth configuration

* check for conflicts with the inferred inputs

* fix invisible inputs

* handle stored form values that don't contain new fields properly

* session token and oauth authentication

* fill in session token variable

* fix merge of default values

* add primaryKey and cursorField to builder types, and consolidate default valeues to types.ts

* add cursor and primary key fields to ui

* save

* add page size and token option inputs

* fixes after rebase

* add pagination

* fix pagination types

* handle empty field_name better

* Update airbyte-webapp/src/locales/en.json

Co-authored-by: Lake Mossman <lake@airbyte.io>

* Update airbyte-webapp/src/components/connectorBuilder/Builder/InputsView.tsx

Co-authored-by: Lake Mossman <lake@airbyte.io>

* inputs editing weirdness

* input form reset

* using the Label component

* reduce redundancy and hide advanced input options for inferred inputs

* unnecessary validation

* typo

* unnecessary effect hook

* build spec even for invalid forms but do not update stream list

* typos

* make sure validation error does not go away

* make primary key and cursor optional, and reorder

* save toggle group progress

* fix style of toggle label

* handle empty values better

* fix page size/token option field validation and rendering

* handle cursor pagination page size option correctly

Co-authored-by: Joe Reuter <joe@airbyte.io>

* [Connector Builder] Add stream slicer (#20748)

* move connector builder components into the same shared components/connectorBuilder directory

* move diff over from poc branch

* save current progress

* add modal for adding streams

* focus stream after adding and reset button style

* add reset confirm modal and select view on add

* style global config and streams buttons

* styling improvements

* handle long stream names better

* pull in connector manifest schema directly

* add box shadows to resizable panels

* upgrade orval and use connector manifest schema directly

* remove airbyte protocol from connector builder api spec

* generate python models from openapi change

* fix position of yaml toggle

* handle no stream case with better looking message

* group global fields into single object and fix console error

* confirmation modal on toggling dirty form + cleanup

* fix connector name display

* undo change to manifest schema

* remove commented code

* remove unnecessary change

* fix spacing

* use shadow mixin for connector img

* add comment about connector img

* change onSubmit to no-op

* remove console log

* clean up styling

* simplify sidebar to remove StreamSelectButton component

* swap colors of toggle

* move FormikPatch to src/core/form

* move types up to connectorBuilder/ level

* use grid display for ui yaml toggle button

* use spread instead of setting array index directly

* add intl in missing places

* pull connector manifest schema in through separate openapi spec

* use correct intl string id

* throttle setting json manifest in yaml editor

* use  button prop instead of manually styling

* consolidate AddStreamButton styles

* fix sidebar flex styles

* use specific flex properties instead of flex

* clean up download and reset button styles

* use row-reverse for yaml editor download button

* fix stream selector styles to remove margins

* give connector setup guide panel same corner and shadow styles

* remove blur from page display

* set view to stream when selected in test panel

* add placeholder when stream name is empty

* switch to index-based stream selection to preserve testing panel selected stream on rename

* handle empty name in stream selector

* make connector form work in connector builder

* wip

* fix small stuff

* add basic input UI

* user inputs

* make most of inputs configuration work

* fix a bunch of stuff

* handle unknown config types

* add warning label

* fix label

* fix some styling

* review comments

* improve state management and error handling

* allow auth configuration

* check for conflicts with the inferred inputs

* fix invisible inputs

* handle stored form values that don't contain new fields properly

* session token and oauth authentication

* fill in session token variable

* fix merge of default values

* add primaryKey and cursorField to builder types, and consolidate default valeues to types.ts

* add cursor and primary key fields to ui

* save

* add page size and token option inputs

* fixes after rebase

* add pagination

* fix pagination types

* handle empty field_name better

* Update airbyte-webapp/src/locales/en.json

Co-authored-by: Lake Mossman <lake@airbyte.io>

* Update airbyte-webapp/src/components/connectorBuilder/Builder/InputsView.tsx

Co-authored-by: Lake Mossman <lake@airbyte.io>

* inputs editing weirdness

* input form reset

* using the Label component

* reduce redundancy and hide advanced input options for inferred inputs

* unnecessary validation

* typo

* unnecessary effect hook

* build spec even for invalid forms but do not update stream list

* typos

* make sure validation error does not go away

* make primary key and cursor optional, and reorder

* save toggle group progress

* fix style of toggle label

* handle empty values better

* fix page size/token option field validation and rendering

* handle cursor pagination page size option correctly

* save stream slicer progress

* finish stream slicer

* fix stream slicer fields and validation

Co-authored-by: Joe Reuter <joe@airbyte.io>

* debounce form builder values update to reduce load

* 🪟🔧  Connector builder: use new lowcode manifest (#20715)

* use new manifest yaml

* Update airbyte-webapp/src/components/connectorBuilder/types.ts

Co-authored-by: Lake Mossman <lake@airbyte.io>

* use updated manifest types

Co-authored-by: Lake Mossman <lake@airbyte.io>

* debounce validation as well

* akways show stream test button in error state if there are errors

* fix type of oauth input

* review comments

* fix more

* start implementing fast fields

* a few more fastfields

* fix some stuff

* complete fast fields work

* memoize a bit more

* remove irrelevant change

* fix types

* some more improvements

* prevent all out-of-line validation calls

* use derivedJsonManifest when in UI view

Co-authored-by: Tim Roes <tim@airbyte.io>
Co-authored-by: lmossman <lake@airbyte.io>
  • Loading branch information
3 people authored and jbfbell committed Jan 13, 2023
1 parent f76ba9b commit 7c2ff54
Show file tree
Hide file tree
Showing 11 changed files with 269 additions and 163 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useField } from "formik";
import { FastField, FastFieldProps, FieldInputProps } from "formik";
import { ReactNode } from "react";
import { FormattedMessage } from "react-intl";

Expand Down Expand Up @@ -64,24 +64,26 @@ const ArrayField: React.FC<ArrayFieldProps> = ({ name, value, setValue, error })
return <TagInput name={name} fieldValue={value} onChange={(value) => setValue(value)} error={error} />;
};

export const BuilderField: React.FC<BuilderFieldProps> = ({
const InnerBuilderField: React.FC<BuilderFieldProps & FastFieldProps<unknown>> = ({
path,
label,
tooltip,
optional = false,
readOnly,
pattern,
field,
meta,
form,
adornment,
...props
}) => {
const [field, meta, helpers] = useField(path);
const hasError = !!meta.error && meta.touched;

if (props.type === "boolean") {
return (
<LabeledSwitch
{...field}
checked={field.value}
{...(field as FieldInputProps<string>)}
checked={field.value as boolean}
label={
<>
{label} {tooltip && <InfoTooltip placement="top-start">{tooltip}</InfoTooltip>}
Expand All @@ -93,7 +95,7 @@ export const BuilderField: React.FC<BuilderFieldProps> = ({

const setValue = (newValue: unknown) => {
props.onChange?.(newValue as string & string[]);
helpers.setValue(newValue);
form.setFieldValue(path, newValue);
};

return (
Expand All @@ -104,23 +106,28 @@ export const BuilderField: React.FC<BuilderFieldProps> = ({
onChange={(e) => {
field.onChange(e);
if (e.target.value === "") {
helpers.setValue(undefined);
form.setFieldValue(path, undefined);
}
props.onChange?.(e.target.value);
}}
className={props.className}
type={props.type}
value={field.value ?? ""}
value={(field.value as string | number | undefined) ?? ""}
error={hasError}
readOnly={readOnly}
adornment={adornment}
/>
)}
{props.type === "array" && (
<ArrayField name={path} value={field.value ?? []} setValue={setValue} error={hasError} />
<ArrayField
name={path}
value={(field.value as string[] | undefined) ?? []}
setValue={setValue}
error={hasError}
/>
)}
{props.type === "enum" && (
<EnumField options={props.options} value={field.value} setValue={setValue} error={hasError} />
<EnumField options={props.options} value={field.value as string} setValue={setValue} error={hasError} />
)}
{hasError && (
<Text className={styles.error}>
Expand All @@ -133,3 +140,13 @@ export const BuilderField: React.FC<BuilderFieldProps> = ({
</ControlLabels>
);
};

export const BuilderField: React.FC<BuilderFieldProps> = (props) => {
return (
<FastField name={props.path}>
{({ field, form, meta }: FastFieldProps<unknown>) => (
<InnerBuilderField {...props} field={field} form={form} meta={meta} />
)}
</FastField>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { faPlus, faUser } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useField } from "formik";
import { useMemo, useState } from "react";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";

import { ListBox, ListBoxControlButtonProps, Option } from "components/ui/ListBox";
Expand All @@ -26,20 +27,18 @@ export const BuilderFieldWithInputs: React.FC<BuilderFieldProps> = (props) => {
);
};

export const UserInputHelper = ({
setValue,
currentValue,
}: {
interface UserInputHelperProps {
setValue: (value: string) => void;
currentValue: string;
}) => {
}

export const UserInputHelper = (props: UserInputHelperProps) => {
const { formatMessage } = useIntl();
const [modalOpen, setModalOpen] = useState(false);
const { builderFormValues } = useConnectorBuilderFormState();
const listOptions = useMemo(() => {
const options: Array<Option<string | undefined>> = [
...builderFormValues.inputs,
...getInferredInputs(builderFormValues),
...getInferredInputs(builderFormValues.global, builderFormValues.inferredInputOverrides),
].map((input) => ({
label: input.definition.title || input.key,
value: input.key,
Expand All @@ -50,45 +49,56 @@ export const UserInputHelper = ({
icon: <FontAwesomeIcon icon={faPlus} />,
});
return options;
}, [builderFormValues, formatMessage]);
return (
<>
<ListBox<string | undefined>
buttonClassName={styles.button}
optionClassName={styles.option}
className={styles.container}
selectedOptionClassName={styles.selectedOption}
controlButton={UserInputHelperControlButton}
selectedValue={undefined}
onSelect={(selectedValue) => {
if (selectedValue) {
setValue(`${currentValue || ""}{{ config['${selectedValue}'] }}`);
} else {
// This hack is necessary because listbox will put the focus back when the option list gets hidden, which conflicts with the auto-focus setting of the modal.
// As it's not possible to prevent listbox from forcing the focus back on the button component, this will wait until the focus went to the button, then opens the modal
// so it can move it to the first input
setTimeout(() => {
setModalOpen(true);
}, 50);
}
}}
options={listOptions}
/>
{modalOpen && (
<InputForm
inputInEditing={newInputInEditing()}
onClose={(newInput) => {
setModalOpen(false);
if (!newInput) {
return;
}, [builderFormValues.global, builderFormValues.inferredInputOverrides, builderFormValues.inputs, formatMessage]);
return <InnerUserInputHelper {...props} listOptions={listOptions} />;
};

const InnerUserInputHelper = React.memo(
({
setValue,
currentValue,
listOptions,
}: UserInputHelperProps & { listOptions: Array<Option<string | undefined>> }) => {
const [modalOpen, setModalOpen] = useState(false);
return (
<>
<ListBox<string | undefined>
buttonClassName={styles.button}
optionClassName={styles.option}
className={styles.container}
selectedOptionClassName={styles.selectedOption}
controlButton={UserInputHelperControlButton}
selectedValue={undefined}
onSelect={(selectedValue) => {
if (selectedValue) {
setValue(`${currentValue || ""}{{ config['${selectedValue}'] }}`);
} else {
// This hack is necessary because listbox will put the focus back when the option list gets hidden, which conflicts with the auto-focus setting of the modal.
// As it's not possible to prevent listbox from forcing the focus back on the button component, this will wait until the focus went to the button, then opens the modal
// so it can move it to the first input
setTimeout(() => {
setModalOpen(true);
}, 50);
}
setValue(`${currentValue}{{ config['${newInput.key}'] }}`);
}}
options={listOptions}
/>
)}
</>
);
};
{modalOpen && (
<InputForm
inputInEditing={newInputInEditing()}
onClose={(newInput) => {
setModalOpen(false);
if (!newInput) {
return;
}
setValue(`${currentValue}{{ config['${newInput.key}'] }}`);
}}
/>
)}
</>
);
}
);

const UserInputHelperControlButton: React.FC<ListBoxControlButtonProps<string | undefined>> = () => {
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useField } from "formik";
import { FastField, FastFieldProps } from "formik";
import React from "react";

import GroupControls from "components/GroupControls";
Expand All @@ -25,10 +25,14 @@ interface BuilderOneOfProps {
tooltip: string;
}

export const BuilderOneOf: React.FC<BuilderOneOfProps> = ({ options, path, label, tooltip }) => {
const [, , oneOfPathHelpers] = useField(path);
const typePath = `${path}.type`;
const [typePathField] = useField(typePath);
const InnerBuilderOneOf: React.FC<BuilderOneOfProps & FastFieldProps<string>> = ({
options,
label,
tooltip,
field: typePathField,
path,
form,
}) => {
const value = typePathField.value;

const selectedOption = options.find((option) => option.typeValue === value);
Expand All @@ -48,7 +52,7 @@ export const BuilderOneOf: React.FC<BuilderOneOfProps> = ({ options, path, label
return;
}
// clear all values for this oneOf and set selected option and default values
oneOfPathHelpers.setValue({
form.setFieldValue(path, {
type: selectedOption.value,
...selectedOption.default,
});
Expand All @@ -60,3 +64,10 @@ export const BuilderOneOf: React.FC<BuilderOneOfProps> = ({ options, path, label
</GroupControls>
);
};
export const BuilderOneOf: React.FC<BuilderOneOfProps> = (props) => {
return (
<FastField name={`${props.path}.type`}>
{(fastFieldProps: FastFieldProps<string>) => <InnerBuilderOneOf {...props} {...fastFieldProps} />}
</FastField>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ export const BuilderSidebar: React.FC<BuilderSidebarProps> = React.memo(({ class
<FontAwesomeIcon icon={faUser} />
<FormattedMessage
id="connectorBuilder.userInputs"
values={{ number: values.inputs.length + getInferredInputs(values).length }}
values={{
number: values.inputs.length + getInferredInputs(values.global, values.inferredInputOverrides).length,
}}
/>
</ViewSelectButton>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ export const InputForm = ({
}) => {
const { values, setFieldValue } = useFormikContext<BuilderFormValues>();
const [inputs, , helpers] = useField<BuilderFormInput[]>("inputs");
const inferredInputs = useMemo(() => getInferredInputs(values), [values]);
const inferredInputs = useMemo(
() => getInferredInputs(values.global, values.inferredInputOverrides),
[values.global, values.inferredInputOverrides]
);
const usedKeys = useMemo(
() => [...inputs.value, ...inferredInputs].map((input) => input.key),
[inputs.value, inferredInputs]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ export const InputsView: React.FC = () => {
const { formatMessage } = useIntl();
const { values } = useFormikContext<BuilderFormValues>();
const [inputInEditing, setInputInEditing] = useState<InputInEditing | undefined>(undefined);
const inferredInputs = useMemo(() => getInferredInputs(values), [values]);
const inferredInputs = useMemo(
() => getInferredInputs(values.global, values.inferredInputOverrides),
[values.global, values.inferredInputOverrides]
);

return (
<BuilderConfigView heading={formatMessage({ id: "connectorBuilder.inputsTitle" })}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useField } from "formik";
import React, { useRef } from "react";
import { FormattedMessage } from "react-intl";

import GroupControls from "components/GroupControls";
Expand Down Expand Up @@ -60,29 +61,53 @@ interface KeyValueListFieldProps {
export const KeyValueListField: React.FC<KeyValueListFieldProps> = ({ path, label, tooltip }) => {
const [{ value: keyValueList }, , { setValue: setKeyValueList }] = useField<Array<[string, string]>>(path);

// need to wrap the setter into a ref because it will be a new function on every formik state update
const setKeyValueListRef = useRef(setKeyValueList);
setKeyValueListRef.current = setKeyValueList;

return (
<GroupControls
label={<ControlLabels label={label} infoTooltipContent={tooltip} />}
control={
<Button type="button" variant="secondary" onClick={() => setKeyValueList([...keyValueList, ["", ""]])}>
<FormattedMessage id="connectorBuilder.addKeyValue" />
</Button>
}
>
{keyValueList.map((keyValue, keyValueIndex) => (
<KeyValueInput
key={keyValueIndex}
keyValue={keyValue}
onChange={(newKeyValue) => {
const updatedList = keyValueList.map((entry, index) => (index === keyValueIndex ? newKeyValue : entry));
setKeyValueList(updatedList);
}}
onRemove={() => {
const updatedList = keyValueList.filter((_, index) => index !== keyValueIndex);
setKeyValueList(updatedList);
}}
/>
))}
</GroupControls>
<KeyValueList label={label} tooltip={tooltip} keyValueList={keyValueList} setKeyValueList={setKeyValueListRef} />
);
};

const KeyValueList = React.memo(
({
keyValueList,
setKeyValueList,
label,
tooltip,
}: Omit<KeyValueListFieldProps, "path"> & {
keyValueList: Array<[string, string]>;
setKeyValueList: React.MutableRefObject<(val: Array<[string, string]>) => void>;
}) => {
return (
<GroupControls
label={<ControlLabels label={label} infoTooltipContent={tooltip} />}
control={
<Button
type="button"
variant="secondary"
onClick={() => setKeyValueList.current([...keyValueList, ["", ""]])}
>
<FormattedMessage id="connectorBuilder.addKeyValue" />
</Button>
}
>
{keyValueList.map((keyValue, keyValueIndex) => (
<KeyValueInput
key={keyValueIndex}
keyValue={keyValue}
onChange={(newKeyValue) => {
const updatedList = keyValueList.map((entry, index) => (index === keyValueIndex ? newKeyValue : entry));
setKeyValueList.current(updatedList);
}}
onRemove={() => {
const updatedList = keyValueList.filter((_, index) => index !== keyValueIndex);
setKeyValueList.current(updatedList);
}}
/>
))}
</GroupControls>
);
}
);
Loading

0 comments on commit 7c2ff54

Please sign in to comment.