Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add details drawer to Grid View #22123

Merged
merged 35 commits into from
Mar 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
583ff81
make UI and tree work with mapped tasks
bbovenzi Feb 16, 2022
2250a4b
move ref and selection to providers
bbovenzi Mar 15, 2022
2925f47
fix test with mock providers
bbovenzi Mar 15, 2022
60cf89f
update TI and DR buttons
bbovenzi Mar 15, 2022
cada012
download logs and external logs
bbovenzi Mar 15, 2022
5b89e18
add extra links to TI details
bbovenzi Mar 15, 2022
8a55597
download log bug fixes
bbovenzi Mar 16, 2022
5adbf0c
fix extra links, hide local TZ if UTC,
bbovenzi Mar 16, 2022
6862f98
confirm mark task failed/success
bbovenzi Mar 16, 2022
2d1b48d
Update confirm modals for runs and tasks
bbovenzi Mar 17, 2022
ff5a461
Fix dialog scrolling
bbovenzi Mar 17, 2022
6c91288
Code cleanup and fix task clear
bbovenzi Mar 17, 2022
b6d3b2f
Fix task/run label, dialog focus, dag details overflow, panel open/close
bbovenzi Mar 17, 2022
3b7c025
Add timezone provider
bbovenzi Mar 18, 2022
cd2c5f1
Fix TimezoneEvent import
bbovenzi Mar 18, 2022
ec930f7
Improve button UX
bbovenzi Mar 21, 2022
a47ed4f
autorefresh dag run details
bbovenzi Mar 21, 2022
912b733
auto-refresh task instance details
bbovenzi Mar 21, 2022
50a8e44
revert useTreeData changes
bbovenzi Mar 22, 2022
20aebb2
Address PR feedback
bbovenzi Mar 22, 2022
a25704d
Handle task/run action sideeffects by separating autorefresh and tree…
bbovenzi Mar 23, 2022
5c60ab0
Clean up views.py endpoints
bbovenzi Mar 24, 2022
a3f70a9
pass request as arg
bbovenzi Mar 25, 2022
ea1ed4d
remove request as arg
bbovenzi Mar 25, 2022
6229ace
Anticipate when the 'Accept' header is not present
uranusjr Mar 28, 2022
7ff5c72
Fix argument count errors
bbovenzi Mar 28, 2022
8c36a1c
Replace hard coded urls
bbovenzi Mar 29, 2022
39e732b
Replace hard coded urls in react components
bbovenzi Mar 29, 2022
4c29813
Update filter upstream link
bbovenzi Mar 29, 2022
09ff24f
Split TaskInstance details component
bbovenzi Mar 29, 2022
566eca6
Fix undefined variables in tests
bbovenzi Mar 29, 2022
aef7325
init_api_connexion in tests
bbovenzi Mar 30, 2022
5824b12
Fix url params, hide last item breadcrumb links
bbovenzi Mar 31, 2022
a3a01dd
Update task run failed copy
bbovenzi Mar 31, 2022
ea3551d
Fix taskinstance/list buttons
bbovenzi Mar 31, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion airflow/www/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"@emotion/cache": "^11.4.0",
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11",
"axios": "^0.26.0",
"bootstrap-3-typeahead": "^4.0.2",
"camelcase-keys": "^7.0.0",
"codemirror": "^5.59.1",
Expand All @@ -92,7 +93,7 @@
"nvd3": "^1.8.6",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-icons": "^4.2.0",
"react-icons": "^4.3.1",
"react-query": "^3.34.16",
"redoc": "^2.0.0-rc.63",
"url-search-params-polyfill": "^8.1.0"
Expand Down
20 changes: 2 additions & 18 deletions airflow/www/static/js/dag.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,14 @@ function updateModalUrls() {
_flt_3_dag_id: dagId,
_flt_3_task_id: taskId,
_flt_3_map_index: mapIndex,
_oc_TaskInstanceModelView: executionDate,
_oc_TaskInstanceModelView: 'dag_run.execution_date',
});

updateButtonUrl(buttons.mapped, {
_flt_3_dag_id: dagId,
_flt_3_task_id: taskId,
_flt_3_run_id: dagRunId,
_oc_TaskInstanceModelView: executionDate,
_oc_TaskInstanceModelView: 'map_index',
});

updateButtonUrl(buttons.log, {
Expand Down Expand Up @@ -313,22 +313,6 @@ $(document).on('click', '#btn_back', () => {
});
});

export function callModalDag(dag) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only called this in the grid view, so we can fully replace it

$('#dagModal').modal({});
$('#dagModal').css('margin-top', '0');
$('#run_id').text(dag.run_id);
executionDate = dag.execution_date;
dagRunId = dag.run_id;
updateButtonUrl(buttons.dag_graph_view, {
dag_id: dag && dag.dag_id,
execution_date: dag && dag.execution_date,
});
updateButtonUrl(buttons.dagrun_details, {
dag_id: dag && dag.dag_id,
run_id: dag && dag.run_id,
});
}

