Skip to content

Support for sorting DAGs in the web UI#11652

Closed
scrdest wants to merge 17 commits into
apache:mainfrom
scrdest:8459-sorting-dags
Closed

Support for sorting DAGs in the web UI#11652
scrdest wants to merge 17 commits into
apache:mainfrom
scrdest:8459-sorting-dags

Conversation

@scrdest

@scrdest scrdest commented Oct 19, 2020

Copy link
Copy Markdown

Adds support for sorting DAGs in the UI by the ID, Schedule (next run, really) and Owner, ASC/DESC.

The sorting is done on the DB level and parameterized by two new URL parameters - sortBy for the model attribute & orderBy for the type of ordering (ascending/descending).

The default behavior is to sort by Dag ID and order by ascending, and therefore should not come as a surprise to current users.

The column headings in the DAG view have been turned to hyperlinks that pass the parameters for the sorting. For more predictable UX, when switching before sorting attributes (or when none is passed), clicking on a header will always sort it by ASC first. Clicking on the same header again after the page reloads will toggle it to DESC instead. Visually:

(None)->[Dag ID] => (Dag ID ASC)
(Dag ID ASC) -> [Dag ID] => (Dag ID DESC)
(Dag ID DESC) -> [Dag ID] => (Dag ID ASC)
(Dag ID ASC) -> [Owner] => (Owner ASC)
(Dag ID DESC) -> [Owner] => (Owner ASC)

Unfortunately, sorting by the most recently executed run as requested by #8459 is not supported yet. The current options were fairly straightforward to handle since the logic that populates the DAG list currently fetches a set of DagModels - this is just an exercise in filtering. Fetching and sorting DagRuns ran the risk of adding a fair bit of extra processing overhead and complicating the logic.

closes: #8459

Screenshots:
Screenshot_2020-10-21 DAGs - Airflow
Screenshot_2020-10-21 DAGs - Airflow(1)
Screenshot_2020-10-21 DAGs - Airflow(2)

@boring-cyborg boring-cyborg Bot added the area:webserver Webserver related Issues label Oct 19, 2020
@boring-cyborg

boring-cyborg Bot commented Oct 19, 2020

Copy link
Copy Markdown

Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contribution Guide (https://github.com/apache/airflow/blob/master/CONTRIBUTING.rst)
Here are some useful points:

  • Pay attention to the quality of your code (flake8, pylint and type annotations). Our pre-commits will help you with that.
  • In case of a new feature add useful documentation (in docstrings or in docs/ directory). Adding a new operator? Check this short guide Consider adding an example DAG that shows how users should use it.
  • Consider using Breeze environment for testing locally, it’s a heavy docker but it ships with a working Airflow and a lot of integrations.
  • Be patient and persistent. It might take some time to get a review or get the final approval from Committers.
  • Please follow ASF Code of Conduct for all communication including (but not limited to) comments on Pull Requests, Mailing list and Slack.
  • Be sure to read the Airflow Coding style.
    Apache Airflow is a community-driven project and together we are making it better 🚀.
    In case of doubts contact the developers at:
    Mailing List: [email protected]
    Slack: https://s.apache.org/airflow-slack

@ashb

ashb commented Oct 19, 2020

Copy link
Copy Markdown
Member

/cc @ryanahamilton

@ryanahamilton ryanahamilton left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This will be a nice update! I believe there used to be a JavaScript implementation of this, but it required the full dataset to be loaded (not paginated) in order to sort properly. Speaking of pagination, I think you need to add sortBy and orderBy arguments to wwwutils.generate_pages() in views.py so those params aren't abandoned on subsequent pages.

Comment thread airflow/www/templates/airflow/dags.html Outdated
Comment thread airflow/www/templates/airflow/dags.html Outdated
Comment thread airflow/www/templates/airflow/dags.html Outdated
Comment thread airflow/www/templates/airflow/dags.html Outdated
@ryanahamilton

Copy link
Copy Markdown
Contributor

Nice, I like the changing icons based on the sort state!

Comment thread airflow/www/templates/airflow/dags.html Outdated
Comment thread airflow/www/utils.py Outdated
Comment on lines 316 to 321

@ashb ashb Oct 23, 2020

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It might be easier/less code to have a single sort_by and have this as

Suggested change
dag_query_key_map = {
'dag_id': DagModel.dag_id,
'owner': DagModel.owners,
'schedule': DagModel.next_dagrun,
# <- add any extra (URL param)->(DagModel attr) mappings here
}
dag_query_key_map = {
'dag_id': DagModel.dag_id,
'-dag_id': DagModel.dag_id.desc(),
'owner': DagModel.owners,
'-owner': DagModel.owners.desc(),
'schedule': DagModel.next_dagrun,
'-schedule': DagModel.next_dagrun.desc(),
# <- add any extra (URL param)->(DagModel attr) mappings here
}

That way we don't need to have extra sorting_order param. I think this makes the code and the URI simpler. (For instance, query_ordering_transform_for_key wouldn't be needed anymore)

