This is an automated email from the ASF dual-hosted git repository. bbovenzi pushed a commit to branch mapped-instance-actions in repository https://gitbox.apache.org/repos/asf/airflow.git
commit 0302732abbe0e2b680691cddb213646df8da93c9 Author: Brent Bovenzi <[email protected]> AuthorDate: Tue Apr 12 14:51:45 2022 -0400 Readd mapped instance table selection --- airflow/www/static/js/tree/Table.jsx | 4 +- airflow/www/static/js/tree/api/useClearTask.js | 4 +- .../www/static/js/tree/api/useConfirmMarkTask.js | 12 +++--- .../www/static/js/tree/api/useMarkFailedTask.js | 4 +- .../www/static/js/tree/api/useMarkSuccessTask.js | 4 +- airflow/www/static/js/tree/api/useRunTask.js | 43 ++++++++++++---------- .../js/tree/details/content/taskInstance/index.jsx | 25 ++++++------- .../content/taskInstance/taskActions/Clear.jsx | 5 ++- .../taskInstance/taskActions/MarkFailed.jsx | 6 ++- .../taskInstance/taskActions/MarkSuccess.jsx | 10 +++-- .../content/taskInstance/taskActions/Run.jsx | 26 ++++--------- 11 files changed, 73 insertions(+), 70 deletions(-) diff --git a/airflow/www/static/js/tree/Table.jsx b/airflow/www/static/js/tree/Table.jsx index 32119cf50e..d4fc7bf752 100644 --- a/airflow/www/static/js/tree/Table.jsx +++ b/airflow/www/static/js/tree/Table.jsx @@ -46,7 +46,7 @@ import { } from 'react-icons/ti'; const IndeterminateCheckbox = forwardRef( - ({ indeterminate, ...rest }, ref) => { + ({ indeterminate, checked, ...rest }, ref) => { const defaultRef = useRef(); const resolvedRef = ref || defaultRef; @@ -55,7 +55,7 @@ const IndeterminateCheckbox = forwardRef( }, [resolvedRef, indeterminate]); return ( - <Checkbox ref={resolvedRef} {...rest} /> + <Checkbox ref={resolvedRef} isChecked={checked} {...rest} /> ); }, ); diff --git a/airflow/www/static/js/tree/api/useClearTask.js b/airflow/www/static/js/tree/api/useClearTask.js index bcf99bb250..eea4b2b656 100644 --- a/airflow/www/static/js/tree/api/useClearTask.js +++ b/airflow/www/static/js/tree/api/useClearTask.js @@ -36,7 +36,7 @@ export default function useClearTask({ return useMutation( ['clearTask', dagId, runId, taskId], ({ - past, future, upstream, downstream, recursive, failed, confirmed, + past, future, upstream, downstream, recursive, failed, confirmed, mapIndexes = [], }) => { const params = new URLSearchParams({ csrf_token: csrfToken, @@ -51,6 +51,7 @@ export default function useClearTask({ downstream, recursive, only_failed: failed, + map_indexes: mapIndexes, }).toString(); return axios.post(clearUrl, params, { @@ -71,6 +72,7 @@ export default function useClearTask({ } if (!status || status !== 'error') { queryClient.invalidateQueries('treeData'); + queryClient.invalidateQueries('mappedInstances', dagId, runId, taskId); startRefresh(); } }, diff --git a/airflow/www/static/js/tree/api/useConfirmMarkTask.js b/airflow/www/static/js/tree/api/useConfirmMarkTask.js index 1450a15d3d..85b5f7df42 100644 --- a/airflow/www/static/js/tree/api/useConfirmMarkTask.js +++ b/airflow/www/static/js/tree/api/useConfirmMarkTask.js @@ -29,9 +29,9 @@ export default function useConfirmMarkTask({ return useMutation( ['confirmStateChange', dagId, runId, taskId, state], ({ - past, future, upstream, downstream, - }) => axios.get(confirmUrl, { - params: { + past, future, upstream, downstream, mapIndexes = [], + }) => { + const params = new URLSearchParams({ dag_id: dagId, dag_run_id: runId, task_id: taskId, @@ -40,7 +40,9 @@ export default function useConfirmMarkTask({ upstream, downstream, state, - }, - }), + map_indexes: mapIndexes, + }); + return axios.get(confirmUrl, { params }); + }, ); } diff --git a/airflow/www/static/js/tree/api/useMarkFailedTask.js b/airflow/www/static/js/tree/api/useMarkFailedTask.js index f2fd28bdb2..333fed21c2 100644 --- a/airflow/www/static/js/tree/api/useMarkFailedTask.js +++ b/airflow/www/static/js/tree/api/useMarkFailedTask.js @@ -33,7 +33,7 @@ export default function useMarkFailedTask({ return useMutation( ['markFailed', dagId, runId, taskId], ({ - past, future, upstream, downstream, + past, future, upstream, downstream, mapIndexes = [], }) => { const params = new URLSearchParams({ csrf_token: csrfToken, @@ -45,6 +45,7 @@ export default function useMarkFailedTask({ future, upstream, downstream, + map_indexes: mapIndexes, }).toString(); return axios.post(failedUrl, params, { @@ -56,6 +57,7 @@ export default function useMarkFailedTask({ { onSuccess: () => { queryClient.invalidateQueries('treeData'); + queryClient.invalidateQueries('mappedInstances', dagId, runId, taskId); startRefresh(); }, }, diff --git a/airflow/www/static/js/tree/api/useMarkSuccessTask.js b/airflow/www/static/js/tree/api/useMarkSuccessTask.js index 92ba539de6..cde919a274 100644 --- a/airflow/www/static/js/tree/api/useMarkSuccessTask.js +++ b/airflow/www/static/js/tree/api/useMarkSuccessTask.js @@ -33,7 +33,7 @@ export default function useMarkSuccessTask({ return useMutation( ['markSuccess', dagId, runId, taskId], ({ - past, future, upstream, downstream, + past, future, upstream, downstream, mapIndexes = [], }) => { const params = new URLSearchParams({ csrf_token: csrfToken, @@ -45,6 +45,7 @@ export default function useMarkSuccessTask({ future, upstream, downstream, + map_indexes: mapIndexes, }).toString(); return axios.post(successUrl, params, { @@ -56,6 +57,7 @@ export default function useMarkSuccessTask({ { onSuccess: () => { queryClient.invalidateQueries('treeData'); + queryClient.invalidateQueries('mappedInstances', dagId, runId, taskId); startRefresh(); }, }, diff --git a/airflow/www/static/js/tree/api/useRunTask.js b/airflow/www/static/js/tree/api/useRunTask.js index 44a9e14bf4..9e45c42f59 100644 --- a/airflow/www/static/js/tree/api/useRunTask.js +++ b/airflow/www/static/js/tree/api/useRunTask.js @@ -32,32 +32,34 @@ export default function useRunTask(dagId, runId, taskId) { const { startRefresh } = useAutoRefresh(); return useMutation( ['runTask', dagId, runId, taskId], - ({ + async ({ ignoreAllDeps, ignoreTaskState, ignoreTaskDeps, - mapIndex = -1, - }) => { - const params = new URLSearchParams({ - csrf_token: csrfToken, - dag_id: dagId, - dag_run_id: runId, - task_id: taskId, - ignore_all_deps: ignoreAllDeps, - ignore_task_deps: ignoreTaskDeps, - ignore_ti_state: ignoreTaskState, - map_index: mapIndex, - }).toString(); + mapIndexes, + }) => Promise.all( + (mapIndexes.length ? mapIndexes : [-1]).map((mi) => { + const params = new URLSearchParams({ + csrf_token: csrfToken, + dag_id: dagId, + dag_run_id: runId, + task_id: taskId, + ignore_all_deps: ignoreAllDeps, + ignore_task_deps: ignoreTaskDeps, + ignore_ti_state: ignoreTaskState, + map_index: mi, + }).toString(); - return axios.post(runUrl, params, { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - }); - }, + return axios.post(runUrl, params, { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + }); + }), + ), { onSuccess: (data) => { - const { message, status } = data; + const { message, status } = data.length ? data[0] : data; if (message && status === 'error') { toast({ description: message, @@ -67,6 +69,7 @@ export default function useRunTask(dagId, runId, taskId) { } if (!status || status !== 'error') { queryClient.invalidateQueries('treeData'); + queryClient.invalidateQueries('mappedInstances', dagId, runId, taskId); startRefresh(); } }, diff --git a/airflow/www/static/js/tree/details/content/taskInstance/index.jsx b/airflow/www/static/js/tree/details/content/taskInstance/index.jsx index 62ffee156a..0e4f441e24 100644 --- a/airflow/www/static/js/tree/details/content/taskInstance/index.jsx +++ b/airflow/www/static/js/tree/details/content/taskInstance/index.jsx @@ -24,7 +24,6 @@ import { Divider, StackDivider, Text, - Flex, } from '@chakra-ui/react'; import RunAction from './taskActions/Run'; @@ -89,39 +88,32 @@ const TaskInstance = ({ taskId, runId }) => { {!isGroup && ( <Box my={3}> <Text as="strong">{taskActionsTitle}</Text> - <Flex maxHeight="20px" minHeight="20px"> - {selectedRows.length ? ( - <Text color="red.500"> - Clear, Mark Failed, and Mark Success do not yet work with individual mapped tasks. - </Text> - ) : <Divider my={2} />} - </Flex> - {/* visibility={selectedRows.length ? 'visible' : 'hidden'} */} + <Divider my={2} /> <VStack justifyContent="center" divider={<StackDivider my={3} />}> <RunAction runId={runId} taskId={taskId} dagId={dagId} - selectedRows={selectedRows} + mapIndexes={selectedRows} /> <ClearAction runId={runId} taskId={taskId} dagId={dagId} executionDate={executionDate} - selectedRows={selectedRows} + mapIndexes={selectedRows} /> <MarkFailedAction runId={runId} taskId={taskId} dagId={dagId} - selectedRows={selectedRows} + mapIndexes={selectedRows} /> <MarkSuccessAction runId={runId} taskId={taskId} dagId={dagId} - selectedRows={selectedRows} + mapIndexes={selectedRows} /> </VStack> <Divider my={2} /> @@ -143,7 +135,12 @@ const TaskInstance = ({ taskId, runId }) => { extraLinks={extraLinks} /> {isMapped && ( - <MappedInstances dagId={dagId} runId={runId} taskId={taskId} selectRows={setSelectedRows} /> + <MappedInstances + dagId={dagId} + runId={runId} + taskId={taskId} + selectRows={setSelectedRows} + /> )} </Box> ); diff --git a/airflow/www/static/js/tree/details/content/taskInstance/taskActions/Clear.jsx b/airflow/www/static/js/tree/details/content/taskInstance/taskActions/Clear.jsx index cada7b59ed..d825976ed2 100644 --- a/airflow/www/static/js/tree/details/content/taskInstance/taskActions/Clear.jsx +++ b/airflow/www/static/js/tree/details/content/taskInstance/taskActions/Clear.jsx @@ -34,7 +34,7 @@ const Run = ({ runId, taskId, executionDate, - selectedRows, + mapIndexes, }) => { const [affectedTasks, setAffectedTasks] = useState([]); @@ -74,6 +74,7 @@ const Run = ({ recursive, failed, confirmed: false, + mapIndexes, }); setAffectedTasks(data); onOpen(); @@ -92,6 +93,7 @@ const Run = ({ recursive, failed, confirmed: true, + mapIndexes, }); setAffectedTasks([]); onClose(); @@ -114,7 +116,6 @@ const Run = ({ colorScheme="blue" onClick={onClick} isLoading={isLoading} - isDisabled={!!selectedRows.length} title="Clearing deletes the previous state of the task instance, allowing it to get re-triggered by the scheduler or a backfill command" > Clear diff --git a/airflow/www/static/js/tree/details/content/taskInstance/taskActions/MarkFailed.jsx b/airflow/www/static/js/tree/details/content/taskInstance/taskActions/MarkFailed.jsx index 6bc10c066e..12f8bcfeef 100644 --- a/airflow/www/static/js/tree/details/content/taskInstance/taskActions/MarkFailed.jsx +++ b/airflow/www/static/js/tree/details/content/taskInstance/taskActions/MarkFailed.jsx @@ -33,7 +33,7 @@ const MarkFailed = ({ dagId, runId, taskId, - selectedRows, + mapIndexes, }) => { const [affectedTasks, setAffectedTasks] = useState([]); @@ -69,6 +69,7 @@ const MarkFailed = ({ future, upstream, downstream, + mapIndexes, }); setAffectedTasks(data); onOpen(); @@ -84,6 +85,7 @@ const MarkFailed = ({ future, upstream, downstream, + mapIndexes, }); setAffectedTasks([]); onClose(); @@ -100,7 +102,7 @@ const MarkFailed = ({ <ActionButton bg={upstream && 'gray.100'} onClick={onToggleUpstream} name="Upstream" /> <ActionButton bg={downstream && 'gray.100'} onClick={onToggleDownstream} name="Downstream" /> </ButtonGroup> - <Button colorScheme="red" onClick={onClick} isLoading={isMarkLoading || isConfirmLoading} isDisabled={!!selectedRows.length}> + <Button colorScheme="red" onClick={onClick} isLoading={isMarkLoading || isConfirmLoading}> Mark Failed </Button> <ConfirmDialog diff --git a/airflow/www/static/js/tree/details/content/taskInstance/taskActions/MarkSuccess.jsx b/airflow/www/static/js/tree/details/content/taskInstance/taskActions/MarkSuccess.jsx index b4d2b8c047..bdf59e6a4d 100644 --- a/airflow/www/static/js/tree/details/content/taskInstance/taskActions/MarkSuccess.jsx +++ b/airflow/www/static/js/tree/details/content/taskInstance/taskActions/MarkSuccess.jsx @@ -29,8 +29,8 @@ import ConfirmDialog from '../../ConfirmDialog'; import ActionButton from './ActionButton'; import { useMarkSuccessTask, useConfirmMarkTask } from '../../../../api'; -const Run = ({ - dagId, runId, taskId, selectedRows, +const MarkSuccess = ({ + dagId, runId, taskId, mapIndexes, }) => { const [affectedTasks, setAffectedTasks] = useState([]); @@ -64,6 +64,7 @@ const Run = ({ future, upstream, downstream, + mapIndexes, }); setAffectedTasks(data); onOpen(); @@ -79,6 +80,7 @@ const Run = ({ future, upstream, downstream, + mapIndexes, }); setAffectedTasks([]); onClose(); @@ -95,7 +97,7 @@ const Run = ({ <ActionButton bg={upstream && 'gray.100'} onClick={onToggleUpstream} name="Upstream" /> <ActionButton bg={downstream && 'gray.100'} onClick={onToggleDownstream} name="Downstream" /> </ButtonGroup> - <Button colorScheme="green" onClick={onClick} isLoading={isMarkLoading || isConfirmLoading} isDisabled={!!selectedRows.length}> + <Button colorScheme="green" onClick={onClick} isLoading={isMarkLoading || isConfirmLoading}> Mark Success </Button> <ConfirmDialog @@ -109,4 +111,4 @@ const Run = ({ ); }; -export default Run; +export default MarkSuccess; diff --git a/airflow/www/static/js/tree/details/content/taskInstance/taskActions/Run.jsx b/airflow/www/static/js/tree/details/content/taskInstance/taskActions/Run.jsx index abb17a8479..464ca7026d 100644 --- a/airflow/www/static/js/tree/details/content/taskInstance/taskActions/Run.jsx +++ b/airflow/www/static/js/tree/details/content/taskInstance/taskActions/Run.jsx @@ -35,7 +35,7 @@ const Run = ({ dagId, runId, taskId, - selectedRows, + mapIndexes, }) => { const containerRef = useContainerRef(); const [ignoreAllDeps, setIgnoreAllDeps] = useState(false); @@ -50,22 +50,12 @@ const Run = ({ const { mutate: onRun, isLoading } = useRunTask(dagId, runId, taskId); const onClick = () => { - if (selectedRows.length) { - selectedRows.forEach((mapIndex) => { - onRun({ - ignoreAllDeps, - ignoreTaskState, - ignoreTaskDeps, - mapIndex, - }); - }); - } else { - onRun({ - ignoreAllDeps, - ignoreTaskState, - ignoreTaskDeps, - }); - } + onRun({ + ignoreAllDeps, + ignoreTaskState, + ignoreTaskDeps, + mapIndexes, + }); }; return ( @@ -96,7 +86,7 @@ const Run = ({ <Tooltip label="Only works with the Celery, CeleryKubernetes or Kubernetes executors" shouldWrapChildren // Will show the tooltip even if the button is disabled - disabled={canRun} + isDisabled={canRun} portalProps={{ containerRef }} > <Button colorScheme="blue" onClick={onClick} isLoading={isLoading} disabled={!canRun}>
