Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate API with Trigger Dag Run #44850

Merged
merged 18 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion airflow/ui/src/components/TriggerDag/TriggerDAGForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { FiPlay } from "react-icons/fi";
import { useColorMode } from "src/context/colorMode";

import { Accordion } from "../ui";
import type { DagParams } from "./TriggerDag";
import type { DagParams } from "./TriggerDAGModal";

type TriggerDAGFormProps = {
dagParams: DagParams;
Expand Down
16 changes: 9 additions & 7 deletions airflow/ui/src/components/TriggerDag/TriggerDAGIconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,15 @@ const TriggerDAGIconButton: React.FC<Props> = ({ dag }) => {
<FiPlay />
</IconButton>

<TriggerDAGModal
dagDisplayName={dag.dag_display_name}
dagId={dag.dag_id}
isPaused={dag.is_paused}
onClose={onClose}
open={open}
/>
{open ? (
<TriggerDAGModal
dagDisplayName={dag.dag_display_name}
dagId={dag.dag_id}
isPaused={dag.is_paused}
onClose={onClose}
open={open}
/>
) : undefined}
</Box>
);
};
Expand Down
142 changes: 115 additions & 27 deletions airflow/ui/src/components/TriggerDag/TriggerDAGModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,30 @@
* under the License.
*/
import { Heading, VStack } from "@chakra-ui/react";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useQueryClient } from "@tanstack/react-query";
import React, { useCallback, useEffect, useState } from "react";

import {
useDagRunServiceGetDagRunsKey,
useDagRunServiceTriggerDagRun,
useDagServiceGetDagDetails,
useDagServiceGetDagsKey,
useDagsServiceRecentDagRunsKey,
} from "openapi/queries";
import { Alert, Dialog } from "src/components/ui";

import { ErrorAlert } from "../ErrorAlert";
import { TogglePause } from "../TogglePause";
import TriggerDAGForm from "./TriggerDAGForm";
import type { DagParams } from "./TriggerDag";
import { TriggerDag as triggerDag } from "./TriggerDag";

export type DagParams = {
configJson: string;
dagId: string;
dataIntervalEnd: string;
dataIntervalStart: string;
notes: string;
runId: string;
};

type TriggerDAGModalProps = {
dagDisplayName: string;
Expand All @@ -41,33 +57,102 @@ const TriggerDAGModal: React.FC<TriggerDAGModalProps> = ({
onClose,
open,
}) => {
const initialDagParams = useMemo(
() => ({
configJson: "{}",
dagId,
dataIntervalEnd: "",
dataIntervalStart: "",
notes: "",
runId: "",
}),
[dagId],
);
const { data, error } = useDagServiceGetDagDetails({ dagId });

const [dagParams, setDagParams] = useState<DagParams>(initialDagParams);
const transformedParams = data?.params
? Object.fromEntries(
Object.entries(data.params).map(([key, param]) => [
key,
(param as { value: unknown }).value,
]),
)
: {};

const initialConf = JSON.stringify(transformedParams, undefined, 2);

const [dagParams, setDagParams] = useState<DagParams>({
configJson: initialConf,
dagId,
dataIntervalEnd: "",
dataIntervalStart: "",
notes: "",
runId: "",
});

useEffect(() => {
const newConfigJson = Boolean(error) ? "{}" : initialConf; // Fallback to "{}" if there's an error

const handleTrigger = useCallback(
setDagParams((prevParams) => ({
...prevParams,
configJson: newConfigJson,
}));
}, [initialConf, error]);

const queryClient = useQueryClient();
const onSuccess = async () => {
await queryClient.invalidateQueries({
queryKey: [useDagServiceGetDagsKey],
});

await queryClient.invalidateQueries({
queryKey: [useDagsServiceRecentDagRunsKey],
});

await queryClient.invalidateQueries({
queryKey: [useDagRunServiceGetDagRunsKey],
});
};
const { mutate } = useDagRunServiceTriggerDagRun({
onSuccess,
});

const onTrigger = useCallback(
(updatedDagParams: DagParams) => {
triggerDag(updatedDagParams);
onClose();
// Parse the configJson string into a JavaScript object
const parsedConfig = JSON.parse(updatedDagParams.configJson) as Record<
string,
unknown
>;

// Validate and format data intervals
const formattedDataIntervalStart = updatedDagParams.dataIntervalStart
? new Date(updatedDagParams.dataIntervalStart).toISOString()
: undefined; // Use null if empty or invalid
const formattedDataIntervalEnd = updatedDagParams.dataIntervalEnd
? new Date(updatedDagParams.dataIntervalEnd).toISOString()
: undefined; // Use null if empty or invalid

mutate({
dagId: updatedDagParams.dagId,
requestBody: {
conf: parsedConfig,
dag_run_id: updatedDagParams.runId,
data_interval_end: formattedDataIntervalEnd,
data_interval_start: formattedDataIntervalStart,
note: updatedDagParams.notes,
},
});
},
[onClose],
[mutate],
);

const handleTrigger = (updatedDagParams: DagParams) => {
onTrigger(updatedDagParams);
onClose();
};

useEffect(() => {
if (!open) {
setDagParams(initialDagParams);
setDagParams({
configJson: initialConf,
dagId,
dataIntervalEnd: "",
dataIntervalStart: "",
notes: "",
runId: "",
});
}
}, [open, initialDagParams]);
}, [open, initialConf, dagId]);

return (
<Dialog.Root onOpenChange={onClose} open={open} size="xl">
Expand All @@ -82,6 +167,7 @@ const TriggerDAGModal: React.FC<TriggerDAGModalProps> = ({
skipConfirm
/>
</Heading>
<ErrorAlert error={error} />
{isPaused ? (
<Alert status="warning" title="Paused DAG">
Triggering will create a DAG run, but it will not start until
Expand All @@ -94,12 +180,14 @@ const TriggerDAGModal: React.FC<TriggerDAGModalProps> = ({
<Dialog.CloseTrigger />

<Dialog.Body>
<TriggerDAGForm
dagParams={dagParams}
onClose={onClose}
onTrigger={handleTrigger}
setDagParams={setDagParams}
/>
{Boolean(error) ? undefined : (
<TriggerDAGForm
dagParams={dagParams}
onClose={onClose}
onTrigger={handleTrigger}
setDagParams={setDagParams}
/>
)}
</Dialog.Body>
</Dialog.Content>
</Dialog.Root>
Expand Down
16 changes: 9 additions & 7 deletions airflow/ui/src/components/TriggerDag/TriggerDAGTextButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@ const TriggerDAGIconButton: React.FC<Props> = ({ dag }) => {
Trigger
</Button>

<TriggerDAGModal
dagDisplayName={dag.dag_display_name}
dagId={dag.dag_id}
isPaused={dag.is_paused}
onClose={onClose}
open={open}
/>
{open ? (
<TriggerDAGModal
dagDisplayName={dag.dag_display_name}
dagId={dag.dag_id}
isPaused={dag.is_paused}
onClose={onClose}
open={open}
/>
) : undefined}
</Box>
);
};
Expand Down
44 changes: 0 additions & 44 deletions airflow/ui/src/components/TriggerDag/TriggerDag.tsx

This file was deleted.