From 9965555d11ce04baff45c570950daf00837412ae Mon Sep 17 00:00:00 2001 From: Pascal Aschwanden Date: Mon, 13 Feb 2023 16:48:16 -0800 Subject: [PATCH 01/16] huge accordion feature and a lot of other stuff from the last 4 months. --- README.md | 8 +- src/psij/testing/service.py | 126 ++- src/psij/web/css/style.css | 785 ++++++++++++++++++ src/psij/web/{ => imgs}/checkmark.png | Bin src/psij/web/imgs/exaworks-name.png | Bin 0 -> 61782 bytes src/psij/web/instance/customization-psij.js | 77 ++ src/psij/web/instance/customization-sdk.js | 54 ++ .../web/js/BuildAccordionModelFromSites.js | 101 +++ src/psij/web/js/RowAccordion.js | 66 ++ src/psij/web/js/SitesModel.js | 338 ++++++++ src/psij/web/js/common.js | 10 + src/psij/web/{ => js}/lib.js | 150 +++- src/psij/web/js/summary.js | 186 +++++ src/psij/web/run.html | 16 +- src/psij/web/site.html | 14 +- src/psij/web/style.css | 549 ------------ src/psij/web/summary.html | 377 ++++----- src/psij/web/tests/testREST.js | 17 + 18 files changed, 2059 insertions(+), 815 deletions(-) create mode 100644 src/psij/web/css/style.css rename src/psij/web/{ => imgs}/checkmark.png (100%) create mode 100644 src/psij/web/imgs/exaworks-name.png create mode 100644 src/psij/web/instance/customization-psij.js create mode 100644 src/psij/web/instance/customization-sdk.js create mode 100644 src/psij/web/js/BuildAccordionModelFromSites.js create mode 100644 src/psij/web/js/RowAccordion.js create mode 100644 src/psij/web/js/SitesModel.js create mode 100644 src/psij/web/js/common.js rename src/psij/web/{ => js}/lib.js (77%) create mode 100644 src/psij/web/js/summary.js delete mode 100644 src/psij/web/style.css create mode 100644 src/psij/web/tests/testREST.js diff --git a/README.md b/README.md index 1725a80..b60a29b 100644 --- a/README.md +++ b/README.md @@ -1 +1,7 @@ -# psi-j-testing-service \ No newline at end of file +# psij-testing-service + +# Helpful aliases: +# for starting the Back end. +alias start='cd ~/psi-j-testing-service;python3 src/psij/testing/service.py' + +# set up sym links like this: ln -s customization-psij.js customization.js diff --git a/src/psij/testing/service.py b/src/psij/testing/service.py index adcaabb..f7e1bd9 100644 --- a/src/psij/testing/service.py +++ b/src/psij/testing/service.py @@ -97,6 +97,13 @@ def iterencode(self, value): yield chunk.encode("utf-8") +def add_cors_headers(): + headers = cherrypy.response.headers + headers['Access-Control-Allow-Origin'] = '*' + headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS' + headers['Access-Control-Allow-Headers'] = 'Content-Type, Accept' + + class TestingAggregatorApp(object): def __init__(self): self.seq = 0 @@ -121,18 +128,22 @@ def result(self) -> None: if not site: raise cherrypy.HTTPError(403, 'This ID is associated with another key') - self.seq += 1 - self._save_test(site_id, data) - - module = data['module'] - function = data['function'] - if module == '_conftest': - if function == '_discover_environment': - self._save_environment(site, data) - if function == '_end': - self._end_tests(site_id, data) - - self._update_totals(site_id, data) + try: + self.seq += 1 + self._save_test(site_id, data) + + module = data['module'] + function = data['function'] + if module == '_conftest': + if function == '_discover_environment': + self._save_environment(site, data) + if function == '_end': + self._end_tests(site_id, data) + + self._update_totals(site_id, data) + except: + logger.info('Request json: %s' % json) + raise def _update_totals(self, site_id, data: Dict[str, object]) -> None: run_id = data['run_id'] @@ -206,6 +217,7 @@ def summary(self, inactiveTimeout: str = "10") -> object: # get latest batch of tests on each site and return totals for passed/failed now = datetime.datetime.now(datetime.timezone.utc) + try: iInactiveTimeout = int(inactiveTimeout) date_limit = now - datetime.timedelta(days=iInactiveTimeout) @@ -306,7 +318,7 @@ def summary(self, inactiveTimeout: str = "10") -> object: date_start = date_start + datetime.timedelta(days=-1) - + add_cors_headers() return resp @cherrypy.expose @@ -338,6 +350,7 @@ def site(self, site_id) -> object: 'completed_count': run.completed_count }) + add_cors_headers() return resp @cherrypy.expose @@ -367,8 +380,90 @@ def run(self, site_id, run_id) -> object: del test_dict['_id'] test_list.append(test_dict) + add_cors_headers() return resp + @cherrypy.expose + @cherrypy.tools.json_out() + def tests(self, sites_to_get, tests_to_match) -> object: + + import json + sites_to_get = json.loads(sites_to_get) + tests_to_match = json.loads( tests_to_match) + + # Example sites_to_get = ["mothra.hidden.uoregon.edu", "reptar.hidden.uoregon.edu", "saturn.hidden.uoregon.edu"] + resp = {} + + for site_id in sites_to_get: + resp[site_id] = self.getSite(site_id, tests_to_match) + + add_cors_headers() + return resp + + + def getSite(self, site_id, tests_to_match): + # Example site_id="mothra.hidden.uoregon.edu" + run_id = "" + + try: + run_id = RunEnv.objects(site_id=site_id, + branch__in=['main','master']).order_by('-run_start_time')[0].run_id + except: + run_id = "" + + + resp = {} + resp['site_id'] = site_id + resp['run_id'] = run_id + branches = [] + resp['branches'] = branches + + runs = RunEnv.objects(site_id=site_id,run_id=run_id).order_by('+run_start_time') + + for run in runs: + + test_list = [] + branch = run.to_mongo().to_dict() + + branch['tests'] = test_list + branch['name'] = run.branch + branches.append(branch) + + tests = Test.objects(site_id=site_id, run_id=run_id, + branch=run.branch, + test_name__in=tests_to_match).order_by('+test_start_time') + + for test in tests: + test_dict = test.to_mongo().to_dict() + del test_dict['_id'] + test_list.append(test_dict) + + + resBySiteIdAndTestName = {} + brs = resp['branches'] + + for testContainer in brs: + + for oneTest in testContainer['tests']: + + testName = oneTest['test_name'] + + foundMatch = 0 + + for test in tests_to_match: + if testName == test: + foundMatch = 1 + + branchMatch = oneTest['branch'] == 'master' + + if foundMatch == 1: + resBySiteIdAndTestName[testName] = oneTest['results'] + resBySiteIdAndTestName[testName]['branch'] = oneTest['branch'] + resBySiteIdAndTestName[testName]['test_start_time'] = oneTest['test_start_time'] + + return resBySiteIdAndTestName + + class Server: def __init__(self, port: int = 9909) -> None: self.port = port @@ -392,11 +487,6 @@ def json_handler(*args, **kwargs): 'tools.staticdir.on': True, 'tools.staticdir.dir': '', 'tools.json_out.handler': json_handler - }, - '/instance': { - 'tools.staticdir.root': '/var/www/html', - 'tools.staticdir.on': True, - 'tools.staticdir.dir': '', } }) diff --git a/src/psij/web/css/style.css b/src/psij/web/css/style.css new file mode 100644 index 0000000..37c4985 --- /dev/null +++ b/src/psij/web/css/style.css @@ -0,0 +1,785 @@ +/*@import url("fontawesome-all.min.css");*/ +@import url("https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,300italic,400,400italic,600"); + + +#toolbar { + position: relative; + width: 100%; + text-align: right; + margin-bottom: 32pt; + background-color: #FEB88B; + background-image: linear-gradient(180deg, #FEB88B 0%, #DE6261 74%); + padding: 15px 0 0 0; + height: 52px; +} + +#toolbar .spacer { + display: inline-block; + width: 8pt; +} + +#breadcrumbs { + position: absolute; + top: 32px; + background-color: #FEd8aB; + border: 1px solid #DE6261; + z-index: 2; +} + +#breadcrumbs .v-breadcrumbs__divider { + color: #DE6261; +} + +#breadcrumbs .v-breadcrumbs { + margin: 0pt; + padding-bottom: 0; + padding-top: 0; +} + +#breadcrumbs li:not(.v-breadcrumbs__divider) { + display: inline-block; + cursor: pointer; + padding: 1pt; + color: #DE6261; +} + +#breadcrumbs li { + font-size: 12px; +} + +#breadcrumbs a:visited { + color: #DE6261; +} + +#breadcrumbs li:hover:not(.v-breadcrumbs__divider) { + color: #DE6261; +} + +body { + background-color: #ffffff; + font-family: "Source Sans Pro", "open sans", Helvetica, sans; +} + +.page-name { + margin-bottom: 16pt; +} + +#container { + max-width: 1024px; + margin-left: auto; + margin-right: auto; +} + +#status-tiles { +} + +.status-tile { + display: inline-block; + margin: 4pt; + background-color: #e0e0e0; + border: 1pt solid #a0a0a0; + border-radius: 4pt; + width: 300px; + height: 80pt; + z-index: 20; +} + +.site-label { + display: flex; + justify-content: center; + align-items: center; + height: 18pt; + font-size: 12pt; + font-weight: bold; + color: #202020; +} + +.branch-tiles { + float: left; +} + +.branch-tile { + position: relative; + display: inline-block; + width: 150px; + height: 16pt; + font-size: 8.5pt; + padding: 2pt; + padding-top: 1pt; + border: 1pt solid #a0a0a0; + margin-top: -1pt; + margin-left: -1pt; + background-color: #c0ffa0; + z-index: 10; +} + +.branch-tile-name { + width: 80pt; + overflow: hidden; + text-overflow: ellipsis; +} + +.branch-tile .counts { + position: absolute; + right: 1pt; + top: 1pt; + height: 16pt; +} + +.clickable { + cursor: pointer; +} + +.branch-ellipsis { + width: 80pt; + text-align: center; +} + +.site-running { + display: inline; + float: right; + top: 0; +} + +.counts { + font-weight: bold; + display: inline-block; + float: right; +} + +.failed-count { + display: inline-block; + padding-top: 1pt; + padding-left: 4pt; + padding-right: 4pt; + padding-bottom: 1pt; + background-color: rgba(255, 0, 0, 0.60); + color: #ffffff; + border-radius: 2pt; + height: 16pt; + margin-top: -2pt; +} + +.status-tile.state-somewhat-bad { + background-color: #f0f0d0; +} + +.status-tile.state-really-bad { + background-color: #f0e0e0; +} + +.status-tile.state-good { + background-color: #e0f0e0; +} + +.branch-tile.state-somewhat-bad, +.branch-heading.state-somewhat-bad, +.site-heading.state-somewhat-bad { + background-color: #ffefa0; +} + +.branch-tile.state-really-bad, +.branch-heading.state-really-bad, +.site-heading.state-really-bad { + background-color: #ffb0a0; +} + +.branch-tile.state-good, +.branch-heading.state-good, +.site-heading.state-good { + background-color: #b0ffa0; +} + +.check-mark { + height: 10pt; +} + + + +.dashboard-title { + position: absolute; + left: 15px; + top: 8px; + color: #ffffff; + font-size: 14px; + font-weight: bold; +} + +.main-section { + padding: 35px 0 25px 0; +} +#toolbar .button { + display: inline-block; + cursor: pointer; + background-color: #FEB88B; + padding: 5px 9px 6px 9px; + border-top: 1px solid #DE6261; + border-left: 1px solid #DE6261; + border-right: 1px solid #DE6261; + border-bottom: 1px solid #DE6261; + margin: 0 5px 0 0; + border-top-right-radius: 5px; + border-top-left-radius: 5px; +} + +#toolbar .button.selected { + background-color: #ffffff !important; + border-bottom: 1px solid white; +} + +.branch-heading { + display: inline-block; + font-size: 11pt; + width: 190px; + padding: 4pt; + border: 1pt solid #a0a0a0; + border-radius: 4pt; + margin: 0; +} + +.site-heading { + display: inline-block; + width: 180pt; + border: 1pt solid #a0a0a0; + border-radius: 4pt; + padding: 7px; + margin: 4pt; +} + +#status-table .site-branch-cell { + padding: 7px; +} +.site-branch-cell { + position: relative; + width: 190px; + border: 1pt solid #a0a0a0; + margin: 4pt; + padding: 4pt; + padding-right: 8pt; + text-align: center; + overflow: hidden; + text-overflow: ellipsis; +} + +.site-branch-cell-name { + width: 100pt; + overflow: hidden; + text-overflow: ellipsis; +} + +.site-branch-cell .counts { + position: absolute; + top: 6pt; + right: 2pt; +} + +.site-branch-cell.state-somewhat-bad { + background-color: #f0f0d0; +} + +.site-branch-cell.state-really-bad { + background-color: #f0e0e0; +} + +.site-branch-cell.state-good { + background-color: #e0f0e0; +} + +.site-branch-cell:not(.absent) { + cursor: pointer; +} + +.site-branch-cell.absent { + border: none; +} + + +.split-cell { + position: relative; + padding: 4pt; + border: thin solid #808080; + border-radius: 4pt; + background-color: #f0f0f0; + background-image: -webkit-linear-gradient(80deg, #f0f0f0 50%, #e0e0e0 50%); +} + +.split-cell-bottom-left { + position: absolute; + bottom: 4pt; + left: 4pt; +} + +.split-cell-top-right { + position: absolute; + top: 4pt; + right: 4pt; +} + +#run-table { + font-size: 11pt; + text-align: left; +} + +#col-run-time { + width: 160pt; +} + +#col-run-id { + width: 80pt; +} + +#run-table th, #run-table td { + padding: 6pt; +} + +td.run-id { + font-family: monospace; +} + +.run-branch { + display: inline-block; +} + +#run-table .site-branch-cell { + margin: 0pt; + text-align: left; +} + +#run-table .site-branch-cell .counts { + float: right; +} + +.branch-list-summary { + margin-bottom: 16pt; +} + +.branch-list h2 { + display: block; +} + +.run-env th { + text-align: left; +} + +.run-env .env-name { + text-align: right; + padding-right: 8pt; +} + +.run-env .col-env-name { + width: 120pt; +} + +.run-env .col-env-value { + width: 180pt; +} + +.run-branch .site-branch-cell { + font-size: 11pt; +} + +.branch { + margin-top: 8pt; +} + +#container .theme--light.v-expansion-panels .v-expansion-panel { + background-color: #f0f0f0; + transition: .1s cubic-bezier(.25,.8,.5,1); + margin: 4pt; + border-radius: 4pt; + min-height: 32pt; +} + +.run-env tr { + font-size: 11pt; + height: 20pt; +} + +.run-env .env-name, .run-env .env-value { + padding-top: 4pt; + vertical-align: top; +} + +.executor-name { + display: inline-block; + margin-top: -2pt; + padding: 2pt; + padding-left: 4pt; + padding-right: 4pt; + background-color: #f7f7f7; + border: thin solid #e0e0e0; + border-radius: 2pt; +} + +.listing { + width: 500pt; + white-space: pre; + font-size: 9pt; + font-family: monospace; + background-color: #d0d0d0; + border: thin solid #c0c0c0; + border-radius: 4pt; + overflow: auto; + padding: 4pt; + margin-top: -4pt; +} + +.listing-log { + max-height: 256pt; + white-space: pre-wrap; +} + +.env-missing-value.material-icons { + display: inline-block; + font-size: 16pt; + margin-top: -3pt; + color: #808080; +} + +.branch-tests { + margin-left: 16pt; +} + +.branch-tests .v-expansion-panel-header { + margin: 2pt; + padding: 2pt; + min-height: 16pt; +} + +#container .branch-tests .theme--light.v-expansion-panels .v-expansion-panel { + background-color: #e0e0e0; + margin: 2pt; + min-height: 0pt; +} + +.branch-tests .v-expansion-panel { + margin: 4pt; + padding: 2pt; + background-color: #d0d0d0; + border: thin solid #c0c0c0; + border-radius: 4pt; +} + +#container .branch-tests .theme--light.v-expansion-panels .v-expansion-panel .test-status { + position: absolute; + right: 8pt; + font-weight: bold; +} + +#container .branch-tests .theme--light.v-expansion-panels .v-expansion-panel.test-status-passed .test-status { + color: #20a000; +} + +#container .branch-tests .theme--light.v-expansion-panels .v-expansion-panel.test-status-failed .test-status { + color: rgba(255, 0, 0, 0.7); +} + +#container .branch-tests .theme--light.v-expansion-panels .v-expansion-panel.test-status-skipped .test-status { + color: rgba(180, 180, 180, 0.7); +} + + +.test-failure { + padding-bottom: 12pt; + padding-left: 8pt; + width: 600pt; +} + +.ansi-bright-green-fg { + color: rgb(30, 140, 0); +} + +.ansi-bright-blue-fg { + color: rgb(0, 0, 180); +} + +.ansi-bright-red-fg { + color: rgb(255, 0, 0); +} + +.ansi-red-fg { + color: rgb(180, 0, 0); +} + + +#status-calendar table { + position: relative; + width: 100%; + border-spacing: 0; +} + +#status-calendar tr:first-child th { + position: sticky; + top: 0pt; +} + +#status-calendar tr:first-child th { + background-color: #DE6261; + color: white; + font-weight: bold; +} + +#status-calendar tr td, +#status-calendar tr th { + background-color: #e2e2e2; + border-bottom: 1px solid #cfcfcf; +} + +#status-calendar tr:nth-child(even) td, +#status-calendar tr:nth-child(even) th { + background-color: #f2f2f2; +} + + +.calendar-month { + height: 14pt; + font-weight: normal; + font-size: 9pt; + padding-top: 5px; + width: 60pt; +} + +.calendar-day { + height: 18pt; + font-weight: normal; + font-size: 11pt; + padding-bottom: 4pt; +} + +.calendar-site { + text-align: left; + font-weight: normal; + font-size: 11pt; + height: 24pt; + padding: 4pt; +} + +.calendar-tile { + margin-left: auto; + margin-right: auto; + display: flex; + flex-direction: column; + flex-wrap: wrap; + height: 10pt; + align-content: center; +} + +.calendar-bubble { + border-radius: 100pt; + border: 0.5px solid rgba(0, 0, 0, 0.2); + display: inline-block; +} + +.calendar-bubble.state-good { + background-color: rgb(106, 255, 77); +} + +.calendar-bubble.state-somewhat-bad { + background-color: rgb(242, 219, 73); +} + +.calendar-bubble.state-really-bad { + background-color: #ffb0a0; +} + + +.calendar-bubble.bubble-large { + width: 8pt; + height: 8pt; + margin-right: 2pt; +} + +.calendar-bubble.bubble-small { + width: 3pt; + height: 3pt; + margin-right: 1pt; + margin-bottom: 1pt; +} + +.calendar-tile.state-somewhat-bad { + background-color: #f0f0d0; +} + +.calendar-tile.state-really-bad { + background-color: #ff4d4d; +} + +.calendar-tile.state-good { + background-color: #6aff4d; +} + +.calendar-tile.state-unknown { + background-color: #e0e0e0; +} + +.bg { + background-color: #f0f0f0; +} + +.calendar-cell { + text-align: center; +} + +.open_close_arrow { + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 8px solid #444444; + margin-left: 8px; + cursor: pointer; +} + +.open_close_arrow[position="otherPos"] { + display: none; +} + +.open_close_arrow[position="oneRowOnly"] { + display: none; +} + +.open_close_arrow.open { + position: relative; + left: 5px; + border-top: 8px solid transparent; + border-bottom: 8px solid transparent; + border-left: 8px solid #444444; +} + +#settings { + position: relative; + top: -8px; + right: 4px; + border: 1px solid #bE4241; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; + box-shadow: 2px 2px 2px; + -moz-box-shadow: 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px; + cursor: pointer; +} + +#settings:active { + box-shadow: 0 0 0; + -moz-box-shadow: 0 0 0; + -webkit-box-shadow: 0 0 0; + position: relative; + top: -6px; + right: 2px; + cursor: pointer; +} + +.main-exaworks-logo { + position: absolute; + top: 0; + left: 12px; + width: 120px; + height: 27px; + z-index: 200; + padding: 5px 15px; + + background: rgba(255, 255, 255, 0.15); + border: solid 1px; + border-color: #fff; + border-color: rgba(255, 255, 255, 0.75); + border-top: 0; + border-radius: 0 0 0.35em 0.35em; +} + + +.RowAccordion { + border-top: 1px solid #e0e0e1; +} +.RowAccordion td { + width: 90px; + padding: 5px; + position:relative; +} + +.RowAccordion td:first-child { + width: 345px; + cursor: pointer; + color: #333333; +} + +.RowAccordion .logo_name { + font-weight: bold; +} + +.RowAccordion .ArrowDown { + width: 0; + height: 0; + display: inline-block; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 8px solid #333333; + margin-right: 11px; + margin-left: 3px; +} + +.RowAccordion .ArrowRight { + display: inline-block; + width: 0; + height: 0; + border-top: 8px solid transparent; + border-bottom: 8px solid transparent; + border-left: 8px solid #333334; + padding: 0 6px 0 0; + margin-left: 8px; + margin-right: 8px; +} + +.RowAccordion .machineLink { + padding: 5px 5px 5px 35px; +} + +.RowAccordion .rowIsClosed { + display: none; +} + +.RowAccordion .container-for-mini-branches { + width: 15px; + position: absolute; + left: 20px; + top: 11px; +} + + +.AccordionHeader td { + width: 88px; +} + +.AccordionHeader td:first-child { + width: 345px; + cursor: pointer; +} + + + +#status-calendar .topHeader { + width: 293px; +} + +#status-calendar .RowAccordion td { + height: 32px; +} + +#status-calendar td:first-child { + width: 290px; +} + +#status-calendar td.logo_name { + width: 100%; +} + +#status-calendar .schedulerCol { + width: 0; +} + + +#status-calendar th.bg { + text-align: left; +} + + +#curated-sites-home .RowAccordion td { + display: inline-block; +} diff --git a/src/psij/web/checkmark.png b/src/psij/web/imgs/checkmark.png similarity index 100% rename from src/psij/web/checkmark.png rename to src/psij/web/imgs/checkmark.png diff --git a/src/psij/web/imgs/exaworks-name.png b/src/psij/web/imgs/exaworks-name.png new file mode 100644 index 0000000000000000000000000000000000000000..df7f0f17aec0430cc9ed3a60bd26f33bef0b258f GIT binary patch literal 61782 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

