Skip to content

Commit 7c2ff54

Browse files
Joe ReuterTim Roeslmossman
authored andcommitted
🪟🧹 Connector builder: Fast fields performance improvements (#20957)
* 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 <[email protected]> * 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 <[email protected]> * 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 <[email protected]> * Update airbyte-webapp/src/components/connectorBuilder/Builder/InputsView.tsx Co-authored-by: Lake Mossman <[email protected]> * 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 <[email protected]> Co-authored-by: lmossman <[email protected]> * 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 <[email protected]> * Update airbyte-webapp/src/components/connectorBuilder/Builder/InputsView.tsx Co-authored-by: Lake Mossman <[email protected]> * 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 <[email protected]> * [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 <[email protected]> * Update airbyte-webapp/src/components/connectorBuilder/Builder/InputsView.tsx Co-authored-by: Lake Mossman <[email protected]> * 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 <[email protected]> * 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 <[email protected]> * use updated manifest types Co-authored-by: Lake Mossman <[email protected]> * 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 <[email protected]> Co-authored-by: lmossman <[email protected]>
1 parent f76ba9b commit 7c2ff54

File tree

11 files changed

+269
-163
lines changed

11 files changed

+269
-163
lines changed

airbyte-webapp/src/components/connectorBuilder/Builder/BuilderField.tsx

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useField } from "formik";
1+
import { FastField, FastFieldProps, FieldInputProps } from "formik";
22
import { ReactNode } from "react";
33
import { FormattedMessage } from "react-intl";
44

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

67-
export const BuilderField: React.FC<BuilderFieldProps> = ({
67+
const InnerBuilderField: React.FC<BuilderFieldProps & FastFieldProps<unknown>> = ({
6868
path,
6969
label,
7070
tooltip,
7171
optional = false,
7272
readOnly,
7373
pattern,
74+
field,
75+
meta,
76+
form,
7477
adornment,
7578
...props
7679
}) => {
77-
const [field, meta, helpers] = useField(path);
7880
const hasError = !!meta.error && meta.touched;
7981

8082
if (props.type === "boolean") {
8183
return (
8284
<LabeledSwitch
83-
{...field}
84-
checked={field.value}
85+
{...(field as FieldInputProps<string>)}
86+
checked={field.value as boolean}
8587
label={
8688
<>
8789
{label} {tooltip && <InfoTooltip placement="top-start">{tooltip}</InfoTooltip>}
@@ -93,7 +95,7 @@ export const BuilderField: React.FC<BuilderFieldProps> = ({
9395

9496
const setValue = (newValue: unknown) => {
9597
props.onChange?.(newValue as string & string[]);
96-
helpers.setValue(newValue);
98+
form.setFieldValue(path, newValue);
9799
};
98100

99101
return (
@@ -104,23 +106,28 @@ export const BuilderField: React.FC<BuilderFieldProps> = ({
104106
onChange={(e) => {
105107
field.onChange(e);
106108
if (e.target.value === "") {
107-
helpers.setValue(undefined);
109+
form.setFieldValue(path, undefined);
108110
}
109111
props.onChange?.(e.target.value);
110112
}}
111113
className={props.className}
112114
type={props.type}
113-
value={field.value ?? ""}
115+
value={(field.value as string | number | undefined) ?? ""}
114116
error={hasError}
115117
readOnly={readOnly}
116118
adornment={adornment}
117119
/>
118120
)}
119121
{props.type === "array" && (
120-
<ArrayField name={path} value={field.value ?? []} setValue={setValue} error={hasError} />
122+
<ArrayField
123+
name={path}
124+
value={(field.value as string[] | undefined) ?? []}
125+
setValue={setValue}
126+
error={hasError}
127+
/>
121128
)}
122129
{props.type === "enum" && (
123-
<EnumField options={props.options} value={field.value} setValue={setValue} error={hasError} />
130+
<EnumField options={props.options} value={field.value as string} setValue={setValue} error={hasError} />
124131
)}
125132
{hasError && (
126133
<Text className={styles.error}>
@@ -133,3 +140,13 @@ export const BuilderField: React.FC<BuilderFieldProps> = ({
133140
</ControlLabels>
134141
);
135142
};
143+
144+
export const BuilderField: React.FC<BuilderFieldProps> = (props) => {
145+
return (
146+
<FastField name={props.path}>
147+
{({ field, form, meta }: FastFieldProps<unknown>) => (
148+
<InnerBuilderField {...props} field={field} form={form} meta={meta} />
149+
)}
150+
</FastField>
151+
);
152+
};

airbyte-webapp/src/components/connectorBuilder/Builder/BuilderFieldWithInputs.tsx

Lines changed: 53 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { faPlus, faUser } from "@fortawesome/free-solid-svg-icons";
22
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
33
import { useField } from "formik";
44
import { useMemo, useState } from "react";
5+
import React from "react";
56
import { FormattedMessage, useIntl } from "react-intl";
67

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

29-
export const UserInputHelper = ({
30-
setValue,
31-
currentValue,
32-
}: {
30+
interface UserInputHelperProps {
3331
setValue: (value: string) => void;
3432
currentValue: string;
35-
}) => {
33+
}
34+
35+
export const UserInputHelper = (props: UserInputHelperProps) => {
3636
const { formatMessage } = useIntl();
37-
const [modalOpen, setModalOpen] = useState(false);
3837
const { builderFormValues } = useConnectorBuilderFormState();
3938
const listOptions = useMemo(() => {
4039
const options: Array<Option<string | undefined>> = [
4140
...builderFormValues.inputs,
42-
...getInferredInputs(builderFormValues),
41+
...getInferredInputs(builderFormValues.global, builderFormValues.inferredInputOverrides),
4342
].map((input) => ({
4443
label: input.definition.title || input.key,
4544
value: input.key,
@@ -50,45 +49,56 @@ export const UserInputHelper = ({
5049
icon: <FontAwesomeIcon icon={faPlus} />,
5150
});
5251
return options;
53-
}, [builderFormValues, formatMessage]);
54-
return (
55-
<>
56-
<ListBox<string | undefined>
57-
buttonClassName={styles.button}
58-
optionClassName={styles.option}
59-
className={styles.container}
60-
selectedOptionClassName={styles.selectedOption}
61-
controlButton={UserInputHelperControlButton}
62-
selectedValue={undefined}
63-
onSelect={(selectedValue) => {
64-
if (selectedValue) {
65-
setValue(`${currentValue || ""}{{ config['${selectedValue}'] }}`);
66-
} else {
67-
// 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.
68-
// 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
69-
// so it can move it to the first input
70-
setTimeout(() => {
71-
setModalOpen(true);
72-
}, 50);
73-
}
74-
}}
75-
options={listOptions}
76-
/>
77-
{modalOpen && (
78-
<InputForm
79-
inputInEditing={newInputInEditing()}
80-
onClose={(newInput) => {
81-
setModalOpen(false);
82-
if (!newInput) {
83-
return;
52+
}, [builderFormValues.global, builderFormValues.inferredInputOverrides, builderFormValues.inputs, formatMessage]);
53+
return <InnerUserInputHelper {...props} listOptions={listOptions} />;
54+
};
55+
56+
const InnerUserInputHelper = React.memo(
57+
({
58+
setValue,
59+
currentValue,
60+
listOptions,
61+
}: UserInputHelperProps & { listOptions: Array<Option<string | undefined>> }) => {
62+
const [modalOpen, setModalOpen] = useState(false);
63+
return (
64+
<>
65+
<ListBox<string | undefined>
66+
buttonClassName={styles.button}
67+
optionClassName={styles.option}
68+
className={styles.container}
69+
selectedOptionClassName={styles.selectedOption}
70+
controlButton={UserInputHelperControlButton}
71+
selectedValue={undefined}
72+
onSelect={(selectedValue) => {
73+
if (selectedValue) {
74+
setValue(`${currentValue || ""}{{ config['${selectedValue}'] }}`);
75+
} else {
76+
// 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.
77+
// 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
78+
// so it can move it to the first input
79+
setTimeout(() => {
80+
setModalOpen(true);
81+
}, 50);
8482
}
85-
setValue(`${currentValue}{{ config['${newInput.key}'] }}`);
8683
}}
84+
options={listOptions}
8785
/>
88-
)}
89-
</>
90-
);
91-
};
86+
{modalOpen && (
87+
<InputForm
88+
inputInEditing={newInputInEditing()}
89+
onClose={(newInput) => {
90+
setModalOpen(false);
91+
if (!newInput) {
92+
return;
93+
}
94+
setValue(`${currentValue}{{ config['${newInput.key}'] }}`);
95+
}}
96+
/>
97+
)}
98+
</>
99+
);
100+
}
101+
);
92102

93103
const UserInputHelperControlButton: React.FC<ListBoxControlButtonProps<string | undefined>> = () => {
94104
return (

airbyte-webapp/src/components/connectorBuilder/Builder/BuilderOneOf.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useField } from "formik";
1+
import { FastField, FastFieldProps } from "formik";
22
import React from "react";
33

44
import GroupControls from "components/GroupControls";
@@ -25,10 +25,14 @@ interface BuilderOneOfProps {
2525
tooltip: string;
2626
}
2727

28-
export const BuilderOneOf: React.FC<BuilderOneOfProps> = ({ options, path, label, tooltip }) => {
29-
const [, , oneOfPathHelpers] = useField(path);
30-
const typePath = `${path}.type`;
31-
const [typePathField] = useField(typePath);
28+
const InnerBuilderOneOf: React.FC<BuilderOneOfProps & FastFieldProps<string>> = ({
29+
options,
30+
label,
31+
tooltip,
32+
field: typePathField,
33+
path,
34+
form,
35+
}) => {
3236
const value = typePathField.value;
3337

3438
const selectedOption = options.find((option) => option.typeValue === value);
@@ -48,7 +52,7 @@ export const BuilderOneOf: React.FC<BuilderOneOfProps> = ({ options, path, label
4852
return;
4953
}
5054
// clear all values for this oneOf and set selected option and default values
51-
oneOfPathHelpers.setValue({
55+
form.setFieldValue(path, {
5256
type: selectedOption.value,
5357
...selectedOption.default,
5458
});
@@ -60,3 +64,10 @@ export const BuilderOneOf: React.FC<BuilderOneOfProps> = ({ options, path, label
6064
</GroupControls>
6165
);
6266
};
67+
export const BuilderOneOf: React.FC<BuilderOneOfProps> = (props) => {
68+
return (
69+
<FastField name={`${props.path}.type`}>
70+
{(fastFieldProps: FastFieldProps<string>) => <InnerBuilderOneOf {...props} {...fastFieldProps} />}
71+
</FastField>
72+
);
73+
};

airbyte-webapp/src/components/connectorBuilder/Builder/BuilderSidebar.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,9 @@ export const BuilderSidebar: React.FC<BuilderSidebarProps> = React.memo(({ class
111111
<FontAwesomeIcon icon={faUser} />
112112
<FormattedMessage
113113
id="connectorBuilder.userInputs"
114-
values={{ number: values.inputs.length + getInferredInputs(values).length }}
114+
values={{
115+
number: values.inputs.length + getInferredInputs(values.global, values.inferredInputOverrides).length,
116+
}}
115117
/>
116118
</ViewSelectButton>
117119

airbyte-webapp/src/components/connectorBuilder/Builder/InputsForm.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ export const InputForm = ({
7070
}) => {
7171
const { values, setFieldValue } = useFormikContext<BuilderFormValues>();
7272
const [inputs, , helpers] = useField<BuilderFormInput[]>("inputs");
73-
const inferredInputs = useMemo(() => getInferredInputs(values), [values]);
73+
const inferredInputs = useMemo(
74+
() => getInferredInputs(values.global, values.inferredInputOverrides),
75+
[values.global, values.inferredInputOverrides]
76+
);
7477
const usedKeys = useMemo(
7578
() => [...inputs.value, ...inferredInputs].map((input) => input.key),
7679
[inputs.value, inferredInputs]

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ export const InputsView: React.FC = () => {
1919
const { formatMessage } = useIntl();
2020
const { values } = useFormikContext<BuilderFormValues>();
2121
const [inputInEditing, setInputInEditing] = useState<InputInEditing | undefined>(undefined);
22-
const inferredInputs = useMemo(() => getInferredInputs(values), [values]);
22+
const inferredInputs = useMemo(
23+
() => getInferredInputs(values.global, values.inferredInputOverrides),
24+
[values.global, values.inferredInputOverrides]
25+
);
2326

2427
return (
2528
<BuilderConfigView heading={formatMessage({ id: "connectorBuilder.inputsTitle" })}>

airbyte-webapp/src/components/connectorBuilder/Builder/KeyValueListField.tsx

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useField } from "formik";
2+
import React, { useRef } from "react";
23
import { FormattedMessage } from "react-intl";
34

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

64+
// need to wrap the setter into a ref because it will be a new function on every formik state update
65+
const setKeyValueListRef = useRef(setKeyValueList);
66+
setKeyValueListRef.current = setKeyValueList;
67+
6368
return (
64-
<GroupControls
65-
label={<ControlLabels label={label} infoTooltipContent={tooltip} />}
66-
control={
67-
<Button type="button" variant="secondary" onClick={() => setKeyValueList([...keyValueList, ["", ""]])}>
68-
<FormattedMessage id="connectorBuilder.addKeyValue" />
69-
</Button>
70-
}
71-
>
72-
{keyValueList.map((keyValue, keyValueIndex) => (
73-
<KeyValueInput
74-
key={keyValueIndex}
75-
keyValue={keyValue}
76-
onChange={(newKeyValue) => {
77-
const updatedList = keyValueList.map((entry, index) => (index === keyValueIndex ? newKeyValue : entry));
78-
setKeyValueList(updatedList);
79-
}}
80-
onRemove={() => {
81-
const updatedList = keyValueList.filter((_, index) => index !== keyValueIndex);
82-
setKeyValueList(updatedList);
83-
}}
84-
/>
85-
))}
86-
</GroupControls>
69+
<KeyValueList label={label} tooltip={tooltip} keyValueList={keyValueList} setKeyValueList={setKeyValueListRef} />
8770
);
8871
};
72+
73+
const KeyValueList = React.memo(
74+
({
75+
keyValueList,
76+
setKeyValueList,
77+
label,
78+
tooltip,
79+
}: Omit<KeyValueListFieldProps, "path"> & {
80+
keyValueList: Array<[string, string]>;
81+
setKeyValueList: React.MutableRefObject<(val: Array<[string, string]>) => void>;
82+
}) => {
83+
return (
84+
<GroupControls
85+
label={<ControlLabels label={label} infoTooltipContent={tooltip} />}
86+
control={
87+
<Button
88+
type="button"
89+
variant="secondary"
90+
onClick={() => setKeyValueList.current([...keyValueList, ["", ""]])}
91+
>
92+
<FormattedMessage id="connectorBuilder.addKeyValue" />
93+
</Button>
94+
}
95+
>
96+
{keyValueList.map((keyValue, keyValueIndex) => (
97+
<KeyValueInput
98+
key={keyValueIndex}
99+
keyValue={keyValue}
100+
onChange={(newKeyValue) => {
101+
const updatedList = keyValueList.map((entry, index) => (index === keyValueIndex ? newKeyValue : entry));
102+
setKeyValueList.current(updatedList);
103+
}}
104+
onRemove={() => {
105+
const updatedList = keyValueList.filter((_, index) => index !== keyValueIndex);
106+
setKeyValueList.current(updatedList);
107+
}}
108+
/>
109+
))}
110+
</GroupControls>
111+
);
112+
}
113+
);

0 commit comments

Comments
 (0)