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/04/09 18:57:49 UTC
[airflow] 01/02: Add Xcom button, hide map index actions, disabled run
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 85f44b97dcc3dd46188127d73b4b3f01d08afb4c
Author: Brent Bovenzi <br...@gmail.com>
AuthorDate: Sat Apr 9 13:27:38 2022 -0400
Add Xcom button, hide map index actions, disabled run
---
airflow/www/static/js/dag.js | 18 +++++++++++++++++
.../content/taskInstance/MappedInstances.jsx | 17 +++++++++-------
.../js/tree/details/content/taskInstance/Nav.jsx | 9 ++++++++-
.../content/taskInstance/taskActions/Run.jsx | 21 ++++++++++++++++----
airflow/www/templates/airflow/dag.html | 23 ++++++++++++++--------
5 files changed, 68 insertions(+), 20 deletions(-)
diff --git a/airflow/www/static/js/dag.js b/airflow/www/static/js/dag.js
index 1606737017..145d1f2666 100644
--- a/airflow/www/static/js/dag.js
+++ b/airflow/www/static/js/dag.js
@@ -124,6 +124,13 @@ function updateModalUrls() {
execution_date: executionDate,
map_index: mapIndex,
});
+
+ updateButtonUrl(buttons.xcom, {
+ dag_id: dagId,
+ task_id: taskId,
+ execution_date: executionDate,
+ map_index: mapIndex,
+ });
}
// Update modal urls on toggle
@@ -170,9 +177,16 @@ export function callModal({
if (mi >= 0) {
$('#modal_map_index').show();
$('#modal_map_index .value').text(mi);
+ // Marking state and clear are not yet supported for mapped instances
+ $('#success_action').hide();
+ $('#failed_action').hide();
+ $('#clear_action').hide();
} else {
$('#modal_map_index').hide();
$('#modal_map_index .value').text('');
+ $('#success_action').show();
+ $('#failed_action').show();
+ $('#clear_action').show();
}
if (isSubDag) {
$('#div_btn_subdag').show();
@@ -197,8 +211,12 @@ export function callModal({
$('#btn_mapped').show();
$('#mapped_dropdown').css('display', 'inline-block');
$('#btn_rendered').hide();
+ $('#btn_xcom').hide();
+ $('#btn_log').hide();
} else {
$('#btn_rendered').show();
+ $('#btn_xcom').show();
+ $('#btn_log').show();
$('#btn_mapped').hide();
$('#mapped_dropdown').hide();
}
diff --git a/airflow/www/static/js/tree/details/content/taskInstance/MappedInstances.jsx b/airflow/www/static/js/tree/details/content/taskInstance/MappedInstances.jsx
index b815f0987f..42bbdca66f 100644
--- a/airflow/www/static/js/tree/details/content/taskInstance/MappedInstances.jsx
+++ b/airflow/www/static/js/tree/details/content/taskInstance/MappedInstances.jsx
@@ -26,9 +26,9 @@ import {
IconButton,
} from '@chakra-ui/react';
import { snakeCase } from 'lodash';
-import { FaMicroscope } from 'react-icons/fa';
-import { GiLog } from 'react-icons/gi';
-import { HiTemplate } from 'react-icons/hi';
+import {
+ MdDetails, MdCode, MdSyncAlt, MdReorder,
+} from 'react-icons/md';
import { getMetaValue } from '../../../../utils';
import { formatDateTime, formatDuration } from '../../../../datetime_utils';
@@ -39,9 +39,10 @@ import Table from '../../../Table';
const renderedTemplatesUrl = getMetaValue('rendered_templates_url');
const logUrl = getMetaValue('log_url');
const taskUrl = getMetaValue('task_url');
+const xcomUrl = getMetaValue('xcom_url');
const IconLink = (props) => (
- <IconButton as={Link} variant="outline" colorScheme="blue" {...props} />
+ <IconButton as={Link} variant="ghost" colorScheme="blue" fontSize="3xl" {...props} />
);
const MappedInstances = ({
@@ -73,6 +74,7 @@ const MappedInstances = ({
const detailsLink = `${taskUrl}&${params}`;
const renderedLink = `${renderedTemplatesUrl}&${params}`;
const logLink = `${logUrl}&${params}`;
+ const xcomLink = `${xcomUrl}&${params}`;
return {
...mi,
state: (
@@ -86,9 +88,10 @@ const MappedInstances = ({
endDate: mi.endDate && formatDateTime(mi.endDate),
links: (
<Flex alignItems="center">
- <IconLink mr={1} title="Rendered Templates" aria-label="Rendered Templates" icon={<HiTemplate />} href={renderedLink} />
- <IconLink mr={1} title="Log" aria-label="Log" icon={<GiLog />} href={logLink} />
- <IconLink title="Details" aria-label="Details" icon={<FaMicroscope />} href={detailsLink} />
+ <IconLink mr={1} title="Details" aria-label="Details" icon={<MdDetails />} href={detailsLink} />
+ <IconLink mr={1} title="Rendered Templates" aria-label="Rendered Templates" icon={<MdCode />} href={renderedLink} />
+ <IconLink mr={1} title="Log" aria-label="Log" icon={<MdReorder />} href={logLink} />
+ <IconLink title="XCom" fontWeight="bold" aria-label="XCom" icon={<MdSyncAlt />} href={xcomLink} />
</Flex>
),
};
diff --git a/airflow/www/static/js/tree/details/content/taskInstance/Nav.jsx b/airflow/www/static/js/tree/details/content/taskInstance/Nav.jsx
index 7550bdb842..1b7062f898 100644
--- a/airflow/www/static/js/tree/details/content/taskInstance/Nav.jsx
+++ b/airflow/www/static/js/tree/details/content/taskInstance/Nav.jsx
@@ -34,12 +34,17 @@ const baseDate = getMetaValue('base_date');
const taskInstancesUrl = getMetaValue('task_instances_list_url');
const renderedK8sUrl = getMetaValue('rendered_k8s_url');
const renderedTemplatesUrl = getMetaValue('rendered_templates_url');
+const xcomUrl = getMetaValue('xcom_url');
const logUrl = getMetaValue('log_url');
const taskUrl = getMetaValue('task_url');
const gridUrl = getMetaValue('grid_url');
const gridUrlNoRoot = getMetaValue('grid_url_no_root');
-const LinkButton = ({ children, ...rest }) => (<Button as={Link} variant="ghost" colorScheme="blue" {...rest}>{children}</Button>);
+const LinkButton = ({ children, ...rest }) => (
+ <Button as={Link} aria-label={children} variant="ghost" colorScheme="blue" {...rest}>
+ {children}
+ </Button>
+);
const Nav = ({
taskId, executionDate, operator, isMapped,
@@ -51,6 +56,7 @@ const Nav = ({
const detailsLink = `${taskUrl}&${params}`;
const renderedLink = `${renderedTemplatesUrl}&${params}`;
const logLink = `${logUrl}&${params}`;
+ const xcomLink = `${xcomUrl}&${params}`;
const k8sLink = `${renderedK8sUrl}&${params}`;
const listParams = new URLSearchParams({
_flt_3_dag_id: dagId,
@@ -89,6 +95,7 @@ const Nav = ({
<LinkButton href={subDagLink}>Zoom into SubDag</LinkButton>
)}
<LinkButton href={logLink}>Log</LinkButton>
+ <LinkButton href={xcomLink}>XCom</LinkButton>
</>
)}
<LinkButton href={allInstancesLink} title="View all instances across all DAG runs">All Instances</LinkButton>
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 204cec44c2..d77c3e947d 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
@@ -22,15 +22,21 @@ import {
Button,
Flex,
ButtonGroup,
+ Tooltip,
} from '@chakra-ui/react';
import { useRunTask } from '../../../../api';
+import { getMetaValue } from '../../../../../utils';
+import { useContainerRef } from '../../../../context/containerRef';
+
+const canRun = getMetaValue('k8s_or_k8scelery_executor') === 'True';
const Run = ({
dagId,
runId,
taskId,
}) => {
+ const containerRef = useContainerRef();
const [ignoreAllDeps, setIgnoreAllDeps] = useState(false);
const onToggleAllDeps = () => setIgnoreAllDeps(!ignoreAllDeps);
@@ -52,7 +58,7 @@ const Run = ({
return (
<Flex justifyContent="space-between" width="100%">
- <ButtonGroup isAttached variant="outline">
+ <ButtonGroup isAttached variant="outline" disabled={!canRun}>
<Button
bg={ignoreAllDeps && 'gray.100'}
onClick={onToggleAllDeps}
@@ -75,9 +81,16 @@ const Run = ({
Ignore Task Deps
</Button>
</ButtonGroup>
- <Button colorScheme="blue" onClick={onClick} isLoading={isLoading}>
- Run
- </Button>
+ <Tooltip
+ label="Only works with the Celery, CeleryKubernetes or Kubernetes executors"
+ shouldWrapChildren // Will show the tooltip even if the button is disabled
+ disabled={canRun}
+ portalProps={{ containerRef }}
+ >
+ <Button colorScheme="blue" onClick={onClick} isLoading={isLoading} disabled={!canRun}>
+ Run
+ </Button>
+ </Tooltip>
</Flex>
);
};
diff --git a/airflow/www/templates/airflow/dag.html b/airflow/www/templates/airflow/dag.html
index 16c0d27cb5..277cd53979 100644
--- a/airflow/www/templates/airflow/dag.html
+++ b/airflow/www/templates/airflow/dag.html
@@ -62,6 +62,7 @@
<meta name="dagrun_details_url" content="{{ url_for('Airflow.dagrun_details', redirect_url=request.base_url, dag_id=dag.dag_id) }}">
<meta name="task_url" content="{{ url_for('Airflow.task', dag_id=dag.dag_id) }}">
<meta name="log_url" content="{{ url_for('Airflow.log', dag_id=dag.dag_id) }}">
+ <meta name="xcom_url" content="{{ url_for('Airflow.xcom', dag_id=dag.dag_id) }}">
<meta name="rendered_templates_url" content="{{ url_for('Airflow.rendered_templates', dag_id=dag.dag_id) }}">
<meta name="rendered_k8s_url" content="{{ url_for('Airflow.rendered_k8s', dag_id=dag.dag_id) }}">
<meta name="task_instances_list_url" content="{{ url_for('TaskInstanceModelView.list') }}">
@@ -234,6 +235,9 @@
<a id="btn_log" class="btn btn-sm" data-base-url="{{ url_for('Airflow.log') }}">
Log
</a>
+ <a id="btn_xcom" class="btn btn-sm" data-base-url="{{ url_for('Airflow.xcom') }}">
+ XCom
+ </a>
<a id="btn_ti" class="btn btn-sm" data-base-url="{{ url_for('TaskInstanceModelView.list') }}" title="View all instances across all DAG runs">
All Instances
</a>
@@ -273,7 +277,7 @@
</div>
{% endif %}
<h4>Task Actions</h4>
- <form method="POST" data-action="{{ url_for('Airflow.run') }}">
+ <form method="POST" data-action="{{ url_for('Airflow.run') }}" id="run_action">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="dag_id" value="{{ dag.dag_id }}">
<input type="hidden" name="task_id">
@@ -281,6 +285,9 @@
<input type="hidden" name="map_index">
<input type="hidden" name="origin" value="{{ request.base_url }}">
<div class="row">
+ <span class="col-xs-12 col-sm-9 text-danger" style="font-size: 12px">
+ {{ "Only works with the Celery, CeleryKubernetes or Kubernetes executors, sorry" if not k8s_or_k8scelery_executor else "" }}
+ </span>
<span class="btn-group col-xs-12 col-sm-9 task-instance-modal-column" data-toggle="buttons">
<label
class="btn btn-default"
@@ -299,14 +306,14 @@
</label>
</span>
<span class="col-xs-12 col-sm-3 task-instance-modal-column">
- <button type="submit" id="btn_run" class="btn btn-primary btn-block" title="Runs a single task instance">
+ <button type="submit" id="btn_run" class="btn btn-primary btn-block" title="Runs a single task instance" {{ " disabled" if not k8s_or_k8scelery_executor else "" }}>
Run
</button>
</span>
</div>
+ <hr style="margin-bottom: 8px;">
</form>
- <hr style="margin-bottom: 8px;">
- <form method="POST" data-action="{{ url_for('Airflow.clear') }}">
+ <form method="POST" data-action="{{ url_for('Airflow.clear') }}" id="clear_action">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="dag_id" value="{{ dag.dag_id }}">
<input type="hidden" name="task_id">
@@ -346,9 +353,9 @@
</button>
</span>
</div>
+ <hr style="margin-bottom: 8px;">
</form>
- <hr style="margin-bottom: 8px;">
- <form method="GET" data-action="{{ url_for('Airflow.confirm') }}">
+ <form method="GET" data-action="{{ url_for('Airflow.confirm') }}" id="failed_action">
<input type="hidden" name="dag_id" value="{{ dag.dag_id }}">
<input type="hidden" name="task_id">
<input type="hidden" name="dag_run_id">
@@ -379,9 +386,9 @@
</button>
</span>
</div>
+ <hr style="margin-bottom: 8px;">
</form>
- <hr style="margin-bottom: 8px;">
- <form method="GET" data-action="{{ url_for('Airflow.confirm') }}">
+ <form method="GET" data-action="{{ url_for('Airflow.confirm') }}" id="success_action">
<input type="hidden" name="dag_id" value="{{ dag.dag_id }}">
<input type="hidden" name="task_id">
<input type="hidden" name="dag_run_id">