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/02 00:47:08 UTC

[airflow] 07/08: add tooltip info to details

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 2192c4a318bec4958599ac79a49744884edb0482
Author: Brent Bovenzi <br...@gmail.com>
AuthorDate: Tue Mar 1 18:19:27 2022 -0500

    add tooltip info to details
---
 .../www/static/js/tree/details/content/DagRun.jsx  |  79 ++++++++++-
 .../js/tree/details/content/TaskInstance.jsx       | 146 ++++++++++++++++++++-
 airflow/www/static/js/tree/details/index.jsx       |   2 +-
 3 files changed, 217 insertions(+), 10 deletions(-)

diff --git a/airflow/www/static/js/tree/details/content/DagRun.jsx b/airflow/www/static/js/tree/details/content/DagRun.jsx
index 58e4b92..abcf908 100644
--- a/airflow/www/static/js/tree/details/content/DagRun.jsx
+++ b/airflow/www/static/js/tree/details/content/DagRun.jsx
@@ -17,15 +17,86 @@
  * under the License.
  */
 
+/* global moment */
+
 import React from 'react';
 import {
   Text,
+  Box,
 } from '@chakra-ui/react';
+import { MdPlayArrow } from 'react-icons/md';
+
+import { formatDateTime, formatDuration } from '../../../datetime_utils';
 
-const DagRun = () => (
-  <>
-    <Text>dag run details</Text>
-  </>
+const DagRun = ({
+  dagRun: {
+    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>
 );
 
 export default DagRun;
diff --git a/airflow/www/static/js/tree/details/content/TaskInstance.jsx b/airflow/www/static/js/tree/details/content/TaskInstance.jsx
index 4ab46e5..bc60737 100644
--- a/airflow/www/static/js/tree/details/content/TaskInstance.jsx
+++ b/airflow/www/static/js/tree/details/content/TaskInstance.jsx
@@ -17,15 +17,151 @@
  * under the License.
  */
 
+/* global moment */
+
 import React from 'react';
 import {
   Text,
+  Box,
 } from '@chakra-ui/react';
 
-const TaskInstance = () => (
-  <>
-    <Text>task instance details</Text>
-  </>
-);
+import { formatDateTime, getDuration, formatDuration } from '../../../datetime_utils';
+
+const TaskInstance = ({
+  instance: {
+    duration, operator, startDate, endDate, state, taskId, runId, // mappedStates,
+  },
+}) => {
+  const isGroup = false; // !!group.children;
+  const groupSummary = [];
+  // const mapSummary = [];
+
+  // if (isGroup) {
+  //   const numMap = finalStatesMap();
+  //   group.children.forEach((child) => {
+  //     const taskInstance = child.instances.find((ti) => ti.runId === runId);
+  //     if (taskInstance) {
+  //       const stateKey = taskInstance.state == null ? 'no_status' : taskInstance.state;
+  //       if (numMap.has(stateKey)) numMap.set(stateKey, numMap.get(stateKey) + 1);
+  //     }
+  //   });
+  //   numMap.forEach((key, val) => {
+  //     if (key > 0) {
+  //       groupSummary.push(
+  //         // eslint-disable-next-line react/no-array-index-key
+  //         <Text key={val} ml="10px">
+  //           {val}
+  //           {': '}
+  //           {key}
+  //         </Text>,
+  //       );
+  //     }
+  //   });
+  // }
+
+  // if (group.isMapped && mappedStates) {
+  //   const numMap = finalStatesMap();
+  //   mappedStates.forEach((s) => {
+  //     const stateKey = s || 'no_status';
+  //     if (numMap.has(stateKey)) numMap.set(stateKey, numMap.get(stateKey) + 1);
+  //   });
+  //   numMap.forEach((key, val) => {
+  //     if (key > 0) {
+  //       mapSummary.push(
+  //         // eslint-disable-next-line react/no-array-index-key
+  //         <Text key={val} ml="10px">
+  //           {val}
+  //           {': '}
+  //           {key}
+  //         </Text>,
+  //       );
+  //     }
+  //   });
+  // }
+
+  const taskIdTitle = isGroup ? 'Task Group Id: ' : 'Task Id: ';
+
+  return (
+    <Box fontSize="12px" py="4px">
+      {/* {group.tooltip && (
+        <Text>{group.tooltip}</Text>
+      )} */}
+      <Text>
+        <Text as="strong">Status:</Text>
+        {' '}
+        {state || 'no status'}
+      </Text>
+      {isGroup && (
+        <>
+          <br />
+          <Text as="strong">Group Summary</Text>
+          {groupSummary}
+        </>
+      )}
+      {/* {group.isMapped && (
+        <>
+          <br />
+          <Text as="strong">
+            {mappedStates.length}
+            {' '}
+            {mappedStates.length === 1 ? 'Task ' : 'Tasks '}
+            Mapped
+          </Text>
+          {mapSummary}
+        </>
+      )} */}
+      <br />
+      <Text>
+        {taskIdTitle}
+        {taskId}
+      </Text>
+      <Text whiteSpace="nowrap">
+        Run Id:
+        {' '}
+        {runId}
+      </Text>
+      {operator && (
+      <Text>
+        Operator:
+        {' '}
+        {operator}
+      </Text>
+      )}
+      <Text>
+        Duration:
+        {' '}
+        {formatDuration(duration || getDuration(startDate, endDate))}
+      </Text>
+      <br />
+      <Text as="strong">UTC</Text>
+      <Text>
+        Started:
+        {' '}
+        {startDate && formatDateTime(moment.utc(startDate))}
+      </Text>
+      <Text>
+        Ended:
+        {' '}
+        {endDate && formatDateTime(moment.utc(endDate))}
+      </Text>
+      <br />
+      <Text as="strong">
+        Local:
+        {' '}
+        {moment().format('Z')}
+      </Text>
+      <Text>
+        Started:
+        {' '}
+        {startDate && formatDateTime(startDate)}
+      </Text>
+      <Text>
+        Ended:
+        {' '}
+        {endDate && formatDateTime(endDate)}
+      </Text>
+    </Box>
+  );
+};
 
 export default TaskInstance;
diff --git a/airflow/www/static/js/tree/details/index.jsx b/airflow/www/static/js/tree/details/index.jsx
index b8f960e..31610a7 100644
--- a/airflow/www/static/js/tree/details/index.jsx
+++ b/airflow/www/static/js/tree/details/index.jsx
@@ -39,7 +39,7 @@ const Details = ({
     <Box>
       {/* TODO: get full instance data from the API */}
       {!selected.runId && !selected.taskId && <DagContent />}
-      {selected.runId && !selected.taskId && <DagRunContent />}
+      {selected.runId && !selected.taskId && <DagRunContent dagRun={selected} />}
       {selected.taskId && <TaskInstanceContent instance={selected} />}
     </Box>
   </Flex>