2015-09-13 20:25:26 +00:00
<!doctype html>
2020-06-19 00:13:09 +00:00
< html lang = "en" >
2015-09-13 20:25:26 +00:00
< 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" >
2015-11-01 10:34:18 +00:00
< meta name = "apple-mobile-web-app-capable" content = "yes" / >
2019-03-29 19:43:16 +00:00
< link rel = "apple-touch-icon-precomposed" href = "favicon-152.png" >
< link rel = "icon" href = "favicon.ico" >
2020-06-26 22:45:47 +00:00
< link rel = "manifest" href = "/manifest.webmanifest" >
2015-09-13 20:25:26 +00:00
< title > Laminar< / title >
2019-03-29 19:43:16 +00:00
< 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 >
2018-08-24 09:15:40 +00:00
2020-06-26 22:45:47 +00:00
< link href = "style.css" rel = "stylesheet" >
< link href = "custom/style.css" rel = "stylesheet" >
2015-09-13 20:25:26 +00:00
< / head >
< body >
2020-06-26 22:45:47 +00:00
< 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 >
2017-07-13 18:57:28 +00:00
< / div >
2020-06-26 22:45:47 +00:00
< / 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 >
2017-07-13 18:57:28 +00:00
< / div >
2020-06-26 22:45:47 +00:00
< 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)}} %< / td > < / tr >
< / table >
2018-09-08 15:16:23 +00:00
< / div >
2020-06-26 22:45:47 +00:00
< div >
< h3 > Utilization< / h3 >
< div > < canvas id = "chartUtil" > < / canvas > < / div >
2018-09-08 15:16:23 +00:00
< / div >
2020-06-26 22:45:47 +00:00
< / div >
2020-09-04 01:08:34 +00:00
< 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 > < canvas id = "chartBuildTimeDist" > < / canvas > < / div >
2020-06-26 22:45:47 +00:00
< / div >
< / section >
2017-07-13 18:57:28 +00:00
< / div > < / template >
2020-06-26 22:45:47 +00:00
2017-07-13 18:57:28 +00:00
< template id = "jobs" > < div >
2020-06-26 22:45:47 +00:00
< 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 >
2017-07-13 18:57:28 +00:00
< / div >
2020-06-26 22:45:47 +00:00
< input class = "form-control" id = "jobFilter" v-model = "search" placeholder = "Filter..." >
< / 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 >
2017-07-13 18:57:28 +00:00
< / div > < / template >
2020-06-26 22:45:47 +00:00
< 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')" > < / a > < / th >
< th > Run < a class = "sort" :class = "(sort.field=='number'?sort.order:'')" v-on:click = "do_sort('number')" > < / a > < / th >
< th class = "text-center" > Started < a class = "sort" :class = "(sort.field=='started'?sort.order:'')" v-on:click = "do_sort('started')" > < / a > < / th >
< th class = "text-center" > Duration < a class = "sort" :class = "(sort.field=='duration'?sort.order:'')" v-on:click = "do_sort('duration')" > < / 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')" > < / a > < / th >
< / tr > < / thead >
< tr v-show = "nQueued" >
2020-09-25 03:29:30 +00:00
< td style = "width:1px" > < span v-html = "runIcon('queued')" > < / span > < / td >
< td colspan = "4" > < i > {{nQueued}} run(s) queued< / i > < / td >
2020-06-26 22:45:47 +00:00
< / 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" > « < / button >
< span > Page {{sort.page+1}} of {{pages}}< / span >
< button class = "btn" v-on:click = "page_next" :disabled = "sort.page==pages-1" > » < / button >
2015-09-20 17:57:05 +00:00
< / div >
2015-09-13 20:25:26 +00:00
< / div >
2017-07-13 18:57:28 +00:00
< / div > < / template >
2020-06-26 22:45:47 +00:00
< template id = "run" > < div style = "display: grid; grid-template-rows: auto 1fr" >
< div style = "padding: 15px" >
2020-09-04 01:10:09 +00:00
< div style = "display: grid; grid-template-columns: auto 25px auto auto 1fr 400px; gap: 5px; align-items: center" >
2020-06-26 22:45:47 +00:00
< 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" > « < / router-link >
< router-link :disabled = "$route.params.number == latestNum" :to = "'/jobs/'+$route.params.name+'/'+(parseInt($route.params.number)+1)" tag = "button" > » < / router-link >
2020-09-04 01:10:09 +00:00
< 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 >
2017-07-13 18:57:28 +00:00
< / div >
2020-06-26 22:45:47 +00:00
< 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 >
2020-09-25 03:29:30 +00:00
< 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 >
2020-06-26 22:45:47 +00:00
< dt v-show = "runComplete(job)" > Completed< / dt > < dd v-show = "job.completed" > {{formatDate(job.completed)}}< / dd >
2020-09-25 03:29:30 +00:00
< dt v-show = "job.started" > Duration< / dt > < dd v-show = "job.started" > {{formatDuration(job.started, job.completed)}}< / dd >
2020-06-26 22:45:47 +00:00
< / 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 >
2017-07-13 18:57:28 +00:00
< / div >
< / div > < / template >
2020-06-26 22:45:47 +00:00
< main id = "app" style = "display: grid; grid-template-rows: auto 1fr auto; height: 100%;" >
2020-07-03 03:13:11 +00:00
< nav id = "nav-top" style = "display: grid; grid-template-columns: auto auto 1fr auto auto; grid-gap: 15px;" >
2020-06-26 22:45:47 +00:00
< 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 >
2020-07-03 03:13:11 +00:00
< span class = "version" > {{version}}< / span >
2020-06-26 22:45:47 +00:00
< 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 >
2017-07-13 18:57:28 +00:00
< / div >
< / nav >
< router-view > < / router-view >
2020-06-26 22:45:47 +00:00
< div id = "connecting-overlay" :class = "{shown:!connected}" >
< div > < span v-html = "runIcon('running')" > < / span > Connecting...< / div >
< / div >
< / main >
2015-09-13 20:25:26 +00:00
< / body >
< / html >