rHT44bzY#R1of5G}wWiZk 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 kHUH;&|8Gz1)7zhrLsO(FZ67tZ2mT%#?f?J) literal 0 HcmV?d00001 diff --git a/src/psij/web/instance/customization-psij.js b/src/psij/web/instance/customization-psij.js new file mode 100644 index 0000000..6860046 --- /dev/null +++ b/src/psij/web/instance/customization-psij.js @@ -0,0 +1,77 @@ +CUSTOMIZATION = { + projectName: "PSI/J" +}; + +var CONF = { + backendURL: "https://psij.testing.exaworks.org/", + STR: { + "dashboardTitle": "Exascale dashboard testing service" + }, + "curated_sites": { + xaxis: [ + "Tests Suite", + "Tests", + "Quickstart example", + "Simple Ensemble" + ], + xaxisTests: [ + "test_parallel_jobs[local:mpirun]", + "test_simple_job[slurm:single]", + "test_simple_job[slurm:multiple]" + ], + yaxis: [ + { + logo_src: "", + logo_name: "University of Oregon", + machines: { + "axis1.hidden.uoregon.edu": { + scheduler: "SLURM" + }, + "illyad.hidden.uoregon.edu": { + scheduler: "SLURM" + }, + "jupiter.hidden.uoregon.edu": { + scheduler: "SLURM" + }, + "reptar.hidden.uoregon.edu": { + scheduler: "SLURM" + }, + "saturn.hidden.uoregon.edu": { + scheduler: "SLURM" + }, + "orthus.hidden.uoregon.edu": { + scheduler: "SLURM" + } + } + }, + { + logo_src: "", + logo_name: "Lawrence Livermore National Lab", + machines: { + "doc.llnl.gov": { + scheduler: "SLURM" + } + } + }, + { + logo_src: "", + logo_name: "Nersc National Lab", + machines: { + "cori08.nersc.gov": { + scheduler: "SLURM" + }, + "perlmutter.nersc": { + schedulor: "SLURM" + } + } + }, + { + logo_src: "", + logo_name: "Oakridge National Lab", + machines: { + } + } + ] + } +}; + diff --git a/src/psij/web/instance/customization-sdk.js b/src/psij/web/instance/customization-sdk.js new file mode 100644 index 0000000..4baceb5 --- /dev/null +++ b/src/psij/web/instance/customization-sdk.js @@ -0,0 +1,54 @@ +CUSTOMIZATION = { + projectName: "SDK" +}; + +var CONF = { + backendURL: "https://sdk.testing.exaworks.org/", + STR: { + "dashboardTitle": "Exascale dashboard testing service" + }, + "curated_sites": { + xaxis: [ + "Tests Suites", + "Flux", + "Parsl", + "Parsl-flux", + "RP", + "Swift-t" + ], + xaxisTests: [ + "flux", + "parsl", + "parsl-flux", + "rp", + "swift-t" + ], + yaxis: [ + { + logo_src: "", + logo_name: "Lawrence Livermore National Lab", + machines: { + "llnl-lassen": { + scheduler: "SLURM" + }, + "llnl-quartz": { + scheduler: "SLURM" + }, + "llnl-ruby": { + scheduler: "SLURM" + } + } + }, + { + logo_src: "", + logo_name: "GitHub Actions", + machines: { + "Github Actions": { + scheduler: "none" + } + } + } + ] + } +}; + diff --git a/src/psij/web/js/BuildAccordionModelFromSites.js b/src/psij/web/js/BuildAccordionModelFromSites.js new file mode 100644 index 0000000..9021e18 --- /dev/null +++ b/src/psij/web/js/BuildAccordionModelFromSites.js @@ -0,0 +1,101 @@ +/* + This builds the DataModel for the Calendar View. + It preps the Data for consumption. + */ +PS.BuildAccordionModelFromSites = function() { + + var get_states_ = function( months ) { + + var sts = []; + var objStates = []; + + for( var month in months ) { + + var days = months[month]; + + for( var day in days ) { + + var res = days[day]; + + var sobj = PS.SitesModel.getMainBranch( res.branches ); + + if( sobj === null) { + // case where there are no branches or no main branch. + sobj = { + completed_count:0, + failed_count:0, + name: 'none' + } + } + + var bc = globalMethods.badnessClass(sobj); + sts.push(bc); + + var branches = PS.SitesModel.getBranchesForSmallBubbles( res.branches ); + + objStates.push({ + mainState: bc, + branches: branches + }); + } + } + + return objStates; + }; + + + var get_ = function( accordionModelRef ) { + + // Accordion Model. + var am = []; + var machObjs = {}; + + for( var x=0; x < PS.sites.length; x++ ) { + + var site = PS.sites[x]; + var domain = globalMethods.getDomain(site.site_id); + + machObjs[domain] = machObjs[domain] || []; + machObjs[domain].push({ + machine: site.site_id, + states: get_states_(site.months ) //["state-good","state-good","state-really-bad","state-good","state-good","state-bad", "state-good", "state-good"] + }); + } + + + for( var domain in machObjs ) { + + am.push({ + logo_name: domain, + machinesFromModel: machObjs[domain] + }); + } + + for( var i=0; i < am.length; i++ ) { + accordionModelRef[i] = am[i]; + } + + accordionModelRef.splice(am.length); + + /* EXAMPLE STUB: + return [{ + logo_name: "uregon.edu", + machinesFromModel: [{ + machine: "axis833334.uregon.edu", + states: ["state-good","state-good","state-really-bad","state-good","state-good"] + }, + { + machine: "axis8690003.uregon.edu", + states: ["state-good","state-good","state-really-bad","state-good","state-good"] + }, + { + machine: "axis2222283.uregon.edu", + states: ["state-good","state-good","state-really-bad","state-good","state-good"] + }] + }];*/ + }; + + return { + get: get_ + } +}(); \ No newline at end of file diff --git a/src/psij/web/js/RowAccordion.js b/src/psij/web/js/RowAccordion.js new file mode 100644 index 0000000..43160c1 --- /dev/null +++ b/src/psij/web/js/RowAccordion.js @@ -0,0 +1,66 @@ +var VC = VC || {}; + +VC.goHere = function(ev) { + + var x = $(event.target); + var site_id = x.html(); + + window.location="site.html?site_id=" + site_id; +}; + + +VC.RowAccordion = Vue.component("row-accordion", { + props: [ + 'show_scheduler', + 'yaxe_prop' // one yaxis property: logo_name, logo source and machines list. + ], + data: function () { + + return { + open: 0 + } + }, + template: '' + + '' + + '' + + '' + + ''+ + ' \ + \ + ' + + '' + + ''+ + '' + + '
' + + '
' + + '
' + + '{{ this.yaxe_prop.logo_name }}
' + + '
' + + '
{{ machineObj.schedulerShow }}' + + '
' + + '
' + + '
' + + '  ' + + '
' + + '
' + + '
', + mounted: function( event ) { + + PS.showOrHideBranchBubbles(); + + }, + methods: { + toggle: function( event ) { + + this.open = this.open ? 0 : 1; + console.log( this.open ); + }, + nice_bubble: function( state ) { + console.dir(state); + return '

