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:01 UTC

[airflow] branch mapped-task-drawer updated (12b8f3e -> 2f8e444)

This is an automated email from the ASF dual-hosted git repository.

bbovenzi pushed a change to branch mapped-task-drawer
in repository https://gitbox.apache.org/repos/asf/airflow.git.


 discard 12b8f3e  add tooltip info to details
 discard 319499d  switch from drawer to details section
 discard e3398de  fix hover and extra prop
 discard 2f443e0  improve rendering and add selected dag run
 discard fbd49c6  reformat grid background colors
 discard d98af9a  basic slide drawer
 discard 911aaeb  make UI and tree work with mapped tasks
 discard c6da3ea  Expand mapped tasks in the Scheduler
 discard b7ea8f8  Create an end-to-end test for running a DAG via the scheduler.
     add d87762b  Don't check if `py` DAG files are zipped during parsing (#21538)
     add eec873c  Alembic migration filename should match revision id (#21621)
     add 66c342d  Support generating SQL script for upgrades (#20962)
     add 6dd61c9  Delay creation of dag_run table object (#21622)
     add 710d699  Support different timeout value for dag file parsing (#21501)
     add 68c8de7  Chart: add envFrom to the flower deployment (#21401)
     add 068e037  Update test example in CONTRIBUTORS_QUICK_START.rst (#21620)
     add aab1189  Add GCSToPrestoOperator (#21084)
     add ea21cb3  Adding Cover Genius to INTHEWILD.md (#21637)
     add 42469f0  Fix bug in Breeze2 auto-complete setup with root files modified (#21636)
     add 074b0c9  Move `confirm` script into `scripts/tools` (#21626)
     add 295efd3  Dataflow Assets (#21639)
     add 4ca837a  Remove wrapper scripts from static_checks folder (#21643)
     add 56285ee  Add params dag_id, task_id etc to XCom.serialize_value (#19505)
     add 5a38d15  Upgrade Postgres client in Docker images (#21631)
     add 752d538  added explaining concept of logical date in DAG run docs (#21433)
     add 38894e8  Adding missing login provider related methods from Flask-Appbuilder (#21294)
     add f011da2  Clarify pendulum use in timezone cases (#21646)
     add 366c66b  Pin Markupsafe until we are able to upgrade Flask/Jinja (#21664)
     add 78490f8  Deprecate helper utility `days_ago` (#21653)
     add b48dc4d  Update best-practices.rst (#21679)
     add b28f4c5  Fix Amazon SES emailer signature (#21681)
     add 61e8a5c  Increase timeout for constraints (#21680)
     add ecd85f8  Add celery_logging_level (#21506)
     add dec05fb  Update EKS sample DAGs and docs (#21523)
     add 68da4d8  Update MySqlOperator example dag (#21434)
     add 066ba15  Convert our internal tools to use rich_click (#21689)
     add d8ae7df  Add extra information about time synchronization needed (#21685)
     add 9ad4de8  Refactor TriggerRule & WeightRule classes to inherit from Enum (#21264)
     add a0fb0bb  Log exception in local executor (#21667)
     add a282329  Simply imports in dev github script (#21702)
     add 62d1ef8  [de]serialize resources on task correctly (#21445)
     add 6061cc4  Add Auto ML operators for Vertex AI service (#21470)
     add 9f8278e  Fix import in unit test example (#21703)
     add 6734eb1  Fix assertion to check actual content (#21678)
     add ba627f3  Run mapped tasks via the normal Scheduler (#21614)
     add 35552b8  Bump upper bound version of jsonschema to 5.0 (#21712)
     add 46a337c  Implement mapped value unpacking (#21641)
     add 4e95935  Extend documentation for states of DAGs & tasks and update trigger rules docs (#21382)
     add 2807193  Replaced hql references to sql in TrinoHook and PrestoHook (#21630)
     add 15a72d0  Fix failing tests on main due to merging incompatible changes (#21733)
     add 2a615ab  Introduce 'Callbacks Sink' classes for sending callbacks (#21301)
     add b2c0a92  Fix graph autorefresh on page load (#21736)
     add bb577a9  Fix stray order_by(TaskInstance.execution_date) (#21705)
     add d1643d1  2.2.4 has been released (#21744)
     add 6e5c9c8  Fix some migrations (#21670)
     add 18fb554  Dev:`constraints-latest` needs to be force-pushed (#21746)
     add 4e17528  Add support for custom command and args in jobs (#20864)
     add e8afff9  Simplify chart docs for configuring Airflow (#21747)
     add 2689624  Remove python 3.5 reference from README (#21749)
     add 169b196  Chart: Default to Airflow 2.2.4 (#21745)
     add 9076b67  Fix triggerer --capacity parameter (#21753)
     add 3b4c26e  Add Dataproc assets/links (#21756)
     add e1fe30c  Fix the triggerer capacity test (#21760)
     add 3c12c2e  Don't show alembic info logs at the start of every cli command (#21758)
     add de41ccc  Change the default auth backend to session (#21640)
     add 3c4524b  (AzureCosmosDBHook) Update to latest Cosmos API (#21514)
     add 3bb63d4  Correct a couple grammatical errors in docs (#21750)
     add e12ad53  Add Paxful to INTHEWILD.md (#21766)
     add 5fbf247  Add `2.2.4` to db migrations map (#21777)
     add feea143  Fix max_active_runs=1 not scheduling runs when min_file_process_interval is high (#21413)
     add 919b75b  Correctly handle multiple '=' in LocalFileSystem secrets. (#21694)
     add 2da207d  Rewrite taskflow-mapping argument validation (#21759)
     add 73eb24f  Fix bigquery_dts parameter docstring typo (#21786)
     add f4495e2  Add --platform as parameter of image building (#21695)
     add b6e141a  Upgrade and record elasticsearch log_id_template changes (#21734)
     add 21151fb  Rename operator mapping map() to apply() (#21754)
     add 272d242  Restore image rendering in AWS Secrets Manager Backend doc (#21772)
     add 8ee8f2b  Use Pendulum's built-in UTC object (#21732)
     add a724523  Make sure emphasis in UPDATING in .md is consistent (#21804)
     add 7e0c6e4  REST API: add rendered fields in task instance. (#21741)
     add dade6e0  Use DB where possible for quicker ``airflow dag`` subcommands (#21793)
     add 608b8c4  Fix test CreateUserJobTest::test_should_disable_default_helm_hooks (#21776)
     add 5a6316f  Add another way to dynamically generate DAGs to docs (#21297)
     add 7e03225  Attempt to upgrede to 22.0.3 version of `pip` (#21818)
     add 59c450e  Make DbApiHook use get_uri from Connection (#21764)
     add dc1deff  Remove 8 year old screenshots (#21819)
     add 6322dad  fix param rendering in docs of SparkSubmitHook (#21788)
     add 2e57f22  Add step to add releases to the committee report helper (#21812)
     add d85781c  Fix typo in chart docs (#21814)
     add 43cacd8  Show Task Map Index in  task instance table (#21774)
     add eafbcb3  Fix doc - replace decreasing by increasing (#21805)
     add 5b41e2d  Update TaskFlow tutorial doc to show how to pass "operator-level" args. (#21446)
     add 16f5185  Limits GitHub3.py in order to avoid backtracking (#21824)
     add 9407f11  Switch to GitHub-rendered Mermaid diagrams (#21682)
     add e4ead2b  extends typing-extensions to be installed with python 3.8+ #21566 (#21567)
     add a159ae8  Remove types from KPO docstring (#21826)
     add f13f9db  Describe policy about support for OS versions used. (#21697)
     add 0378659  Added Hook for Amazon RDS. Added `boto3_stub` library for autocomplete. (#20642)
     add c75774d  Add `db clean` CLI command for purging old data (#20838)
     add c8d64c9  Add Github integration steps for committers (#21834)
     add b26d4d8  Fix assignment of unassigned triggers (#21770)
     add 7ea0f76  Truncate stack trace to DAG user code for exceptions raised during execution (#20731)
     add f0b6398  Bug Fix - S3DeleteObjectsOperator will try and delete all keys (#21458)
     add 537c244  Add ALL_SKIPPED trigger rule (#21662)
     add a1845c6  Databricks: add support for triggering jobs by name (#21663)
     add 900bad1  Fix oracle test connection (#21699)
     add df31902  Removed 'request.referrer' from views.py  (#21751)
     add 942f8fd  Add GCSToTrinoOperator (#21704)
     add 3e4fab4  Fix handling cached parameters for Breeze2 (#21849)
     add cb24ee9  Add SageMakerDeleteModelOperator (#21673)
     add bc1b422  Fix logging JDBC SQL error when task fails (#21540)
     add 27d19e7  Databricks SQL operators (#21363)
     add 43907e9  Add unit tests to infer `multiple_outputs` when invoking decorator `__call__` (#21773)
     add e93820b  Minor `pre-commit` config clean up (#21794)
     add 03d6aaa  Airflow `db downgrade` cli command (#21596)
     add e782b37  Add dbt Cloud provider (#20998)
     add 0c55ca2  Suppress hook warnings from the Bigquery transfers (#20119)
     add 13b2c40  Add 'method' to attributes in HttpSensor. (#21831)
     add 768d851  Fix DAG date range bug (#20507)
     add d726579  Fix handling of empty (None) tags in `bulk_write_to_db` (#21757)
     add 6442356  Quick Update GCS Presto (#21855)
     add 5276ef8  Add JSON output on SqlToS3Operator (#21779)
     add f0bbb9d  Add 'Show record' option for variables (#21342)
     add c819b4f  Configurable AWS Session Factory (#21778)
     add a85f00b  Fix mixup up shadowed ImportError in db_cleanup (#21862)
     add f5832a6  update value from database to celery workers (#21859)
     add c1abd63  Allow to switch easily between Bullseye and Buster debian versions (#21546)
     add 5d89dea  Switch to Debian 11 (bullseye) as base for our dockerfiles (#21378)
     add 8299ade  Revert "Switch to Debian 11 (bullseye) as base for our dockerfiles (#21378)" (#21874)
     add 2049998  Update to latest version in Dockerfile (and add instructions) (#21876)
     add 4ad21f5  Log traceback in trigger excs (#21213)
     add bb26f96  Make Grid and and Graph view work with task mapping (#21740)
     add 82e1abf  Fix UPDATING section on SqlAlchemy 1.4 scheme changes (#21887)
     add d9017a0  Update databricks.rst (#21886)
     add 3218cca  Fix the Type Hints in ``RedshiftSQLOperator`` (#21885)
     add 6ca118d  Allow templates in more DataprocUpdateClusterOperator fields (#21865)
     add 69f6f9e  Autogenerate migration reference doc (#21601)
     add 6b0ca64  Fix filesystem sensor for directories (#21729)
     add 9e67692  add celery.task_timeout_error metric (#21602)
     add 33edeb2  Feature: Add invoke lambda function operator (#21686)
     add 2dd251d  Update modules_management.rst (#21889)
     add 3035d3a  Switch to Debian 11 (bullseye) as base for our dockerfiles (#21378) (#21875)
     add 5befc7f  Fix TaskDecorator type hints (#21881)
     add 08575dd  Change BaseOperatorLink interface to take a ti_key, not a datetime (#21798)
     add f97c25d  Limits Yandexcloud to 0.145 to unblock main failing tests. (#21899)
     add 351fa53  Fix Kubernetes example with wrong operator casing (#21898)
     add ace8c6e  EdgeModifier refactoring (#21404)
     add 3aebb21  Deprecate non-JSON conn.extra (#21816)
     add 5e7ad0b  Limit yandexcloud to < 0.142 (#21903)
     add e856aba  Fix handling some None parameters in kubernetes 23 libs. (#21905)
     add fb6b2d1  Make project_id argument optional in all dataproc operators (#21866)
     add 1691968  Update list of non-core files/paths (#21907)
     add 62bf127  Add-showing-runtime-error-feature-to-DatabricksSubmitRunOperator (#21709)
     add 7689969  Refactor KubernetesPodOperator tests (#21911)
     add 563ecfa  Add Python 3.9 support to Hive (#21893)
     new adfc609  make UI and tree work with mapped tasks
     new 780d6a2  basic slide drawer
     new ee86937  reformat grid background colors
     new eb96150  improve rendering and add selected dag run
     new ce953b3  fix hover and extra prop
     new 5cb4def  switch from drawer to details section
     new 2192c4a  add tooltip info to details
     new 2f8e444  use API

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (12b8f3e)
            \
             N -- N -- N   refs/heads/mapped-task-drawer (2f8e444)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 8 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .github/ISSUE_TEMPLATE/airflow_bug_report.yml      |    3 +-
 .../airflow_helmchart_bug_report.yml               |    3 +-
 .../airflow_providers_bug_report.yml               |    4 +-
 .github/boring-cyborg.yml                          |    1 -
 .github/workflows/build-images.yml                 |    1 +
 .github/workflows/ci.yml                           |    3 +-
 .hadolint.yaml                                     |    1 +
 .pre-commit-config.yaml                            |   55 +-
 BREEZE.rst                                         |  141 ++-
 CHANGELOG.txt                                      |   72 ++
 CI.rst                                             |   37 +-
 CI_DIAGRAMS.md                                     |  312 +++++
 COMMITTERS.rst                                     |   11 +
 CONTRIBUTING.rst                                   |   23 +-
 CONTRIBUTORS_QUICK_START.rst                       |   27 +-
 Dockerfile                                         |   45 +-
 Dockerfile.ci                                      |   31 +-
 IMAGES.rst                                         |   20 +-
 INSTALL                                            |   20 +-
 INTHEWILD.md                                       |    2 +
 PULL_REQUEST_WORKFLOW.rst                          |  107 +-
 README.md                                          |   49 +-
 SELECTIVE_CHECKS.md                                |  144 +++
 STATIC_CODE_CHECKS.rst                             |   61 +-
 TESTING.rst                                        |    2 +-
 UPDATING.md                                        |  100 +-
 airflow/__init__.py                                |    1 +
 .../api_connexion/endpoints/extra_link_endpoint.py |   18 +-
 .../endpoints/task_instance_endpoint.py            |   31 +-
 airflow/api_connexion/openapi/v1.yaml              |    6 +
 airflow/api_connexion/schemas/common_schema.py     |   15 +
 .../api_connexion/schemas/task_instance_schema.py  |    4 +
 .../timetables => airflow/callbacks}/__init__.py   |    0
 .../callbacks/base_callback_sink.py                |   15 +-
 airflow/{utils => callbacks}/callback_requests.py  |    7 +-
 airflow/callbacks/pipe_callback_sink.py            |   47 +
 airflow/cli/cli_parser.py                          |  115 +-
 airflow/cli/commands/celery_command.py             |    6 +-
 airflow/cli/commands/dag_command.py                |   66 +-
 airflow/cli/commands/db_command.py                 |   65 +-
 airflow/cli/commands/task_command.py               |    2 -
 airflow/config_templates/config.yml                |   15 +-
 airflow/config_templates/default_airflow.cfg       |   11 +-
 airflow/config_templates/default_test.cfg          |    1 +
 airflow/configuration.py                           |   43 +-
 airflow/contrib/hooks/databricks_hook.py           |    1 -
 airflow/dag_processing/manager.py                  |   34 +-
 airflow/dag_processing/processor.py                |   12 +-
 airflow/decorators/__init__.pyi                    |    2 +-
 airflow/decorators/base.py                         |  174 +--
 airflow/decorators/task_group.py                   |   17 +-
 airflow/example_dags/example_bash_operator.py      |    8 +-
 .../example_branch_datetime_operator.py            |   14 +-
 .../example_branch_day_of_week_operator.py         |    4 +-
 airflow/example_dags/example_branch_labels.py      |    7 +-
 airflow/example_dags/example_branch_operator.py    |    5 +-
 .../example_branch_python_dop_operator_3.py        |    4 +-
 airflow/example_dags/example_complex.py            |    4 +-
 airflow/example_dags/example_dag_decorator.py      |    9 +-
 .../example_external_task_marker_dag.py            |    4 +-
 .../example_dags/example_kubernetes_executor.py    |    5 +-
 .../example_latest_only_with_trigger.py            |    8 +-
 airflow/example_dags/example_nested_branch_dag.py  |    4 +-
 .../example_passing_params_via_test_command.py     |    8 +-
 airflow/example_dags/example_python_operator.py    |    5 +-
 .../example_dags/example_short_circuit_operator.py |    4 +-
 airflow/example_dags/example_skip_dag.py           |    9 +-
 airflow/example_dags/example_sla_dag.py            |    8 +-
 airflow/example_dags/example_task_group.py         |    7 +-
 .../example_dags/example_task_group_decorator.py   |    7 +-
 .../example_time_delta_sensor_async.py             |    8 +-
 .../example_dags/example_trigger_controller_dag.py |    4 +-
 airflow/example_dags/example_trigger_target_dag.py |    4 +-
 airflow/example_dags/example_xcom.py               |    4 +-
 airflow/example_dags/example_xcomargs.py           |    7 +-
 airflow/example_dags/plugins/workday.py            |    5 +-
 airflow/example_dags/subdags/subdag.py             |    4 +-
 airflow/example_dags/tutorial_etl_dag.py           |    5 +-
 airflow/example_dags/tutorial_taskflow_api_etl.py  |   10 +-
 airflow/executors/base_executor.py                 |   14 +
 airflow/executors/celery_executor.py               |   24 +-
 airflow/executors/debug_executor.py                |    1 -
 airflow/executors/local_executor.py                |    4 +-
 airflow/hooks/dbapi.py                             |   17 +-
 airflow/jobs/backfill_job.py                       |    2 +-
 airflow/jobs/scheduler_job.py                      |   23 +-
 airflow/jobs/triggerer_job.py                      |   18 +-
 airflow/kubernetes/pod_generator_deprecated.py     |    9 +-
 .../004c1210f153_increase_queue_name_size_limit.py |    3 +-
 ...6b6f902_increase_length_of_fab_ab_view_menu_.py |    7 +-
 .../versions/03bc53e68815_add_sm_dag_index.py      |    3 +-
 .../versions/05f30312d566_merge_heads.py           |    3 +-
 ..._merge_heads.py => 08364691d074_merge_heads.py} |    3 +-
 ...5d12_add_max_active_runs_column_to_dagmodel_.py |    7 +-
 .../0a2a5b66e19d_add_task_reschedule_table.py      |    3 +-
 .../0e2a74e0fc9f_add_time_zone_awareness.py        |    1 +
 ...dfa7_add_dag_id_state_index_on_dag_run_table.py |    3 +-
 .../versions/13eb55f81627_for_compatibility.py     |    3 +-
 ...ta_interval_start_end_to_dagmodel_and_dagrun.py |    1 +
 .../versions/1507a7289a2f_create_is_encrypted.py   |    3 +-
 ...cfc09e3_add_is_encrypted_column_to_variable_.py |    3 +-
 .../migrations/versions/1b38cef5b76e_add_dagrun.py |    3 +-
 .../versions/211e584da130_add_ti_state_index.py    |    3 +-
 ...30d7c24_add_executor_config_to_task_instance.py |    3 +-
 .../2c6edca13270_resource_based_permissions.py     |    1 +
 ...e42bb497a22_rename_last_scheduler_run_column.py |    7 +-
 .../versions/2e541a1dcfed_task_duration.py         |    3 +-
 .../versions/2e82aab8ef20_rename_user_table.py     |    3 +-
 ...d44a_rename_concurrency_column_in_dag_table_.py |   14 +-
 ...338e90f54d61_more_logging_into_task_isntance.py |    3 +-
 ...7a1ff4_add_kubernetes_resource_checkpointing.py |    3 +-
 .../364159666cbd_add_job_id_to_dagrun_table.py     |    5 +-
 .../versions/3c20cacc0044_add_dagrun_run_type.py   |    7 +-
 .../versions/40e67319e3a9_dagrun_config.py         |    3 +-
 .../versions/41f5f12752f8_add_superuser_field.py   |    3 +-
 .../versions/4446e08588_dagrun_start_end.py        |    3 +-
 ...2da_increase_size_of_connection_extra_field_.py |    3 +-
 ...a3f1493b9_add_k8s_yaml_to_rendered_templates.py |    1 +
 ...236f1_add_fractional_seconds_to_mysql_tables.py |    3 +-
 .../versions/502898887f84_adding_extra_to_log.py   |    3 +-
 ...0_fix_mssql_exec_date_rendered_task_instance.py |    1 +
 .../versions/52d714495f0_job_id_indices.py         |    3 +-
 ...54bebd308c5f_add_trigger_table_and_task_info.py |    7 +-
 .../561833c1c74b_add_password_column_to_user.py    |    3 +-
 .../587bdf053233_adding_index_for_dag_id_in_job.py |    7 +-
 ...27fdd3_increase_length_of_email_and_username.py |    3 +-
 .../5e7d17757c7a_add_pid_field_to_taskinstance.py  |    3 +-
 ...73d9401f_add_description_field_to_connection.py |    7 +-
 ...7aae_fix_description_field_in_connection_to_.py |    7 +-
 .../64de9cddf6c9_add_task_fails_journal_table.py   |    3 +-
 ...a59344a4_make_taskinstance_pool_not_nullable.py |    3 +-
 ...867_change_datetime_to_datetime2_6_on_mssql_.py |    1 +
 ...e3737b18f_added_timetable_description_column.py |    7 +-
 .../versions/7939bcff74ba_add_dagtags_table.py     |    7 +-
 .../7b2661a43ba3_taskinstance_keyed_to_dagrun.py   |    7 +-
 ...8c147f_remove_can_read_permission_on_config_.py |    3 +-
 .../83f031fd9f1c_improve_mssql_compatibility.py    |    3 +-
 .../849da589634d_prefix_dag_permissions.py         |    1 +
 .../versions/8504051e801b_xcom_dag_task_indices.py |    3 +-
 ...15af_add_rendered_task_instance_fields_table.py |    5 +-
 .../856955da8476_fix_sqlite_foreign_key.py         |    3 +-
 .../8646922c8a04_change_default_pool_slots_to_1.py |   38 +-
 ...0d1215c0_add_kubernetes_scheduler_uniqueness.py |    3 +-
 ...d48763f6d53_add_unique_constraint_to_conn_id.py |    7 +-
 .../8f966b9c467a_set_conn_type_as_non_nullable.py  |    7 +-
 ...7b86_increase_pool_name_size_in_taskinstance.py |    7 +-
 .../versions/92c57b58940d_add_fab_tables.py        |    1 +
 ...1e647c8_task_reschedule_fk_on_cascade_delete.py |    3 +-
 .../versions/947454bf1dff_add_ti_job_id_index.py   |    3 +-
 .../versions/952da73b5eff_add_dag_code_table.py    |    3 +-
 .../versions/9635ae0956e7_index_taskfail.py        |    3 +-
 ...93827b8_add_queued_at_column_to_dagrun_table.py |    7 +-
 ...606e2_add_scheduling_decision_to_dagrun_and_.py |    7 +-
 ...ad25_resource_based_permissions_for_default_.py |    3 +-
 ...914482_add_data_compressed_to_serialized_dag.py |    1 +
 ...67d16b_add_pool_slots_field_to_task_instance.py |    3 +-
 .../versions/a56c9515abdc_remove_dag_stat_table.py |    3 +-
 ...eea_add_precision_to_execution_date_in_mysql.py |    7 +-
 .../b247b1e3d1ed_add_queued_by_job_id_to_ti.py     |    1 +
 .../b25a55525161_increase_length_of_pool_name.py   |    1 +
 .../b3b105409875_add_root_dag_id_to_dag.py         |    7 +-
 ...cfc896_add_a_column_to_track_the_encryption_.py |    1 +
 ...13e_add_notification_sent_column_to_sla_miss.py |    3 +-
 .../bbf4a7ad0465_remove_id_column_from_xcom.py     |    1 +
 ...3e6c56_make_xcom_value_column_a_large_binary.py |    1 +
 ...a23_add_has_import_errors_column_to_dagmodel.py |    1 +
 .../bef4f3d11e8b_drop_kuberesourceversion_and_.py  |    7 +-
 .../bf00311e1990_add_index_to_taskinstance.py      |    3 +-
 ...c306b5b5ae4a_switch_xcom_table_to_use_run_id.py |   48 +-
 .../c381b21cb7e4_add_session_table_to_db.py        |    7 +-
 .../versions/c8ffec048a3b_add_fields_to_dag.py     |    3 +-
 ...623dc7_add_max_tries_column_to_task_instance.py |    3 +-
 ...26fe78_add_index_on_state_dag_id_for_queued_.py |    7 +-
 .../versions/cf5dc11e79ad_drop_user_and_chart.py   |    3 +-
 .../d2ae31099d61_increase_text_size_for_mysql.py   |    1 +
 .../d38e04c12aa2_add_serialized_dag_table.py       |    3 +-
 ...c3a5a_add_dag_hash_column_to_serialized_dag_.py |    7 +-
 .../versions/dd25f486b8ea_add_idx_log_dag.py       |    3 +-
 .../dd4ecb8fbee3_add_schedule_interval_to_dag.py   |    1 +
 ...65e7455d70_add_description_field_to_variable.py |    7 +-
 .../e1a11ece99cc_add_external_executor_id_to_ti.py |    1 +
 .../e38be357a868_update_schema_for_smart_sensor.py |    3 +-
 .../versions/e3a246e0dc1_current_schema.py         |    1 +
 ...53f75_add_taskmap_and_map_id_on_taskinstance.py |    9 +-
 ...4a3141f0_make_xcom_pkey_columns_non_nullable.py |    7 +-
 ...ac86c_change_field_in_dagcode_to_mediumtext_.py |    3 +-
 .../f23433877c24_fix_mysql_not_null_constraint.py  |    3 +-
 .../versions/f2ca10b85618_add_dag_stats_table.py   |    3 +-
 ...62e7089_add_task_log_filename_template_model.py |    3 +-
 ...935f_increase_length_for_connection_password.py |    7 +-
 airflow/models/abstractoperator.py                 |  193 ++-
 airflow/models/baseoperator.py                     |  138 +--
 airflow/models/connection.py                       |   43 +-
 airflow/models/dag.py                              |   28 +-
 airflow/models/dagbag.py                           |   33 +-
 airflow/models/dagrun.py                           |   50 +-
 airflow/models/mappedoperator.py                   |  294 +++--
 airflow/models/renderedtifields.py                 |    2 +-
 airflow/models/taskinstance.py                     |  138 ++-
 airflow/models/taskmixin.py                        |   21 +-
 airflow/models/trigger.py                          |   16 +-
 airflow/models/xcom.py                             |  133 ++-
 airflow/operators/trigger_dagrun.py                |   21 +-
 airflow/provider.yaml.schema.json                  |    1 +
 .../aws/example_dags/example_eks_templated.py      |   42 +-
 .../example_eks_with_fargate_in_one_step.py        |   14 +-
 .../example_eks_with_fargate_profile.py            |   21 +-
 .../example_eks_with_nodegroup_in_one_step.py      |   16 +-
 .../example_dags/example_eks_with_nodegroups.py    |   26 +-
 .../amazon/aws/example_dags/example_lambda.py}     |   32 +-
 .../amazon/aws/example_dags/example_sagemaker.py   |  177 +++
 airflow/providers/amazon/aws/hooks/base_aws.py     |   44 +-
 .../providers/amazon/aws/hooks/lambda_function.py  |   91 +-
 airflow/providers/amazon/aws/hooks/rds.py          |   59 +
 airflow/providers/amazon/aws/hooks/sagemaker.py    |   11 +
 .../providers/amazon/aws/operators/aws_lambda.py   |  102 ++
 airflow/providers/amazon/aws/operators/emr.py      |   18 +-
 .../providers/amazon/aws/operators/redshift_sql.py |    4 +-
 airflow/providers/amazon/aws/operators/s3.py       |   14 +-
 .../providers/amazon/aws/operators/sagemaker.py    |   22 +
 airflow/providers/amazon/aws/sensors/eks.py        |   12 +
 .../providers/amazon/aws/transfers/sql_to_s3.py    |   36 +-
 airflow/providers/amazon/aws/utils/emailer.py      |    5 +-
 airflow/providers/amazon/provider.yaml             |   14 +
 airflow/providers/apache/beam/operators/beam.py    |   28 +-
 airflow/providers/apache/hive/provider.yaml        |    3 -
 .../providers/apache/spark/hooks/spark_submit.py   |    2 +-
 .../kubernetes/example_dags/example_kubernetes.py  |    2 +-
 .../cncf/kubernetes/operators/kubernetes_pod.py    |   14 +-
 .../databricks/example_dags/example_databricks.py  |    7 +-
 .../example_dags/example_databricks_sql.py         |  113 ++
 airflow/providers/databricks/hooks/databricks.py   |  365 +-----
 .../hooks/{databricks.py => databricks_base.py}    |  334 ++----
 .../providers/databricks/hooks/databricks_sql.py   |  189 +++
 .../providers/databricks/operators/databricks.py   |   24 +-
 .../databricks/operators/databricks_sql.py         |  267 +++++
 airflow/providers/databricks/provider.yaml         |   20 +-
 .../providers/dbt}/__init__.py                     |    0
 .../providers/{alibaba => dbt/cloud}/CHANGELOG.rst |    0
 .../providers/dbt/cloud}/__init__.py               |    0
 .../providers/dbt/cloud/example_dags}/__init__.py  |    0
 .../dbt/cloud/example_dags/example_dbt_cloud.py    |   75 ++
 .../providers/dbt/cloud/hooks}/__init__.py         |    0
 airflow/providers/dbt/cloud/hooks/dbt.py           |  499 ++++++++
 .../providers/dbt/cloud/operators}/__init__.py     |    0
 airflow/providers/dbt/cloud/operators/dbt.py       |  209 ++++
 .../{databricks => dbt/cloud}/provider.yaml        |   45 +-
 .../providers/dbt/cloud/sensors}/__init__.py       |    0
 airflow/providers/dbt/cloud/sensors/dbt.py         |   65 +
 airflow/providers/dependencies.json                |    9 +
 .../tutorial_taskflow_api_etl_docker_virtualenv.py |    2 +-
 .../google/cloud/example_dags/example_vertex_ai.py |  153 +++
 .../google/cloud/hooks/vertex_ai/auto_ml.py        | 1256 ++++++++++++++++++++
 .../providers/google/cloud/links}/__init__.py      |    0
 airflow/providers/google/cloud/links/base.py       |   51 +
 airflow/providers/google/cloud/links/dataflow.py   |   50 +
 airflow/providers/google/cloud/links/dataproc.py   |  131 ++
 airflow/providers/google/cloud/links/vertex_ai.py  |  119 ++
 .../providers/google/cloud/operators/bigquery.py   |   18 +-
 .../google/cloud/operators/bigquery_dts.py         |    6 +-
 .../google/cloud/operators/cloud_composer.py       |   34 +-
 .../providers/google/cloud/operators/dataflow.py   |    5 +
 .../providers/google/cloud/operators/datafusion.py |   62 +-
 .../providers/google/cloud/operators/dataproc.py   |  180 ++-
 .../google/cloud/operators/dataproc_metastore.py   |   47 +-
 .../google/cloud/operators/vertex_ai/auto_ml.py    |  623 ++++++++++
 .../google/cloud/operators/vertex_ai/custom_job.py |   90 +-
 .../google/cloud/operators/vertex_ai/dataset.py    |   88 +-
 airflow/providers/google/cloud/sensors/dataproc.py |    6 +-
 .../google/cloud/transfers/bigquery_to_bigquery.py |   21 +-
 .../google/cloud/transfers/gcs_to_bigquery.py      |  133 ++-
 airflow/providers/google/common/links/storage.py   |   23 +-
 airflow/providers/google/provider.yaml             |   15 +-
 airflow/providers/http/sensors/http.py             |    1 +
 airflow/providers/microsoft/azure/hooks/cosmos.py  |   88 +-
 .../microsoft/azure/operators/data_factory.py      |   25 +-
 .../providers/mysql/example_dags/example_mysql.py  |    6 +-
 airflow/providers/mysql/hooks/mysql.py             |    8 -
 airflow/providers/oracle/hooks/oracle.py           |   15 +
 airflow/providers/postgres/hooks/postgres.py       |    8 +-
 .../providers/presto/example_dags}/__init__.py     |    0
 .../presto/example_dags/example_gcs_to_presto.py}  |   36 +-
 airflow/providers/presto/hooks/presto.py           |  115 +-
 airflow/providers/presto/provider.yaml             |    6 +
 .../providers/presto/transfers}/__init__.py        |    0
 .../providers/presto/transfers/gcs_to_presto.py    |  122 ++
 airflow/providers/qubole/operators/qubole.py       |   20 +-
 .../providers/trino/example_dags}/__init__.py      |    0
 .../trino/example_dags/example_gcs_to_trino.py}    |   36 +-
 airflow/providers/trino/hooks/trino.py             |  121 +-
 airflow/providers/trino/provider.yaml              |    6 +
 .../providers/trino/transfers}/__init__.py         |    0
 airflow/providers/trino/transfers/gcs_to_trino.py  |  124 ++
 airflow/secrets/local_filesystem.py                |    7 +-
 airflow/sensors/filesystem.py                      |    2 +-
 airflow/serialization/serialized_objects.py        |   41 +-
 airflow/settings.py                                |   14 +-
 airflow/task/task_runner/standard_task_runner.py   |   18 +-
 airflow/ti_deps/deps/trigger_rule_dep.py           |   14 +
 airflow/utils/context.py                           |   45 +
 airflow/utils/context.pyi                          |    5 +-
 airflow/utils/dates.py                             |    7 +
 airflow/utils/db.py                                |  251 +++-
 airflow/utils/db_cleanup.py                        |  315 +++++
 airflow/utils/edgemodifier.py                      |  107 +-
 airflow/utils/log/file_task_handler.py             |    5 +-
 airflow/utils/log/secrets_masker.py                |    7 +-
 airflow/utils/operator_resources.py                |   26 +
 airflow/utils/task_group.py                        |   19 +-
 airflow/utils/trigger_rule.py                      |   22 +-
 airflow/utils/weight_rule.py                       |   22 +-
 airflow/www/fab_security/manager.py                |   15 +
 airflow/www/package.json                           |    2 +
 airflow/www/static/js/calendar.js                  |    2 +-
 airflow/www/static/js/connection_form.js           |    2 +-
 airflow/www/static/js/dag.js                       |    2 +-
 airflow/www/static/js/dag_code.js                  |    2 +-
 airflow/www/static/js/dags.js                      |    2 +-
 airflow/www/static/js/graph.js                     |   65 +-
 airflow/www/static/js/task_instances.js            |   19 +
 airflow/www/static/js/ti_log.js                    |    2 +-
 airflow/www/static/js/tree/InstanceTooltip.jsx     |   23 +-
 airflow/www/static/js/tree/StatusBox.jsx           |    6 +-
 airflow/www/static/js/tree/Tree.jsx                |   16 +-
 .../tree/{details/content/Dag.jsx => api/index.js} |   21 +-
 .../js/{meta_value.js => tree/api/useDag.js}       |   14 +-
 .../{details/content/Dag.jsx => api/useTasks.js}   |   19 +-
 airflow/www/static/js/tree/dagRuns/Bar.jsx         |    2 +-
 airflow/www/static/js/tree/details/Header.jsx      |    5 +-
 airflow/www/static/js/tree/details/content/Dag.jsx |   36 +-
 .../js/tree/details/content/TaskInstance.jsx       |  100 +-
 airflow/www/static/js/tree/details/index.jsx       |   34 +-
 airflow/www/static/js/tree/index.jsx               |   13 +-
 airflow/www/static/js/tree/renderTaskRows.jsx      |    2 +-
 airflow/www/static/js/tree/useTreeData.js          |    2 +-
 airflow/www/static/js/{meta_value.js => utils.js}  |   17 +-
 airflow/www/static/screenshots/gantt.png           |  Bin 31140 -> 0 bytes
 airflow/www/static/screenshots/graph.png           |  Bin 38282 -> 0 bytes
 airflow/www/static/screenshots/tree.png            |  Bin 35259 -> 0 bytes
 airflow/www/templates/airflow/dag.html             |    4 +-
 airflow/www/templates/airflow/dags.html            |    2 +-
 airflow/www/templates/airflow/variable_list.html   |    4 +
 .../{variable_list.html => variable_show.html}     |   25 +-
 .../templates/airflow/variable_show_widget.html    |   70 ++
 airflow/www/views.py                               |  137 ++-
 airflow/www/widgets.py                             |    6 +
 airflow/www/yarn.lock                              |  104 +-
 breeze                                             |   63 +-
 breeze-complete                                    |   12 +-
 chart/Chart.yaml                                   |   20 +-
 chart/UPDATING.rst                                 |   15 +
 chart/templates/flower/flower-deployment.yaml      |    2 +
 chart/templates/jobs/create-user-job.yaml          |   27 +-
 chart/templates/jobs/migrate-database-job.yaml     |   10 +-
 chart/tests/test_create_user_job.py                |  102 +-
 chart/tests/test_extra_env_env_from.py             |    4 +
 chart/tests/test_migrate_database_job.py           |   50 +
 chart/values.schema.json                           |   71 +-
 chart/values.yaml                                  |   44 +-
 dev/README_RELEASE_AIRFLOW.md                      |   11 +-
 dev/README_RELEASE_HELM_CHART.md                   |    8 +-
 dev/airflow-github                                 |   34 +-
 dev/assign_cherry_picked_prs_with_milestone.py     |    2 +-
 ...0004-using-docker-images-as-test-environment.md |    2 +-
 dev/breeze/setup.cfg                               |    1 +
 dev/breeze/src/airflow_breeze/breeze.py            |   16 +-
 dev/breeze/src/airflow_breeze/cache.py             |    4 +-
 dev/breeze/src/airflow_breeze/ci/build_image.py    |   29 +-
 dev/breeze/src/airflow_breeze/ci/build_params.py   |    4 +-
 dev/breeze/src/airflow_breeze/pre_commit_ids.py    |    3 +-
 dev/breeze/src/airflow_ci/freespace.py             |    2 +-
 dev/breeze/tests/test_build_image.py               |   60 +
 dev/check_files.py                                 |    2 +-
 dev/prepare_release_issue.py                       |    2 +-
 dev/provider_packages/prepare_provider_packages.py |    4 +-
 dev/requirements.txt                               |    5 +-
 dev/retag_docker_images.py                         |    2 +-
 dev/send_email.py                                  |    2 +-
 ...calculate_statistics_provider_testing_issues.py |    2 +-
 .../connections/aws.rst                            |  100 ++
 docs/apache-airflow-providers-amazon/index.rst     |    1 +
 .../operators/eks.rst                              |   54 +
 .../operators/lambda.rst                           |   58 +
 .../operators/sagemaker.rst                        |   66 +
 .../secrets-backends/aws-secrets-manager.rst       |    5 +-
 .../connections/databricks.rst                     |   15 +-
 docs/apache-airflow-providers-databricks/index.rst |   21 +-
 .../operators/copy_into.rst                        |   76 ++
 .../operators}/index.rst                           |   31 +-
 .../{operators.rst => operators/run_now.rst}       |   79 +-
 .../operators/sql.rst                              |  105 ++
 .../operators/submit_run.rst                       |   97 ++
 .../commits.rst}                                   |   31 +-
 .../connections.rst                                |   88 ++
 .../index.rst                                      |   47 +-
 .../installing-providers-from-sources.rst          |    0
 .../operators.rst                                  |  108 ++
 .../operators/cloud/vertex_ai.rst                  |   90 ++
 .../connections/odbc.rst                           |    6 +-
 docs/apache-airflow-providers-presto/index.rst     |    7 +
 .../operators/transfer/gcs_to_presto.rst           |   52 +
 docs/apache-airflow-providers-trino/index.rst      |    7 +
 .../operators/transfer/gcs_to_trino.rst            |   52 +
 docs/apache-airflow/best-practices.rst             |  173 ++-
 docs/apache-airflow/concepts/dags.rst              |   48 +-
 docs/apache-airflow/concepts/operators.rst         |    2 +-
 docs/apache-airflow/concepts/scheduler.rst         |    2 +-
 docs/apache-airflow/concepts/tasks.rst             |    6 +
 docs/apache-airflow/configurations-ref.rst         |    5 +
 docs/apache-airflow/dag-run.rst                    |   40 +-
 docs/apache-airflow/executor/kubernetes.rst        |    5 +-
 docs/apache-airflow/extra-packages-ref.rst         |    2 +
 docs/apache-airflow/faq.rst                        |   60 +-
 docs/apache-airflow/howto/define_extra_link.rst    |   26 +-
 .../howto/dynamic-dag-generation.rst               |  140 +++
 docs/apache-airflow/howto/email-config.rst         |    5 +-
 docs/apache-airflow/howto/index.rst                |    1 +
 docs/apache-airflow/howto/set-config.rst           |    5 +
 docs/apache-airflow/howto/set-up-database.rst      |    2 +-
 docs/apache-airflow/howto/timetable.rst            |    8 +-
 docs/apache-airflow/img/watcher.png                |  Bin 0 -> 41592 bytes
 docs/apache-airflow/installation/dependencies.rst  |    2 +-
 docs/apache-airflow/installation/prerequisites.rst |    2 +-
 .../installation/supported-versions.rst            |    2 +-
 docs/apache-airflow/installation/upgrading.rst     |   11 +
 docs/apache-airflow/lineage.rst                    |    7 +-
 .../logging-monitoring/callbacks.rst               |    8 +-
 .../logging-monitoring/check-health.rst            |    2 +-
 docs/apache-airflow/logging-monitoring/metrics.rst |    1 +
 docs/apache-airflow/migrations-ref.rst             |  450 +++----
 docs/apache-airflow/modules_management.rst         |    1 +
 docs/apache-airflow/plugins.rst                    |   36 +-
 docs/apache-airflow/security/api.rst               |    4 +-
 docs/apache-airflow/start/docker.rst               |    2 +-
 docs/apache-airflow/timezone.rst                   |   19 +-
 docs/apache-airflow/tutorial.rst                   |   15 +-
 docs/apache-airflow/tutorial_taskflow_api.rst      |    4 +-
 docs/apache-airflow/upgrading-from-1-10/index.rst  |    5 +
 docs/docker-stack/build-arg-ref.rst                |    7 +-
 docs/docker-stack/build.rst                        |   16 +-
 .../customizing/add-build-essential-custom.sh      |    2 +-
 .../docker-examples/customizing/custom-sources.sh  |    2 +-
 .../customizing/github-different-repository.sh     |    2 +-
 .../docker-examples/customizing/github-main.sh     |    2 +-
 .../customizing/github-v2-2-test.sh                |    2 +-
 .../customizing/pypi-dev-runtime-deps.sh           |    2 +-
 .../customizing/pypi-extras-and-deps.sh            |    2 +-
 .../customizing/pypi-selected-version.sh           |    2 +-
 .../extending/embedding-dags/test_dag.py           |   10 +-
 .../restricted/restricted_environments.sh          |    3 +-
 docs/exts/operators_and_hooks_ref.py               |    2 +-
 docs/helm-chart/airflow-configuration.rst          |   46 +-
 docs/helm-chart/production-guide.rst               |    7 +-
 .../aws/Amazon-RDS_light-bg@4x.png                 |  Bin 0 -> 53014 bytes
 docs/integration-logos/dbt/dbt.png                 |  Bin 0 -> 21953 bytes
 docs/spelling_wordlist.txt                         |    6 +
 images/ci/pull_request_ci_flow.md5                 |    1 -
 images/ci/pull_request_ci_flow.mermaid             |  116 --
 images/ci/pull_request_ci_flow.png                 |  Bin 192880 -> 0 bytes
 images/ci/push_ci_flow.md5                         |    1 -
 images/ci/push_ci_flow.mermaid                     |  112 --
 images/ci/push_ci_flow.png                         |  Bin 200048 -> 0 bytes
 images/ci/scheduled_ci_flow.md5                    |    1 -
 images/ci/scheduled_ci_flow.mermaid                |   98 --
 images/ci/scheduled_ci_flow.png                    |  Bin 171588 -> 0 bytes
 images/pr/selective_checks.md5                     |    1 -
 images/pr/selective_checks.mermaid                 |   35 -
 images/pr/selective_checks.png                     |  Bin 64501 -> 0 bytes
 scripts/ci/docker-compose/_docker.env              |    1 +
 ...ackend-mssql.yml => backend-mssql-bullseye.yml} |    4 +-
 ...{backend-mssql.yml => backend-mssql-buster.yml} |    0
 scripts/ci/docker-compose/base.yml                 |    1 +
 scripts/ci/libraries/_build_images.sh              |    7 +-
 scripts/ci/libraries/_initialization.sh            |   11 +-
 scripts/ci/pre_commit/pre_commit_check_license.sh  |   49 +-
 scripts/ci/pre_commit/pre_commit_flake8.sh         |   25 +-
 scripts/ci/pre_commit/pre_commit_helm_lint.sh      |   13 +-
 .../ci/pre_commit/pre_commit_lint_dockerfile.sh    |   36 +-
 scripts/ci/pre_commit/pre_commit_mermaid.sh        |  107 --
 .../pre_commit/pre_commit_migration_documented.py  |   67 --
 .../pre_commit/pre_commit_migration_reference.py   |  134 +++
 .../pre_commit_migration_reference.sh}             |   11 +-
 scripts/ci/pre_commit/pre_commit_mypy.sh           |   26 +-
 scripts/ci/pre_commit/supported_versions.py        |    2 +-
 scripts/ci/static_checks/check_license.sh          |   63 -
 scripts/ci/static_checks/helm_lint.sh              |   28 -
 scripts/ci/static_checks/lint_dockerfile.sh        |   51 -
 scripts/ci/static_checks/mypy.sh                   |   40 -
 scripts/ci/static_checks/ui_lint.sh                |    2 +-
 scripts/ci/static_checks/www_lint.sh               |    2 +-
 .../ci_run_single_airflow_test_in_docker.sh        |    6 +-
 .../determine_debian_version_specific_variables.sh |   49 +
 scripts/docker/install_airflow.sh                  |    8 +-
 ...install_airflow_dependencies_from_branch_tip.sh |    5 +
 .../docker/install_from_docker_context_files.sh    |    3 +
 scripts/docker/install_mssql.sh                    |   35 +-
 scripts/docker/install_mysql.sh                    |    8 +-
 .../{install_mysql.sh => install_postgres.sh}      |   38 +-
 .../run_migration_reference.sh}                    |    8 +-
 confirm => scripts/tools/confirm                   |    0
 setup.cfg                                          |   26 +-
 setup.py                                           |   32 +-
 .../endpoints/test_extra_link_endpoint.py          |   16 +-
 .../endpoints/test_task_instance_endpoint.py       |   16 +-
 .../schemas/test_task_instance_schema.py           |   15 +-
 tests/cli/commands/test_celery_command.py          |    2 +-
 tests/cli/commands/test_db_command.py              |  222 +++-
 tests/cli/commands/test_triggerer_command.py       |    2 +-
 tests/core/test_configuration.py                   |   22 +
 tests/dag_processing/test_manager.py               |    2 +-
 tests/dag_processing/test_processor.py             |    2 +-
 tests/dags/test_mapped_classic.py                  |   10 +-
 tests/dags/test_mapped_taskflow.py                 |    2 +-
 tests/decorators/test_python.py                    |  117 +-
 tests/hooks/test_dbapi.py                          |   61 +-
 tests/jobs/test_scheduler_job.py                   |  111 +-
 tests/jobs/test_triggerer_job.py                   |   11 +-
 tests/models/test_baseoperator.py                  |   21 +-
 tests/models/test_connection.py                    |    8 +
 tests/models/test_dag.py                           |   27 +
 tests/models/test_dagbag.py                        |   50 +
 tests/models/test_dagrun.py                        |   34 +-
 tests/models/test_taskinstance.py                  |  168 ++-
 tests/models/test_trigger.py                       |   52 +
 tests/models/test_xcom.py                          |   88 +-
 tests/operators/test_trigger_dagrun.py             |   28 +-
 tests/providers/amazon/aws/hooks/test_base_aws.py  |   33 +-
 .../amazon/aws/hooks/test_lambda_function.py       |    6 +-
 .../providers/amazon/aws/hooks/test_rds.py         |   14 +-
 tests/providers/amazon/aws/hooks/test_sagemaker.py |   22 +-
 .../aws/operators/test_emr_create_job_flow.py      |    8 +-
 .../providers/amazon/aws/operators/test_lambda.py  |  109 ++
 .../amazon/aws/operators/test_s3_delete_objects.py |   96 ++
 .../amazon/aws/operators/test_sagemaker_model.py   |   20 +-
 .../amazon/aws/transfers/test_sql_to_s3.py         |   54 +
 tests/providers/amazon/aws/utils/test_emailer.py   |   11 +-
 tests/providers/apache/beam/operators/test_beam.py |   40 +-
 tests/providers/apache/hive/hooks/test_hive.py     |   31 -
 .../apache/hive/transfers/test_hive_to_mysql.py    |    9 -
 .../apache/hive/transfers/test_hive_to_samba.py    |    9 -
 .../apache/hive/transfers/test_mssql_to_hive.py    |    8 +-
 .../apache/hive/transfers/test_mysql_to_hive.py    |    7 -
 .../kubernetes/operators/test_kubernetes_pod.py    |  289 +++--
 .../providers/databricks/hooks/test_databricks.py  |  231 +++-
 .../databricks/hooks/test_databricks_sql.py        |   84 ++
 .../databricks/operators/test_databricks.py        |   57 +
 .../databricks/operators/test_databricks_sql.py    |  170 +++
 tests/{timetables => providers/dbt}/__init__.py    |    0
 .../dbt/cloud}/__init__.py                         |    0
 .../dbt/cloud/hooks}/__init__.py                   |    0
 tests/providers/dbt/cloud/hooks/test_dbt_cloud.py  |  600 ++++++++++
 .../dbt/cloud/operators}/__init__.py               |    0
 .../dbt/cloud/operators/test_dbt_cloud.py          |  374 ++++++
 .../dbt/cloud/sensors}/__init__.py                 |    0
 .../providers/dbt/cloud/sensors/test_dbt_cloud.py  |   71 ++
 .../google/cloud/hooks/vertex_ai/test_auto_ml.py   |  175 +++
 .../google/cloud/operators/test_bigquery.py        |   19 +-
 .../google/cloud/operators/test_dataproc.py        |  132 +-
 .../google/cloud/operators/test_mlengine.py        |    4 +-
 .../google/cloud/operators/test_vertex_ai.py       |  345 ++++++
 .../cloud/operators/test_vertex_ai_system.py       |    4 +
 .../cloud/transfers/test_bigquery_to_bigquery.py   |    2 +-
 .../google/cloud/transfers/test_gcs_to_bigquery.py |  113 +-
 .../microsoft/azure/hooks/test_azure_cosmos.py     |   78 +-
 .../microsoft/azure/operators/test_azure_cosmos.py |    8 +-
 .../azure/operators/test_azure_data_factory.py     |    2 +-
 tests/providers/oracle/hooks/test_oracle.py        |    6 +
 .../presto/transfers}/__init__.py                  |    0
 .../providers/presto/transfers/test_gcs_presto.py  |  145 +++
 tests/providers/qubole/operators/test_qubole.py    |    8 +-
 tests/providers/snowflake/hooks/test_snowflake.py  |    1 +
 .../snowflake/transfers/test_snowflake_to_slack.py |   12 +-
 .../trino/transfers}/__init__.py                   |    0
 tests/providers/trino/transfers/test_gcs_trino.py  |  145 +++
 tests/secrets/test_local_filesystem.py             |   17 +
 tests/sensors/test_external_task_sensor.py         |    2 +-
 tests/sensors/test_filesystem.py                   |   36 +-
 tests/serialization/test_dag_serialization.py      |  190 +--
 .../task/task_runner/test_standard_task_runner.py  |   24 +-
 tests/test_utils/mock_executor.py                  |    2 +
 tests/test_utils/mock_operators.py                 |   16 +-
 .../perf/scheduler_dag_execution_timing.py         |    2 +-
 tests/ti_deps/deps/test_trigger_rule_dep.py        |   57 +
 tests/utils/test_db.py                             |  133 ++-
 tests/utils/test_db_cleanup.py                     |  265 +++++
 tests/utils/test_edgemodifier.py                   |  205 ++++
 tests/utils/test_operator_resources.py             |    9 +
 tests/utils/test_task_group.py                     |    8 +-
 tests/utils/test_trigger_rule.py                   |    8 +-
 tests/utils/test_weight_rule.py                    |    5 +
 tests/www/views/test_views_extra_links.py          |   47 +-
 591 files changed, 17221 insertions(+), 5164 deletions(-)
 create mode 100644 CI_DIAGRAMS.md
 create mode 100644 SELECTIVE_CHECKS.md
 copy {tests/timetables => airflow/callbacks}/__init__.py (100%)
 copy scripts/ci/pre_commit/pre_commit_helm_lint.sh => airflow/callbacks/base_callback_sink.py (74%)
 mode change 100755 => 100644
 rename airflow/{utils => callbacks}/callback_requests.py (95%)
 create mode 100644 airflow/callbacks/pipe_callback_sink.py
 rename airflow/migrations/versions/{b0125267960b_merge_heads.py => 08364691d074_merge_heads.py} (95%)
 copy airflow/{example_dags/example_time_delta_sensor_async.py => providers/amazon/aws/example_dags/example_lambda.py} (56%)
 create mode 100644 airflow/providers/amazon/aws/example_dags/example_sagemaker.py
 create mode 100644 airflow/providers/amazon/aws/hooks/rds.py
 create mode 100644 airflow/providers/amazon/aws/operators/aws_lambda.py
 create mode 100644 airflow/providers/databricks/example_dags/example_databricks_sql.py
 copy airflow/providers/databricks/hooks/{databricks.py => databricks_base.py} (60%)
 create mode 100644 airflow/providers/databricks/hooks/databricks_sql.py
 create mode 100644 airflow/providers/databricks/operators/databricks_sql.py
 copy {tests/timetables => airflow/providers/dbt}/__init__.py (100%)
 copy airflow/providers/{alibaba => dbt/cloud}/CHANGELOG.rst (100%)
 copy {tests/timetables => airflow/providers/dbt/cloud}/__init__.py (100%)
 copy {tests/timetables => airflow/providers/dbt/cloud/example_dags}/__init__.py (100%)
 create mode 100644 airflow/providers/dbt/cloud/example_dags/example_dbt_cloud.py
 copy {tests/timetables => airflow/providers/dbt/cloud/hooks}/__init__.py (100%)
 create mode 100644 airflow/providers/dbt/cloud/hooks/dbt.py
 copy {tests/timetables => airflow/providers/dbt/cloud/operators}/__init__.py (100%)
 create mode 100644 airflow/providers/dbt/cloud/operators/dbt.py
 copy airflow/providers/{databricks => dbt/cloud}/provider.yaml (55%)
 copy {tests/www/api/experimental => airflow/providers/dbt/cloud/sensors}/__init__.py (100%)
 create mode 100644 airflow/providers/dbt/cloud/sensors/dbt.py
 create mode 100644 airflow/providers/google/cloud/hooks/vertex_ai/auto_ml.py
 copy {tests/timetables => airflow/providers/google/cloud/links}/__init__.py (100%)
 create mode 100644 airflow/providers/google/cloud/links/base.py
 create mode 100644 airflow/providers/google/cloud/links/dataflow.py
 create mode 100644 airflow/providers/google/cloud/links/dataproc.py
 create mode 100644 airflow/providers/google/cloud/links/vertex_ai.py
 create mode 100644 airflow/providers/google/cloud/operators/vertex_ai/auto_ml.py
 copy {tests/timetables => airflow/providers/presto/example_dags}/__init__.py (100%)
 copy airflow/{example_dags/example_trigger_controller_dag.py => providers/presto/example_dags/example_gcs_to_presto.py} (52%)
 copy {tests/timetables => airflow/providers/presto/transfers}/__init__.py (100%)
 create mode 100644 airflow/providers/presto/transfers/gcs_to_presto.py
 copy {tests/www/api/experimental => airflow/providers/trino/example_dags}/__init__.py (100%)
 copy airflow/{example_dags/example_trigger_controller_dag.py => providers/trino/example_dags/example_gcs_to_trino.py} (53%)
 copy {tests/www/api/experimental => airflow/providers/trino/transfers}/__init__.py (100%)
 create mode 100644 airflow/providers/trino/transfers/gcs_to_trino.py
 create mode 100644 airflow/utils/db_cleanup.py
 copy airflow/www/static/js/tree/{details/content/Dag.jsx => api/index.js} (72%)
 copy airflow/www/static/js/{meta_value.js => tree/api/useDag.js} (79%)
 copy airflow/www/static/js/tree/{details/content/Dag.jsx => api/useTasks.js} (80%)
 rename airflow/www/static/js/{meta_value.js => utils.js} (74%)
 delete mode 100644 airflow/www/static/screenshots/gantt.png
 delete mode 100644 airflow/www/static/screenshots/graph.png
 delete mode 100644 airflow/www/static/screenshots/tree.png
 copy airflow/www/templates/airflow/{variable_list.html => variable_show.html} (53%)
 create mode 100644 airflow/www/templates/airflow/variable_show_widget.html
 create mode 100644 dev/breeze/tests/test_build_image.py
 create mode 100644 docs/apache-airflow-providers-amazon/operators/lambda.rst
 create mode 100644 docs/apache-airflow-providers-amazon/operators/sagemaker.rst
 create mode 100644 docs/apache-airflow-providers-databricks/operators/copy_into.rst
 copy docs/{apache-airflow/howto => apache-airflow-providers-databricks/operators}/index.rst (58%)
 rename docs/apache-airflow-providers-databricks/{operators.rst => operators/run_now.rst} (53%)
 create mode 100644 docs/apache-airflow-providers-databricks/operators/sql.rst
 create mode 100644 docs/apache-airflow-providers-databricks/operators/submit_run.rst
 copy docs/{apache-airflow/howto/index.rst => apache-airflow-providers-dbt-cloud/commits.rst} (57%)
 create mode 100644 docs/apache-airflow-providers-dbt-cloud/connections.rst
 copy docs/{apache-airflow-providers-databricks => apache-airflow-providers-dbt-cloud}/index.rst (60%)
 copy docs/{apache-airflow-providers-zendesk => apache-airflow-providers-dbt-cloud}/installing-providers-from-sources.rst (100%)
 create mode 100644 docs/apache-airflow-providers-dbt-cloud/operators.rst
 create mode 100644 docs/apache-airflow-providers-presto/operators/transfer/gcs_to_presto.rst
 create mode 100644 docs/apache-airflow-providers-trino/operators/transfer/gcs_to_trino.rst
 create mode 100644 docs/apache-airflow/howto/dynamic-dag-generation.rst
 create mode 100644 docs/apache-airflow/img/watcher.png
 create mode 100644 docs/integration-logos/aws/Amazon-RDS_light-bg@4x.png
 create mode 100644 docs/integration-logos/dbt/dbt.png
 delete mode 100644 images/ci/pull_request_ci_flow.md5
 delete mode 100644 images/ci/pull_request_ci_flow.mermaid
 delete mode 100644 images/ci/pull_request_ci_flow.png
 delete mode 100644 images/ci/push_ci_flow.md5
 delete mode 100644 images/ci/push_ci_flow.mermaid
 delete mode 100644 images/ci/push_ci_flow.png
 delete mode 100644 images/ci/scheduled_ci_flow.md5
 delete mode 100644 images/ci/scheduled_ci_flow.mermaid
 delete mode 100644 images/ci/scheduled_ci_flow.png
 delete mode 100644 images/pr/selective_checks.md5
 delete mode 100644 images/pr/selective_checks.mermaid
 delete mode 100644 images/pr/selective_checks.png
 copy scripts/ci/docker-compose/{backend-mssql.yml => backend-mssql-bullseye.yml} (93%)
 rename scripts/ci/docker-compose/{backend-mssql.yml => backend-mssql-buster.yml} (100%)
 delete mode 100755 scripts/ci/pre_commit/pre_commit_mermaid.sh
 delete mode 100755 scripts/ci/pre_commit/pre_commit_migration_documented.py
 create mode 100755 scripts/ci/pre_commit/pre_commit_migration_reference.py
 rename scripts/ci/{static_checks/flake8.sh => pre_commit/pre_commit_migration_reference.sh} (81%)
 delete mode 100755 scripts/ci/static_checks/check_license.sh
 delete mode 100755 scripts/ci/static_checks/helm_lint.sh
 delete mode 100755 scripts/ci/static_checks/lint_dockerfile.sh
 delete mode 100755 scripts/ci/static_checks/mypy.sh
 create mode 100644 scripts/docker/determine_debian_version_specific_variables.sh
 copy scripts/docker/{install_mysql.sh => install_postgres.sh} (54%)
 copy scripts/{ci/pre_commit/pre_commit_mypy.sh => in_container/run_migration_reference.sh} (79%)
 rename confirm => scripts/tools/confirm (100%)
 copy scripts/ci/pre_commit/pre_commit_helm_lint.sh => tests/providers/amazon/aws/hooks/test_rds.py (73%)
 mode change 100755 => 100644
 create mode 100644 tests/providers/amazon/aws/operators/test_lambda.py
 create mode 100644 tests/providers/databricks/hooks/test_databricks_sql.py
 create mode 100644 tests/providers/databricks/operators/test_databricks_sql.py
 copy tests/{timetables => providers/dbt}/__init__.py (100%)
 copy tests/{timetables => providers/dbt/cloud}/__init__.py (100%)
 copy tests/{timetables => providers/dbt/cloud/hooks}/__init__.py (100%)
 create mode 100644 tests/providers/dbt/cloud/hooks/test_dbt_cloud.py
 copy tests/{timetables => providers/dbt/cloud/operators}/__init__.py (100%)
 create mode 100644 tests/providers/dbt/cloud/operators/test_dbt_cloud.py
 copy tests/{timetables => providers/dbt/cloud/sensors}/__init__.py (100%)
 create mode 100644 tests/providers/dbt/cloud/sensors/test_dbt_cloud.py
 create mode 100644 tests/providers/google/cloud/hooks/vertex_ai/test_auto_ml.py
 copy tests/{www/api/experimental => providers/presto/transfers}/__init__.py (100%)
 create mode 100644 tests/providers/presto/transfers/test_gcs_presto.py
 copy tests/{www/api/experimental => providers/trino/transfers}/__init__.py (100%)
 create mode 100644 tests/providers/trino/transfers/test_gcs_trino.py
 create mode 100644 tests/utils/test_db_cleanup.py

[airflow] 03/08: reformat grid background colors

Posted by bb...@apache.org.
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 ee869372889c0f2739c09b8d48ed0431d96fd3da
Author: Brent Bovenzi <br...@gmail.com>
AuthorDate: Fri Feb 25 11:58:23 2022 -0500

    reformat grid background colors
---
 airflow/www/static/js/tree/InstanceTooltip.jsx | 16 ++---
 airflow/www/static/js/tree/SidePanel.jsx       | 45 +++++++++++--
 airflow/www/static/js/tree/StatusBox.jsx       | 19 +++---
 airflow/www/static/js/tree/Tree.jsx            | 28 ++++----
 airflow/www/static/js/tree/dagRuns/Bar.jsx     |  9 ++-
 airflow/www/static/js/tree/dagRuns/index.jsx   |  3 +-
 airflow/www/static/js/tree/renderTaskRows.jsx  | 88 ++++++++++++++------------
 7 files changed, 128 insertions(+), 80 deletions(-)

diff --git a/airflow/www/static/js/tree/InstanceTooltip.jsx b/airflow/www/static/js/tree/InstanceTooltip.jsx
index bc0d58c..b0d0584 100644
--- a/airflow/www/static/js/tree/InstanceTooltip.jsx
+++ b/airflow/www/static/js/tree/InstanceTooltip.jsx
@@ -125,29 +125,29 @@ const InstanceTooltip = ({
         </>
       )}
       <br />
-      <Text>
+      {/* <Text>
         {taskIdTitle}
         {taskId}
-      </Text>
-      <Text whiteSpace="nowrap">
+      </Text> */}
+      {/* <Text whiteSpace="nowrap">
         Run Id:
         {' '}
         {runId}
-      </Text>
-      {operator && (
+      </Text> */}
+      {/* {operator && (
       <Text>
         Operator:
         {' '}
         {operator}
       </Text>
-      )}
+      )} */}
       <Text>
         Duration:
         {' '}
         {formatDuration(duration || getDuration(startDate, endDate))}
       </Text>
       <br />
-      <Text as="strong">UTC</Text>
+      {/* <Text as="strong">UTC</Text>
       <Text>
         Started:
         {' '}
@@ -173,7 +173,7 @@ const InstanceTooltip = ({
         Ended:
         {' '}
         {endDate && formatDateTime(endDate)}
-      </Text>
+      </Text> */}
     </Box>
   );
 };
diff --git a/airflow/www/static/js/tree/SidePanel.jsx b/airflow/www/static/js/tree/SidePanel.jsx
index 3515f1c..7a21eba 100644
--- a/airflow/www/static/js/tree/SidePanel.jsx
+++ b/airflow/www/static/js/tree/SidePanel.jsx
@@ -21,29 +21,60 @@
 
 import React from 'react';
 import {
-  Box,
   chakra,
   Flex,
   Text,
+  useDisclosure,
+  CloseButton,
+  Button,
+  IconButton,
 } from '@chakra-ui/react';
+import { MdKeyboardArrowLeft, MdKeyboardArrowRight } from 'react-icons/md';
 
 import { formatDateTime } from '../datetime_utils';
 
-const SidePanel = ({ instance: { runId, taskId, executionDate }, isOpen }) => (
-  <Box bg="gray.200" maxWidth={isOpen ? 300 : 0} minWidth={isOpen ? 300 : 0} transition="all 0.5s" position="relative" overflow="hidden">
-    <Flex right={isOpen ? 0 : -300} top={0} transition="right 0.5s, max-width 0.5s" width={300} flexDirection="column" m={2}>
-      <Text as="h4">
+const SidePanel = ({ instance: { runId, taskId, executionDate } }) => {
+  const { isOpen, onOpen, onClose } = useDisclosure();
+  if (!isOpen) {
+    return (
+      <IconButton
+        ml={2}
+        icon={<MdKeyboardArrowLeft size={18} />}
+        aria-label="Open Details Panel"
+        onClick={onOpen}
+      />
+    );
+  }
+  const title = runId && taskId
+    ? (
+      <>
         <chakra.span>Task Instance: </chakra.span>
         <chakra.b>{taskId}</chakra.b>
         <chakra.span> at </chakra.span>
         <chakra.b>{formatDateTime(moment.utc(executionDate))}</chakra.b>
+      </>
+    )
+    : (
+      <chakra.span>Dag Details: </chakra.span>
+    );
+
+  return (
+    <Flex bg="gray.200" maxWidth={300} minWidth={300} flexDirection="column" p={3}>
+      <IconButton
+        ml={2}
+        icon={<MdKeyboardArrowRight size={18} />}
+        aria-label="Close Details Panel"
+        onClick={onClose}
+      />
+      <Text as="h4">
+        {title}
       </Text>
       <Text>
         {/* eslint-disable-next-line max-len */}
         Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Nunc vel risus commodo viverra maecenas accumsan. Ut porttitor leo a diam sollicitudin tempor id eu. Molestie at elementum eu facilisis sed odio morbi quis commodo. Facilisis leo vel fringilla est ullamcorper eget nulla facilisi etiam. Est sit amet facilisis magna etiam tempor orci eu. Id semper risus in hendrerit gravida rutrum. Ac odio tempor orci dapibus  [...]
       </Text>
     </Flex>
-  </Box>
-);
+  );
+};
 
 export default SidePanel;
diff --git a/airflow/www/static/js/tree/StatusBox.jsx b/airflow/www/static/js/tree/StatusBox.jsx
index dce0fda..b4abc93 100644
--- a/airflow/www/static/js/tree/StatusBox.jsx
+++ b/airflow/www/static/js/tree/StatusBox.jsx
@@ -24,9 +24,10 @@ import {
   Flex,
   Box,
   Tooltip,
+  useTheme,
 } from '@chakra-ui/react';
 
-import { callModal } from '../dag';
+// import { callModal } from '../dag';
 import InstanceTooltip from './InstanceTooltip';
 
 const StatusBox = ({
@@ -35,21 +36,19 @@ const StatusBox = ({
   const {
     executionDate, taskId, tryNumber = 0, operator, runId,
   } = instance;
+  const { colors } = useTheme();
+  const hoverBlue = `${colors.blue[100]}50`;
 
-  const onOpenModal = () => executionDate && callModal(taskId, executionDate, extraLinks, tryNumber, operator === 'SubDagOperator' || undefined, runId);
-  const onClick = () => {
-    if (group.isMapped) {
-      onSelectInstance(instance);
-    } else {
-      onSelectInstance({});
-      onOpenModal();
-    }
+  // const onOpenModal = () => executionDate && callModal(taskId, executionDate, extraLinks, tryNumber, operator === 'SubDagOperator' || undefined, runId);
+  const onClick = (e) => {
+    e.stopPropagation();
+    onSelectInstance(instance);
   };
 
   // Fetch the corresponding column element and set its background color when hovering
   const onMouseOver = () => {
     [...containerRef.current.getElementsByClassName(`js-${runId}`)]
-      .forEach((e) => { e.style.backgroundColor = 'rgba(113, 128, 150, 0.1)'; });
+      .forEach((e) => { e.style.backgroundColor = hoverBlue; });
   };
   const onMouseLeave = () => {
     [...containerRef.current.getElementsByClassName(`js-${runId}`)]
diff --git a/airflow/www/static/js/tree/Tree.jsx b/airflow/www/static/js/tree/Tree.jsx
index 095adbd..ff1402f 100644
--- a/airflow/www/static/js/tree/Tree.jsx
+++ b/airflow/www/static/js/tree/Tree.jsx
@@ -59,7 +59,7 @@ const Tree = () => {
 
   return (
     <Box position="relative" ref={containerRef}>
-      <FormControl display="flex" alignItems="center" justifyContent="flex-end" width="100%">
+      <FormControl display="flex" alignItems="center" justifyContent="flex-end" width="100%" mb={2}>
         {isRefreshOn && <Spinner color="blue.500" speed="1s" mr="4px" />}
         <FormLabel htmlFor="auto-refresh" mb={0} fontSize="12px" fontWeight="normal">
           Auto-refresh
@@ -68,19 +68,21 @@ const Tree = () => {
       </FormControl>
       <Text transform="rotate(-90deg)" position="absolute" left="-6px" top="130px">Runs</Text>
       <Text transform="rotate(-90deg)" position="absolute" left="-6px" top="190px">Tasks</Text>
-      <Box pl="24px">
+      <Box pl="24px" height="100%" onClick={() => setSelectedInstance({})}>
         <Flex position="relative" flexDirection="row" justifyContent="space-between" overflow="hidden">
-          <Table mr="24px" overflowX="auto" ref={scrollRef} height={0}>
-            <Thead>
-              <DagRuns containerRef={containerRef} />
-            </Thead>
-            <Tbody>
-              {renderTaskRows({
-                task: groups, containerRef, onSelectInstance,
-              })}
-            </Tbody>
-          </Table>
-          <SidePanel isOpen={!!runId} instance={selectedInstance} />
+          <Box mr="12px" pb="12px" overflowX="auto" ref={scrollRef} maxWidth="60vw">
+            <Table height={0}>
+              <Thead>
+                <DagRuns containerRef={containerRef} selectedInstance={selectedInstance} />
+              </Thead>
+              <Tbody>
+                {renderTaskRows({
+                  task: groups, containerRef, onSelectInstance, selectedInstance,
+                })}
+              </Tbody>
+            </Table>
+          </Box>
+          <SidePanel instance={selectedInstance} />
         </Flex>
       </Box>
     </Box>
diff --git a/airflow/www/static/js/tree/dagRuns/Bar.jsx b/airflow/www/static/js/tree/dagRuns/Bar.jsx
index a0fa5b1..4dbe20d 100644
--- a/airflow/www/static/js/tree/dagRuns/Bar.jsx
+++ b/airflow/www/static/js/tree/dagRuns/Bar.jsx
@@ -26,6 +26,7 @@ import {
   Tooltip,
   Text,
   VStack,
+  useTheme,
 } from '@chakra-ui/react';
 import { MdPlayArrow } from 'react-icons/md';
 
@@ -35,13 +36,16 @@ import { callModalDag } from '../../dag';
 const BAR_HEIGHT = 100;
 
 const DagRunBar = ({
-  run, max, index, totalRuns, containerRef,
+  run, max, index, totalRuns, containerRef, selectedInstance,
 }) => {
+  const { colors } = useTheme();
+  const hoverBlue = `${colors.blue[100]}50`;
   let highlightHeight = '100%';
   if (containerRef && containerRef.current) {
     const table = containerRef.current.getElementsByTagName('tbody')[0];
     highlightHeight = table.offsetHeight + BAR_HEIGHT;
   }
+  const isSelected = run.runId === selectedInstance.runId;
   return (
     <Box position="relative">
       <Flex
@@ -93,7 +97,8 @@ const DagRunBar = ({
         top="1px"
         height={highlightHeight}
         className={`js-${run.runId}`}
-        _peerHover={{ backgroundColor: 'rgba(113, 128, 150, 0.1)' }}
+        bg={isSelected ? 'blue.100' : undefined}
+        _peerHover={!isSelected && { backgroundColor: hoverBlue }}
         zIndex={0}
         transition="background-color 0.2s"
       />
diff --git a/airflow/www/static/js/tree/dagRuns/index.jsx b/airflow/www/static/js/tree/dagRuns/index.jsx
index a0a4931..7de949f 100644
--- a/airflow/www/static/js/tree/dagRuns/index.jsx
+++ b/airflow/www/static/js/tree/dagRuns/index.jsx
@@ -36,7 +36,7 @@ const DurationTick = ({ children, ...rest }) => (
   </Text>
 );
 
-const DagRuns = ({ containerRef }) => {
+const DagRuns = ({ containerRef, selectedInstance }) => {
   const { data: { dagRuns = [] } } = useTreeData();
   const durations = [];
   const runs = dagRuns.map((dagRun) => {
@@ -97,6 +97,7 @@ const DagRuns = ({ containerRef }) => {
               index={i}
               totalRuns={runs.length}
               containerRef={containerRef}
+              selectedInstance={selectedInstance}
             />
           ))}
         </Flex>
diff --git a/airflow/www/static/js/tree/renderTaskRows.jsx b/airflow/www/static/js/tree/renderTaskRows.jsx
index f5a7ba0..7eff252 100644
--- a/airflow/www/static/js/tree/renderTaskRows.jsx
+++ b/airflow/www/static/js/tree/renderTaskRows.jsx
@@ -28,6 +28,7 @@ import {
   Flex,
   useDisclosure,
   Collapse,
+  useTheme,
 } from '@chakra-ui/react';
 import { FiChevronUp, FiChevronDown } from 'react-icons/fi';
 
@@ -40,7 +41,7 @@ import { getMetaValue } from '../utils';
 const dagId = getMetaValue('dag_id');
 
 const renderTaskRows = ({
-  task, containerRef, level = 0, isParentOpen, onSelectInstance,
+  task, containerRef, level = 0, isParentOpen, onSelectInstance, selectedInstance,
 }) => task.children.map((t) => (
   <Row
     key={t.id}
@@ -50,40 +51,37 @@ const renderTaskRows = ({
     prevTaskId={task.id}
     isParentOpen={isParentOpen}
     onSelectInstance={onSelectInstance}
+    selectedInstance={selectedInstance}
   />
 ));
 
 const TaskName = ({
   isGroup = false, isMapped = false, onToggle, isOpen, level, taskName,
 }) => (
-  <Box _groupHover={{ backgroundColor: 'rgba(113, 128, 150, 0.1)' }} transition="background-color 0.2s">
-    <Flex
-      as={isGroup ? 'button' : 'div'}
-      onClick={() => isGroup && onToggle()}
-      color={level > 4 && 'white'}
-      aria-label={taskName}
-      title={taskName}
-      mr={4}
-      width="100%"
-      backgroundColor={`rgba(203, 213, 224, ${0.25 * level})`}
-      alignItems="center"
+  <Flex
+    as={isGroup ? 'button' : 'div'}
+    onClick={() => isGroup && onToggle()}
+    aria-label={taskName}
+    title={taskName}
+    mr={4}
+    width="100%"
+    alignItems="center"
+  >
+    <Text
+      display="inline"
+      fontSize="12px"
+      ml={level * 4 + 4}
+      isTruncated
     >
-      <Text
-        display="inline"
-        fontSize="12px"
-        ml={level * 4 + 4}
-        isTruncated
-      >
-        {taskName}
-        {isMapped && (
-          ' [ ]'
-        )}
-      </Text>
-      {isGroup && (
-        isOpen ? <FiChevronDown data-testid="open-group" /> : <FiChevronUp data-testid="closed-group" />
+      {taskName}
+      {isMapped && (
+        ' [ ]'
       )}
-    </Flex>
-  </Box>
+    </Text>
+    {isGroup && (
+      isOpen ? <FiChevronDown data-testid="open-group" /> : <FiChevronUp data-testid="closed-group" />
+    )}
+  </Flex>
 );
 
 const TaskInstances = ({
@@ -104,16 +102,20 @@ const TaskInstances = ({
             onSelectInstance={onSelectInstance}
           />
         )
-        : <Box key={`${run.runId}-${task.id}`} width="18px" data-testid="blank-task" />;
+        : <Box key={`${run.runId}-${task.id}`} width="16px" data-testid="blank-task" />;
     })}
   </Flex>
 );
 
-const Row = ({
-  task, containerRef, level, prevTaskId, isParentOpen = true, onSelectInstance,
-}) => {
+const Row = (props) => {
+  const {
+    task, containerRef, level, prevTaskId, isParentOpen = true, onSelectInstance, selectedInstance,
+  } = props;
   const { data: { dagRuns = [] } } = useTreeData();
+  const { colors } = useTheme();
+  const hoverBlue = `${colors.blue[100]}50`;
   const isGroup = !!task.children;
+  const isSelected = selectedInstance.taskId === task.id;
 
   const taskName = prevTaskId ? task.id.replace(`${prevTaskId}.`, '') : task.id;
 
@@ -136,21 +138,23 @@ const Row = ({
   return (
     <>
       <Tr
-        backgroundColor={`rgba(203, 213, 224, ${0.25 * level})`}
+        bg={isSelected ? 'blue.100' : undefined}
         borderBottomWidth={isFullyOpen ? 1 : 0}
-        borderBottomColor={level > 1 ? 'white' : 'gray.200'}
+        borderBottomColor="gray.200"
         role="group"
+        _hover={!isSelected && { bg: hoverBlue }}
+        transition="background-color 0.2s"
       >
         <Td
-          _groupHover={level > 3 && {
-            color: 'white',
-          }}
+          bg={isSelected ? 'blue.100' : 'white'}
+          _groupHover={!isSelected && ({ bg: 'blue.50' })}
           p={0}
+          transition="background-color 0.2s"
           lineHeight="18px"
           position="sticky"
           left={0}
-          backgroundColor="white"
           borderBottom={0}
+          zIndex={2}
         >
           <Collapse in={isFullyOpen}>
             <TaskName
@@ -164,7 +168,11 @@ const Row = ({
           </Collapse>
         </Td>
         <Td width={0} p={0} borderBottom={0} />
-        <Td p={0} align="right" _groupHover={{ backgroundColor: 'rgba(113, 128, 150, 0.1)' }} transition="background-color 0.2s" borderBottom={0}>
+        <Td
+          p={0}
+          align="right"
+          borderBottom={0}
+        >
           <Collapse in={isFullyOpen}>
             <TaskInstances
               dagRuns={dagRuns}
@@ -177,7 +185,9 @@ const Row = ({
       </Tr>
       {isGroup && (
         renderTaskRows({
-          task, containerRef, level: level + 1, isParentOpen: isOpen, onSelectInstance,
+          ...props,
+          level: level + 1,
+          isParentOpen: isOpen,
         })
       )}
     </>

[airflow] 05/08: fix hover and extra prop

Posted by bb...@apache.org.
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 ce953b379925f3fba3ab0f0053b434f943631451
Author: Brent Bovenzi <br...@gmail.com>
AuthorDate: Mon Feb 28 21:01:53 2022 -0500

    fix hover and extra prop
---
 airflow/www/static/js/tree/StatusBox.jsx      | 5 +++--
 airflow/www/static/js/tree/renderTaskRows.jsx | 1 -
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/airflow/www/static/js/tree/StatusBox.jsx b/airflow/www/static/js/tree/StatusBox.jsx
index 815e6a1..0953a79 100644
--- a/airflow/www/static/js/tree/StatusBox.jsx
+++ b/airflow/www/static/js/tree/StatusBox.jsx
@@ -37,7 +37,7 @@ const StatusBox = ({
   const hoverBlue = `${colors.blue[100]}50`;
 
   // Fetch the corresponding column element and set its background color when hovering
-  const onMouseOver = () => {
+  const onMouseEnter = () => {
     if (selectedInstance.runId !== runId) {
       [...containerRef.current.getElementsByClassName(`js-${runId}`)]
         .forEach((e) => { e.style.backgroundColor = hoverBlue; });
@@ -50,6 +50,7 @@ const StatusBox = ({
 
   const onClick = (e) => {
     e.stopPropagation();
+    onMouseLeave();
     onSelectInstance(instance);
   };
 
@@ -73,7 +74,7 @@ const StatusBox = ({
           cursor={!group.children && 'pointer'}
           data-testid="task-instance"
           zIndex={1}
-          onMouseEnter={onMouseOver}
+          onMouseEnter={onMouseEnter}
           onMouseLeave={onMouseLeave}
           {...rest}
         >
diff --git a/airflow/www/static/js/tree/renderTaskRows.jsx b/airflow/www/static/js/tree/renderTaskRows.jsx
index 9b454f0..7440774 100644
--- a/airflow/www/static/js/tree/renderTaskRows.jsx
+++ b/airflow/www/static/js/tree/renderTaskRows.jsx
@@ -98,7 +98,6 @@ const TaskInstances = ({
             key={key}
             instance={instance}
             containerRef={containerRef}
-            extraLinks={task.extraLinks}
             group={task}
             onSelectInstance={onSelectInstance}
             selectedInstance={selectedInstance}

[airflow] 01/08: make UI and tree work with mapped tasks

Posted by bb...@apache.org.
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 adfc609476992318a2068dd20ab62f1a0591b806
Author: Brent Bovenzi <br...@gmail.com>
AuthorDate: Wed Feb 16 11:27:29 2022 -0500

    make UI and tree work with mapped tasks
---
 airflow/www/static/js/tree/InstanceTooltip.jsx |  15 +++
 airflow/www/utils.py                           | 136 ++++++++++++-------------
 2 files changed, 78 insertions(+), 73 deletions(-)

diff --git a/airflow/www/static/js/tree/InstanceTooltip.jsx b/airflow/www/static/js/tree/InstanceTooltip.jsx
index e22189d..bc0d58c 100644
--- a/airflow/www/static/js/tree/InstanceTooltip.jsx
+++ b/airflow/www/static/js/tree/InstanceTooltip.jsx
@@ -25,6 +25,21 @@ import { Box, Text } from '@chakra-ui/react';
 import { formatDateTime, getDuration, formatDuration } from '../datetime_utils';
 import { finalStatesMap } from '../utils';
 
+const STATES = [
+  ['success', 0],
+  ['failed', 0],
+  ['upstream_failed', 0],
+  ['up_for_retry', 0],
+  ['up_for_reschedule', 0],
+  ['running', 0],
+  ['deferred', 0],
+  ['sensing', 0],
+  ['queued', 0],
+  ['scheduled', 0],
+  ['skipped', 0],
+  ['no_status', 0],
+];
+
 const InstanceTooltip = ({
   group,
   instance: {
diff --git a/airflow/www/utils.py b/airflow/www/utils.py
index b1f5e0d..ed765d4 100644
--- a/airflow/www/utils.py
+++ b/airflow/www/utils.py
@@ -43,9 +43,8 @@ from airflow.models import errors
 from airflow.models.taskinstance import TaskInstance
 from airflow.utils import timezone
 from airflow.utils.code_utils import get_python_source
-from airflow.utils.helpers import alchemy_to_dict
 from airflow.utils.json import AirflowJsonEncoder
-from airflow.utils.state import State, TaskInstanceState
+from airflow.utils.state import State
 from airflow.www.forms import DateTimeWithTimezoneField
 from airflow.www.widgets import AirflowDateTimePickerWidget
 
@@ -56,82 +55,13 @@ def datetime_to_string(value: Optional[DateTime]) -> Optional[str]:
     return value.isoformat()
 
 
-def get_mapped_instances(task_instance, session):
-    return (
-        session.query(TaskInstance)
-        .filter(
-            TaskInstance.dag_id == task_instance.dag_id,
-            TaskInstance.run_id == task_instance.run_id,
-            TaskInstance.task_id == task_instance.task_id,
-            TaskInstance.map_index >= 0,
-        )
-        .all()
-    )
-
-
-def get_instance_with_map(task_instance, session):
-    if task_instance.map_index == -1:
-        return alchemy_to_dict(task_instance)
-    mapped_instances = get_mapped_instances(task_instance, session)
-    return get_mapped_summary(task_instance, mapped_instances)
-
-
-def get_mapped_summary(parent_instance, task_instances):
-    priority = [
-        TaskInstanceState.FAILED,
-        TaskInstanceState.UPSTREAM_FAILED,
-        TaskInstanceState.UP_FOR_RETRY,
-        TaskInstanceState.UP_FOR_RESCHEDULE,
-        TaskInstanceState.QUEUED,
-        TaskInstanceState.SCHEDULED,
-        TaskInstanceState.DEFERRED,
-        TaskInstanceState.SENSING,
-        TaskInstanceState.RUNNING,
-        TaskInstanceState.SHUTDOWN,
-        TaskInstanceState.RESTARTING,
-        TaskInstanceState.REMOVED,
-        TaskInstanceState.SUCCESS,
-        TaskInstanceState.SKIPPED,
-    ]
-
-    mapped_states = [ti.state for ti in task_instances]
-
-    group_state = None
-    for state in priority:
-        if state in mapped_states:
-            group_state = state
-            break
-
-    group_start_date = datetime_to_string(
-        min((ti.start_date for ti in task_instances if ti.start_date), default=None)
-    )
-    group_end_date = datetime_to_string(
-        max((ti.end_date for ti in task_instances if ti.end_date), default=None)
-    )
-
-    return {
-        'task_id': parent_instance.task_id,
-        'run_id': parent_instance.run_id,
-        'state': group_state,
-        'start_date': group_start_date,
-        'end_date': group_end_date,
-        'mapped_states': mapped_states,
-        'operator': parent_instance.operator,
-        'execution_date': datetime_to_string(parent_instance.execution_date),
-        'try_number': parent_instance.try_number,
-    }
-
-
 def encode_ti(
-    task_instance: Optional[TaskInstance], is_mapped: Optional[bool], session: Optional[Session]
+    task_instance: Optional[TaskInstance], is_mapped: Optional[bool], session: Session
 ) -> Optional[Dict[str, Any]]:
     if not task_instance:
         return None
 
-    if is_mapped:
-        return get_mapped_summary(task_instance, task_instances=get_mapped_instances(task_instance, session))
-
-    return {
+    summary = {
         'task_id': task_instance.task_id,
         'dag_id': task_instance.dag_id,
         'run_id': task_instance.run_id,
@@ -144,6 +74,66 @@ def encode_ti(
         'try_number': task_instance.try_number,
     }
 
+    def get_mapped_summary(task_instances):
+        priority = [
+            'failed',
+            'upstream_failed',
+            'up_for_retry',
+            'up_for_reschedule',
+            'queued',
+            'scheduled',
+            'deferred',
+            'sensing',
+            'running',
+            'shutdown',
+            'restarting',
+            'removed',
+            'no_status',
+            'success',
+            'skipped',
+        ]
+
+        mapped_states = [ti.state for ti in task_instances]
+
+        group_state = None
+        for state in priority:
+            if state in mapped_states:
+                group_state = state
+                break
+
+        group_start_date = datetime_to_string(
+            min((ti.start_date for ti in task_instances if ti.start_date), default=None)
+        )
+        group_end_date = datetime_to_string(
+            max((ti.end_date for ti in task_instances if ti.end_date), default=None)
+        )
+
+        return {
+            'task_id': task_instance.task_id,
+            'run_id': task_instance.run_id,
+            'state': group_state,
+            'start_date': group_start_date,
+            'end_date': group_end_date,
+            'mapped_states': mapped_states,
+            'operator': task_instance.operator,
+            'execution_date': datetime_to_string(task_instance.execution_date),
+            'try_number': task_instance.try_number,
+        }
+
+    if is_mapped:
+        return get_mapped_summary(
+            session.query(TaskInstance)
+            .filter(
+                TaskInstance.dag_id == task_instance.dag_id,
+                TaskInstance.run_id == task_instance.run_id,
+                TaskInstance.task_id == task_instance.task_id,
+                TaskInstance.map_index >= 0,
+            )
+            .all()
+        )
+
+    return summary
+
 
 def encode_dag_run(dag_run: Optional[models.DagRun]) -> Optional[Dict[str, Any]]:
     if not dag_run:

[airflow] 06/08: switch from drawer to details section

Posted by bb...@apache.org.
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 5cb4defb5ebbe395f7d912561c2ffdf337f5706a
Author: Brent Bovenzi <br...@gmail.com>
AuthorDate: Tue Mar 1 14:00:11 2022 -0500

    switch from drawer to details section
---
 airflow/www/forms.py                               |  4 +-
 airflow/www/static/js/tree/InstanceTooltip.jsx     | 83 ++------------------
 airflow/www/static/js/tree/SidePanel.jsx           | 90 ----------------------
 airflow/www/static/js/tree/StatusBox.jsx           |  6 +-
 airflow/www/static/js/tree/Tree.jsx                | 66 ++++++++--------
 airflow/www/static/js/tree/dagRuns/Bar.jsx         |  6 +-
 airflow/www/static/js/tree/dagRuns/Tooltip.jsx     | 51 +-----------
 airflow/www/static/js/tree/dagRuns/index.jsx       |  6 +-
 airflow/www/static/js/tree/details/Header.jsx      | 85 ++++++++++++++++++++
 airflow/www/static/js/tree/details/content/Dag.jsx | 31 ++++++++
 .../www/static/js/tree/details/content/DagRun.jsx  | 31 ++++++++
 .../js/tree/details/content/TaskInstance.jsx       | 31 ++++++++
 airflow/www/static/js/tree/details/index.jsx       | 48 ++++++++++++
 airflow/www/static/js/tree/renderTaskRows.jsx      | 22 +++---
 14 files changed, 291 insertions(+), 269 deletions(-)

diff --git a/airflow/www/forms.py b/airflow/www/forms.py
index 3a07cbe..3c3d0ac 100644
--- a/airflow/www/forms.py
+++ b/airflow/www/forms.py
@@ -104,13 +104,13 @@ class DateTimeWithNumRunsForm(FlaskForm):
     )
     num_runs = SelectField(
         "Number of runs",
-        default=25,
+        default=10,
         choices=(
             (5, "5"),
+            (10, "10"),
             (25, "25"),
             (50, "50"),
             (100, "100"),
-            (365, "365"),
         ),
     )
 
diff --git a/airflow/www/static/js/tree/InstanceTooltip.jsx b/airflow/www/static/js/tree/InstanceTooltip.jsx
index b0d0584..e5c1117 100644
--- a/airflow/www/static/js/tree/InstanceTooltip.jsx
+++ b/airflow/www/static/js/tree/InstanceTooltip.jsx
@@ -17,33 +17,16 @@
  * 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';
-
-const STATES = [
-  ['success', 0],
-  ['failed', 0],
-  ['upstream_failed', 0],
-  ['up_for_retry', 0],
-  ['up_for_reschedule', 0],
-  ['running', 0],
-  ['deferred', 0],
-  ['sensing', 0],
-  ['queued', 0],
-  ['scheduled', 0],
-  ['skipped', 0],
-  ['no_status', 0],
-];
+import { formatDateTime } from '../datetime_utils';
 
 const InstanceTooltip = ({
   group,
   instance: {
-    duration, operator, startDate, endDate, state, taskId, runId, mappedStates,
+    startDate, state, runId, mappedStates,
   },
 }) => {
   const isGroup = !!group.children;
@@ -93,25 +76,20 @@ 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>
+        <Text as="strong">
+          {isGroup ? 'Overall ' : ''}
+          Status:
+        </Text>
         {' '}
         {state || 'no status'}
       </Text>
-      {isGroup && (
-        <>
-          <br />
-          <Text as="strong">Group Summary</Text>
-          {groupSummary}
-        </>
-      )}
+      {isGroup && groupSummary}
       {group.isMapped && (
         <>
           <br />
@@ -124,56 +102,11 @@ const InstanceTooltip = ({
           {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>
   );
 };
diff --git a/airflow/www/static/js/tree/SidePanel.jsx b/airflow/www/static/js/tree/SidePanel.jsx
deleted file mode 100644
index 88439a0..0000000
--- a/airflow/www/static/js/tree/SidePanel.jsx
+++ /dev/null
@@ -1,90 +0,0 @@
-/*!
- * 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.
- */
-
-/* global moment */
-
-import React from 'react';
-import {
-  chakra,
-  Flex,
-  Text,
-  useDisclosure,
-  IconButton,
-} from '@chakra-ui/react';
-import { MdKeyboardArrowLeft, MdKeyboardArrowRight } from 'react-icons/md';
-
-import { formatDateTime } from '../datetime_utils';
-
-const SidePanel = ({ instance: { runId, taskId, executionDate } }) => {
-  const { isOpen, onOpen, onClose } = useDisclosure();
-  if (!isOpen) {
-    return (
-      <IconButton
-        m={2}
-        icon={<MdKeyboardArrowLeft size={18} />}
-        aria-label="Open Details Panel"
-        onClick={onOpen}
-      />
-    );
-  }
-  let title = '';
-  if (runId && taskId) {
-    title = (
-      <>
-        <chakra.span>Task Instance: </chakra.span>
-        <chakra.b>{taskId}</chakra.b>
-        <chakra.span> at </chakra.span>
-        <chakra.b>{formatDateTime(moment.utc(executionDate))}</chakra.b>
-      </>
-    );
-  } else if (runId) {
-    title = (
-      <>
-        <chakra.span>Dag Run: </chakra.span>
-        <chakra.b>{runId}</chakra.b>
-        <chakra.span> at </chakra.span>
-        <chakra.b>{formatDateTime(moment.utc(executionDate))}</chakra.b>
-      </>
-    );
-  } else {
-    title = (
-      <chakra.span>Dag Details: </chakra.span>
-    );
-  }
-
-  return (
-    <Flex bg="gray.200" maxWidth={isOpen ? '50%' : 0} minWidth={isOpen ? 300 : 0} flexDirection="column" p={3}>
-      <IconButton
-        m={2}
-        icon={<MdKeyboardArrowRight size={18} />}
-        aria-label="Close Details Panel"
-        onClick={onClose}
-      />
-      <Text as="h4">
-        {title}
-      </Text>
-      <Text>
-        {/* eslint-disable-next-line max-len */}
-        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Nunc vel risus commodo viverra maecenas accumsan. Ut porttitor leo a diam sollicitudin tempor id eu. Molestie at elementum eu facilisis sed odio morbi quis commodo. Facilisis leo vel fringilla est ullamcorper eget nulla facilisi etiam. Est sit amet facilisis magna etiam tempor orci eu. Id semper risus in hendrerit gravida rutrum. Ac odio tempor orci dapibus  [...]
-      </Text>
-    </Flex>
-  );
-};
-
-export default SidePanel;
diff --git a/airflow/www/static/js/tree/StatusBox.jsx b/airflow/www/static/js/tree/StatusBox.jsx
index 0953a79..9609d9a 100644
--- a/airflow/www/static/js/tree/StatusBox.jsx
+++ b/airflow/www/static/js/tree/StatusBox.jsx
@@ -30,7 +30,7 @@ import {
 import InstanceTooltip from './InstanceTooltip';
 
 const StatusBox = ({
-  group, instance, containerRef, onSelectInstance, selectedInstance, ...rest
+  group, instance, containerRef, onSelect, selected, ...rest
 }) => {
   const { runId } = instance;
   const { colors } = useTheme();
@@ -38,7 +38,7 @@ const StatusBox = ({
 
   // Fetch the corresponding column element and set its background color when hovering
   const onMouseEnter = () => {
-    if (selectedInstance.runId !== runId) {
+    if (selected.runId !== runId) {
       [...containerRef.current.getElementsByClassName(`js-${runId}`)]
         .forEach((e) => { e.style.backgroundColor = hoverBlue; });
     }
@@ -51,7 +51,7 @@ const StatusBox = ({
   const onClick = (e) => {
     e.stopPropagation();
     onMouseLeave();
-    onSelectInstance(instance);
+    onSelect(instance);
   };
 
   return (
diff --git a/airflow/www/static/js/tree/Tree.jsx b/airflow/www/static/js/tree/Tree.jsx
index 199e373..1f60d03 100644
--- a/airflow/www/static/js/tree/Tree.jsx
+++ b/airflow/www/static/js/tree/Tree.jsx
@@ -34,13 +34,13 @@ import {
 import useTreeData from './useTreeData';
 import renderTaskRows from './renderTaskRows';
 import DagRuns from './dagRuns';
-import SidePanel from './SidePanel';
+import Details from './details';
 
 const Tree = () => {
   const containerRef = useRef();
   const scrollRef = useRef();
   const { data: { groups = {}, dagRuns = [] }, isRefreshOn, onToggleRefresh } = useTreeData();
-  const [selectedInstance, setSelectedInstance] = useState({});
+  const [selected, setSelected] = useState({});
 
   const dagRunIds = dagRuns.map((dr) => dr.runId);
 
@@ -52,46 +52,42 @@ const Tree = () => {
     }
   }, []);
 
-  const { runId, taskId } = selectedInstance;
-  const onSelectInstance = (newInstance) => (
+  const { runId, taskId } = selected;
+  const onSelect = (newInstance) => (
     (newInstance.runId === runId && newInstance.taskId === taskId)
-      ? setSelectedInstance({})
-      : setSelectedInstance(newInstance)
+      ? setSelected({})
+      : setSelected(newInstance)
   );
 
   return (
-    <Box position="relative" ref={containerRef}>
-      <FormControl display="flex" alignItems="center" justifyContent="flex-end" width="100%" mb={2}>
-        {isRefreshOn && <Spinner color="blue.500" speed="1s" mr="4px" />}
-        <FormLabel htmlFor="auto-refresh" mb={0} fontSize="12px" fontWeight="normal">
-          Auto-refresh
-        </FormLabel>
-        <Switch id="auto-refresh" onChange={onToggleRefresh} isChecked={isRefreshOn} size="lg" />
-      </FormControl>
+    <Flex pl="24px" position="relative" flexDirection="row" justifyContent="space-between" ref={containerRef}>
       <Text transform="rotate(-90deg)" position="absolute" left="-6px" top="130px">Runs</Text>
       <Text transform="rotate(-90deg)" position="absolute" left="-6px" top="190px">Tasks</Text>
-      <Box pl="24px" height="100%" onClick={() => setSelectedInstance({})}>
-        <Flex position="relative" flexDirection="row" justifyContent="space-between" overflow="hidden">
-          <Box mr="12px" pb="12px" overflowX="auto" ref={scrollRef} maxWidth="60vw">
-            <Table height={0}>
-              <Thead>
-                <DagRuns
-                  containerRef={containerRef}
-                  selectedInstance={selectedInstance}
-                  onSelectInstance={onSelectInstance}
-                />
-              </Thead>
-              <Tbody>
-                {renderTaskRows({
-                  task: groups, containerRef, onSelectInstance, selectedInstance, dagRunIds,
-                })}
-              </Tbody>
-            </Table>
-          </Box>
-          <SidePanel instance={selectedInstance} />
-        </Flex>
+      <Box mr="12px" pb="12px" overflowX="auto" ref={scrollRef} maxWidth="300px" minWidth="300px" position="relative">
+        <FormControl display="flex" alignItems="center" justifyContent="flex-end" width="100%" mb={2}>
+          {isRefreshOn && <Spinner color="blue.500" speed="1s" mr="4px" />}
+          <FormLabel htmlFor="auto-refresh" mb={0} fontSize="12px" fontWeight="normal">
+            Auto-refresh
+          </FormLabel>
+          <Switch id="auto-refresh" onChange={onToggleRefresh} isChecked={isRefreshOn} size="lg" />
+        </FormControl>
+        <Table height={0}>
+          <Thead>
+            <DagRuns
+              containerRef={containerRef}
+              selected={selected}
+              onSelect={onSelect}
+            />
+          </Thead>
+          <Tbody>
+            {renderTaskRows({
+              task: groups, containerRef, onSelect, selected, dagRunIds,
+            })}
+          </Tbody>
+        </Table>
       </Box>
-    </Box>
+      <Details selected={selected} onSelect={onSelect} />
+    </Flex>
   );
 };
 
diff --git a/airflow/www/static/js/tree/dagRuns/Bar.jsx b/airflow/www/static/js/tree/dagRuns/Bar.jsx
index c64abdd..1c8dd6b 100644
--- a/airflow/www/static/js/tree/dagRuns/Bar.jsx
+++ b/airflow/www/static/js/tree/dagRuns/Bar.jsx
@@ -35,7 +35,7 @@ import DagRunTooltip from './Tooltip';
 const BAR_HEIGHT = 100;
 
 const DagRunBar = ({
-  run, max, index, totalRuns, containerRef, selectedInstance, onSelectInstance,
+  run, max, index, totalRuns, containerRef, selected, onSelect,
 }) => {
   const { colors } = useTheme();
   const hoverBlue = `${colors.blue[100]}50`;
@@ -44,7 +44,7 @@ const DagRunBar = ({
     const table = containerRef.current.getElementsByTagName('tbody')[0];
     highlightHeight = table.offsetHeight + BAR_HEIGHT;
   }
-  const isSelected = run.runId === selectedInstance.runId;
+  const isSelected = run.runId === selected.runId;
   return (
     <Box position="relative">
       <Flex
@@ -59,7 +59,7 @@ const DagRunBar = ({
         zIndex={1}
         onClick={(e) => {
           e.stopPropagation();
-          onSelectInstance(run);
+          onSelect(run);
         }}
         position="relative"
         data-peer
diff --git a/airflow/www/static/js/tree/dagRuns/Tooltip.jsx b/airflow/www/static/js/tree/dagRuns/Tooltip.jsx
index 4e42cde..70b7f6a 100644
--- a/airflow/www/static/js/tree/dagRuns/Tooltip.jsx
+++ b/airflow/www/static/js/tree/dagRuns/Tooltip.jsx
@@ -17,8 +17,6 @@
  * under the License.
  */
 
-/* global moment */
-
 import React from 'react';
 import { Box, Text } from '@chakra-ui/react';
 import { MdPlayArrow } from 'react-icons/md';
@@ -27,20 +25,19 @@ import { formatDateTime, formatDuration } from '../../datetime_utils';
 
 const DagRunTooltip = ({
   dagRun: {
-    state, runId, duration, dataIntervalStart, dataIntervalEnd, startDate, endDate, runType,
+    state, duration, dataIntervalEnd, runType,
   },
 }) => (
-  <Box fontSize="12px" py="4px">
+  <Box fontSize="12px" py="2px">
     <Text>
       <Text as="strong">Status:</Text>
       {' '}
       {state || 'no status'}
     </Text>
-    <br />
     <Text whiteSpace="nowrap">
-      Run Id:
+      Run:
       {' '}
-      {runId}
+      {formatDateTime(dataIntervalEnd)}
     </Text>
     <Text>
       Run Type:
@@ -53,46 +50,6 @@ const DagRunTooltip = ({
       {' '}
       {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>
 );
 
diff --git a/airflow/www/static/js/tree/dagRuns/index.jsx b/airflow/www/static/js/tree/dagRuns/index.jsx
index 7459634..7ff4e39 100644
--- a/airflow/www/static/js/tree/dagRuns/index.jsx
+++ b/airflow/www/static/js/tree/dagRuns/index.jsx
@@ -36,7 +36,7 @@ const DurationTick = ({ children, ...rest }) => (
   </Text>
 );
 
-const DagRuns = ({ containerRef, selectedInstance, onSelectInstance }) => {
+const DagRuns = ({ containerRef, selected, onSelect }) => {
   const { data: { dagRuns = [] } } = useTreeData();
   const durations = [];
   const runs = dagRuns.map((dagRun) => {
@@ -97,8 +97,8 @@ const DagRuns = ({ containerRef, selectedInstance, onSelectInstance }) => {
               index={i}
               totalRuns={runs.length}
               containerRef={containerRef}
-              selectedInstance={selectedInstance}
-              onSelectInstance={onSelectInstance}
+              selected={selected}
+              onSelect={onSelect}
             />
           ))}
         </Flex>
diff --git a/airflow/www/static/js/tree/details/Header.jsx b/airflow/www/static/js/tree/details/Header.jsx
new file mode 100644
index 0000000..b9d3086
--- /dev/null
+++ b/airflow/www/static/js/tree/details/Header.jsx
@@ -0,0 +1,85 @@
+/*!
+ * 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 {
+  Breadcrumb,
+  BreadcrumbItem,
+  BreadcrumbLink,
+  Box,
+  Heading,
+} from '@chakra-ui/react';
+import { MdPlayArrow } from 'react-icons/md';
+
+import useTreeData from '../useTreeData';
+import { formatDateTime } from '../../datetime_utils';
+import getMetaValue from '../../meta_value';
+
+const dagId = getMetaValue('dag_id');
+
+const LabelValue = ({ label, value }) => (
+  <Box position="relative">
+    <Heading as="h5" size="sm" color="gray.300" position="absolute" top="-12px">{label}</Heading>
+    <Heading as="h3" size="md">{value}</Heading>
+  </Box>
+);
+
+const Header = ({
+  selected: { taskId, runId },
+  onSelect,
+}) => {
+  const { data: { dagRuns = [] } } = useTreeData();
+  const dagRun = dagRuns.find((r) => r.runId === runId);
+  // console.log(dagRun);
+  let runLabel = dagRun ? formatDateTime(dagRun.dataIntervalEnd) : '';
+  if (dagRun && dagRun.runType === 'manual') {
+    runLabel = (
+      <>
+        <MdPlayArrow style={{ display: 'inline' }} />
+        {runLabel}
+      </>
+    );
+  }
+
+  return (
+    <Breadcrumb>
+      <BreadcrumbItem isCurrentPage={!runId && !taskId}>
+        <BreadcrumbLink onClick={() => onSelect({})}>
+          <LabelValue label="DAG" value={dagId} />
+        </BreadcrumbLink>
+      </BreadcrumbItem>
+      {runId && (
+        <BreadcrumbItem isCurrentPage={runId && !taskId}>
+          <BreadcrumbLink onClick={() => onSelect({ runId })}>
+            <LabelValue label="Run" value={runLabel} />
+          </BreadcrumbLink>
+        </BreadcrumbItem>
+      )}
+      {taskId && (
+        <BreadcrumbItem isCurrentPage>
+          <BreadcrumbLink>
+            <LabelValue label="Task" value={taskId} />
+          </BreadcrumbLink>
+        </BreadcrumbItem>
+      )}
+    </Breadcrumb>
+  );
+};
+
+export default Header;
diff --git a/airflow/www/static/js/tree/details/content/Dag.jsx b/airflow/www/static/js/tree/details/content/Dag.jsx
new file mode 100644
index 0000000..be460ba
--- /dev/null
+++ b/airflow/www/static/js/tree/details/content/Dag.jsx
@@ -0,0 +1,31 @@
+/*!
+ * 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 {
+  Text,
+} from '@chakra-ui/react';
+
+const Dag = () => (
+  <>
+    <Text>dag details</Text>
+  </>
+);
+
+export default Dag;
diff --git a/airflow/www/static/js/tree/details/content/DagRun.jsx b/airflow/www/static/js/tree/details/content/DagRun.jsx
new file mode 100644
index 0000000..58e4b92
--- /dev/null
+++ b/airflow/www/static/js/tree/details/content/DagRun.jsx
@@ -0,0 +1,31 @@
+/*!
+ * 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 {
+  Text,
+} from '@chakra-ui/react';
+
+const DagRun = () => (
+  <>
+    <Text>dag run details</Text>
+  </>
+);
+
+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
new file mode 100644
index 0000000..4ab46e5
--- /dev/null
+++ b/airflow/www/static/js/tree/details/content/TaskInstance.jsx
@@ -0,0 +1,31 @@
+/*!
+ * 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 {
+  Text,
+} from '@chakra-ui/react';
+
+const TaskInstance = () => (
+  <>
+    <Text>task instance details</Text>
+  </>
+);
+
+export default TaskInstance;
diff --git a/airflow/www/static/js/tree/details/index.jsx b/airflow/www/static/js/tree/details/index.jsx
new file mode 100644
index 0000000..b8f960e
--- /dev/null
+++ b/airflow/www/static/js/tree/details/index.jsx
@@ -0,0 +1,48 @@
+/*!
+ * 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 {
+  Flex,
+  Box,
+  Divider,
+} from '@chakra-ui/react';
+
+import Header from './Header';
+import TaskInstanceContent from './content/TaskInstance';
+import DagRunContent from './content/DagRun';
+import DagContent from './content/Dag';
+
+const Details = ({
+  selected,
+  onSelect,
+}) => (
+  <Flex borderLeftWidth="1px" flexDirection="column" p={3} flexGrow={1}>
+    <Header selected={selected} onSelect={onSelect} />
+    <Divider my={2} />
+    <Box>
+      {/* TODO: get full instance data from the API */}
+      {!selected.runId && !selected.taskId && <DagContent />}
+      {selected.runId && !selected.taskId && <DagRunContent />}
+      {selected.taskId && <TaskInstanceContent instance={selected} />}
+    </Box>
+  </Flex>
+);
+
+export default Details;
diff --git a/airflow/www/static/js/tree/renderTaskRows.jsx b/airflow/www/static/js/tree/renderTaskRows.jsx
index 7440774..5e8234e 100644
--- a/airflow/www/static/js/tree/renderTaskRows.jsx
+++ b/airflow/www/static/js/tree/renderTaskRows.jsx
@@ -40,7 +40,7 @@ import { getMetaValue } from '../utils';
 const dagId = getMetaValue('dag_id');
 
 const renderTaskRows = ({
-  task, containerRef, level = 0, isParentOpen, onSelectInstance, selectedInstance, dagRunIds
+  task, containerRef, level = 0, isParentOpen, onSelect, selected, dagRunIds,
 }) => task.children.map((t) => (
   <Row
     key={t.id}
@@ -49,8 +49,8 @@ const renderTaskRows = ({
     containerRef={containerRef}
     prevTaskId={task.id}
     isParentOpen={isParentOpen}
-    onSelectInstance={onSelectInstance}
-    selectedInstance={selectedInstance}
+    onSelect={onSelect}
+    selected={selected}
     dagRunIds={dagRunIds}
   />
 ));
@@ -85,7 +85,7 @@ const TaskName = ({
 );
 
 const TaskInstances = ({
-  task, containerRef, dagRunIds, onSelectInstance, selectedInstance,
+  task, containerRef, dagRunIds, onSelect, selected,
 }) => (
   <Flex justifyContent="flex-end">
     {dagRunIds.map((runId) => {
@@ -99,8 +99,8 @@ const TaskInstances = ({
             instance={instance}
             containerRef={containerRef}
             group={task}
-            onSelectInstance={onSelectInstance}
-            selectedInstance={selectedInstance}
+            onSelect={onSelect}
+            selected={selected}
           />
         )
         : <Box key={key} width="16px" data-testid="blank-task" />;
@@ -115,15 +115,15 @@ const Row = (props) => {
     level,
     prevTaskId,
     isParentOpen = true,
-    onSelectInstance,
-    selectedInstance,
+    onSelect,
+    selected,
     dagRunIds,
   } = props;
   // const { data: { dagRuns = [] } } = useTreeData();
   const { colors } = useTheme();
   const hoverBlue = `${colors.blue[100]}50`;
   const isGroup = !!task.children;
-  const isSelected = selectedInstance.taskId === task.id;
+  const isSelected = selected.taskId === task.id;
 
   const taskName = prevTaskId ? task.id.replace(`${prevTaskId}.`, '') : task.id;
 
@@ -186,8 +186,8 @@ const Row = (props) => {
               dagRunIds={dagRunIds}
               task={task}
               containerRef={containerRef}
-              onSelectInstance={onSelectInstance}
-              selectedInstance={selectedInstance}
+              onSelect={onSelect}
+              selected={selected}
             />
           </Collapse>
         </Td>

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

Posted by bb...@apache.org.
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>

[airflow] 08/08: use API

Posted by bb...@apache.org.
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 2f8e4446324ecc7ac40ef5427b4638ecc8ea1d36
Author: Brent Bovenzi <br...@gmail.com>
AuthorDate: Tue Mar 1 19:44:16 2022 -0500

    use API
---
 airflow/www/package.json                           |   2 +
 airflow/www/static/js/tree/StatusBox.jsx           |   6 +-
 airflow/www/static/js/tree/Tree.jsx                |  16 ++--
 .../tree/{details/content/Dag.jsx => api/index.js} |  21 +++--
 .../{details/content/Dag.jsx => api/useDag.js}     |  19 ++--
 .../{details/content/Dag.jsx => api/useTasks.js}   |  19 ++--
 airflow/www/static/js/tree/dagRuns/Bar.jsx         |   2 +-
 airflow/www/static/js/tree/details/Header.jsx      |   5 +-
 airflow/www/static/js/tree/details/content/Dag.jsx |  36 ++++++-
 .../js/tree/details/content/TaskInstance.jsx       | 100 ++++++++++----------
 airflow/www/static/js/tree/details/index.jsx       |  34 ++++---
 airflow/www/static/js/tree/index.jsx               |  13 ++-
 airflow/www/yarn.lock                              | 104 +++++++++++++++++++--
 13 files changed, 257 insertions(+), 120 deletions(-)

diff --git a/airflow/www/package.json b/airflow/www/package.json
index 6d52987..717d5b1 100644
--- a/airflow/www/package.json
+++ b/airflow/www/package.json
@@ -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",
@@ -92,6 +93,7 @@
     "react": "^17.0.2",
     "react-dom": "^17.0.2",
     "react-icons": "^4.2.0",
+    "react-query": "^3.34.16",
     "redoc": "^2.0.0-rc.63",
     "url-search-params-polyfill": "^8.1.0"
   },
diff --git a/airflow/www/static/js/tree/StatusBox.jsx b/airflow/www/static/js/tree/StatusBox.jsx
index 9609d9a..62762c5 100644
--- a/airflow/www/static/js/tree/StatusBox.jsx
+++ b/airflow/www/static/js/tree/StatusBox.jsx
@@ -32,7 +32,7 @@ import InstanceTooltip from './InstanceTooltip';
 const StatusBox = ({
   group, instance, containerRef, onSelect, selected, ...rest
 }) => {
-  const { runId } = instance;
+  const { runId, taskId } = instance;
   const { colors } = useTheme();
   const hoverBlue = `${colors.blue[100]}50`;
 
@@ -51,7 +51,9 @@ const StatusBox = ({
   const onClick = (e) => {
     e.stopPropagation();
     onMouseLeave();
-    onSelect(instance);
+    onSelect({
+      taskId, runId, instance, task: group,
+    });
   };
 
   return (
diff --git a/airflow/www/static/js/tree/Tree.jsx b/airflow/www/static/js/tree/Tree.jsx
index 1f60d03..aeeaeb5 100644
--- a/airflow/www/static/js/tree/Tree.jsx
+++ b/airflow/www/static/js/tree/Tree.jsx
@@ -63,14 +63,14 @@ const Tree = () => {
     <Flex pl="24px" position="relative" flexDirection="row" justifyContent="space-between" ref={containerRef}>
       <Text transform="rotate(-90deg)" position="absolute" left="-6px" top="130px">Runs</Text>
       <Text transform="rotate(-90deg)" position="absolute" left="-6px" top="190px">Tasks</Text>
-      <Box mr="12px" pb="12px" overflowX="auto" ref={scrollRef} maxWidth="300px" minWidth="300px" position="relative">
-        <FormControl display="flex" alignItems="center" justifyContent="flex-end" width="100%" mb={2}>
-          {isRefreshOn && <Spinner color="blue.500" speed="1s" mr="4px" />}
-          <FormLabel htmlFor="auto-refresh" mb={0} fontSize="12px" fontWeight="normal">
-            Auto-refresh
-          </FormLabel>
-          <Switch id="auto-refresh" onChange={onToggleRefresh} isChecked={isRefreshOn} size="lg" />
-        </FormControl>
+      <FormControl display="flex" position="absolute" left="220px">
+        {isRefreshOn && <Spinner color="blue.500" speed="1s" mr="4px" />}
+        <FormLabel htmlFor="auto-refresh" mb={0} fontSize="12px" fontWeight="normal">
+          Auto-refresh
+        </FormLabel>
+        <Switch id="auto-refresh" onChange={onToggleRefresh} isChecked={isRefreshOn} size="lg" />
+      </FormControl>
+      <Box mr="12px" pb="12px" overflowX="auto" ref={scrollRef} maxWidth="300px" minWidth="300px" position="relative" mt="24px">
         <Table height={0}>
           <Thead>
             <DagRuns
diff --git a/airflow/www/static/js/tree/details/content/Dag.jsx b/airflow/www/static/js/tree/api/index.js
similarity index 72%
copy from airflow/www/static/js/tree/details/content/Dag.jsx
copy to airflow/www/static/js/tree/api/index.js
index be460ba..58edd88 100644
--- a/airflow/www/static/js/tree/details/content/Dag.jsx
+++ b/airflow/www/static/js/tree/api/index.js
@@ -17,15 +17,18 @@
  * under the License.
  */
 
-import React from 'react';
-import {
-  Text,
-} from '@chakra-ui/react';
+import axios from 'axios';
+import camelcaseKeys from 'camelcase-keys';
 
-const Dag = () => (
-  <>
-    <Text>dag details</Text>
-  </>
+import useDag from './useDag';
+import useTasks from './useTasks';
+
+axios.defaults.baseURL = '/api/v1';
+axios.interceptors.response.use(
+  (res) => (res.data ? camelcaseKeys(res.data, { deep: true }) : res),
 );
 
-export default Dag;
+export {
+  useDag,
+  useTasks,
+};
diff --git a/airflow/www/static/js/tree/details/content/Dag.jsx b/airflow/www/static/js/tree/api/useDag.js
similarity index 80%
copy from airflow/www/static/js/tree/details/content/Dag.jsx
copy to airflow/www/static/js/tree/api/useDag.js
index be460ba..6c19ee4 100644
--- a/airflow/www/static/js/tree/details/content/Dag.jsx
+++ b/airflow/www/static/js/tree/api/useDag.js
@@ -17,15 +17,12 @@
  * under the License.
  */
 
-import React from 'react';
-import {
-  Text,
-} from '@chakra-ui/react';
+import axios from 'axios';
+import { useQuery } from 'react-query';
 
-const Dag = () => (
-  <>
-    <Text>dag details</Text>
-  </>
-);
-
-export default Dag;
+export default function useDag(dagId) {
+  return useQuery(
+    ['dag', dagId],
+    () => axios.get(`/dags/${dagId}`),
+  );
+}
diff --git a/airflow/www/static/js/tree/details/content/Dag.jsx b/airflow/www/static/js/tree/api/useTasks.js
similarity index 80%
copy from airflow/www/static/js/tree/details/content/Dag.jsx
copy to airflow/www/static/js/tree/api/useTasks.js
index be460ba..3dd11e30 100644
--- a/airflow/www/static/js/tree/details/content/Dag.jsx
+++ b/airflow/www/static/js/tree/api/useTasks.js
@@ -17,15 +17,12 @@
  * under the License.
  */
 
-import React from 'react';
-import {
-  Text,
-} from '@chakra-ui/react';
+import axios from 'axios';
+import { useQuery } from 'react-query';
 
-const Dag = () => (
-  <>
-    <Text>dag details</Text>
-  </>
-);
-
-export default Dag;
+export default function useTasks(dagId) {
+  return useQuery(
+    ['tasks', dagId],
+    () => axios.get(`/dags/${dagId}/tasks`),
+  );
+}
diff --git a/airflow/www/static/js/tree/dagRuns/Bar.jsx b/airflow/www/static/js/tree/dagRuns/Bar.jsx
index 1c8dd6b..94c84e7 100644
--- a/airflow/www/static/js/tree/dagRuns/Bar.jsx
+++ b/airflow/www/static/js/tree/dagRuns/Bar.jsx
@@ -59,7 +59,7 @@ const DagRunBar = ({
         zIndex={1}
         onClick={(e) => {
           e.stopPropagation();
-          onSelect(run);
+          onSelect({ runId: run.runId, dagRun: run });
         }}
         position="relative"
         data-peer
diff --git a/airflow/www/static/js/tree/details/Header.jsx b/airflow/www/static/js/tree/details/Header.jsx
index b9d3086..c362606 100644
--- a/airflow/www/static/js/tree/details/Header.jsx
+++ b/airflow/www/static/js/tree/details/Header.jsx
@@ -27,9 +27,8 @@ import {
 } from '@chakra-ui/react';
 import { MdPlayArrow } from 'react-icons/md';
 
-import useTreeData from '../useTreeData';
 import { formatDateTime } from '../../datetime_utils';
-import getMetaValue from '../../meta_value';
+import { getMetaValue } from '../../utils';
 
 const dagId = getMetaValue('dag_id');
 
@@ -43,8 +42,8 @@ const LabelValue = ({ label, value }) => (
 const Header = ({
   selected: { taskId, runId },
   onSelect,
+  dagRuns,
 }) => {
-  const { data: { dagRuns = [] } } = useTreeData();
   const dagRun = dagRuns.find((r) => r.runId === runId);
   // console.log(dagRun);
   let runLabel = dagRun ? formatDateTime(dagRun.dataIntervalEnd) : '';
diff --git a/airflow/www/static/js/tree/details/content/Dag.jsx b/airflow/www/static/js/tree/details/content/Dag.jsx
index be460ba..e71d9c2 100644
--- a/airflow/www/static/js/tree/details/content/Dag.jsx
+++ b/airflow/www/static/js/tree/details/content/Dag.jsx
@@ -20,12 +20,38 @@
 import React from 'react';
 import {
   Text,
+  Tag,
+  Code,
+  Flex,
+  HStack,
 } from '@chakra-ui/react';
 
-const Dag = () => (
-  <>
-    <Text>dag details</Text>
-  </>
-);
+import { getMetaValue } from '../../../utils';
+import { useDag } from '../../api';
+
+const dagId = getMetaValue('dag_id');
+
+const Dag = () => {
+  const { data: dag } = useDag(dagId);
+  if (!dag) return null;
+  const {
+    description, tags, fileloc, owners,
+  } = dag;
+  return (
+    <>
+      {description && <Text>{description}</Text>}
+      <HStack>{tags.map((tag) => <Tag key={tag.name} size="lg">{tag.name}</Tag>)}</HStack>
+      <Text>
+        Relative File Location:
+        {' '}
+        <Code colorScheme="blackAlpha">{fileloc}</Code>
+      </Text>
+      <Flex>
+        <Text mr={2}>Owner:</Text>
+        {owners.map((o) => <Text key={o}>{o}</Text>)}
+      </Flex>
+    </>
+  );
+};
 
 export default Dag;
diff --git a/airflow/www/static/js/tree/details/content/TaskInstance.jsx b/airflow/www/static/js/tree/details/content/TaskInstance.jsx
index bc60737..0c0a21e 100644
--- a/airflow/www/static/js/tree/details/content/TaskInstance.jsx
+++ b/airflow/www/static/js/tree/details/content/TaskInstance.jsx
@@ -24,68 +24,70 @@ import {
   Text,
   Box,
 } from '@chakra-ui/react';
+import { finalStatesMap } from '../../../utils';
 
 import { formatDateTime, getDuration, formatDuration } from '../../../datetime_utils';
 
 const TaskInstance = ({
   instance: {
-    duration, operator, startDate, endDate, state, taskId, runId, // mappedStates,
+    duration, operator, startDate, endDate, state, taskId, runId, mappedStates,
   },
+  task,
 }) => {
-  const isGroup = false; // !!group.children;
+  const isGroup = !!task.children;
   const groupSummary = [];
-  // const mapSummary = [];
+  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 (isGroup) {
+    const numMap = finalStatesMap();
+    task.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>,
-  //       );
-  //     }
-  //   });
-  // }
+  if (task.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>
-      )} */}
+      {task.tooltip && (
+        <Text>{task.tooltip}</Text>
+      )}
       <Text>
         <Text as="strong">Status:</Text>
         {' '}
@@ -98,7 +100,7 @@ const TaskInstance = ({
           {groupSummary}
         </>
       )}
-      {/* {group.isMapped && (
+      {task.isMapped && (
         <>
           <br />
           <Text as="strong">
@@ -109,7 +111,7 @@ const TaskInstance = ({
           </Text>
           {mapSummary}
         </>
-      )} */}
+      )}
       <br />
       <Text>
         {taskIdTitle}
diff --git a/airflow/www/static/js/tree/details/index.jsx b/airflow/www/static/js/tree/details/index.jsx
index 31610a7..ee3b044 100644
--- a/airflow/www/static/js/tree/details/index.jsx
+++ b/airflow/www/static/js/tree/details/index.jsx
@@ -28,21 +28,31 @@ import Header from './Header';
 import TaskInstanceContent from './content/TaskInstance';
 import DagRunContent from './content/DagRun';
 import DagContent from './content/Dag';
+import useTreeData from '../useTreeData';
 
 const Details = ({
   selected,
   onSelect,
-}) => (
-  <Flex borderLeftWidth="1px" flexDirection="column" p={3} flexGrow={1}>
-    <Header selected={selected} onSelect={onSelect} />
-    <Divider my={2} />
-    <Box>
-      {/* TODO: get full instance data from the API */}
-      {!selected.runId && !selected.taskId && <DagContent />}
-      {selected.runId && !selected.taskId && <DagRunContent dagRun={selected} />}
-      {selected.taskId && <TaskInstanceContent instance={selected} />}
-    </Box>
-  </Flex>
-);
+}) => {
+  const { data: { dagRuns = [] } } = useTreeData();
+  console.log(selected);
+  return (
+    <Flex borderLeftWidth="1px" flexDirection="column" p={3} flexGrow={1}>
+      <Header selected={selected} onSelect={onSelect} dagRuns={dagRuns} />
+      <Divider my={2} />
+      <Box>
+        {/* TODO: get full instance data from the API */}
+        {!selected.runId && !selected.taskId && <DagContent />}
+        {selected.runId && !selected.taskId && <DagRunContent dagRun={selected.dagRun} />}
+        {selected.taskId && (
+        <TaskInstanceContent
+          instance={selected.instance}
+          task={selected.task}
+        />
+        )}
+      </Box>
+    </Flex>
+  );
+};
 
 export default Details;
diff --git a/airflow/www/static/js/tree/index.jsx b/airflow/www/static/js/tree/index.jsx
index 454f4f0..4eea821 100644
--- a/airflow/www/static/js/tree/index.jsx
+++ b/airflow/www/static/js/tree/index.jsx
@@ -24,6 +24,7 @@ import ReactDOM from 'react-dom';
 import { ChakraProvider } from '@chakra-ui/react';
 import { CacheProvider } from '@emotion/react';
 import createCache from '@emotion/cache';
+import { QueryClient, QueryClientProvider } from 'react-query';
 import Tree from './Tree';
 
 // create shadowRoot
@@ -36,12 +37,22 @@ const myCache = createCache({
 const mainElement = document.getElementById('react-container');
 shadowRoot.appendChild(mainElement);
 
+const queryClient = new QueryClient({
+  defaultOptions: {
+    queries: {
+      refetchOnWindowFocus: false,
+    },
+  },
+});
+
 function App() {
   return (
     <React.StrictMode>
       <CacheProvider value={myCache}>
         <ChakraProvider>
-          <Tree />
+          <QueryClientProvider client={queryClient}>
+            <Tree />
+          </QueryClientProvider>
         </ChakraProvider>
       </CacheProvider>
     </React.StrictMode>
diff --git a/airflow/www/yarn.lock b/airflow/www/yarn.lock
index 79c0165..0e9a1ee 100644
--- a/airflow/www/yarn.lock
+++ b/airflow/www/yarn.lock
@@ -1263,7 +1263,7 @@
     core-js-pure "^3.16.0"
     regenerator-runtime "^0.13.4"
 
-"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.13":
+"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.13", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2":
   version "7.17.2"
   resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941"
   integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==
@@ -3254,6 +3254,13 @@ axe-core@^4.0.2:
   resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.3.tgz#b55cd8e8ddf659fe89b064680e1c6a4dceab0325"
   integrity sha512-/lqqLAmuIPi79WYfRpy2i8z+x+vxU3zX2uAm0gs1q52qTuKwolOj1P8XbufpXcsydrpKx2yGn2wzAnxCMV86QA==
 
+axios@^0.26.0:
+  version "0.26.0"
+  resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.0.tgz#9a318f1c69ec108f8cd5f3c3d390366635e13928"
+  integrity sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==
+  dependencies:
+    follow-redirects "^1.14.8"
+
 axobject-query@^2.2.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
@@ -3594,6 +3601,11 @@ base@^0.11.1:
     mixin-deep "^1.2.0"
     pascalcase "^0.1.1"
 
+big-integer@^1.6.16:
+  version "1.6.51"
+  resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686"
+  integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==
+
 big.js@^3.1.3:
   version "3.2.0"
   resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
@@ -3682,6 +3694,20 @@ braces@^3.0.1, braces@~3.0.2:
   dependencies:
     fill-range "^7.0.1"
 
+broadcast-channel@^3.4.1:
+  version "3.7.0"
+  resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937"
+  integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==
+  dependencies:
+    "@babel/runtime" "^7.7.2"
+    detect-node "^2.1.0"
+    js-sha3 "0.8.0"
+    microseconds "0.2.0"
+    nano-time "1.0.0"
+    oblivious-set "1.0.0"
+    rimraf "3.0.2"
+    unload "2.2.0"
+
 brorand@^1.0.1, brorand@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
@@ -5082,6 +5108,11 @@ detect-node-es@^1.1.0:
   resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493"
   integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==
 
+detect-node@^2.0.4, detect-node@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
+  integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
+
 diff-sequences@^27.0.6:
   version "27.0.6"
   resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.0.6.tgz#3305cb2e55a033924054695cc66019fd7f8e5723"
@@ -5994,6 +6025,11 @@ focus-lock@^0.9.1:
   dependencies:
     tslib "^2.0.3"
 
+follow-redirects@^1.14.8:
+  version "1.14.9"
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7"
+  integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==
+
 for-in@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@@ -7621,6 +7657,11 @@ js-levenshtein@^1.1.6:
   resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d"
   integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==
 
+js-sha3@0.8.0:
+  version "0.8.0"
+  resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
+  integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==
+
 "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -8072,6 +8113,14 @@ marked@^4.0.10:
   resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.12.tgz#2262a4e6fd1afd2f13557726238b69a48b982f7d"
   integrity sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ==
 
+match-sorter@^6.0.2:
+  version "6.3.1"
+  resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.1.tgz#98cc37fda756093424ddf3cbc62bfe9c75b92bda"
+  integrity sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==
+  dependencies:
+    "@babel/runtime" "^7.12.5"
+    remove-accents "0.4.2"
+
 mathml-tag-names@^2.1.3:
   version "2.1.3"
   resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3"
@@ -8198,6 +8247,11 @@ micromatch@^4.0.2, micromatch@^4.0.4:
     braces "^3.0.1"
     picomatch "^2.2.3"
 
+microseconds@0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39"
+  integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==
+
 miller-rabin@^4.0.0:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
@@ -8422,6 +8476,13 @@ nan@^2.12.1:
   resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
   integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
 
+nano-time@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef"
+  integrity sha1-sFVPaa2J4i0JB/ehKwmTpdlhN+8=
+  dependencies:
+    big-integer "^1.6.16"
+
 nanoid@^3.1.23:
   version "3.1.23"
   resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81"
@@ -8756,6 +8817,11 @@ object.values@^1.1.4:
     define-properties "^1.1.3"
     es-abstract "^1.18.2"
 
+oblivious-set@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566"
+  integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==
+
 once@^1.3.0, once@^1.3.1, once@^1.4.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
@@ -9735,6 +9801,15 @@ react-is@^17.0.1:
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
   integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
 
+react-query@^3.34.16:
+  version "3.34.16"
+  resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.34.16.tgz#279ea180bcaeaec49c7864b29d1711ee9f152594"
+  integrity sha512-7FvBvjgEM4YQ8nPfmAr+lJfbW95uyW/TVjFoi2GwCkF33/S8ajx45tuPHPFGWs4qYwPy1mzwxD4IQfpUDrefNQ==
+  dependencies:
+    "@babel/runtime" "^7.5.5"
+    broadcast-channel "^3.4.1"
+    match-sorter "^6.0.2"
+
 react-remove-scroll-bar@^2.1.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.2.0.tgz#d4d545a7df024f75d67e151499a6ab5ac97c8cdd"
@@ -10007,6 +10082,11 @@ remark@^13.0.0:
     remark-stringify "^9.0.0"
     unified "^9.1.0"
 
+remove-accents@0.4.2:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5"
+  integrity sha1-CkPTqq4egNuRngeuJUsoXZ4ce7U=
+
 remove-trailing-separator@^1.0.1:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
@@ -10127,6 +10207,13 @@ rgba-regex@^1.0.0:
   resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3"
   integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=
 
+rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+  integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
+  dependencies:
+    glob "^7.1.3"
+
 rimraf@^2.5.4, rimraf@^2.6.3:
   version "2.7.1"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
@@ -10134,13 +10221,6 @@ rimraf@^2.5.4, rimraf@^2.6.3:
   dependencies:
     glob "^7.1.3"
 
-rimraf@^3.0.0, rimraf@^3.0.2:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
-  integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
-  dependencies:
-    glob "^7.1.3"
-
 ripemd160@^2.0.0, ripemd160@^2.0.1:
   version "2.0.2"
   resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
@@ -11365,6 +11445,14 @@ universalify@^0.1.0, universalify@^0.1.2:
   resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
   integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
 
+unload@2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7"
+  integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==
+  dependencies:
+    "@babel/runtime" "^7.6.2"
+    detect-node "^2.0.4"
+
 unset-value@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"

[airflow] 02/08: basic slide drawer

Posted by bb...@apache.org.
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 780d6a22ebf73f153d58240ba3247ebbf050c163
Author: Brent Bovenzi <br...@gmail.com>
AuthorDate: Wed Feb 16 13:57:33 2022 -0500

    basic slide drawer
---
 airflow/www/static/js/tree/SidePanel.jsx      | 49 +++++++++++++++++
 airflow/www/static/js/tree/StatusBox.jsx      | 75 +++++++++++++++------------
 airflow/www/static/js/tree/Tree.jsx           | 25 ++++++---
 airflow/www/static/js/tree/renderTaskRows.jsx | 19 +++++--
 4 files changed, 125 insertions(+), 43 deletions(-)

diff --git a/airflow/www/static/js/tree/SidePanel.jsx b/airflow/www/static/js/tree/SidePanel.jsx
new file mode 100644
index 0000000..3515f1c
--- /dev/null
+++ b/airflow/www/static/js/tree/SidePanel.jsx
@@ -0,0 +1,49 @@
+/*!
+ * 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.
+ */
+
+/* global moment */
+
+import React from 'react';
+import {
+  Box,
+  chakra,
+  Flex,
+  Text,
+} from '@chakra-ui/react';
+
+import { formatDateTime } from '../datetime_utils';
+
+const SidePanel = ({ instance: { runId, taskId, executionDate }, isOpen }) => (
+  <Box bg="gray.200" maxWidth={isOpen ? 300 : 0} minWidth={isOpen ? 300 : 0} transition="all 0.5s" position="relative" overflow="hidden">
+    <Flex right={isOpen ? 0 : -300} top={0} transition="right 0.5s, max-width 0.5s" width={300} flexDirection="column" m={2}>
+      <Text as="h4">
+        <chakra.span>Task Instance: </chakra.span>
+        <chakra.b>{taskId}</chakra.b>
+        <chakra.span> at </chakra.span>
+        <chakra.b>{formatDateTime(moment.utc(executionDate))}</chakra.b>
+      </Text>
+      <Text>
+        {/* eslint-disable-next-line max-len */}
+        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Nunc vel risus commodo viverra maecenas accumsan. Ut porttitor leo a diam sollicitudin tempor id eu. Molestie at elementum eu facilisis sed odio morbi quis commodo. Facilisis leo vel fringilla est ullamcorper eget nulla facilisi etiam. Est sit amet facilisis magna etiam tempor orci eu. Id semper risus in hendrerit gravida rutrum. Ac odio tempor orci dapibus  [...]
+      </Text>
+    </Flex>
+  </Box>
+);
+
+export default SidePanel;
diff --git a/airflow/www/static/js/tree/StatusBox.jsx b/airflow/www/static/js/tree/StatusBox.jsx
index c22f0b2..dce0fda 100644
--- a/airflow/www/static/js/tree/StatusBox.jsx
+++ b/airflow/www/static/js/tree/StatusBox.jsx
@@ -30,12 +30,21 @@ import { callModal } from '../dag';
 import InstanceTooltip from './InstanceTooltip';
 
 const StatusBox = ({
-  group, instance, containerRef, extraLinks = [], ...rest
+  group, instance, containerRef, extraLinks = [], onSelectInstance, ...rest
 }) => {
   const {
     executionDate, taskId, tryNumber = 0, operator, runId,
   } = instance;
-  const onClick = () => executionDate && callModal(taskId, executionDate, extraLinks, tryNumber, operator === 'SubDagOperator' || undefined, runId);
+
+  const onOpenModal = () => executionDate && callModal(taskId, executionDate, extraLinks, tryNumber, operator === 'SubDagOperator' || undefined, runId);
+  const onClick = () => {
+    if (group.isMapped) {
+      onSelectInstance(instance);
+    } else {
+      onSelectInstance({});
+      onOpenModal();
+    }
+  };
 
   // Fetch the corresponding column element and set its background color when hovering
   const onMouseOver = () => {
@@ -48,37 +57,39 @@ const StatusBox = ({
   };
 
   return (
-    <Tooltip
-      label={<InstanceTooltip instance={instance} group={group} />}
-      fontSize="md"
-      portalProps={{ containerRef }}
-      hasArrow
-      placement="top"
-      openDelay={400}
-    >
-      <Flex
-        p="1px"
-        my="1px"
-        mx="2px"
-        justifyContent="center"
-        alignItems="center"
-        onClick={onClick}
-        cursor={!group.children && 'pointer'}
-        data-testid="task-instance"
-        zIndex={1}
-        onMouseEnter={onMouseOver}
-        onMouseLeave={onMouseLeave}
-        {...rest}
+    <>
+      <Tooltip
+        label={<InstanceTooltip instance={instance} group={group} />}
+        fontSize="md"
+        portalProps={{ containerRef }}
+        hasArrow
+        placement="top"
+        openDelay={400}
       >
-        <Box
-          width="10px"
-          height="10px"
-          backgroundColor={stateColors[instance.state] || 'white'}
-          borderRadius="2px"
-          borderWidth={instance.state ? 0 : 1}
-        />
-      </Flex>
-    </Tooltip>
+        <Flex
+          p="1px"
+          my="1px"
+          mx="2px"
+          justifyContent="center"
+          alignItems="center"
+          onClick={onClick}
+          cursor={!group.children && 'pointer'}
+          data-testid="task-instance"
+          zIndex={1}
+          onMouseEnter={onMouseOver}
+          onMouseLeave={onMouseLeave}
+          {...rest}
+        >
+          <Box
+            width="10px"
+            height="10px"
+            backgroundColor={stateColors[instance.state] || 'white'}
+            borderRadius="2px"
+            borderWidth={instance.state ? 0 : 1}
+          />
+        </Flex>
+      </Tooltip>
+    </>
   );
 };
 
diff --git a/airflow/www/static/js/tree/Tree.jsx b/airflow/www/static/js/tree/Tree.jsx
index 450e002..095adbd 100644
--- a/airflow/www/static/js/tree/Tree.jsx
+++ b/airflow/www/static/js/tree/Tree.jsx
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-import React, { useRef, useEffect } from 'react';
+import React, { useRef, useEffect, useState } from 'react';
 import {
   Table,
   Tbody,
@@ -28,16 +28,19 @@ import {
   Spinner,
   Text,
   Thead,
+  Flex,
 } from '@chakra-ui/react';
 
 import useTreeData from './useTreeData';
 import renderTaskRows from './renderTaskRows';
 import DagRuns from './dagRuns';
+import SidePanel from './SidePanel';
 
 const Tree = () => {
   const containerRef = useRef();
   const scrollRef = useRef();
   const { data: { groups = {} }, isRefreshOn, onToggleRefresh } = useTreeData();
+  const [selectedInstance, setSelectedInstance] = useState({});
 
   useEffect(() => {
     // Set initial scroll to far right if it is scrollable
@@ -47,6 +50,13 @@ const Tree = () => {
     }
   }, []);
 
+  const { runId, taskId } = selectedInstance;
+  const onSelectInstance = (newInstance) => (
+    (newInstance.runId === runId && newInstance.taskId === taskId)
+      ? setSelectedInstance({})
+      : setSelectedInstance(newInstance)
+  );
+
   return (
     <Box position="relative" ref={containerRef}>
       <FormControl display="flex" alignItems="center" justifyContent="flex-end" width="100%">
@@ -58,17 +68,20 @@ const Tree = () => {
       </FormControl>
       <Text transform="rotate(-90deg)" position="absolute" left="-6px" top="130px">Runs</Text>
       <Text transform="rotate(-90deg)" position="absolute" left="-6px" top="190px">Tasks</Text>
-      <Box px="24px">
-        <Box position="relative" width="100%" overflowX="auto" ref={scrollRef}>
-          <Table>
+      <Box pl="24px">
+        <Flex position="relative" flexDirection="row" justifyContent="space-between" overflow="hidden">
+          <Table mr="24px" overflowX="auto" ref={scrollRef} height={0}>
             <Thead>
               <DagRuns containerRef={containerRef} />
             </Thead>
             <Tbody>
-              {renderTaskRows({ task: groups, containerRef })}
+              {renderTaskRows({
+                task: groups, containerRef, onSelectInstance,
+              })}
             </Tbody>
           </Table>
-        </Box>
+          <SidePanel isOpen={!!runId} instance={selectedInstance} />
+        </Flex>
       </Box>
     </Box>
   );
diff --git a/airflow/www/static/js/tree/renderTaskRows.jsx b/airflow/www/static/js/tree/renderTaskRows.jsx
index afd97e6..f5a7ba0 100644
--- a/airflow/www/static/js/tree/renderTaskRows.jsx
+++ b/airflow/www/static/js/tree/renderTaskRows.jsx
@@ -40,7 +40,7 @@ import { getMetaValue } from '../utils';
 const dagId = getMetaValue('dag_id');
 
 const renderTaskRows = ({
-  task, containerRef, level = 0, isParentOpen,
+  task, containerRef, level = 0, isParentOpen, onSelectInstance,
 }) => task.children.map((t) => (
   <Row
     key={t.id}
@@ -49,6 +49,7 @@ const renderTaskRows = ({
     containerRef={containerRef}
     prevTaskId={task.id}
     isParentOpen={isParentOpen}
+    onSelectInstance={onSelectInstance}
   />
 ));
 
@@ -85,7 +86,9 @@ const TaskName = ({
   </Box>
 );
 
-const TaskInstances = ({ task, containerRef, dagRuns }) => (
+const TaskInstances = ({
+  task, containerRef, dagRuns, onSelectInstance,
+}) => (
   <Flex justifyContent="flex-end">
     {dagRuns.map((run) => {
       // Check if an instance exists for the run, or return an empty box
@@ -98,6 +101,7 @@ const TaskInstances = ({ task, containerRef, dagRuns }) => (
             containerRef={containerRef}
             extraLinks={task.extraLinks}
             group={task}
+            onSelectInstance={onSelectInstance}
           />
         )
         : <Box key={`${run.runId}-${task.id}`} width="18px" data-testid="blank-task" />;
@@ -106,7 +110,7 @@ const TaskInstances = ({ task, containerRef, dagRuns }) => (
 );
 
 const Row = ({
-  task, containerRef, level, prevTaskId, isParentOpen = true,
+  task, containerRef, level, prevTaskId, isParentOpen = true, onSelectInstance,
 }) => {
   const { data: { dagRuns = [] } } = useTreeData();
   const isGroup = !!task.children;
@@ -162,13 +166,18 @@ const Row = ({
         <Td width={0} p={0} borderBottom={0} />
         <Td p={0} align="right" _groupHover={{ backgroundColor: 'rgba(113, 128, 150, 0.1)' }} transition="background-color 0.2s" borderBottom={0}>
           <Collapse in={isFullyOpen}>
-            <TaskInstances dagRuns={dagRuns} task={task} containerRef={containerRef} />
+            <TaskInstances
+              dagRuns={dagRuns}
+              task={task}
+              containerRef={containerRef}
+              onSelectInstance={onSelectInstance}
+            />
           </Collapse>
         </Td>
       </Tr>
       {isGroup && (
         renderTaskRows({
-          task, containerRef, level: level + 1, isParentOpen: isOpen,
+          task, containerRef, level: level + 1, isParentOpen: isOpen, onSelectInstance,
         })
       )}
     </>

[airflow] 04/08: improve rendering and add selected dag run

Posted by bb...@apache.org.
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 eb961505bac36095c84bd6c2b99e9ce49e6f37bc
Author: Brent Bovenzi <br...@gmail.com>
AuthorDate: Mon Feb 28 12:24:27 2022 -0500

    improve rendering and add selected dag run
---
 airflow/www/static/js/tree/SidePanel.jsx      | 28 +++++++++++++++++--------
 airflow/www/static/js/tree/StatusBox.jsx      | 24 ++++++++++-----------
 airflow/www/static/js/tree/Tree.jsx           | 12 ++++++++---
 airflow/www/static/js/tree/dagRuns/Bar.jsx    |  9 ++++----
 airflow/www/static/js/tree/dagRuns/index.jsx  |  3 ++-
 airflow/www/static/js/tree/renderTaskRows.jsx | 30 ++++++++++++++++++---------
 6 files changed, 65 insertions(+), 41 deletions(-)

diff --git a/airflow/www/static/js/tree/SidePanel.jsx b/airflow/www/static/js/tree/SidePanel.jsx
index 7a21eba..88439a0 100644
--- a/airflow/www/static/js/tree/SidePanel.jsx
+++ b/airflow/www/static/js/tree/SidePanel.jsx
@@ -25,8 +25,6 @@ import {
   Flex,
   Text,
   useDisclosure,
-  CloseButton,
-  Button,
   IconButton,
 } from '@chakra-ui/react';
 import { MdKeyboardArrowLeft, MdKeyboardArrowRight } from 'react-icons/md';
@@ -38,30 +36,42 @@ const SidePanel = ({ instance: { runId, taskId, executionDate } }) => {
   if (!isOpen) {
     return (
       <IconButton
-        ml={2}
+        m={2}
         icon={<MdKeyboardArrowLeft size={18} />}
         aria-label="Open Details Panel"
         onClick={onOpen}
       />
     );
   }
-  const title = runId && taskId
-    ? (
+  let title = '';
+  if (runId && taskId) {
+    title = (
       <>
         <chakra.span>Task Instance: </chakra.span>
         <chakra.b>{taskId}</chakra.b>
         <chakra.span> at </chakra.span>
         <chakra.b>{formatDateTime(moment.utc(executionDate))}</chakra.b>
       </>
-    )
-    : (
+    );
+  } else if (runId) {
+    title = (
+      <>
+        <chakra.span>Dag Run: </chakra.span>
+        <chakra.b>{runId}</chakra.b>
+        <chakra.span> at </chakra.span>
+        <chakra.b>{formatDateTime(moment.utc(executionDate))}</chakra.b>
+      </>
+    );
+  } else {
+    title = (
       <chakra.span>Dag Details: </chakra.span>
     );
+  }
 
   return (
-    <Flex bg="gray.200" maxWidth={300} minWidth={300} flexDirection="column" p={3}>
+    <Flex bg="gray.200" maxWidth={isOpen ? '50%' : 0} minWidth={isOpen ? 300 : 0} flexDirection="column" p={3}>
       <IconButton
-        ml={2}
+        m={2}
         icon={<MdKeyboardArrowRight size={18} />}
         aria-label="Close Details Panel"
         onClick={onClose}
diff --git a/airflow/www/static/js/tree/StatusBox.jsx b/airflow/www/static/js/tree/StatusBox.jsx
index b4abc93..815e6a1 100644
--- a/airflow/www/static/js/tree/StatusBox.jsx
+++ b/airflow/www/static/js/tree/StatusBox.jsx
@@ -27,34 +27,32 @@ import {
   useTheme,
 } from '@chakra-ui/react';
 
-// import { callModal } from '../dag';
 import InstanceTooltip from './InstanceTooltip';
 
 const StatusBox = ({
-  group, instance, containerRef, extraLinks = [], onSelectInstance, ...rest
+  group, instance, containerRef, onSelectInstance, selectedInstance, ...rest
 }) => {
-  const {
-    executionDate, taskId, tryNumber = 0, operator, runId,
-  } = instance;
+  const { runId } = instance;
   const { colors } = useTheme();
   const hoverBlue = `${colors.blue[100]}50`;
 
-  // const onOpenModal = () => executionDate && callModal(taskId, executionDate, extraLinks, tryNumber, operator === 'SubDagOperator' || undefined, runId);
-  const onClick = (e) => {
-    e.stopPropagation();
-    onSelectInstance(instance);
-  };
-
   // Fetch the corresponding column element and set its background color when hovering
   const onMouseOver = () => {
-    [...containerRef.current.getElementsByClassName(`js-${runId}`)]
-      .forEach((e) => { e.style.backgroundColor = hoverBlue; });
+    if (selectedInstance.runId !== runId) {
+      [...containerRef.current.getElementsByClassName(`js-${runId}`)]
+        .forEach((e) => { e.style.backgroundColor = hoverBlue; });
+    }
   };
   const onMouseLeave = () => {
     [...containerRef.current.getElementsByClassName(`js-${runId}`)]
       .forEach((e) => { e.style.backgroundColor = null; });
   };
 
+  const onClick = (e) => {
+    e.stopPropagation();
+    onSelectInstance(instance);
+  };
+
   return (
     <>
       <Tooltip
diff --git a/airflow/www/static/js/tree/Tree.jsx b/airflow/www/static/js/tree/Tree.jsx
index ff1402f..199e373 100644
--- a/airflow/www/static/js/tree/Tree.jsx
+++ b/airflow/www/static/js/tree/Tree.jsx
@@ -39,9 +39,11 @@ import SidePanel from './SidePanel';
 const Tree = () => {
   const containerRef = useRef();
   const scrollRef = useRef();
-  const { data: { groups = {} }, isRefreshOn, onToggleRefresh } = useTreeData();
+  const { data: { groups = {}, dagRuns = [] }, isRefreshOn, onToggleRefresh } = useTreeData();
   const [selectedInstance, setSelectedInstance] = useState({});
 
+  const dagRunIds = dagRuns.map((dr) => dr.runId);
+
   useEffect(() => {
     // Set initial scroll to far right if it is scrollable
     const runsContainer = scrollRef.current;
@@ -73,11 +75,15 @@ const Tree = () => {
           <Box mr="12px" pb="12px" overflowX="auto" ref={scrollRef} maxWidth="60vw">
             <Table height={0}>
               <Thead>
-                <DagRuns containerRef={containerRef} selectedInstance={selectedInstance} />
+                <DagRuns
+                  containerRef={containerRef}
+                  selectedInstance={selectedInstance}
+                  onSelectInstance={onSelectInstance}
+                />
               </Thead>
               <Tbody>
                 {renderTaskRows({
-                  task: groups, containerRef, onSelectInstance, selectedInstance,
+                  task: groups, containerRef, onSelectInstance, selectedInstance, dagRunIds,
                 })}
               </Tbody>
             </Table>
diff --git a/airflow/www/static/js/tree/dagRuns/Bar.jsx b/airflow/www/static/js/tree/dagRuns/Bar.jsx
index 4dbe20d..c64abdd 100644
--- a/airflow/www/static/js/tree/dagRuns/Bar.jsx
+++ b/airflow/www/static/js/tree/dagRuns/Bar.jsx
@@ -31,12 +31,11 @@ import {
 import { MdPlayArrow } from 'react-icons/md';
 
 import DagRunTooltip from './Tooltip';
-import { callModalDag } from '../../dag';
 
 const BAR_HEIGHT = 100;
 
 const DagRunBar = ({
-  run, max, index, totalRuns, containerRef, selectedInstance,
+  run, max, index, totalRuns, containerRef, selectedInstance, onSelectInstance,
 }) => {
   const { colors } = useTheme();
   const hoverBlue = `${colors.blue[100]}50`;
@@ -53,14 +52,14 @@ const DagRunBar = ({
         alignItems="flex-end"
         justifyContent="center"
         mb="2px"
-        // py="2px"
         px="2px"
         mx="1px"
         cursor="pointer"
         width="14px"
         zIndex={1}
-        onClick={() => {
-          callModalDag({ execution_date: run.executionDate, dag_id: run.dagId, run_id: run.runId });
+        onClick={(e) => {
+          e.stopPropagation();
+          onSelectInstance(run);
         }}
         position="relative"
         data-peer
diff --git a/airflow/www/static/js/tree/dagRuns/index.jsx b/airflow/www/static/js/tree/dagRuns/index.jsx
index 7de949f..7459634 100644
--- a/airflow/www/static/js/tree/dagRuns/index.jsx
+++ b/airflow/www/static/js/tree/dagRuns/index.jsx
@@ -36,7 +36,7 @@ const DurationTick = ({ children, ...rest }) => (
   </Text>
 );
 
-const DagRuns = ({ containerRef, selectedInstance }) => {
+const DagRuns = ({ containerRef, selectedInstance, onSelectInstance }) => {
   const { data: { dagRuns = [] } } = useTreeData();
   const durations = [];
   const runs = dagRuns.map((dagRun) => {
@@ -98,6 +98,7 @@ const DagRuns = ({ containerRef, selectedInstance }) => {
               totalRuns={runs.length}
               containerRef={containerRef}
               selectedInstance={selectedInstance}
+              onSelectInstance={onSelectInstance}
             />
           ))}
         </Flex>
diff --git a/airflow/www/static/js/tree/renderTaskRows.jsx b/airflow/www/static/js/tree/renderTaskRows.jsx
index 7eff252..9b454f0 100644
--- a/airflow/www/static/js/tree/renderTaskRows.jsx
+++ b/airflow/www/static/js/tree/renderTaskRows.jsx
@@ -32,7 +32,6 @@ import {
 } from '@chakra-ui/react';
 import { FiChevronUp, FiChevronDown } from 'react-icons/fi';
 
-import useTreeData from './useTreeData';
 import StatusBox from './StatusBox';
 
 import { getMetaValue } from '../utils';
@@ -41,7 +40,7 @@ import { getMetaValue } from '../utils';
 const dagId = getMetaValue('dag_id');
 
 const renderTaskRows = ({
-  task, containerRef, level = 0, isParentOpen, onSelectInstance, selectedInstance,
+  task, containerRef, level = 0, isParentOpen, onSelectInstance, selectedInstance, dagRunIds
 }) => task.children.map((t) => (
   <Row
     key={t.id}
@@ -52,6 +51,7 @@ const renderTaskRows = ({
     isParentOpen={isParentOpen}
     onSelectInstance={onSelectInstance}
     selectedInstance={selectedInstance}
+    dagRunIds={dagRunIds}
   />
 ));
 
@@ -85,33 +85,42 @@ const TaskName = ({
 );
 
 const TaskInstances = ({
-  task, containerRef, dagRuns, onSelectInstance,
+  task, containerRef, dagRunIds, onSelectInstance, selectedInstance,
 }) => (
   <Flex justifyContent="flex-end">
-    {dagRuns.map((run) => {
+    {dagRunIds.map((runId) => {
       // Check if an instance exists for the run, or return an empty box
-      const instance = task.instances.find((gi) => gi.runId === run.runId);
+      const instance = task.instances.find((gi) => gi.runId === runId);
+      const key = `${runId}-${task.id}`;
       return instance
         ? (
           <StatusBox
-            key={`${run.runId}-${task.id}`}
+            key={key}
             instance={instance}
             containerRef={containerRef}
             extraLinks={task.extraLinks}
             group={task}
             onSelectInstance={onSelectInstance}
+            selectedInstance={selectedInstance}
           />
         )
-        : <Box key={`${run.runId}-${task.id}`} width="16px" data-testid="blank-task" />;
+        : <Box key={key} width="16px" data-testid="blank-task" />;
     })}
   </Flex>
 );
 
 const Row = (props) => {
   const {
-    task, containerRef, level, prevTaskId, isParentOpen = true, onSelectInstance, selectedInstance,
+    task,
+    containerRef,
+    level,
+    prevTaskId,
+    isParentOpen = true,
+    onSelectInstance,
+    selectedInstance,
+    dagRunIds,
   } = props;
-  const { data: { dagRuns = [] } } = useTreeData();
+  // const { data: { dagRuns = [] } } = useTreeData();
   const { colors } = useTheme();
   const hoverBlue = `${colors.blue[100]}50`;
   const isGroup = !!task.children;
@@ -175,10 +184,11 @@ const Row = (props) => {
         >
           <Collapse in={isFullyOpen}>
             <TaskInstances
-              dagRuns={dagRuns}
+              dagRunIds={dagRunIds}
               task={task}
               containerRef={containerRef}
               onSelectInstance={onSelectInstance}
+              selectedInstance={selectedInstance}
             />
           </Collapse>
         </Td>