You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by bb...@apache.org on 2022/03/08 20:57:20 UTC
[airflow] 11/11: dag run actions w/ react-query
This is an automated email from the ASF dual-hosted git repository.
bbovenzi pushed a commit to branch mapped-task-drawer
in repository https://gitbox.apache.org/repos/asf/airflow.git
commit 194a371f11e026ba74a7a15691d63d190ea4cae8
Author: Brent Bovenzi <br...@gmail.com>
AuthorDate: Tue Mar 8 15:54:45 2022 -0500
dag run actions w/ react-query
---
airflow/www/static/js/tree/Tree.jsx | 3 +-
airflow/www/static/js/tree/api/index.js | 6 ++
.../js/tree/api/{index.js => useClearRun.js} | 38 +++++++++----
.../js/tree/api/{index.js => useMarkFailedRun.js} | 38 +++++++++----
.../js/tree/api/{index.js => useMarkSuccessRun.js} | 38 +++++++++----
.../www/static/js/tree/details/content/DagRun.jsx | 64 ++--------------------
airflow/www/static/js/tree/index.jsx | 1 -
airflow/www/static/js/tree/useTreeData.js | 20 ++++++-
8 files changed, 110 insertions(+), 98 deletions(-)
diff --git a/airflow/www/static/js/tree/Tree.jsx b/airflow/www/static/js/tree/Tree.jsx
index b777d73..a0fa54b 100644
--- a/airflow/www/static/js/tree/Tree.jsx
+++ b/airflow/www/static/js/tree/Tree.jsx
@@ -128,7 +128,8 @@ const Tree = () => {
overflowX="auto"
ref={scrollRef}
flexGrow={1}
- width={isOpen && '300px'}
+ maxWidth={isOpen && '300px'}
+ minWidth={isOpen && '300px'}
>
<Table height={0}>
<Thead>
diff --git a/airflow/www/static/js/tree/api/index.js b/airflow/www/static/js/tree/api/index.js
index 3327fef..96c4a67 100644
--- a/airflow/www/static/js/tree/api/index.js
+++ b/airflow/www/static/js/tree/api/index.js
@@ -22,6 +22,9 @@ import camelcaseKeys from 'camelcase-keys';
import useDag from './useDag';
import useTasks from './useTasks';
+import useClearRun from './useClearRun';
+import useMarkFailedRun from './useMarkFailedRun';
+import useMarkSuccessRun from './useMarkSuccessRun';
axios.interceptors.response.use(
(res) => (res.data ? camelcaseKeys(res.data, { deep: true }) : res),
@@ -30,4 +33,7 @@ axios.interceptors.response.use(
export {
useDag,
useTasks,
+ useClearRun,
+ useMarkFailedRun,
+ useMarkSuccessRun,
};
diff --git a/airflow/www/static/js/tree/api/index.js b/airflow/www/static/js/tree/api/useClearRun.js
similarity index 52%
copy from airflow/www/static/js/tree/api/index.js
copy to airflow/www/static/js/tree/api/useClearRun.js
index 3327fef..8be4d17 100644
--- a/airflow/www/static/js/tree/api/index.js
+++ b/airflow/www/static/js/tree/api/useClearRun.js
@@ -18,16 +18,32 @@
*/
import axios from 'axios';
-import camelcaseKeys from 'camelcase-keys';
+import { useMutation, useQueryClient } from 'react-query';
+import { getMetaValue } from '../../utils';
-import useDag from './useDag';
-import useTasks from './useTasks';
+export default function useClearRun(dagId, runId) {
+ const queryClient = useQueryClient();
+ return useMutation(
+ ['dagRunClear', dagId, runId],
+ () => {
+ const csrfToken = getMetaValue('csrf_token');
+ const params = new URLSearchParams({
+ csrf_token: csrfToken,
+ confirmed: true,
+ dag_id: dagId,
+ dag_run_id: runId,
+ }).toString();
-axios.interceptors.response.use(
- (res) => (res.data ? camelcaseKeys(res.data, { deep: true }) : res),
-);
-
-export {
- useDag,
- useTasks,
-};
+ return axios.post('/dagrun_clear', params, {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ },
+ });
+ },
+ {
+ onSettled: () => {
+ queryClient.invalidateQueries('treeData');
+ },
+ },
+ );
+}
diff --git a/airflow/www/static/js/tree/api/index.js b/airflow/www/static/js/tree/api/useMarkFailedRun.js
similarity index 52%
copy from airflow/www/static/js/tree/api/index.js
copy to airflow/www/static/js/tree/api/useMarkFailedRun.js
index 3327fef..dec25fe 100644
--- a/airflow/www/static/js/tree/api/index.js
+++ b/airflow/www/static/js/tree/api/useMarkFailedRun.js
@@ -18,16 +18,32 @@
*/
import axios from 'axios';
-import camelcaseKeys from 'camelcase-keys';
+import { useMutation, useQueryClient } from 'react-query';
+import { getMetaValue } from '../../utils';
-import useDag from './useDag';
-import useTasks from './useTasks';
+export default function useMarkFailedRun(dagId, runId) {
+ const queryClient = useQueryClient();
+ return useMutation(
+ ['dagRunFailed', dagId, runId],
+ () => {
+ const csrfToken = getMetaValue('csrf_token');
+ const params = new URLSearchParams({
+ csrf_token: csrfToken,
+ confirmed: true,
+ dag_id: dagId,
+ dag_run_id: runId,
+ }).toString();
-axios.interceptors.response.use(
- (res) => (res.data ? camelcaseKeys(res.data, { deep: true }) : res),
-);
-
-export {
- useDag,
- useTasks,
-};
+ return axios.post('/dagrun_failed', params, {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ },
+ });
+ },
+ {
+ onSettled: () => {
+ queryClient.invalidateQueries('treeData');
+ },
+ },
+ );
+}
diff --git a/airflow/www/static/js/tree/api/index.js b/airflow/www/static/js/tree/api/useMarkSuccessRun.js
similarity index 52%
copy from airflow/www/static/js/tree/api/index.js
copy to airflow/www/static/js/tree/api/useMarkSuccessRun.js
index 3327fef..7e1d589 100644
--- a/airflow/www/static/js/tree/api/index.js
+++ b/airflow/www/static/js/tree/api/useMarkSuccessRun.js
@@ -18,16 +18,32 @@
*/
import axios from 'axios';
-import camelcaseKeys from 'camelcase-keys';
+import { useMutation, useQueryClient } from 'react-query';
+import { getMetaValue } from '../../utils';
-import useDag from './useDag';
-import useTasks from './useTasks';
+export default function useMarkSuccessRun(dagId, runId) {
+ const queryClient = useQueryClient();
+ return useMutation(
+ ['dagRunSuccess', dagId, runId],
+ () => {
+ const csrfToken = getMetaValue('csrf_token');
+ const params = new URLSearchParams({
+ csrf_token: csrfToken,
+ confirmed: true,
+ dag_id: dagId,
+ dag_run_id: runId,
+ }).toString();
-axios.interceptors.response.use(
- (res) => (res.data ? camelcaseKeys(res.data, { deep: true }) : res),
-);
-
-export {
- useDag,
- useTasks,
-};
+ return axios.post('/dagrun_success', params, {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ },
+ });
+ },
+ {
+ onSettled: () => {
+ queryClient.invalidateQueries('treeData');
+ },
+ },
+ );
+}
diff --git a/airflow/www/static/js/tree/details/content/DagRun.jsx b/airflow/www/static/js/tree/details/content/DagRun.jsx
index be06794..b47907b 100644
--- a/airflow/www/static/js/tree/details/content/DagRun.jsx
+++ b/airflow/www/static/js/tree/details/content/DagRun.jsx
@@ -20,7 +20,6 @@
/* global moment */
import React from 'react';
-import axios from 'axios';
import {
Flex,
Text,
@@ -30,71 +29,16 @@ import {
import { MdPlayArrow } from 'react-icons/md';
import { formatDateTime, formatDuration } from '../../../datetime_utils';
-import { getMetaValue } from '../../../utils';
+import { useClearRun, useMarkFailedRun, useMarkSuccessRun } from '../../api';
const DagRun = ({
dagRun: {
dagId, state, runId, duration, dataIntervalStart, dataIntervalEnd, startDate, endDate, runType,
},
}) => {
- const csrfToken = getMetaValue('csrf_token');
-
- const onClear = async () => {
- const params = new URLSearchParams({
- csrf_token: csrfToken,
- confirmed: true,
- dag_id: dagId,
- dag_run_id: runId,
- }).toString();
-
- try {
- await axios.post('/dagrun_clear', params, {
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded',
- },
- });
- } catch (e) {
- console.error(e);
- }
- };
-
- const markFailed = async () => {
- const params = new URLSearchParams({
- csrf_token: csrfToken,
- confirmed: true,
- dag_id: dagId,
- dag_run_id: runId,
- }).toString();
-
- try {
- await axios.post('/dagrun_failed', params, {
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded',
- },
- });
- } catch (e) {
- console.error(e);
- }
- };
-
- const markSuccess = async () => {
- const params = new URLSearchParams({
- csrf_token: csrfToken,
- confirmed: true,
- dag_id: dagId,
- dag_run_id: runId,
- }).toString();
-
- try {
- await axios.post('/dagrun_success', params, {
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded',
- },
- });
- } catch (e) {
- console.error(e);
- }
- };
+ const { mutate: onClear } = useClearRun(dagId, runId);
+ const { mutate: markFailed } = useMarkFailedRun(dagId, runId);
+ const { mutate: markSuccess } = useMarkSuccessRun(dagId, runId);
return (
<Box fontSize="12px" py="4px">
diff --git a/airflow/www/static/js/tree/index.jsx b/airflow/www/static/js/tree/index.jsx
index a509d25..4eea821 100644
--- a/airflow/www/static/js/tree/index.jsx
+++ b/airflow/www/static/js/tree/index.jsx
@@ -36,7 +36,6 @@ const myCache = createCache({
});
const mainElement = document.getElementById('react-container');
shadowRoot.appendChild(mainElement);
-const queryClient = new QueryClient();
const queryClient = new QueryClient({
defaultOptions: {
diff --git a/airflow/www/static/js/tree/useTreeData.js b/airflow/www/static/js/tree/useTreeData.js
index e26a9c9..24481b3 100644
--- a/airflow/www/static/js/tree/useTreeData.js
+++ b/airflow/www/static/js/tree/useTreeData.js
@@ -19,6 +19,7 @@
/* global treeData, localStorage, autoRefreshInterval, fetch */
+import { useEffect } from 'react';
import { useDisclosure } from '@chakra-ui/react';
import camelcaseKeys from 'camelcase-keys';
import { useQuery } from 'react-query';
@@ -54,8 +55,9 @@ const formatData = (data) => {
const useTreeData = () => {
const initialData = formatData(treeData);
+ const canRefresh = isPaused !== 'True' && !JSON.parse(localStorage.getItem(autoRefreshKey));
- const defaultIsOpen = isPaused !== 'True' && !JSON.parse(localStorage.getItem(autoRefreshKey)) && areActiveRuns(initialData.dagRuns);
+ const defaultIsOpen = canRefresh && areActiveRuns(initialData.dagRuns);
const { isOpen: isRefreshOn, onToggle, onClose } = useDisclosure({ defaultIsOpen });
const onToggleRefresh = () => {
@@ -88,12 +90,24 @@ const useTreeData = () => {
dagRuns: [],
};
}, {
- // only enabled and refetch if the refresh switch is on
- enabled: isRefreshOn,
+ // only refetch if the refresh switch is on
refetchInterval: isRefreshOn && autoRefreshInterval * 1000,
initialData,
});
+ // turn on autorefresh if data is active again
+ useEffect(() => {
+ if (
+ query.data.dagRuns
+ && JSON.stringify(query.data.dagRuns) !== JSON.stringify(initialData.dagRuns)
+ && canRefresh
+ && areActiveRuns(query.data.dagRuns)
+ && !isRefreshOn
+ ) {
+ onToggle();
+ }
+ }, [canRefresh, initialData.dagRuns, isRefreshOn, onToggle, query.data]);
+
return {
...query,
isRefreshOn,