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 d86f6984393a45b74324943f04f47e8b808f61e2 Author: Brent Bovenzi <[email protected]> AuthorDate: Tue Mar 8 13:40:23 2022 -0500 dag run actions --- airflow/www/static/js/tree/Tree.jsx | 12 +- airflow/www/static/js/tree/api/index.js | 1 - airflow/www/static/js/tree/api/useDag.js | 2 +- airflow/www/static/js/tree/api/useTasks.js | 2 +- .../www/static/js/tree/details/content/DagRun.jsx | 204 ++++++++++++++------- airflow/www/templates/airflow/dag.html | 1 + 6 files changed, 148 insertions(+), 74 deletions(-) diff --git a/airflow/www/static/js/tree/Tree.jsx b/airflow/www/static/js/tree/Tree.jsx index 0d84639..b777d73 100644 --- a/airflow/www/static/js/tree/Tree.jsx +++ b/airflow/www/static/js/tree/Tree.jsx @@ -53,8 +53,12 @@ const Tree = () => { const { isOpen, onToggle } = useDisclosure({ defaultIsOpen: isPanelOpen }); const toggleSidePanel = () => { - if (!isOpen) localStorage.setItem(sidePanelKey, true); - else localStorage.setItem(sidePanelKey, false); + if (!isOpen) { + localStorage.setItem(sidePanelKey, true); + } else { + setSelected({}); + localStorage.setItem(sidePanelKey, false); + } onToggle(); }; @@ -123,8 +127,8 @@ const Tree = () => { pb="12px" overflowX="auto" ref={scrollRef} - maxWidth={isOpen && '300px'} - minWidth={isOpen && '300px'} + flexGrow={1} + width={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 58edd88..3327fef 100644 --- a/airflow/www/static/js/tree/api/index.js +++ b/airflow/www/static/js/tree/api/index.js @@ -23,7 +23,6 @@ import camelcaseKeys from 'camelcase-keys'; import useDag from './useDag'; import useTasks from './useTasks'; -axios.defaults.baseURL = '/api/v1'; axios.interceptors.response.use( (res) => (res.data ? camelcaseKeys(res.data, { deep: true }) : res), ); diff --git a/airflow/www/static/js/tree/api/useDag.js b/airflow/www/static/js/tree/api/useDag.js index 1343302..143bbe0 100644 --- a/airflow/www/static/js/tree/api/useDag.js +++ b/airflow/www/static/js/tree/api/useDag.js @@ -23,6 +23,6 @@ import { useQuery } from 'react-query'; export default function useDag(dagId) { return useQuery( ['dag', dagId], - () => axios.get(`/dags/${dagId}/details`), + () => axios.get(`/api/v1/dags/${dagId}/details`), ); } diff --git a/airflow/www/static/js/tree/api/useTasks.js b/airflow/www/static/js/tree/api/useTasks.js index 3dd11e30..5edb137 100644 --- a/airflow/www/static/js/tree/api/useTasks.js +++ b/airflow/www/static/js/tree/api/useTasks.js @@ -23,6 +23,6 @@ import { useQuery } from 'react-query'; export default function useTasks(dagId) { return useQuery( ['tasks', dagId], - () => axios.get(`/dags/${dagId}/tasks`), + () => axios.get(`/api/v1/dags/${dagId}/tasks`), ); } diff --git a/airflow/www/static/js/tree/details/content/DagRun.jsx b/airflow/www/static/js/tree/details/content/DagRun.jsx index abcf908..be06794 100644 --- a/airflow/www/static/js/tree/details/content/DagRun.jsx +++ b/airflow/www/static/js/tree/details/content/DagRun.jsx @@ -20,83 +20,153 @@ /* global moment */ import React from 'react'; +import axios from 'axios'; import { + Flex, Text, Box, + Button, } from '@chakra-ui/react'; import { MdPlayArrow } from 'react-icons/md'; import { formatDateTime, formatDuration } from '../../../datetime_utils'; +import { getMetaValue } from '../../../utils'; const DagRun = ({ dagRun: { - state, runId, duration, dataIntervalStart, dataIntervalEnd, startDate, endDate, runType, + dagId, state, runId, duration, dataIntervalStart, dataIntervalEnd, startDate, endDate, runType, }, -}) => ( - <Box fontSize="12px" py="4px"> - <Text> - <Text as="strong">Status:</Text> - {' '} - {state || 'no status'} - </Text> - <br /> - <Text whiteSpace="nowrap"> - Run Id: - {' '} - {runId} - </Text> - <Text> - Run Type: - {' '} - {runType === 'manual' && <MdPlayArrow style={{ display: 'inline' }} />} - {runType} - </Text> - <Text> - Duration: - {' '} - {formatDuration(duration)} - </Text> - <br /> - <Text as="strong">Data Interval:</Text> - <Text> - Start: - {' '} - {formatDateTime(dataIntervalStart)} - </Text> - <Text> - End: - {' '} - {formatDateTime(dataIntervalEnd)} - </Text> - <br /> - <Text as="strong">UTC</Text> - <Text> - Started: - {' '} - {formatDateTime(moment.utc(startDate))} - </Text> - <Text> - Ended: - {' '} - {endDate && formatDateTime(moment.utc(endDate))} - </Text> - <br /> - <Text as="strong"> - Local: - {' '} - {moment().format('Z')} - </Text> - <Text> - Started: - {' '} - {formatDateTime(startDate)} - </Text> - <Text> - Ended: - {' '} - {endDate && formatDateTime(endDate)} - </Text> - </Box> -); +}) => { + 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); + } + }; + + return ( + <Box fontSize="12px" py="4px"> + <Flex justifyContent="space-evenly"> + <Button onClick={onClear}>Clear</Button> + <Button onClick={markFailed} colorScheme="red">Mark Failed</Button> + <Button onClick={markSuccess} colorScheme="green">Mark Success</Button> + </Flex> + <Text> + <Text as="strong">Status:</Text> + {' '} + {state || 'no status'} + </Text> + <br /> + <Text whiteSpace="nowrap"> + Run Id: + {' '} + {runId} + </Text> + <Text> + Run Type: + {' '} + {runType === 'manual' && <MdPlayArrow style={{ display: 'inline' }} />} + {runType} + </Text> + <Text> + Duration: + {' '} + {formatDuration(duration)} + </Text> + <br /> + <Text as="strong">Data Interval:</Text> + <Text> + Start: + {' '} + {formatDateTime(dataIntervalStart)} + </Text> + <Text> + End: + {' '} + {formatDateTime(dataIntervalEnd)} + </Text> + <br /> + <Text as="strong">UTC</Text> + <Text> + Started: + {' '} + {formatDateTime(moment.utc(startDate))} + </Text> + <Text> + Ended: + {' '} + {endDate && formatDateTime(moment.utc(endDate))} + </Text> + <br /> + <Text as="strong"> + Local: + {' '} + {moment().format('Z')} + </Text> + <Text> + Started: + {' '} + {formatDateTime(startDate)} + </Text> + <Text> + Ended: + {' '} + {endDate && formatDateTime(endDate)} + </Text> + </Box> + ); +}; export default DagRun; diff --git a/airflow/www/templates/airflow/dag.html b/airflow/www/templates/airflow/dag.html index f2444abab..0f3387a 100644 --- a/airflow/www/templates/airflow/dag.html +++ b/airflow/www/templates/airflow/dag.html @@ -39,6 +39,7 @@ <meta name="paused_url" content="{{ url_for('Airflow.paused') }}"> <meta name="tree_data" content="{{ url_for('Airflow.tree_data') }}"> <meta name="is_paused" content="{{ dag_is_paused }}"> + <meta name="csrf_token" content="{{ csrf_token() }}"> {% if dag_model is defined and dag_model.next_dagrun_create_after is defined and dag_model.next_dagrun_create_after is not none %} <meta name="next_dagrun_create_after" content="{{ dag_model.next_dagrun_create_after }}"> <meta name="next_dagrun_data_interval_start" content="{{ dag_model.next_dagrun_data_interval_start }}">
