go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/scheduler/appengine/frontend/templates/includes/base.html (about)

     1  {{define "base"}}
     2  <!DOCTYPE html>
     3  <html lang="en">
     4  <!-- Copyright 2015 The LUCI Authors. All rights reserved.
     5  Use of this source code is governed under the Apache License, Version 2.0
     6  that can be found in the LICENSE file. -->
     7  <head>
     8    <meta http-equiv="Content-type" content="text/html; charset=UTF-8">
     9    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    10    <meta name="viewport" content="width=device-width, initial-scale=1">
    11    <link href="/static/bootstrap/css/bootstrap.min.css" rel="stylesheet">
    12    <title>{{template "title" .}}</title>
    13    <style type="text/css">
    14      body {
    15        padding-top: 10px;
    16        padding-bottom: 10px;
    17      }
    18      body.anonymous {
    19        background-color: #eee;
    20      }
    21      .navbar {
    22        margin-bottom: 20px;
    23      }
    24      #account-picture-nav {
    25        margin-top: 10px;
    26        margin-bottom: 10px;
    27      }
    28      #account-picture-nav img {
    29        border-radius: 6px;
    30      }
    31      #account-text-nav {
    32        margin-left: 8px;
    33        margin-right: 0px;
    34      }
    35      .popover{
    36        max-width: 400px;
    37      }
    38      footer hr {
    39        margin: 10px 0px;
    40      }
    41    </style>
    42    {{template "head" .}}
    43  </head>
    44  
    45  {{if .IsAnonymous}}
    46  <body class="anonymous">
    47  {{else}}
    48  <body>
    49  {{end}}
    50    <div class="modal fade" tabindex="-1" role="dialog" id="pause-job-modal">
    51      <div class="modal-dialog" role="document">
    52        <div class="modal-content">
    53          <div class="modal-header">
    54            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
    55            <h4 class="modal-title">Pausing</h4>
    56          </div>
    57          <div class="modal-body">
    58            <form id="pause-job-prompt-form">
    59              <div class="form-group">
    60                <label for="pause-reason" class="control-label">
    61                  Provide a reason (it will be recorded):
    62                </label>
    63                <input type="text" class="form-control" id="pause-reason">
    64              </div>
    65            </form>
    66          </div>
    67          <div class="modal-footer">
    68            <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
    69            <button type="submit" class="btn btn-primary" id="pause-btn" form="pause-job-prompt-form">Pause</button>
    70          </div>
    71        </div>
    72      </div>
    73    </div>
    74  
    75    <div class="container">
    76      <div class="navbar navbar-default" role="navigation">
    77        <div class="navbar-header">
    78          <button type="button" class="navbar-toggle"
    79                  data-toggle="collapse" data-target=".navbar-collapse">
    80            <span class="sr-only">Toggle navigation</span>
    81            <span class="icon-bar"></span>
    82            <span class="icon-bar"></span>
    83            <span class="icon-bar"></span>
    84          </button>
    85          <span class="navbar-brand">
    86            <span id="progress-spinner" class="not-spinning">
    87              <a href="/">LUCI Scheduler</a>
    88            </span>
    89          </span>
    90        </div>
    91        <div class="navbar-collapse collapse">
    92          <ul class="nav navbar-nav"></ul>
    93          <p class="nav navbar-text navbar-right" id="account-text-nav">
    94            {{if .IsAnonymous}}
    95              <a href="{{.LoginURL}}" class="navbar-link">Login</a>
    96            {{else}}
    97              <span>{{.User.Email}}</span>
    98              <span> |</span>
    99              <a href="{{.LogoutURL}}" class="navbar-link">Logout</a>
   100            {{end}}
   101            {{if .User.Picture}}
   102            <p class="nav navbar-right" id="account-picture-nav">
   103              <img src="{{.User.Picture}}" width="30" height="30">
   104            </p>
   105            {{end}}
   106          </p>
   107        </div>
   108      </div>
   109  
   110      <div id="content-box">
   111        {{template "content" .}}
   112      </div>
   113  
   114      <footer>
   115        <hr>
   116        <p class="text-right" style="color: #cccccc">
   117          <small>Handled in <span>{{call .HandlerDuration}}</span></small>
   118          <small style="margin-left: 20px">Version: <span>{{.AppVersion}}</span></small>
   119        </p>
   120      </footer>
   121    </div>
   122  
   123    <script src="/static/jquery/jquery.min.js"></script>
   124    <script src="/static/bootstrap/js/bootstrap.min.js"></script>
   125    <script>
   126      var xsrfToken = "{{.XsrfToken}}";
   127  
   128      function jobFromButton(btn) {
   129        var form = $(btn).closest("form");
   130        return {
   131          project: $("input#projectID", form).val(),
   132          job: $("input#jobName", form).val(),
   133        };
   134      };
   135  
   136      function invocationFromButton(btn) {
   137        var form = $(btn).closest("form");
   138        return {
   139          project: $("input#projectID", form).val(),
   140          job: $("input#jobName", form).val(),
   141          invocation: $("input#invID", form).val(),
   142        };
   143      };
   144  
   145      function postJobAction(btn, action, reason) {
   146        var form = $(btn).closest("form");
   147        if (!form.attr("submitted")) {
   148          var job = jobFromButton(btn);
   149          var url = "/actions/" + action + "/" + job.project + "/" + job.job;
   150          $("#xsrf_token", form).val(xsrfToken);
   151          $("#reason", form).val(reason || "");
   152          form.attr("action", url);
   153          form.attr("submitted", "yes");
   154          form.submit();
   155        }
   156      };
   157  
   158      function postInvocationAction(btn, action) {
   159        var form = $(btn).closest("form");
   160        if (!form.attr("submitted")) {
   161          var inv = invocationFromButton(btn);
   162          var url = "/actions/" + action + "/" + inv.project + "/" + inv.job + "/" + inv.invocation;
   163          $("#xsrf_token", form).val(xsrfToken);
   164          form.attr("action", url);
   165          form.attr("submitted", "yes");
   166          form.submit();
   167        }
   168      };
   169  
   170      $("#pause-job-modal").on("show.bs.modal", function(event) {
   171        // The modal dialog itself.
   172        var modal = $(this);
   173        // The button that triggered the modal. Indirectly points to the job.
   174        // Consumed by postJobAction.
   175        var pauseBtn = $(event.relatedTarget);
   176  
   177        // Indicate which job we are pausing.
   178        $(".modal-title", modal).text("Pausing " + jobFromButton(pauseBtn).job);
   179  
   180        // Actually pause the job when the prompt is closed affirmatively.
   181        modal.unbind("submit");
   182        modal.submit(function(event) {
   183          // Disable form buttons and prevent the modal from closing, the page
   184          // will reload after postJobAction call.
   185          $("button", modal).prop("disabled", true);
   186          $("input", modal).prop("disabled", true);
   187          $("#pause-btn", modal).text("Pausing");
   188          modal.off("keydown.dismiss.bs.modal");
   189  
   190          // Initiate the action, this will reload the page eventually.
   191          postJobAction(pauseBtn, "pauseJob", $("#pause-reason", modal).val());
   192  
   193          // Prevent default form submission handler (GET request).
   194          event.preventDefault();
   195        });
   196      });
   197  
   198      // Auto-focus the input box when the modal is shown.
   199      $("#pause-job-modal").on("shown.bs.modal", function() {
   200        $("#pause-reason", $(this)).focus();
   201      });
   202  
   203      // Initialize all popovers.
   204      $('[data-toggle="popover"]').popover();
   205    </script>
   206  </body>
   207  
   208  </html>
   209  {{end}}
   210  
   211  
   212  {{define "job-action-buttons"}}
   213  <form style="display: inline" method="POST">
   214    <input type="hidden" id="xsrf_token" name="xsrf_token" value="">
   215    <input type="hidden" id="projectID" value="{{.ProjectID}}">
   216    <input type="hidden" id="jobName" value="{{.JobName}}">
   217    <input type="hidden" id="reason" name="reason" value="">
   218    <div class="btn-group btn-group-xs" style="width: 160px" role="group">
   219      {{if .Paused}}
   220        <button {{if not .CanResume}}disabled{{end}} type="button"
   221                class="btn btn-primary"
   222                onclick="postJobAction(this, 'resumeJob')">
   223          Resume
   224        </button>
   225      {{else}}
   226        <button {{if not .CanPause}}disabled{{end}} type="button"
   227                class="btn btn-primary"
   228                data-toggle="modal" data-backdrop="static"
   229                data-target="#pause-job-modal">
   230          Pause
   231        </button>
   232      {{end}}
   233      <button {{if not .CanAbort}}disabled{{end}} type="button"
   234              class="btn btn-danger"
   235              onclick="postJobAction(this, 'abortJob')">
   236        Abort
   237      </button>
   238      <button {{if not .CanTrigger}}disabled{{end}} type="button"
   239              class="btn btn-success"
   240              onclick="postJobAction(this, 'triggerJob')">
   241        Trigger
   242      </button>
   243    </div>
   244  </form>
   245  {{end}}
   246  
   247  
   248  {{define "invocation-action-buttons"}}
   249  <form style="display: inline" method="POST">
   250    <input type="hidden" id="xsrf_token" name="xsrf_token" value="">
   251    <input type="hidden" id="projectID" value="{{.ProjectID}}">
   252    <input type="hidden" id="jobName" value="{{.JobName}}">
   253    <input type="hidden" id="invID" value="{{.InvID}}">
   254    <div class="btn-group btn-group-xs" role="group">
   255      <button {{if not .CanAbort}}disabled{{end}} type="button"
   256              class="btn btn-danger"
   257              onclick="postInvocationAction(this, 'abortInvocation')">
   258        Abort
   259      </button>
   260    </div>
   261  </form>
   262  {{end}}
   263  
   264  
   265  {{define "job-id-ref"}}
   266  <span class="glyphicon {{.JobFlavorIcon}}" aria-hidden="true" title="{{.JobFlavorTitle}}">
   267  </span>
   268  <a href="/jobs/{{.ProjectID}}/{{.JobName}}">{{.JobName}}</a>
   269  {{end}}
   270  
   271  {{define "job-id-static"}}
   272  <span class="glyphicon {{.JobFlavorIcon}}" aria-hidden="true" title="{{.JobFlavorTitle}}">
   273  </span>
   274  {{.JobName}}
   275  {{end}}
   276  
   277  {{define "triggers-list"}}
   278  <ul>
   279    {{range .}}
   280    <li>
   281      <span style="font-family:monospace;">
   282      {{if .URL}}
   283        <a href="{{.URL}}" target="_blank">{{.Title}}</a>
   284      {{else}}
   285        {{.Title}}
   286      {{end}}
   287      </span>
   288      ({{.RelTime}}{{if .EmittedBy}} by <b>{{.EmittedBy}}</b>{{end}})
   289    </li>
   290    {{end}}
   291  </ul>
   292  {{end}}