Skip to content

Commit 14b04f2

Browse files
guan404mingbbovenzi
andcommitted
feat: add dag_run_conf to RunBackfillForm
Co-authored-by: Brent Bovenzi <4600967+bbovenzi@users.noreply.github.com>
1 parent 36766d1 commit 14b04f2

File tree

3 files changed

+198
-123
lines changed

3 files changed

+198
-123
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*!
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
import { Accordion, Box, Field } from "@chakra-ui/react";
20+
import { type Control, type FieldValues, type Path, Controller } from "react-hook-form";
21+
22+
import type { ParamsSpec } from "src/queries/useDagParams";
23+
import { useParamStore } from "src/queries/useParamStore";
24+
25+
import { FlexibleForm, flexibleFormDefaultSection } from "./FlexibleForm";
26+
import { JsonEditor } from "./JsonEditor";
27+
28+
type ConfigFormProps<T extends FieldValues = FieldValues> = {
29+
readonly children?: React.ReactNode;
30+
readonly control: Control<T>;
31+
readonly errors: {
32+
conf?: string;
33+
date?: unknown;
34+
};
35+
readonly initialParamsDict: { paramsDict: ParamsSpec };
36+
readonly setErrors: React.Dispatch<
37+
React.SetStateAction<{
38+
conf?: string;
39+
date?: unknown;
40+
}>
41+
>;
42+
};
43+
44+
const ConfigForm = <T extends FieldValues = FieldValues>({
45+
children,
46+
control,
47+
errors,
48+
initialParamsDict,
49+
setErrors,
50+
}: ConfigFormProps<T>) => {
51+
const { conf, setConf } = useParamStore();
52+
53+
const validateAndPrettifyJson = (value: string) => {
54+
try {
55+
const parsedJson = JSON.parse(value) as JSON;
56+
57+
setErrors((prev) => ({ ...prev, conf: undefined }));
58+
59+
const formattedJson = JSON.stringify(parsedJson, undefined, 2);
60+
61+
if (formattedJson !== conf) {
62+
setConf(formattedJson); // Update only if the value is different
63+
}
64+
65+
return formattedJson;
66+
} catch (error) {
67+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred.";
68+
69+
setErrors((prev) => ({
70+
...prev,
71+
conf: `Invalid JSON format: ${errorMessage}`,
72+
}));
73+
74+
return value;
75+
}
76+
};
77+
78+
return (
79+
<Accordion.Root
80+
collapsible
81+
defaultValue={[flexibleFormDefaultSection]}
82+
mb={4}
83+
size="lg"
84+
variant="enclosed"
85+
>
86+
<FlexibleForm
87+
flexibleFormDefaultSection={flexibleFormDefaultSection}
88+
initialParamsDict={initialParamsDict}
89+
/>
90+
<Accordion.Item key="advancedOptions" value="advancedOptions">
91+
<Accordion.ItemTrigger cursor="button">Advanced Options</Accordion.ItemTrigger>
92+
<Accordion.ItemContent>
93+
<Box p={4}>
94+
{children}
95+
<Controller
96+
control={control}
97+
name={"conf" as Path<T>}
98+
render={({ field }) => (
99+
<Field.Root invalid={Boolean(errors.conf)} mt={6}>
100+
<Field.Label fontSize="md">Configuration JSON</Field.Label>
101+
<JsonEditor
102+
{...field}
103+
onBlur={() => {
104+
field.onChange(validateAndPrettifyJson(field.value as string));
105+
}}
106+
/>
107+
{Boolean(errors.conf) ? <Field.ErrorText>{errors.conf}</Field.ErrorText> : undefined}
108+
</Field.Root>
109+
)}
110+
/>
111+
</Box>
112+
</Accordion.ItemContent>
113+
</Accordion.Item>
114+
</Accordion.Root>
115+
);
116+
};
117+
118+
export default ConfigForm;