\n' + + '  \n' + + '
'; + } + } +}); diff --git a/src/psij/web/js/SitesModel.js b/src/psij/web/js/SitesModel.js new file mode 100644 index 0000000..82c5863 --- /dev/null +++ b/src/psij/web/js/SitesModel.js @@ -0,0 +1,338 @@ +var PS = PS || {}; +/* + This builds the Data model for the curated sites view. + */ +PS.SitesModel = function() { + + var callback_; + + var getModel_ = function( callback ) { + + callback_ = callback; + getLatestResultForTestOnAllSites_(); + }; + + + var makeModel_ = function() { + + var curSite = makeModelInstance_( CONF.curated_sites ); + + callback_( curSite ); + }; + + + var makeModelInstance_ = function( cur_site ) { + + var curSite = $.extend({}, cur_site ); + + for( var yIndex=0; yIndex < curSite.yaxis.length; yIndex++ ) { + + var machinesInAccordion = []; + + curSite.yaxis[yIndex].horizontalSummary = makeGoodStatesArray_(curSite.xaxis.length); + + loadMachines_( curSite, machinesInAccordion, yIndex); + + curSite.yaxis[yIndex].machinesFromModel = machinesInAccordion; + + + } + + return curSite; + }; + + + var makeGoodStatesArray_ = function( entryCount ) { + + var x = new Array(entryCount).fill(PS.STATES.GOOD); + console.log(x); + return x; + }; + + var getMainBranch_ = function( branches ) { + + var branchToSearchFor = location.href.indexOf("/sdk.") > -1 ? "master" : "main"; + + for( var i=0; i < branches.length; i++ ) { + + var branch = branches[i]; + if( branch.name === branchToSearchFor) { + return branch; + } + } + + return null; + }; + + + var loadMachines_ = function( curSite, machinesInAccordion, yIndex ) { + + var yobj = curSite.yaxis[yIndex]; + + for( var siteId in yobj.machines ) { + + var machinesObj = yobj.machines[siteId]; + var site = getSiteBySiteId_(siteId); + + if (site) { + + var keys = Object.keys( site.months ); + var lastKeyIdx = keys.length - 1; + var lastMon = keys[ lastKeyIdx ]; + + var days = site.months[lastMon]; + var daysKeys = Object.keys( days ); + var lastDayKeyIdx = daysKeys.length - 1; + var lastDay = daysKeys[ lastDayKeyIdx ]; + + var sobj_outer = site.months[lastMon][lastDay]; + var sobj = getMainBranch_( sobj_outer.branches ); + + if( sobj === null) { + // case where there are no branches or no main branch. + sobj = { + completed_count:0, + failed_count:0, + name: 'none' + } + } + + var state = globalMethods.badnessClass(sobj); + + var s1 = getMachineStateByTestingColumn_(siteId, 0); + var s2 = getMachineStateByTestingColumn_(siteId, 1); + var s3 = getMachineStateByTestingColumn_(siteId, 2); + var s4 = getMachineStateByTestingColumn_(siteId, 3); + var s5 = getMachineStateByTestingColumn_(siteId, 4); + + if (state !== PS.STATES.GOOD && state !== "") { + curSite.yaxis[yIndex].horizontalSummary[0] = PS.STATES.REALLY_BAD; + } + + if (s1 !== PS.STATES.GOOD && s1 !== "") { + curSite.yaxis[yIndex].horizontalSummary[1] = PS.STATES.REALLY_BAD; + } + + if (s2 !== PS.STATES.GOOD && s2 !== "") { + curSite.yaxis[yIndex].horizontalSummary[2] = PS.STATES.REALLY_BAD; + } + + if (s3 !== PS.STATES.GOOD && s3 !== "") { + curSite.yaxis[yIndex].horizontalSummary[3] = PS.STATES.REALLY_BAD; + } + + if (s4 !== PS.STATES.GOOD && s4 !== "" && curSite.xaxis.length > 4 ) { + curSite.yaxis[yIndex].horizontalSummary[4] = PS.STATES.REALLY_BAD; + } + + if (s5 !== PS.STATES.GOOD && s5 !== "" && curSite.xaxis.length > 5 ) { + curSite.yaxis[yIndex].horizontalSummary[5] = PS.STATES.REALLY_BAD; + } + + var states = [state,s1,s2,s3]; + + if( curSite.xaxis.length > 4 ) { + states.push(s4); + } + + if( curSite.xaxis.length > 5 ) { + states.push(s5); + } + + var objStates = []; + + for( var y=0; y < states.length; y++ ) { + objStates.push({ + mainState: states[y], + branches: [] + }); + } + + machinesInAccordion.push({ + machine: siteId, + schedulerShow: machinesObj.scheduler, + states: objStates + }); + } + } + }; + + + /* + * curated sites: + * columnIndex - 0 is the first column, "Test Suite", + * 1 is Tests, etc. + */ + var getMachineStateByTestingColumn_ = function( siteId, columnIndex) { + + var xTests = CONF.curated_sites.xaxisTests; + var testName = xTests[columnIndex]; + + var resultSetupAndCall = resultsBySiteIdAndCol_[ siteId ][ testName ]; + + var bl = getStatus_(resultSetupAndCall, testName); + return bl; + }; + + + var getMachineArray_ = function() { + + var yaxis = CONF.curated_sites.yaxis; + var machine_arr = []; + + for( var x in yaxis ) { + + var lm_obj = yaxis[x]; + var machineKeys = Object.keys(lm_obj.machines); + machine_arr = machine_arr.concat( machineKeys ) + } + + return machine_arr; + }; + + + var getLatestResultForTestOnAllSites_ = function() { + + var t_arr = CONF.curated_sites.xaxisTests; + var js = JSON.stringify( t_arr ); + var path = "tests"; + var ma = getMachineArray_(); + var params = "sites_to_get=" + JSON.stringify( ma ) + + "&tests_to_match=" + js; + + var url = PS.getURL(path); + + $.get(url, params, handleTests_); + }; + + + var resultsBySiteIdAndCol_ = {}; + + var handleTests_ = function(results) { + + resultsBySiteIdAndCol_ = results; + + makeModel_(); + callback_(); + }; + + + var handleColumn_ = function( zCol, testsBySites ) { + + var xTests = CONF.curated_sites.xaxisTests; + var testName = xTests[zCol]; + + for( var siteId in testsBySites ) { + + var result = getResult_( testsBySites[siteId], testName ); + console.log('siteId: ' + siteId); + var boolRes = getStatus_( result ); + + resultsBySiteIdAndCol_[ siteId ] = resultsBySiteIdAndCol_[ siteId ] || []; + resultsBySiteIdAndCol_[ siteId ][ zCol ] = boolRes; + + //console.log( siteId ); + //console.dir( result ); + } + }; + + + var getStatus_ = function( result, testName ) { + + // SDK page send back results in a slightly different format. + if( result && result[testName] ) { + + return result[testName].passed === true ? PS.STATES.GOOD : PS.STATES.REALLY_BAD; + } + + // PSIJ + if( result === undefined ) { + return PS.STATES.EMPTY; + } + + if( result && result.call && result.call.passed && + result.setup && result.setup.passed ) { + + return PS.STATES.GOOD; + } + + return PS.STATES.REALLY_BAD; + }; + + + var getResult_ = function( allTestsForSite, testName ) { + + for( var i=0; i < allTestsForSite.length; i++ ) { + + var test = allTestsForSite[i]; + + if( test.test_name === testName ) { + console.log('branch: ' + test.branch); + return test.results; + } + } + + return false; + }; + + + + var getSiteBySiteId_ = function( siteId ) { + + for( var y=0; y < PS.sites.length; y++ ) { + + var site = PS.sites[y]; + + if( siteId === site.site_id ) { + return site; + } + } + + return null; + }; + + + var calendarBubbleClass_ = function(d) { + + var size = function(name) { + return name == "main" || name == "master" ? "bubble-large" : "bubble-small"; + }; + + var bc = globalMethods.badnessClass( d ); + + if (d == null || (d.completed_count == 0 && d.failed_count == 0)) { + return "state-unknown "; + } + else { + return globalMethods.badnessClass(d) + " " + size(d.name); + } + }; + + var getBranchesForSmallBubbles_ = function( branches ) { + + var br = []; + + for( var x=0; x < branches.length; x++ ) { + + var branch = branches[x]; + var bc = calendarBubbleClass_( branch ); + var bs = globalMethods.calendarBubbleStyleObj( branch ); + + if( branch.name !== "main" && branch.name !== "master") { + br.push({ + calendarBubbleClass: bc, + calendarBubbleStyle: bs + }); + } + } + + return br; + }; + + return { + getBranchesForSmallBubbles: getBranchesForSmallBubbles_, + getMainBranch: getMainBranch_, + getLatestResultForTestOnAllSites: getLatestResultForTestOnAllSites_, + getModel: getModel_ + } +}(); \ No newline at end of file diff --git a/src/psij/web/js/common.js b/src/psij/web/js/common.js new file mode 100644 index 0000000..101684b --- /dev/null +++ b/src/psij/web/js/common.js @@ -0,0 +1,10 @@ +var PS = PS || {}; + +PS.sites = [ +]; + +settingsDefaults({"viewMode": "calendar", "inactiveTimeout": 10, "showBranchBubbles": false}); + +PS.getURL = function( path ) { + return CONF.backendURL + path; +}; diff --git a/src/psij/web/lib.js b/src/psij/web/js/lib.js similarity index 77% rename from src/psij/web/lib.js rename to src/psij/web/js/lib.js index d81417c..5f37cd4 100644 --- a/src/psij/web/lib.js +++ b/src/psij/web/js/lib.js @@ -1,10 +1,29 @@ +// lib.js +var PS = PS || {}; +PS.STATES = { + "GOOD": "state-good", + "SOMEWHAT_BAD": "state-somewhat-bad", + "REALLY_BAD": "state-really-bad", + "EMPTY": "empty" +}; + var badness = function(obj) { - if (obj['failed_count'] > 0) { - if (obj['completed_count'] < obj['failed_count']) { - return 2; + + if( obj['completed_count'] === 0 ) { + // empty. + return 3; + } + + if( obj['completed_count'] <= 2 ) { + return 2; // red. + } + + if (obj['failed_count'] > 0 ) { + if (obj['completed_count'] < obj['failed_count'] ) { + return 2; // red } else { - return 1; + return 1; // orange } } else { @@ -24,7 +43,7 @@ var getDayData = function(site, day) { return month[day.day]; } } - return null; + return {branches:[]}; } var getBranchData = function(branch, dayData) { @@ -33,6 +52,7 @@ var getBranchData = function(branch, dayData) { } var name = branch.name; if (dayData != null) { + for (var i = 0; i < dayData.branches.length; i++) { if (dayData.branches[i].name == name) { return dayData.branches[i]; @@ -54,19 +74,40 @@ var settingsDefaults = function(dict) { var makeSetting = function(name, callback, type) { return { get: function() { - var val = Cookies.get(name); - if (type == "bool") { - return val == "true"; - } - else { - return val; + + var sbb = localStorage.getItem(name); + + if( name === 'showBranchBubbles' ) { + sbb = localStorage.getItem('showBranchBubbles') === 'true' ? 'true' : false; + } else if( name === 'inactiveTimeout' ) { + sbb = localStorage.getItem('inactiveTimeout') || 10; } + + return sbb; }, set: function(val) { - Cookies.set(name, val); + + localStorage.setItem( name, val ); callback(); - } + + if( name === "showBranchBubbles" ) { + console.log('showBranchbubbles:'); + console.dir(val); + } + } + } +}; + + +PS.showOrHideBranchBubbles = function() { + + var show = localStorage.getItem('showBranchBubbles') === 'true'; + + if( show ) { + $('.container-for-mini-branches').show(); + } else { + $('.container-for-mini-branches').hide(); } }; @@ -90,7 +131,6 @@ ansi_up.use_classes = true; var globalMethods = { sort: function(key, lst) { - console.log(lst); if (!lst) { return lst; } @@ -105,9 +145,9 @@ var globalMethods = { for (var i = 0; i < copy.length; i++) { var site = copy[i]; site.key = site.site_id.split('.').reverse().join('.'); - console.log(site.key) } strComp = function(a, b) {if (a > b) return 1; else if (a == b) return 0; else return -1;}; + return copy.sort((a, b) => strComp(a.key, b.key)); }, limit: function(array, n) { @@ -121,11 +161,13 @@ var globalMethods = { badnessClass: function(obj) { switch(badness(obj)) { case 0: - return "state-good"; + return PS.STATES.GOOD; case 1: - return "state-somewhat-bad"; + return PS.STATES.SOMEWHAT_BAD; case 2: - return "state-really-bad"; + return PS.STATES.REALLY_BAD; + case 3: + return PS.STATES.EMPTY; } }, badnessSort: function(lst) { @@ -134,7 +176,8 @@ var globalMethods = { }); }, branchSort: function(lst) { - if (setting("showBranchBubbles") != "true") { + + if (localStorage.getItem("showBranchBubbles") != "true") { return lst.filter(branch => (branch.name == "main") || (branch.name == "master")); } var sorted = lst.slice().sort((a, b) => { @@ -149,8 +192,55 @@ var globalMethods = { }); return sorted; }, + // could be more optimized + isSingleUrl: function( url ) { + + var count = 0; + var test_domain = this.getDomain( url ); + + for( var x in this.sites ) { + + var site = this.sites[x]; + var loop_domain = this.getDomain( site.site_id ); + + if( test_domain === loop_domain ) { + count++; + } + } + + console.dir( this.sitesSort(this.sites) ); + console.log( test_domain + count ); + return count < 2; + }, + getPosition: function( url ) { + + if( this.isSingleUrl(url) ) { + return 'oneRowOnly'; + } + + var domain = globalMethods.getDomain( url ); + PS.urls = PS.urls || {}; + + PS.urls[domain] = PS.urls[domain] || 0; + PS.urls[domain]++; + + if( PS.urls[domain] <= 2 ) { + return "firstPos"; + } + + return "otherPos"; + }, + getDomain: function( url ) { + + var uparts = url.split('.'); + var len = uparts.length; + var first = uparts[len - 2]; + var first_dot = first ? (first + '.') : ""; + + return first_dot + uparts[len - 1]; + }, navigate: function(loc) { - console.log(loc); + //console.log(loc); return "event.stopPropagation(); window.location=\"" + loc + "\""; }, shortenId: function(id) { @@ -319,14 +409,18 @@ var globalMethods = { } var d = getBranchData(branch, getDayData(site, day)); if (d == null || (d.completed_count == 0 && d.failed_count == 0)) { - return "state-unknown, " + size(branch); + return "state-unknown " + size(branch); } else { - return this.badnessClass(d) + ", " + size(branch); + return this.badnessClass(d); // + ", " + size(branch); } }, calendarBubbleStyle: function(site, day, branch) { + var d = getBranchData(branch, getDayData(site, day)); + return globalMethods.calendarBubbleStyleObj(d); + }, + calendarBubbleStyleObj: function( d ) { var color; if (d != null) { var completed = d.completed_count; @@ -379,7 +473,10 @@ var globalMethods = { }, getDayData: getDayData, breadcrumbs: function() { - var b = [{text: CUSTOMIZATION.projectName + " Tests", href: "summary.html"}]; + + var projName = CUSTOMIZATION.projectName; + + var b = [{text: projName + " Tests", href: "summary.html"}]; var level = 0; if (window.location.pathname.startsWith("/site.html")) { level = 1; @@ -398,11 +495,16 @@ var globalMethods = { } return b; }, + updateRender: function() { + this.$forceUpdate(); + }, setting: setting } $(document).ready(function() { + setTimeout(function() { + $('.clickable').each(function() { if ($(this).attr('onclick') !== undefined) { var v = $(this).attr('onclick'); @@ -413,4 +515,4 @@ $(document).ready(function() { } }); }, 500); -}); \ No newline at end of file +}); diff --git a/src/psij/web/js/summary.js b/src/psij/web/js/summary.js new file mode 100644 index 0000000..07f2c48 --- /dev/null +++ b/src/psij/web/js/summary.js @@ -0,0 +1,186 @@ + +var setViewMode = function (viewMode) { + + if (viewMode === undefined) { + viewMode = Cookies.get('viewMode'); + } + if (viewMode === undefined) { + viewMode = 'calendar'; + } + + Cookies.set('viewMode', viewMode); + + $('.view-mode-group').removeClass('selected'); + $('#view-mode-' + viewMode).addClass('selected'); + + siteStatus.mode = viewMode; + + if( viewMode === 'calendar' ) { + setTimeout( PS.bindRowOpenClose, 0 ); + } + + if( viewMode === 'home' ) { + PS.SitesModel.getLatestResultForTestOnAllSites(); + } +}; + + +PS.SummaryModel = function() { + + var set = function(dst, src) { + dst.length = 0; + for (var i = 0; i < src.length; i++) { + dst.push(src[i]); + } + }; + + var updateSummary = function() { + + var context = PS.getURL('summary'); + var inact = localStorage.getItem('inactiveTimeout'); + inact = inact ? inact : 10; + + var obj = { + inactiveTimeout: inact + }; + + + $.get(context, obj, function(data) { + + set(PS.sites, data); + + PS.accordionModel = PS.accordionModel || []; + PS.BuildAccordionModelFromSites.get(PS.accordionModel); + + console.log('after summary get:'); + console.dir(PS.accordionModel); + + PS.makeSites(); + + // Vue wants to rerender this section immediately after this function + // That would wipe out showOrHideBranchBubbles. Give Vue the chance + // to do it rerender, then run showOrHideBranchBubbles. + setTimeout(PS.showOrHideBranchBubbles,0); + }); + }; + + $(document).ready( updateSummary ); + + return { + updateSummary: updateSummary + } +}(); + + + + +var siteStatus; + +PS.bindRowOpenClose = function() { + + PS.urls = {}; + console.log($('.open_close_arrow').length); + + $('.open_close_arrow').unbind('click').bind('click', function() { + + var parent = $(this).closest('tr'); + var site_el = parent.find('[site_id]'); + var siteIdClicked = site_el.attr('site_id'); + + console.log( siteIdClicked ); + $(this).toggleClass('open'); + + $('[site_id="' + siteIdClicked + '"][position="otherPosOnc"]').parent().toggle(); + }); +}; + + + +PS.makeSites = function() { + + var init_ = function( sites_model ) { + + if( !sites_model ) { + return false; + } + + PS.BuildAccordionModelFromSites.get(PS.accordionModel); + + siteStatus = new Vue({ + el: "#container", + components: { + }, + vuetify: new Vuetify(), + data: { + sites: PS.sites, + accordionModel: PS.accordionModel, + mode: '', + now: moment().utc().startOf("day"), + STR: CONF.STR, + curated_sites: sites_model, + settingsDialog: false + }, + methods: globalMethods, + computed: { + inactiveTimeout: makeSetting("inactiveTimeout", PS.SummaryModel.updateSummary), + showBranchBubbles: makeSetting("showBranchBubbles", PS.SummaryModel.updateSummary, "bool"), + allBranches: function () { + + console.log('allBranches:'); + console.dir(this.sites); + + var unique = {}; + for (var i = 0; i < this.sites.length; i++) { + + var site = this.sites[i]; + var branches = site.branches; + for (var j = 0; j < branches.length; j++) { + var branch = branches[j]; + if (branch.name in unique) { + var existing = unique[branch.name]; + existing['failed_count'] += branch['failed_count']; + existing['completed_count'] += branch['completed_count']; + } else { + unique[branch.name] = {...branch}; + unique[branch.name]['sites'] = {}; + } + unique[branch.name]['sites'][site.site_id] = branch; + } + } + + values = []; + for (var k in unique) { + values.push(unique[k]); + } + return this.sort('name', values); + }, + branchIndexMap: function () { + var all = this.allBranches; + var map = {}; + for (var i = 0; i < all.length; i++) { + map[all[i].name] = i; + } + return map; + } + } + }); + + setViewMode(); + PS.bindRowOpenClose(); + }; + + + + $(document).ready( PS.bindRowOpenClose ); + + if( !PS.already_made_site ) { + PS.already_made_site = 1; + + PS.SitesModel.getModel( init_ ); + } + + window.reget = function() { + PS.SitesModel.getModel( init_ ); + }; + +}; \ No newline at end of file diff --git a/src/psij/web/run.html b/src/psij/web/run.html index 36e5be2..415e34b 100644 --- a/src/psij/web/run.html +++ b/src/psij/web/run.html @@ -8,12 +8,13 @@ crossorigin="anonymous"> - - + + + - +
@@ -33,7 +34,7 @@ {{ branch.name }}
{{ branch.failed_count }} - +
@@ -122,6 +123,9 @@

+ + + - - + + - +
@@ -48,7 +48,7 @@
{{ branch.failed_count }} - +
@@ -57,6 +57,8 @@ + + - - - - - - - - - - - - - - -
- -
-
- calendar_today -
-
- grid_view -
-
- table_view + + Summary + + + + + + + + + + + + + + + + + + + + + +
+ -
 
- + + +
+ + + +
+ home +
+ +
+ calendar_today +
+
+ grid_view +
+
+ table_view +
+ + +
 
+ +