Additionally this order probably doesn't belong in this file -- but instead in the views.py file, probably in the home function.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

(If you think the current way is clearer, tell me. But I do think the location is wrong for this, as it is specific to one particular view.)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I see your point, but I feel like the suggested way is a bigger PITA from a long-term maintenance perspective - you have to add each new sortable in duplicate. It also seems less intuitive when looking at the URL - the current setup basically just replicates the underlying SQL. All in all, I was trying to make the two bits as independently testable as possible.

I may be getting ahead of myself, but it should also make things easier if someone wanted to sort by multiple columns - e.g. ASC by ID and DESC by owner would be orderBy=asc;desc and then you could just zip() it with sortBy's items.

Re: the module location, point taken. I will move things around as appropriate. I was kind of hoping someone would slap me and point me to the right place if this one wasn't it, so - appreciated!

@ryw

ryw commented Oct 27, 2020

Copy link
Copy Markdown
Member

thanks for working on this @scrdest and your first Airflow contribution :)

@ryanahamilton

Copy link
Copy Markdown
Contributor

@scrdest heads up, I've made several recent markup changes to the table in dag.html that are yielding conflicts. Should be pretty straightforward to resolve!

@kaxil

kaxil commented Nov 4, 2020

Copy link
Copy Markdown
Member

Can you please rebase your PR on latest Master since we have applied Black and PyUpgrade on Master.

It will help if your squash your commits into single commit first so that there are less conflicts.

@scrdest

scrdest commented Nov 5, 2020

Copy link
Copy Markdown
Author

@kaxil - rebased.

@ryanahamilton ryanahamilton left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I pulled this down and tested it locally—it's looking really good. Left a couple suggestions.

Comment thread airflow/www/templates/airflow/dags.html Outdated
Comment thread airflow/www/templates/airflow/dags.html Outdated
@github-actions

Copy link
Copy Markdown
Contributor

The Workflow run is cancelling this PR. It has some failed jobs matching ^Pylint$,^Static checks,^Build docs$,^Spell check docs$,^Backport packages$,^Provider packages,^Checks: Helm tests$,^Test OpenAPI*.

@github-actions

Copy link
Copy Markdown
Contributor

The Workflow run is cancelling this PR. It has some failed jobs matching ^Pylint$,^Static checks,^Build docs$,^Spell check docs$,^Backport packages$,^Provider packages,^Checks: Helm tests$,^Test OpenAPI*.

@github-actions

Copy link
Copy Markdown
Contributor

The Workflow run is cancelling this PR. It has some failed jobs matching ^Pylint$,^Static checks,^Build docs$,^Spell check docs$,^Backport packages$,^Provider packages,^Checks: Helm tests$,^Test OpenAPI*.

@ryanahamilton ryanahamilton added the area:UI Related to UI/UX. For Frontend Developers. label Nov 18, 2020
@kaxil
kaxil requested a review from ryanahamilton November 19, 2020 12:50
@github-actions

Copy link
Copy Markdown
Contributor

The Workflow run is cancelling this PR. It has some failed jobs matching ^Pylint$,^Static checks,^Build docs$,^Spell check docs$,^Backport packages$,^Provider packages,^Checks: Helm tests$,^Test OpenAPI*.

@kaxil kaxil added this to the Airflow 2.0.0 (rc1) milestone Nov 26, 2020
Comment thread airflow/www/templates/airflow/dags.html Outdated
@ryanahamilton
ryanahamilton requested a review from ashb December 3, 2020 14:02
Comment thread airflow/www/views.py Outdated
Comment thread airflow/www/views.py Outdated
@potiuk