airflow-core/src/airflow/ui/src/components/DagActions/RunBackfillForm.tsx

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ import { Button } from "src/components/ui";
2525
import { reprocessBehaviors } from "src/constants/reprocessBehaviourParams";
2626
import { useCreateBackfill } from "src/queries/useCreateBackfill";
2727
import { useCreateBackfillDryRun } from "src/queries/useCreateBackfillDryRun";
28+
import { useDagParams } from "src/queries/useDagParams";
2829
import { useTogglePause } from "src/queries/useTogglePause";
2930
import { pluralize } from "src/utils";
3031

32+
import ConfigForm from "../ConfigForm";
3133
import { DateTimeInput } from "../DateTimeInput";
3234
import { ErrorAlert } from "../ErrorAlert";
35+
import type { DagRunTriggerParams } from "../TriggerDag/TriggerDAGForm";
3336
import { Checkbox } from "../ui/Checkbox";
3437
import { RadioCardItem, RadioCardLabel, RadioCardRoot } from "../ui/RadioCard";
3538

@@ -39,14 +42,16 @@ type RunBackfillFormProps = {
3942
};
4043
const today = new Date().toISOString().slice(0, 16);
4144

45+
type BackfillFormProps = DagRunTriggerParams & Omit<BackfillPostBody, "dag_run_conf">;
46+
4247
const RunBackfillForm = ({ dag, onClose }: RunBackfillFormProps) => {
4348
const [errors, setErrors] = useState<{ conf?: string; date?: unknown }>({});
4449
const [unpause, setUnpause] = useState(true);
45-
46-
const { control, handleSubmit, reset, watch } = useForm<BackfillPostBody>({
50+
const initialParamsDict = useDagParams(dag.dag_id, true);
51+
const { control, handleSubmit, reset, watch } = useForm<BackfillFormProps>({
4752
defaultValues: {
53+
conf: "",
4854
dag_id: dag.dag_id,
49-
dag_run_conf: {},
5055
from_date: "",
5156
max_active_runs: 1,
5257
reprocess_behavior: "none",
@@ -55,7 +60,7 @@ const RunBackfillForm = ({ dag, onClose }: RunBackfillFormProps) => {
5560
},
5661
mode: "onBlur",
5762
});
58-
const values = useWatch<BackfillPostBody>({
63+
const values = useWatch<BackfillFormProps>({
5964
control,
6065
});
6166

@@ -88,7 +93,7 @@ const RunBackfillForm = ({ dag, onClose }: RunBackfillFormProps) => {
8893
const dataIntervalStart = watch("from_date");
8994
const dataIntervalEnd = watch("to_date");
9095

91-
const onSubmit = (fdata: BackfillPostBody) => {
96+
const onSubmit = (fdata: BackfillFormProps) => {
9297
if (unpause && dag.is_paused) {
9398
togglePause({
9499
dagId: dag.dag_id,
@@ -98,11 +103,14 @@ const RunBackfillForm = ({ dag, onClose }: RunBackfillFormProps) => {
98103
});
99104
}
100105
createBackfill({
101-
requestBody: fdata,
106+
requestBody: {
107+
...fdata,
108+
dag_run_conf: JSON.parse(fdata.conf) as Record<string, unknown>,
109+
},
102110
});
103111
};
104112

105-
const onCancel = (fdata: BackfillPostBody) => {
113+
const onCancel = (fdata: BackfillFormProps) => {
106114
reset(fdata);
107115
onClose();
108116
};
@@ -237,6 +245,13 @@ const RunBackfillForm = ({ dag, onClose }: RunBackfillFormProps) => {
237245
<Spacer />
238246
</>
239247
) : undefined}
248+
249+
<ConfigForm
250+
control={control}
251+
errors={errors}
252+
initialParamsDict={initialParamsDict}
253+
setErrors={setErrors}
254+
/>
240255
</VStack>
241256
<Box as="footer" display="flex" justifyContent="flex-end" mt={4}>
242257
<HStack w="full">

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy