<!doctype html>
<html lang="en">
<head>
 <base href="/">
 <meta charset="utf-8">
 <meta http-equiv="X-UA-Compatible" content="IE=edge">
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <meta name="apple-mobile-web-app-capable" content="yes" />
 <link rel="apple-touch-icon-precomposed" href="favicon-152.png">
 <link rel="icon" href="favicon.ico">
 <link rel="manifest" href="/manifest.webmanifest">
 <title>Laminar</title>
 <script src="js/vue.min.js"></script>
 <script src="js/vue-router.min.js"></script>
 <script src="js/ansi_up.js"></script>
 <script src="js/Chart.min.js"></script>
 <script src="js/app.js" defer></script>

 <link href="style.css" rel="stylesheet">
 <link href="custom/style.css" rel="stylesheet">
</head>
<body>
 <template id="home"><div id="page-home-main">
  <nav>
   <table class="table striped">
    <tr v-for="job in jobsQueued">
     <td><router-link  :to="'/jobs/'+job.name">{{job.name}}</router-link> <i>queued</i></td>
    </tr>
    <tr v-for="job in jobsRunning">
     <td>
      <span v-html="runIcon(job.result)"></span>
      <router-link :to="'/jobs/'+job.name">{{job.name}}</router-link>
      <router-link :to="'/jobs/'+job.name+'/'+job.number">#{{job.number}}</router-link>
      <small style="float:right;">{{formatDuration(job.started, job.completed)}}</small>
      <div class="progress" style="margin-top: 5px;">
       <div class="progress-bar" :class="{overtime:job.overtime,indeterminate:!job.etc}" :style="job.etc && {width:job.progress+'%'}"></div>
      </div>
     </td>
    </tr>
    <tr v-for="job in jobsRecent">
     <td>
      <span v-html="runIcon(job.result)"></span>
      <router-link :to="'/jobs/'+job.name">{{job.name}}</router-link>
      <router-link :to="'/jobs/'+job.name+'/'+job.number">#{{job.number}}</router-link><br>
      <small>Took {{formatDuration(job.started, job.completed)}} at {{formatDate(job.started)}}</small>
     </td>
    </tr>
   </table>
  </nav>
  <section style="border-left: 1px solid #d0d0d0;">
   <div id="page-home-stats">
    <div>
     <h3>Recent regressions</h3>
     <table>
      <tr v-for="job in resultChanged" v-if="job.lastFailure>job.lastSuccess"><td><router-link :to="'/jobs/'+job.name+'/'+job.lastFailure">{{job.name}} #{{job.lastFailure}}</router-link> since <router-link :to="'/jobs/'+job.name+'/'+job.lastSuccess">#{{job.lastSuccess}}</router-link></tr>
     </table>
    </div>
    <div>
     <h3>Low pass rates</h3>
     <table>
      <tr v-for="job in lowPassRates"><td><router-link :to="'/jobs/'+job.name">{{job.name}}</router-link></td><td>{{Math.round(job.passRate*100)}}&nbsp;%</td></tr>
     </table>
    </div>
    <div>
     <h3>Utilization</h3>
     <div><canvas id="chartUtil"></canvas></div>
    </div>
   </div>
   <div id="page-home-plots">
    <div><canvas id="chartBpd"></canvas></div>
    <div><canvas id="chartBpj"></canvas></div>
    <div><canvas id="chartTpj"></canvas></div>
    <div><canvas id="chartBuildTimeChanges"></canvas></div>
   </div>
  </section>
 </div></template>
  
 <template id="jobs"><div>
  <nav style="display: grid; grid-auto-flow: column; justify-content: space-between; align-items: end; padding: 10px 15px;">
   <div style="display:grid; grid-auto-flow: column; grid-gap: 15px; padding: 5px 0;">
    <a v-show="ungrouped.length" :class="{'active':group==null}" href v-on:click.prevent="group = null">Ungrouped Jobs</a>
    <a v-for="g in Object.keys(groups)" :class="{'active':g==group}" href v-on:click.prevent="group = g">{{g}}</a>
   </div>
   <div style="display: grid; grid-auto-flow: column; align-items: center; gap: 15px">
    <router-link :to="wallboardLink()" style="display: inherit;" title="Wallboard">
     <svg width="18" viewBox="0 0 13 13">
      <g fill="#728494">
       <rect x="0" y="2" width="6" height="4" />
       <rect x="0" y="7" width="6" height="4" />
       <rect x="7" y="2" width="6" height="4" />
       <rect x="7" y="7" width="6" height="4" />
      </g>
     </svg>
    </router-link>
    <input class="form-control" id="jobFilter" v-model="search" placeholder="Filter...">
   </div>
  </nav>
  <table class="striped" id="job-list">
    <tr v-for="job in filteredJobs()">
    <td><router-link :to="'/jobs/'+job.name">{{job.name}}</router-link></td>
    <td style="white-space: nowrap;"><span v-html="runIcon(job.result)"></span> <router-link :to="'/jobs/'+job.name+'/'+job.number">#{{job.number}}</router-link></td>
    <td>{{formatDate(job.started)}}</td>
    <td>{{formatDuration(job.started,job.completed)}}</td>
    </tr>
  </table>
 </div></template>
 
 <template id="wallboard"><div class="wallboard">
  <router-link :to="'/jobs/'+job.name+'/'+job.number" tag="div" v-for="job in wallboardJobs()" :data-result="job.result">
   <span style="font-size: 36px; font-weight: bold;">{{job.name}} #{{job.number}}</span><br>
   <span style="font-size: 30px;">{{formatDate(job.started)}}</span><br>
   <span style="font-size: 26px;">{{job.reason}}</span>
  </router-link>
 </div></template>

 <template id="job"><div id="page-job-main">
  <div style="padding: 15px;">
   <h2>{{$route.params.name}}</h2>
   <div v-html="description"></div>
   <dl>
    <dt>Last Successful Run</dt>
    <dd><router-link v-if="lastSuccess" :to="'/jobs/'+$route.params.name+'/'+lastSuccess.number">#{{lastSuccess.number}}</router-link> {{lastSuccess?' - at '+formatDate(lastSuccess.started):'never'}}</dd>
    <dt>Last Failed Run</dt>
    <dd><router-link v-if="lastFailed" :to="'/jobs/'+$route.params.name+'/'+lastFailed.number">#{{lastFailed.number}}</router-link> {{lastFailed?' - at '+formatDate(lastFailed.started):'never'}}</dd>
   </dl>
  </div>
  <div style="display: grid; justify-content: center; padding: 15px;">
   <canvas id="chartBt"></canvas>
  </div>
  <div style="grid-column: 1/-1">
   <table class="striped">
    <thead><tr>
     <th><a class="sort" :class="(sort.field=='result'?sort.order:'')" v-on:click="do_sort('result')">&nbsp;</a></th>
     <th>Run <a class="sort" :class="(sort.field=='number'?sort.order:'')" v-on:click="do_sort('number')">&nbsp;</a></th>
     <th class="text-center">Started <a class="sort" :class="(sort.field=='started'?sort.order:'')" v-on:click="do_sort('started')">&nbsp;</a></th>
     <th class="text-center">Duration <a class="sort" :class="(sort.field=='duration'?sort.order:'')" v-on:click="do_sort('duration')">&nbsp;</a></th>
     <th class="text-center vp-sm-hide">Reason <a class="sort" :class="(sort.field=='reason'?sort.order:'')" v-on:click="do_sort('reason')">&nbsp;</a></th>
    </tr></thead>
    <tr v-show="nQueued">
     <td style="width:1px"><span v-html="runIcon('queued')"></span></td>
     <td colspan="4"><i>{{nQueued}} run(s) queued</i></td>
    </tr>
    <tr v-for="job in jobsRunning.concat(jobsRecent)" track-by="$index">
     <td style="width:1px"><span v-html="runIcon(job.result)"></span></td>
     <td><router-link :to="'/jobs/'+$route.params.name+'/'+job.number">#{{job.number}}</router-link></td>
     <td class="text-center">{{formatDate(job.started)}}</td>
     <td class="text-center">{{formatDuration(job.started, job.completed)}}</td>
     <td class="text-center vp-sm-hide">{{job.reason}}</td>
    </tr>
   </table>
   <div style="float: right; margin: 15px; display: inline-grid; grid-auto-flow: column; gap: 10px; align-items: center">
    <button v-on:click="page_prev" :disabled="sort.page==0">&laquo;</button>
    <span>Page {{sort.page+1}} of {{pages}}</span>
    <button class="btn" v-on:click="page_next" :disabled="sort.page==pages-1">&raquo;</button>
   </div>
  </div>
 </div></template>
 
 <template id="run"><div style="display: grid; grid-template-rows: auto 1fr">
  <div style="padding: 15px">
   <div style="display: grid; grid-template-columns: auto 25px auto auto 1fr 400px; gap: 5px; align-items: center">
    <h2 style="white-space: nowrap"><span v-html="runIcon(job.result)"></span> {{$route.params.name}} #{{$route.params.number}}</h2>
    <span></span>
    <router-link :disabled="$route.params.number == 1" :to="'/jobs/'+$route.params.name+'/'+($route.params.number-1)" tag="button">&laquo;</router-link>
    <router-link :disabled="$route.params.number == latestNum" :to="'/jobs/'+$route.params.name+'/'+(parseInt($route.params.number)+1)" tag="button">&raquo;</router-link>
    <span></span>
    <div class="progress" v-show="job.result == 'running'">
     <div class="progress-bar" :class="{overtime:job.overtime,indeterminate:!job.etc}" :style="job.etc && {width:job.progress+'%'}"></div>
    </div>
   </div>
   <div id="page-run-detail">
    <dl>
     <dt>Reason</dt><dd>{{job.reason}}</dd>
     <dt v-show="job.upstream.num > 0">Upstream</dt><dd v-show="job.upstream.num > 0"><router-link :to="'/jobs/'+job.upstream.name">{{job.upstream.name}}</router-link> <router-link :to="'/jobs/'+job.upstream.name+'/'+job.upstream.num">#{{job.upstream.num}}</router-link></li></dd>
     <dt>Queued for</dt><dd>{{formatDuration(job.queued, job.started ? job.started : Math.floor(Date.now()/1000))}}</dd>
     <dt v-show="job.started">Started</dt><dd v-show="job.started">{{formatDate(job.started)}}</dd>
     <dt v-show="runComplete(job)">Completed</dt><dd v-show="job.completed">{{formatDate(job.completed)}}</dd>
     <dt v-show="job.started">Duration</dt><dd v-show="job.started">{{formatDuration(job.started, job.completed)}}</dd>
    </dl>
    <dl v-show="job.artifacts.length">
     <dt>Artifacts</dt>
     <dd>
      <ul style="margin-bottom: 0">
       <li v-for="art in job.artifacts"><a :href="art.url" target="_self">{{art.filename}}</a> [{{ art.size | iecFileSize }}]</li>
      </ul>
     </dd>
    </dl>
   </div>
  </div>
  <div class="console-log">
   <code v-html="log"></code>
   <span v-show="job.result == 'running'" v-html="runIcon('running')" style="display: block;"></span>
  </div>
 </div></template>

 <main id="app" style="display: grid; grid-template-rows: auto 1fr auto; height: 100%;">
  <nav id="nav-top" style="display: grid; grid-template-columns: auto auto 1fr auto auto; grid-gap: 15px;">
   <router-link to="/" style="display: grid; grid-auto-flow: column; align-items: center; margin: 5px; font-size: 20px;">
    <img src="icon.png"> {{title}}
   </router-link>
   <div id="nav-top-links" style="display: grid; grid-auto-flow: column; justify-content: start; gap: 15px; padding: 0 15px; align-items: center; font-size: 16px;">
    <router-link to="/jobs">Jobs</router-link>
    <router-link v-for="(crumb,i) in _route.path.slice(1).split('/').slice(1,-1)" :to="_route.path.split('/').slice(0,i+3).join('/')">{{crumb}}</router-link>
   </div>
   <div></div>
   <span class="version">{{version}}</span>
   <div style="display: grid; align-items: center; padding: 0 15px">
    <a v-on:click="toggleNotifications(!notify)" class="nav-icon" :class="{active:notify}" v-show="supportsNotifications" :title="(notify?'Disable':'Enable')+' notifications'">
     <svg width="18" viewBox="0 0 12 12">
      <g stroke-width="0.5">
       <path d="m 6,9 c -1,0 -1,0 -1,1 0,1 2,1 2,0 0,-1 0,-1 -1,-1 z" />
       <path d="m 1,10 c 3,-3 1,-9 5,-9 4,0 2,6 5,9 1,1 -3,-1 -5,-1 -2,0 -6,2 -5,1 z" />
      </g>
     </svg>
    </a>
   </div>
  </nav>
  <router-view></router-view>
  <div id="connecting-overlay" :class="{shown:!connected}">
   <div><span v-html="runIcon('running')"></span> Connecting...</div>
  </div>
 </main>
</body>
</html>