// Task Instance Modal actions
$('form[data-action]').on('submit', function submit(e) {
e.preventDefault();
Expand Down
2 changes: 2 additions & 0 deletions airflow/www/static/js/datetime_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export const defaultFormatWithTZ = 'YYYY-MM-DD, HH:mm:ss z';
export const defaultTZFormat = 'z (Z)';
export const dateTimeAttrFormat = 'YYYY-MM-DDThh:mm:ssTZD';

export const TimezoneEvent = 'timezone';

export function formatTimezone(what) {
if (what instanceof moment) {
return what.isUTC() ? 'UTC' : what.format(defaultTZFormat);
Expand Down
10 changes: 9 additions & 1 deletion airflow/www/static/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
/* global $, moment, Airflow, window, localStorage, document, hostName, csrfToken */
/* global $, moment, Airflow, window, localStorage, document, hostName, csrfToken, Event */

import {
dateTimeAttrFormat,
formatTimezone,
isoDateToTimeEl,
setDisplayedTimezone,
TimezoneEvent,
} from './datetime_utils';

window.isoDateToTimeEl = isoDateToTimeEl;
Expand All @@ -43,6 +44,13 @@ function displayTime() {

function changeDisplayedTimezone(tz) {
localStorage.setItem('selected-timezone', tz);

// dispatch an event that React can listen for
const event = new Event(TimezoneEvent);
event.value = tz;
event.key = 'selected-timezone';
document.dispatchEvent(event);

setDisplayedTimezone(tz);
displayTime();
$('body').trigger({
Expand Down
78 changes: 9 additions & 69 deletions airflow/www/static/js/tree/InstanceTooltip.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,17 @@
* under the License.
*/

/* global moment */

import React from 'react';
import { Box, Text } from '@chakra-ui/react';

import { formatDateTime, getDuration, formatDuration } from '../datetime_utils';
import { finalStatesMap } from '../utils';
import { formatDuration, getDuration } from '../datetime_utils';
import Time from './Time';

const InstanceTooltip = ({
group,
instance: {
duration, operator, startDate, endDate, state, taskId, runId, mappedStates,
startDate, endDate, duration, state, runId, mappedStates,
},
}) => {
const isGroup = !!group.children;
Expand Down Expand Up @@ -78,87 +77,28 @@ const InstanceTooltip = ({
});
}

const taskIdTitle = isGroup ? 'Task Group Id: ' : 'Task Id: ';

return (
<Box fontSize="12px" py="4px">
<Box fontSize="12px" py="2px">
{group.tooltip && (
<Text>{group.tooltip}</Text>
)}
<Text>
<Text as="strong">Status:</Text>
{isGroup ? 'Overall ' : ''}
Status:
{' '}
{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 />
{isGroup && groupSummary}
<Text>
{taskIdTitle}
{taskId}
</Text>
<Text whiteSpace="nowrap">
Run Id:
{' '}
{runId}
</Text>
{operator && (
<Text>
Operator:
Started:
{' '}
{operator}
<Time dateTime={startDate} />
</Text>
)}
<Text>
Duration:
{' '}
{formatDuration(duration || getDuration(startDate, endDate))}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this show when the task is still in progress?

Do we not show end date anymore?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

endDate is in the details but not in the tooltip.
When in progress it will use Date.now() instead of 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>
);
};
Expand Down
46 changes: 46 additions & 0 deletions airflow/www/static/js/tree/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->

# Grid View

In 2.3.0 the Tree view was completely rebuilt using React and renamed to Grid. Here is a primer on the new technologies used:

## [React](https://reactjs.org/)

The most popular javascript framework for building user interfaces with reusable components.
Written as javascript and html together in `.jsx` files.
In-component state can be managed via `useState()`, application state that spans many components can be managed via a context provider (see `/context` for examples), API state can be managed by React Query (see below)


## [Chakra UI](https://chakra-ui.com/)

A good component and helper function library. Tooltips, modals, toasts, switches, etc are all out of the box
Styles are applied via global theme when initializing the app or inline with individual components like `<Box padding="5px" />`


## [React Query](https://react-query.tanstack.com/)

A powerful async data handler that makes it easy to manage loading/error states as well as caching, refetching, background updates, etc.
This is our state management for any data that comes from an API.
Each API request is its own hook. Ie `useTasks` will get all the tasks for a DAG


## [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/)

Easily write tests for react components and hooks
45 changes: 45 additions & 0 deletions airflow/www/static/js/tree/ResetRoot.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*!
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import React from 'react';
import { Button, Link } from '@chakra-ui/react';

import { getMetaValue } from '../utils';

const root = getMetaValue('root');
const url = getMetaValue('grid_url_no_root');

const ResetRoot = () => (
root
? (
<Button
as={Link}
variant="outline"
href={url}
colorScheme="blue"
mr={2}
title="Reset root to show the whole DAG"
>
Reset Root
</Button>
)
: null
);

export default ResetRoot;
Loading