potiuk commented Dec 7, 2020

Copy link
Copy Markdown
Member

Long thread :) - I think however that one is not critical and can be done in 2.1 ? @ashb @ryanahamilton WDYT?

@jkmalek
jkmalek force-pushed the 8459-sorting-dags branch from 2de1a14 to e522fd7 Compare August 4, 2021 11:02
@jkmalek
jkmalek force-pushed the 8459-sorting-dags branch from e522fd7 to 5585e10 Compare August 4, 2021 11:19
@jkmalek

jkmalek commented Aug 4, 2021

Copy link
Copy Markdown

@jedcunningham rebased and fixed up where necessary; thanks for the heads-up on view tests!

@jedcunningham jedcunningham left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The pagination links also aren't maintaining orderBy and orderDir, but I haven't dug into why. Do they work for you?

Comment on lines +26 to +43
dag_id_query = dag_query_for_key(sorting_key='dag_id')
dag_id_query_casetest = dag_query_for_key(sorting_key='dAg_Id')

assert dag_id_query == DagModel.dag_id
assert dag_id_query_casetest == dag_id_query

owner_query = dag_query_for_key(sorting_key='owner')
owner_query_casetest = dag_query_for_key(sorting_key='oWnEr')

assert owner_query == DagModel.owners
assert owner_query != dag_id_query
assert owner_query_casetest == owner_query

schedule_query = dag_query_for_key(sorting_key='next_dagrun')

assert schedule_query == DagModel.next_dagrun
assert schedule_query != dag_id_query
assert schedule_query != owner_query

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: This whole section could utilize pytest.mark.parameterize which would make it cleaner imo, e.g. (untested):

Suggested change
dag_id_query = dag_query_for_key(sorting_key='dag_id')
dag_id_query_casetest = dag_query_for_key(sorting_key='dAg_Id')
assert dag_id_query == DagModel.dag_id
assert dag_id_query_casetest == dag_id_query
owner_query = dag_query_for_key(sorting_key='owner')
owner_query_casetest = dag_query_for_key(sorting_key='oWnEr')
assert owner_query == DagModel.owners
assert owner_query != dag_id_query
assert owner_query_casetest == owner_query
schedule_query = dag_query_for_key(sorting_key='next_dagrun')
assert schedule_query == DagModel.next_dagrun
assert schedule_query != dag_id_query
assert schedule_query != owner_query
@pytest.mark.parameterize(
"key, expected_query",
[
["dag_id", DagModel.dag_id],
["dAg_Id", DagModel.dag_id],
["owner", DagModel.owners],
["oWnEr", DagModel.owners],
["next_dagrun", DagModel.next_dagrun],
["NEXT_DAGRUN", DagModel.next_dagrun],
]
)
def test_dag_query_for_key(key, expected_query):
assert dag_query_for_key(sorting_key=key) == expected_query

The same pattern could be used for query_ordering_transform_for_key and build_dag_sorting_query.

Comment on lines +29 to +30
{% set curr_ordering = ('unsorted' if request.args.get('orderDir') != attr_name else request_ordering ) %}
{% set new_ordering = ('asc' if request.args.get('orderDir') != attr_name or curr_ordering != 'asc' else 'desc' ) %}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
{% set curr_ordering = ('unsorted' if request.args.get('orderDir') != attr_name else request_ordering ) %}
{% set new_ordering = ('asc' if request.args.get('orderDir') != attr_name or curr_ordering != 'asc' else 'desc' ) %}
{% set curr_ordering = ('unsorted' if request.args.get('orderBy') != attr_name else request_ordering ) %}
{% set new_ordering = ('asc' if request.args.get('orderBy') != attr_name or curr_ordering != 'asc' else 'desc' ) %}

@kaxil

kaxil commented Sep 14, 2021

Copy link
Copy Markdown
Member

@scrdest Can you address the requested changes please

@kaxil kaxil modified the milestones: Airflow 2.2, Airflow 2.3 Sep 14, 2021
@bbovenzi
bbovenzi self-requested a review September 14, 2021 14:26
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 5 days if no further activity occurs. Thank you for your contributions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:UI Related to UI/UX. For Frontend Developers. area:webserver Webserver related Issues stale Stale PRs per the .github/workflows/stale.yml policy file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add ability to sort dag list in the UI by Dag, Owner, Last Run