{#
  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.

#}
{% extends "airflow/master.html" %}

{% block title %}Airflow - DAGs{% endblock %}

{% block head_css %}
{{ super() }}
<link href="{{ url_for("static", filename="dataTables.bootstrap.css") }}" rel="stylesheet" type="text/css" >
<link href="{{ url_for("static", filename="bootstrap-toggle.min.css") }}" rel="stylesheet" type="text/css">
{% endblock %}

{% block body %}
  <h2>DAGs</h2>

  <div id="main_content">
    <div class="row">
      <div class="col-sm-2">
      </div>
      <div class="col-sm-10">
        <form id="search_form" class="form-inline" style="width: 100%; text-align: right;">
            <div id="dags_filter" class="form-group" style="width: 100%;">
              <label for="dag_query" style="width:20%; text-align: right;">Search:</label>
              <input id="dag_query" type="text" class="typeahead form-control" data-provide="typeahead" style="width:50%;" value="{{search_query}}">
            </div>
        </form>
      </div>
    </div>
    <table id="dags" class="table table-striped table-bordered">
        <thead>
            <tr>
                <th></th>
                <th width="12"><span id="pause_header" class="glyphicon glyphicon-info-sign" title="Use this toggle to pause a DAG. The scheduler won't schedule new tasks instances for a paused DAG. Tasks already running at pause time won't be affected."></span></th>
                <th>DAG</th>
                <th>Schedule</th>
                <th>Owner</th>
                <th style="padding-left: 5px;">Recent Tasks
                  <span id="statuses_info" class="glyphicon glyphicon-info-sign" aria-hidden="true" title="Status of tasks from all active DAG runs or, if not currently active, from most recent run."></span>
                  <img id="loading" width="15" src="{{ url_for("static", filename="loading.gif") }}">
                </th>
                <th style="padding-left: 5px;">Last Run <span id="statuses_info" class="glyphicon glyphicon-info-sign" aria-hidden="true" title="Execution Date/Time of Highest Dag Run."></span>
                </th>
                <th style="padding-left: 5px;">DAG Runs
                  <span id="statuses_info" class="glyphicon glyphicon-info-sign" aria-hidden="true" title="Status of all previous DAG runs."></span>
                  <img id="loading" width="15" src="{{ url_for("static", filename="loading.gif") }}">
                </th>
                <th class="text-center">Links</th>
            </tr>
        </thead>
        <tbody>
        {% for dag_id in dag_ids_in_page %}
            {% set dag = webserver_dags[dag_id] if dag_id in webserver_dags else None %}
            <tr>
                <!-- Column 1: Edit dag -->
                <td class="text-center" style="width:10px;">
                    {% if dag_id in orm_dags %}
                  <a href="{{ url_for('dagmodel.edit_view') }}?id={{ dag_id }}" title="Info">
                        <span class="glyphicon glyphicon-edit" aria-hidden="true"></span>
                    </a>
                    {% endif %}
                </td>

                <!-- Column 2: Turn dag on/off -->
                <td>
                  {% if dag_id in orm_dags %}
                    <input id="toggle-{{ dag_id }}" dag_id="{{ dag_id }}" type="checkbox" {{ "checked" if not orm_dags[dag_id].is_paused else "" }} data-toggle="toggle" data-size="mini" method="post">
                  {% endif %}
                </td>

                <!-- Column 3: Name -->
                <td>
                    {% if dag_id in webserver_dags %}
                    <a href="{{ url_for('airflow.'+dag.default_view, dag_id=dag.dag_id) }}" title="{{ dag.description }}">
                        {{ dag_id }}
                    </a>
                    {% else %}
                        {{ dag_id }}
                        <span class="glyphicon glyphicon-info-sign" class="info" aria-hidden="true" title="This DAG isn't available in the web server's DagBag object. It shows up in this list because the scheduler marked it as active in the metadata database."></span>
                    {% endif %}
                    {% if dag_id not in orm_dags %}
                        <span class="glyphicon glyphicon-info-sign" class="info" aria-hidden="true" title="This DAG seems to be existing only locally. The master scheduler doesn't seem to be aware of its existence."></span>
                    {% endif %}
                </td>

                <!-- Column 4: Dag Schedule -->
                <td>
                    {% if dag_id in webserver_dags %}
                  <a class="label label-default schedule {{ dag.dag_id }}" href="{{ url_for('dagrun.index_view') }}?flt2_dag_id_equals={{ dag.dag_id }}">
                        {{ dag.schedule_interval }}
                    </a>
                    {% endif %}
                </td>

                <!-- Column 5: Dag Owners -->
                <td>
                  {{ dag.owner if dag else orm_dags[dag_id].owners }}
                </td>

                <!-- Column 6: Recent Tasks -->
                <td style="padding:0px; width:200px; height:10px;">
                    <svg height="10" width="10" id='task-run-{{ dag.safe_dag_id }}' style="display: block;"></svg>
                </td>

                <!-- Column 7: Last Run -->
                <td class="text-nowrap latest_dag_run {{ dag.dag_id }}">
                  {% if dag %}
                    {% set last_run = dag.get_last_dagrun(include_externally_triggered=True) %}
                    {% if last_run and last_run.execution_date %}
                      <a href="{{ url_for('airflow.graph', dag_id=dag.dag_id, execution_date=last_run.execution_date) }}">
                        {{ last_run.execution_date.strftime("%Y-%m-%d %H:%M") }}
                      </a>
                      <span aria-hidden="true" id="statuses_info" title="Start Date: {{ last_run.start_date.strftime("%Y-%m-%d %H:%M") }}" class="glyphicon glyphicon-info-sign"></span>
                    {% endif %}
                  {% endif %}
                </td>

                <!-- Column 8: Dag Runs -->
                <td style="padding:0px; width:120px; height:10px;">
                    <svg height="10" width="10" id='dag-run-{{ dag.safe_dag_id }}' style="display: block;"></svg>
                </td>

                <!-- Column 9: Links -->
                <td class="text-center" style="display:flex; flex-direction:row; justify-content:space-around;">
                {% if dag %}

                <!-- Trigger Dag -->
                <a href="{{ url_for('airflow.trigger', dag_id=dag.dag_id) }}"
                   onclick="return confirmTriggerDag('{{ dag.safe_dag_id }}')">
                    <span class="glyphicon glyphicon-play-circle" aria-hidden="true" data-original-title="Trigger Dag"></span>
                </a>

                <!-- Tree -->
                <a href="{{ url_for('airflow.tree', dag_id=dag.dag_id, num_runs=num_runs) }}">
                    <span class="glyphicon glyphicon-tree-deciduous" aria-hidden="true" data-original-title="Tree View"></span>
                </a>

                <!-- Graph -->
                <a href="{{ url_for('airflow.graph', dag_id=dag.dag_id) }}">
                    <span class="glyphicon glyphicon-certificate" aria-hidden="true" data-original-title="Graph View"></span>
                </a>

                <!-- Duration -->
                <a href="{{ url_for('airflow.duration', dag_id=dag.dag_id) }}">
                    <span class="glyphicon glyphicon-stats" aria-hidden="true" data-original-title="Tasks Duration"></span>
                </a>

                <!-- Retries -->
                <a href="{{ url_for('airflow.tries', dag_id=dag.dag_id) }}">
                    <span class="glyphicon glyphicon-duplicate" aria-hidden="true" data-original-title="Task Tries"></span>
                </a>

                <!-- Landing Times -->
                <a href="{{ url_for("airflow.landing_times", dag_id=dag.dag_id) }}">
                    <span class="glyphicon glyphicon-plane" aria-hidden="true" data-original-title="Landing Times"></span>
                </a>

                <!-- Gantt -->
                <a href="{{ url_for("airflow.gantt", dag_id=dag.dag_id) }}">
                    <span class="glyphicon glyphicon-align-left" aria-hidden="true" data-original-title="Gantt View"></span>
                </a>

                <!-- Code -->
                <a href="{{ url_for("airflow.code", dag_id=dag.dag_id) }}">
                    <span class="glyphicon glyphicon-file" aria-hidden="true" data-original-title="Code View"></span>
                </a>

                <!-- Logs -->
                <a href="{{ url_for('log.index_view') }}?sort=1&amp;desc=1&amp;flt1_dag_id_equals={{ dag.dag_id }}">
                    <span class="glyphicon glyphicon-align-justify" aria-hidden="true" data-original-title="Logs"></span>
                </a>
                {% endif %}

                <!-- Refresh -->
                <a href="{{ url_for("airflow.refresh", dag_id=dag_id) }}">
                  <span class="glyphicon glyphicon-refresh" aria-hidden="true" data-original-title="Refresh"></span>
                </a>

                <!-- Delete -->
                <!-- Use dag_id instead of dag.dag_id, because the DAG might not exist in the webserver's DagBag -->
                <a href="{{ url_for('airflow.delete', dag_id=dag_id) }}"
                  onclick="return confirmDeleteDag('{{ dag_id }}')">
                   <span class="glyphicon glyphicon-remove-circle" style="color:red" aria-hidden="true" data-original-title="Delete Dag"></span>
                </a>
                </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
    <div class="row">
      <div class="col-sm-12" style="text-align:right;">
        <div class="dataTables_info" id="dags_info" role="status" aria-live="polite" style="padding-top: 0px;">Showing {{num_dag_from}} to {{num_dag_to}} of {{num_of_all_dags}} entries</div>
      </div>
    </div>
    <div class="row">
      <div class="col-sm-12" style="text-align:left;">
        <div class="dataTables_info" id="dags_paginate">
          {{paging}}
        </div>
      </div>

    </div>
    {% if not hide_paused %}
    <a href="{{ url_for('admin.index') }}?showPaused=False">Hide Paused DAGs</a>
    {% else %}
    <a href="{{ url_for('admin.index') }}?showPaused=True">Show Paused DAGs</a>
    {% endif %}
  </div>
{% endblock %}

{% block tail %}
  {{ super() }}
  <script src="{{ url_for('static', filename='d3.v3.min.js') }}"></script>
  <script src="{{ url_for('static', filename='jquery.dataTables.min.js') }}"></script>
  <script src="{{ url_for('static', filename='bootstrap-toggle.min.js') }}"></script>
  <script src="{{ url_for('static', filename='bootstrap3-typeahead.min.js') }}"></script>
  <script>

      const DAGS_INDEX = "{{ url_for('admin.index') }}";
      const ENTER_KEY_CODE = 13;

      $('#dag_query').on('keypress', function (e) {
        // check for key press on ENTER (key code 13) to trigger the search
        if (e.which === ENTER_KEY_CODE) {
          search_query = $('#dag_query').val();
          window.location = DAGS_INDEX + "?search="+ encodeURI(search_query);
          e.preventDefault();
        }
      });

      $('#page_size').on('change', function() {
        p_size = $(this).val();
        window.location = DAGS_INDEX + "?page_size=" + p_size;
      });

      function confirmTriggerDag(dag_id){
          return confirm("Are you sure you want to run '"+dag_id+"' now?");
      }

      function confirmDeleteDag(dag_id){
          return confirm("Are you sure you want to delete '"+dag_id+"' now?\n\
          This option will delete ALL metadata, DAG runs, etc.\n\
          EXCEPT Log.\n\
          This cannot be undone.");
      }
      all_dags = $("[id^=toggle]");
      $.each(all_dags, function(i,v) {
        $(v).change (function() {
          var dag_id =  $(v).attr('dag_id');
          if ($(v).prop('checked')) {
            is_paused = 'true'
          } else {
            is_paused = 'false'
          }
          url = 'airflow/paused?is_paused=' + is_paused + '&dag_id=' + dag_id;
          $.post(url);
        });
      });

      var $input = $(".typeahead");
      unique_options_search = new Set([
          {% for token in auto_complete_data %}
            "{{token}}",
          {% endfor %}
        ]);

      $input.typeahead({
        source: [...unique_options_search],
        autoSelect: false,
        afterSelect: function(value) {
          search_query = value.trim()
          if (search_query) {
            window.location = DAGS_INDEX + "?search="+ encodeURI(search_query);
          }
        }
      });

      $input.change(function() {
        var current = $input.typeahead("getActive");
      });

      $input.attr("autocomplete", "off");

      $('#dags').dataTable({
        "iDisplayLength": 500,
        "bSort": false,
        "searching": false,
        "ordering": false,
        "paging": false,
        "info": false
      });
      $("#main_content").show(250);
      diameter = 25;
      circle_margin = 4;
      stroke_width = 2;
      stroke_width_hover = 6;
      d3.json("{{ url_for('airflow.blocked') }}", function(error, json) {
        $.each(json, function() {
          $('.label.schedule.' + this.dag_id)
          .attr('title', this.active_dag_run + '/' + this.max_active_runs + ' active dag runs')
          .tooltip();
          if(this.active_dag_run >= this.max_active_runs) {
            $('.label.schedule.' + this.dag_id)
            .css('background-color', 'red');
          }
        });
      });
      d3.json("{{ url_for('airflow.dag_stats') }}", function(error, json) {
        for(var dag_id in json) {
            states = json[dag_id];
            g = d3.select('svg#dag-run-' + dag_id)
              .attr('height', diameter + (stroke_width_hover * 2))
              .attr('width', '110px')
              .selectAll("g")
              .data(states)
              .enter()
              .append('g')
              .attr('transform', function(d, i) {
                x = (i * (diameter + circle_margin)) + (diameter/2 + circle_margin);
                y = (diameter/2) + stroke_width_hover;
                return 'translate(' + x + ',' + y + ')';
              });

            g.append('text')
              .attr('fill', 'black')
              .attr('text-anchor', 'middle')
              .attr('vertical-align', 'middle')
              .attr('font-size', 8)
              .attr('y', 3)
              .text(function(d){ return d.count > 0 ? d.count : ''; });

            g.append('circle')
              .attr('stroke-width', function(d) {
                  if (d.count > 0)
                    return stroke_width;
                  else {
                    return 1;
                  }
              })
              .attr('stroke', function(d) {
                  if (d.count > 0)
                    return d.color;
                  else {
                    return 'gainsboro';
                  }
              })
              .attr('fill-opacity', 0)
              .attr('r', diameter/2)
              .attr('title', function(d) {return d.state})
              .attr('style', function(d) {
                if (d.count > 0)
                    return"cursor:pointer;"
              })
              .on('click', function(d, i) {
                  if (d.count > 0)
                    window.location = "{{ url_for('dagrun.index_view') }}?flt1_dag_id_equals=" + d.dag_id + "&flt2_state_equals=" + d.state;
              })
              .on('mouseover', function(d, i) {
                if (d.count > 0) {
                    d3.select(this).transition().duration(400)
                      .attr('fill-opacity', 0.3)
                      .style("stroke-width", stroke_width_hover);
                }
              })
              .on('mouseout', function(d, i) {
                if (d.count > 0) {
                    d3.select(this).transition().duration(400)
                      .attr('fill-opacity', 0)
                      .style("stroke-width", stroke_width);
                }
              })
              .style("opacity", 0)
              .transition()
              .duration(500)
              .delay(function(d, i){return i*50;})
              .style("opacity", 1);
            d3.select("#loading").remove();
        }
        $("#pause_header").tooltip();
        $("#statuses_info").tooltip();

        $("circle").tooltip({
          html: true,
          container: "body",
        });
      });
      d3.json("{{ url_for('airflow.task_stats') }}", function(error, json) {
        for(var dag_id in json) {
            states = json[dag_id];
            g = d3.select('svg#task-run-' + dag_id)
              .attr('height', diameter + (stroke_width_hover * 2))
              .attr('width', '300px')
              .selectAll("g")
              .data(states)
              .enter()
              .append('g')
              .attr('transform', function(d, i) {
                x = (i * (diameter + circle_margin)) + (diameter/2 + circle_margin);
                y = (diameter/2) + stroke_width_hover;
                return 'translate(' + x + ',' + y + ')';
              });

            g.append('text')
              .attr('fill', 'black')
              .attr('text-anchor', 'middle')
              .attr('vertical-align', 'middle')
              .attr('font-size', 8)
              .attr('y', 3)
              .text(function(d){ return d.count > 0 ? d.count : ''; });

            g.append('circle')
              .attr('stroke-width', function(d) {
                  if (d.count > 0)
                    return stroke_width;
                  else {
                    return 1;
                  }
              })
              .attr('stroke', function(d) {
                  if (d.count > 0)
                    return d.color;
                  else {
                    return 'gainsboro';
                  }
              })
              .attr('fill-opacity', 0)
              .attr('r', diameter/2)
              .attr('title', function(d) {return d.state})
              .attr('style', function(d) {
                if (d.count > 0)
                    return"cursor:pointer;"
              })
              .on('click', function(d, i) {
                  if (d.count > 0)
                    window.location = "{{ url_for('taskinstance.index_view') }}?flt1_dag_id_equals=" + d.dag_id + "&flt2_state_equals=" + d.state;
              })
              .on('mouseover', function(d, i) {
                if (d.count > 0) {
                    d3.select(this).transition().duration(400)
                      .attr('fill-opacity', 0.3)
                      .style("stroke-width", stroke_width_hover);
                }
              })
              .on('mouseout', function(d, i) {
                if (d.count > 0) {
                    d3.select(this).transition().duration(400)
                      .attr('fill-opacity', 0)
                      .style("stroke-width", stroke_width);
                }
              })
              .style("opacity", 0)
              .transition()
              .duration(500)
              .delay(function(d, i){return i*50;})
              .style("opacity", 1);
            d3.select("#loading").remove();
        }
        $("#pause_header").tooltip();
        $("#statuses_info").tooltip();

        $("circle").tooltip({
          html: true,
          container: "body",
        });
      });
  </script>
{% endblock %}
