Skip to content

Commit e39b90f

Browse files
Joe Reuterlmossman
andauthored
🪟🐛 Make modal scrollable (#21973)
* make modal scrollable * remove unnecessary prop * fix * fix common case * add overflow to confirmation module content --------- Co-authored-by: lmossman <[email protected]>
1 parent f3c94fb commit e39b90f

File tree

7 files changed

+240
-234
lines changed

7 files changed

+240
-234
lines changed

airbyte-webapp/src/components/common/ConfirmationModal/ConfirmationModal.module.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
font-size: 14px;
88
padding: 25px;
99
white-space: pre-line;
10+
overflow: auto;
1011
}
1112

1213
.buttonContent {

airbyte-webapp/src/components/connectorBuilder/Builder/InputsForm.module.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
@use "scss/variables";
22
@use "scss/colors";
33

4-
.inputForm {
4+
.inputFormBody {
55
gap: variables.$spacing-lg;
66
display: flex;
77
flex-direction: column;

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

Lines changed: 103 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -181,118 +181,117 @@ const InputModal = ({
181181
id={inputInEditing.isNew ? "connectorBuilder.inputModal.newTitle" : "connectorBuilder.inputModal.editTitle"}
182182
/>
183183
}
184+
wrapIn={Form}
184185
onClose={onClose}
185186
>
186-
<Form>
187-
<ModalBody className={styles.inputForm}>
188-
<BuilderField
189-
path="definition.title"
190-
type="string"
191-
onChange={(newValue) => {
192-
if (!isInferredInputOverride) {
193-
setFieldValue("key", sluggify(newValue || ""), true);
194-
}
195-
}}
196-
label={formatMessage({ id: "connectorBuilder.inputModal.inputName" })}
197-
tooltip={formatMessage({ id: "connectorBuilder.inputModal.inputNameTooltip" })}
198-
/>
199-
<BuilderField
200-
path="key"
201-
type="string"
202-
readOnly
203-
label={formatMessage({ id: "connectorBuilder.inputModal.fieldId" })}
204-
tooltip={formatMessage(
205-
{ id: "connectorBuilder.inputModal.fieldIdTooltip" },
206-
{
207-
syntaxExample: `{{config['${values.key || "my_input"}']}}`,
208-
}
209-
)}
210-
/>
211-
<BuilderField
212-
path="definition.description"
213-
optional
214-
type="string"
215-
label={formatMessage({ id: "connectorBuilder.inputModal.description" })}
216-
tooltip={formatMessage({ id: "connectorBuilder.inputModal.descriptionTooltip" })}
217-
/>
218-
{values.type !== "unknown" && !isInferredInputOverride ? (
219-
<>
220-
<BuilderField
221-
path="type"
222-
type="enum"
223-
options={["string", "number", "integer", "array", "boolean", "enum"]}
224-
onChange={() => {
225-
setFieldValue("definition.default", undefined);
226-
}}
227-
label={formatMessage({ id: "connectorBuilder.inputModal.type" })}
228-
tooltip={formatMessage({ id: "connectorBuilder.inputModal.typeTooltip" })}
229-
/>
230-
{values.type === "enum" && (
231-
<BuilderField
232-
path="definition.enum"
233-
type="array"
234-
optional
235-
label={formatMessage({ id: "connectorBuilder.inputModal.enum" })}
236-
tooltip={formatMessage({ id: "connectorBuilder.inputModal.enumTooltip" })}
237-
/>
238-
)}
239-
<BuilderField
240-
path="definition.airbyte_secret"
241-
type="boolean"
242-
optional
243-
label={formatMessage({ id: "connectorBuilder.inputModal.secret" })}
244-
tooltip={formatMessage({ id: "connectorBuilder.inputModal.secretTooltip" })}
245-
/>
187+
<ModalBody className={styles.inputFormBody}>
188+
<BuilderField
189+
path="definition.title"
190+
type="string"
191+
onChange={(newValue) => {
192+
if (!isInferredInputOverride) {
193+
setFieldValue("key", sluggify(newValue || ""), true);
194+
}
195+
}}
196+
label={formatMessage({ id: "connectorBuilder.inputModal.inputName" })}
197+
tooltip={formatMessage({ id: "connectorBuilder.inputModal.inputNameTooltip" })}
198+
/>
199+
<BuilderField
200+
path="key"
201+
type="string"
202+
readOnly
203+
label={formatMessage({ id: "connectorBuilder.inputModal.fieldId" })}
204+
tooltip={formatMessage(
205+
{ id: "connectorBuilder.inputModal.fieldIdTooltip" },
206+
{
207+
syntaxExample: `{{config['${values.key || "my_input"}']}}`,
208+
}
209+
)}
210+
/>
211+
<BuilderField
212+
path="definition.description"
213+
optional
214+
type="string"
215+
label={formatMessage({ id: "connectorBuilder.inputModal.description" })}
216+
tooltip={formatMessage({ id: "connectorBuilder.inputModal.descriptionTooltip" })}
217+
/>
218+
{values.type !== "unknown" && !isInferredInputOverride ? (
219+
<>
220+
<BuilderField
221+
path="type"
222+
type="enum"
223+
options={["string", "number", "integer", "array", "boolean", "enum"]}
224+
onChange={() => {
225+
setFieldValue("definition.default", undefined);
226+
}}
227+
label={formatMessage({ id: "connectorBuilder.inputModal.type" })}
228+
tooltip={formatMessage({ id: "connectorBuilder.inputModal.typeTooltip" })}
229+
/>
230+
{values.type === "enum" && (
246231
<BuilderField
247-
path="required"
248-
type="boolean"
232+
path="definition.enum"
233+
type="array"
249234
optional
250-
label={formatMessage({ id: "connectorBuilder.inputModal.required" })}
251-
tooltip={formatMessage({ id: "connectorBuilder.inputModal.requiredTooltip" })}
235+
label={formatMessage({ id: "connectorBuilder.inputModal.enum" })}
236+
tooltip={formatMessage({ id: "connectorBuilder.inputModal.enumTooltip" })}
252237
/>
238+
)}
239+
<BuilderField
240+
path="definition.airbyte_secret"
241+
type="boolean"
242+
optional
243+
label={formatMessage({ id: "connectorBuilder.inputModal.secret" })}
244+
tooltip={formatMessage({ id: "connectorBuilder.inputModal.secretTooltip" })}
245+
/>
246+
<BuilderField
247+
path="required"
248+
type="boolean"
249+
optional
250+
label={formatMessage({ id: "connectorBuilder.inputModal.required" })}
251+
tooltip={formatMessage({ id: "connectorBuilder.inputModal.requiredTooltip" })}
252+
/>
253+
<BuilderField
254+
path="showDefaultValueField"
255+
type="boolean"
256+
optional
257+
label={formatMessage({ id: "connectorBuilder.inputModal.showDefaultValueField" })}
258+
tooltip={formatMessage({ id: "connectorBuilder.inputModal.showDefaultValueFieldTooltip" })}
259+
/>
260+
{values.showDefaultValueField && (
253261
<BuilderField
254-
path="showDefaultValueField"
255-
type="boolean"
262+
path="definition.default"
263+
type={values.type}
264+
options={(values.definition.enum || []) as string[]}
256265
optional
257-
label={formatMessage({ id: "connectorBuilder.inputModal.showDefaultValueField" })}
258-
tooltip={formatMessage({ id: "connectorBuilder.inputModal.showDefaultValueFieldTooltip" })}
266+
label={formatMessage({ id: "connectorBuilder.inputModal.default" })}
259267
/>
260-
{values.showDefaultValueField && (
261-
<BuilderField
262-
path="definition.default"
263-
type={values.type}
264-
options={(values.definition.enum || []) as string[]}
265-
optional
266-
label={formatMessage({ id: "connectorBuilder.inputModal.default" })}
267-
/>
268-
)}
269-
</>
270-
) : (
271-
<Callout className={styles.calloutContainer}>
272-
{isInferredInputOverride ? (
273-
<FormattedMessage id="connectorBuilder.inputModal.inferredInputMessage" />
274-
) : (
275-
<FormattedMessage id="connectorBuilder.inputModal.unsupportedInput" />
276-
)}
277-
</Callout>
278-
)}
279-
</ModalBody>
280-
<ModalFooter>
281-
{!inputInEditing.isNew && !inputInEditing.isInferredInputOverride && (
282-
<div className={styles.deleteButtonContainer}>
283-
<Button variant="danger" type="button" onClick={onDelete}>
284-
<FormattedMessage id="form.delete" />
285-
</Button>
286-
</div>
287-
)}
288-
<Button variant="secondary" type="reset" onClick={onClose}>
289-
<FormattedMessage id="form.cancel" />
290-
</Button>
291-
<Button type="submit" disabled={!isValid}>
292-
<FormattedMessage id={inputInEditing.isNew ? "form.create" : "form.saveChanges"} />
293-
</Button>
294-
</ModalFooter>
295-
</Form>
268+
)}
269+
</>
270+
) : (
271+
<Callout className={styles.calloutContainer}>
272+
{isInferredInputOverride ? (
273+
<FormattedMessage id="connectorBuilder.inputModal.inferredInputMessage" />
274+
) : (
275+
<FormattedMessage id="connectorBuilder.inputModal.unsupportedInput" />
276+
)}
277+
</Callout>
278+
)}
279+
</ModalBody>
280+
<ModalFooter>
281+
{!inputInEditing.isNew && !inputInEditing.isInferredInputOverride && (
282+
<div className={styles.deleteButtonContainer}>
283+
<Button variant="danger" type="button" onClick={onDelete}>
284+
<FormattedMessage id="form.delete" />
285+
</Button>
286+
</div>
287+
)}
288+
<Button variant="secondary" type="reset" onClick={onClose}>
289+
<FormattedMessage id="form.cancel" />
290+
</Button>
291+
<Button type="submit" disabled={!isValid}>
292+
<FormattedMessage id={inputInEditing.isNew ? "form.create" : "form.saveChanges"} />
293+
</Button>
294+
</ModalFooter>
296295
</Modal>
297296
);
298297
};

airbyte-webapp/src/components/ui/Modal/Modal.module.scss

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@
2626
}
2727

2828
.modalPanel {
29-
margin-left: auto;
30-
margin-right: auto;
29+
max-height: 100%;
30+
display: flex;
3131
}
3232

3333
.card {
3434
margin-left: variables.$width-size-menu;
3535
max-width: calc(100vw - #{variables.$width-size-menu} - #{variables.$spacing-lg} * 2);
36+
display: flex;
37+
flex-direction: column;
3638

3739
&.sm {
3840
width: variables.$width-modal-sm;

airbyte-webapp/src/components/ui/Modal/Modal.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ export interface ModalProps {
1212
cardless?: boolean;
1313
size?: "sm" | "md" | "lg" | "xl";
1414
testId?: string;
15+
/**
16+
* If specified, the full content of the modal including header, body and footer is wrapped in this component (only a class name prop might be set on the component)
17+
*/
18+
wrapIn?: React.FC<React.PropsWithChildren<{ className?: string }>>;
1519
}
1620

1721
const cardStyleBySize = {
@@ -28,6 +32,7 @@ export const Modal: React.FC<React.PropsWithChildren<ModalProps>> = ({
2832
onClose,
2933
cardless,
3034
testId,
35+
wrapIn,
3136
}) => {
3237
const [isOpen, setIsOpen] = useState(true);
3338

@@ -36,10 +41,12 @@ export const Modal: React.FC<React.PropsWithChildren<ModalProps>> = ({
3641
onClose?.();
3742
};
3843

44+
const Wrapper = wrapIn || "div";
45+
3946
return (
4047
<Dialog open={isOpen} onClose={onModalClose} data-testid={testId} className={styles.modalPageContainer}>
4148
<Overlay />
42-
<div className={styles.modalContainer}>
49+
<Wrapper className={styles.modalContainer}>
4350
<Dialog.Panel className={styles.modalPanel}>
4451
{cardless ? (
4552
children
@@ -49,7 +56,7 @@ export const Modal: React.FC<React.PropsWithChildren<ModalProps>> = ({
4956
</Card>
5057
)}
5158
</Dialog.Panel>
52-
</div>
59+
</Wrapper>
5360
</Dialog>
5461
);
5562
};

0 commit comments

Comments
 (0)