diff --git a/airflow/ui/src/components/TriggerDag/TriggerDAGForm.tsx b/airflow/ui/src/components/TriggerDag/TriggerDAGForm.tsx index 8288849ecf1f1..19f1aedbd0125 100644 --- a/airflow/ui/src/components/TriggerDag/TriggerDAGForm.tsx +++ b/airflow/ui/src/components/TriggerDag/TriggerDAGForm.tsx @@ -48,14 +48,18 @@ export type DagRunTriggerParams = { const TriggerDAGForm = ({ dagId, onClose, open }: TriggerDAGFormProps) => { const [errors, setErrors] = useState<{ conf?: string; date?: unknown }>({}); const conf = useDagParams(dagId, open); - const { error: errorTrigger, isPending, triggerDagRun } = useTrigger(onClose); + const { + dateValidationError, + error: errorTrigger, + isPending, + triggerDagRun, + } = useTrigger({ onSuccessConfirm: onClose }); const { control, formState: { isDirty }, handleSubmit, reset, - setValue, watch, } = useForm({ defaultValues: { @@ -74,28 +78,27 @@ const TriggerDAGForm = ({ dagId, onClose, open }: TriggerDAGFormProps) => { } }, [conf, reset]); + useEffect(() => { + if (Boolean(dateValidationError)) { + setErrors((prev) => ({ ...prev, date: dateValidationError })); + } + }, [dateValidationError]); + const dataIntervalStart = watch("dataIntervalStart"); const dataIntervalEnd = watch("dataIntervalEnd"); const handleReset = () => { setErrors({ conf: undefined, date: undefined }); - reset(); + reset({ + conf, + dagRunId: "", + dataIntervalEnd: "", + dataIntervalStart: "", + note: "", + }); }; const onSubmit = (data: DagRunTriggerParams) => { - if (Boolean(data.dataIntervalStart) !== Boolean(data.dataIntervalEnd)) { - setErrors((prev) => ({ - ...prev, - date: { - body: { - detail: - "Either both Data Interval Start and End must be provided, or both must be empty.", - }, - }, - })); - - return; - } triggerDagRun(dagId, data); }; @@ -119,23 +122,8 @@ const TriggerDAGForm = ({ dagId, onClose, open }: TriggerDAGFormProps) => { } }; - const validateDates = ( - fieldName: "dataIntervalEnd" | "dataIntervalStart", - ) => { - const startDate = dataIntervalStart - ? new Date(dataIntervalStart) - : undefined; - const endDate = dataIntervalEnd ? new Date(dataIntervalEnd) : undefined; - + const resetDateError = () => { setErrors((prev) => ({ ...prev, date: undefined })); - - if (startDate && endDate) { - if (fieldName === "dataIntervalStart" && startDate > endDate) { - setValue("dataIntervalStart", dataIntervalEnd); - } else if (fieldName === "dataIntervalEnd" && endDate < startDate) { - setValue("dataIntervalEnd", dataIntervalStart); - } - } }; const { colorMode } = useColorMode(); @@ -160,7 +148,7 @@ const TriggerDAGForm = ({ dagId, onClose, open }: TriggerDAGFormProps) => { validateDates("dataIntervalStart")} + onBlur={resetDateError} placeholder="yyyy-mm-ddThh:mm" size="sm" type="datetime-local" @@ -180,7 +168,7 @@ const TriggerDAGForm = ({ dagId, onClose, open }: TriggerDAGFormProps) => { validateDates("dataIntervalEnd")} + onBlur={resetDateError} placeholder="yyyy-mm-ddThh:mm" size="sm" type="datetime-local" diff --git a/airflow/ui/src/queries/useTrigger.ts b/airflow/ui/src/queries/useTrigger.ts index b454d0176a78f..d70efc8aeffb2 100644 --- a/airflow/ui/src/queries/useTrigger.ts +++ b/airflow/ui/src/queries/useTrigger.ts @@ -28,10 +28,17 @@ import { import type { DagRunTriggerParams } from "src/components/TriggerDag/TriggerDAGForm"; import { toaster } from "src/components/ui"; -export const useTrigger = (onClose: () => void) => { +export const useTrigger = ({ + onSuccessConfirm, +}: { + onSuccessConfirm: () => void; +}) => { const queryClient = useQueryClient(); const [error, setError] = useState(undefined); + const [dateValidationError, setDateValidationError] = + useState(undefined); + const onSuccess = async () => { const queryKeys = [ useDagServiceGetDagsKey, @@ -43,14 +50,13 @@ export const useTrigger = (onClose: () => void) => { queryKeys.map((key) => queryClient.invalidateQueries({ queryKey: [key] }), ), - ).then(() => { - toaster.create({ - description: "DAG run has been successfully triggered.", - title: "DAG Run Request Submitted", - type: "success", - }); - onClose(); + ); + toaster.create({ + description: "DAG run has been successfully triggered.", + title: "DAG Run Request Submitted", + type: "success", }); + onSuccessConfirm(); }; const onError = (_error: unknown) => { @@ -71,13 +77,42 @@ export const useTrigger = (onClose: () => void) => { unknown >; - const formattedDataIntervalStart = dagRunRequestBody.dataIntervalStart - ? new Date(dagRunRequestBody.dataIntervalStart).toISOString() + const DataIntervalStart = dagRunRequestBody.dataIntervalStart + ? new Date(dagRunRequestBody.dataIntervalStart) : undefined; - const formattedDataIntervalEnd = dagRunRequestBody.dataIntervalEnd - ? new Date(dagRunRequestBody.dataIntervalEnd).toISOString() + const DataIntervalEnd = dagRunRequestBody.dataIntervalEnd + ? new Date(dagRunRequestBody.dataIntervalEnd) : undefined; + if (Boolean(DataIntervalStart) !== Boolean(DataIntervalEnd)) { + setDateValidationError({ + body: { + detail: + "Either both Data Interval Start Date and End Date must be provided, or both must be empty.", + }, + }); + + return; + } + + if (DataIntervalStart && DataIntervalEnd) { + if (DataIntervalStart > DataIntervalEnd) { + setDateValidationError({ + body: { + detail: + "Data Interval Start Date must be less than or equal to Data Interval End Date.", + }, + }); + + return; + } + } + + const formattedDataIntervalStart = + DataIntervalStart?.toISOString() ?? undefined; + const formattedDataIntervalEnd = + DataIntervalEnd?.toISOString() ?? undefined; + const checkDagRunId = dagRunRequestBody.dagRunId === "" ? undefined @@ -97,5 +132,5 @@ export const useTrigger = (onClose: () => void) => { }); }; - return { error, isPending, triggerDagRun }; + return { dateValidationError, error, isPending, triggerDagRun }; };