diff --git a/front/src/css/dashboard.css b/front/src/css/dashboard.css new file mode 100644 index 0000000..8992c43 --- /dev/null +++ b/front/src/css/dashboard.css @@ -0,0 +1,479 @@ +/* Timeline colors, related to Window Performances */ +.resultsMenu { + margin-top: 2em; +} +.resultsMenu .menuItem { + display: inline-block; + margin: 1em; + width: 8em; + height: 7em; + color: #fff; + border: 3px solid #fff; + border-radius: 0.5em; + cursor: pointer; + text-decoration: none; +} +.resultsMenu .back { + color: #5e2846; + border-color: #5e2846; +} +.resultsMenu .menuItem div { + padding-top: 0.5em; + font-size: 3em; +} +.resultsMenu .active, +.resultsMenu .menuItem.active:hover { + color: #ffa319; + border-color: #ffa319; +} +.resultsMenu .menuItem:hover { + color: #ffa319; +} +.resultsMenu span { + position: relative; + top: 0.5em; +} +.testedUrl { + color: inherit; +} +h4 { + margin-bottom: 0.5em; +} +.summary, +.metrics, +.execution { + margin-top: 2em; + padding: 1em; + background: #fff; + color: #000; + border-radius: 0.5em; + text-align: left; +} +.notations { + display: table; + width: 90%; + margin: 0 10%; + border-spacing: 1em; +} +.notations > div { + display: table-row; +} +.notations > div > div { + display: table-cell; + height: 2.5em; + vertical-align: middle; +} +.notations .notation { + font-weight: bold; + text-align: center; +} +.notations .criteria { + font-weight: normal; +} +.notations .A, +.notations .B, +.notations .C, +.notations .D, +.notations .E, +.notations .F, +.notations .NA { + width: 2.5em; + font-size: 2em; + text-align: center; + border-radius: 0.5em; + font-weight: bold; +} +.notations .grade .A, +.notations .grade .B, +.notations .grade .C, +.notations .grade .D, +.notations .grade .E, +.notations .grade .F, +.notations .grade .NA { + width: 1em; + height: 1em; + font-size: 1em; + color: transparent; + position: relative; + top: 0.15em; +} +.notations .A { + /* green */ + background: #00DB61; +} +.notations .B { + /* green */ + background: #CAD600; +} +.notations .C { + /* yellow */ + background: #FFD119; +} +.notations .D { + /* orange */ + background: #FFA319; +} +.notations .E { + /* red */ + background: #FF6600; +} +.notations .F { + /* red */ + background: #FF1919; +} +.notations .NA { + /* Non applicable */ + background: #CCC; +} +.notations .icon-eye { + color: #9c4274; + cursor: pointer; +} +.notations .criteria .table { + width: 75%; +} +.notations .criteria .label { + width: 70%; +} +.notations .criteria .result { + width: 20%; + font-weight: bold; + white-space: nowrap; + text-align: center; +} +.notations .warning .label, +.notations .warning .result { + color: #FF1919; +} +.notations .criteria .info { + width: 10%; + text-align: center; +} +.notations .criteria .icon-question { + color: #f1c40f; + cursor: pointer; +} +.timeline { + margin: 2em 0 5em; +} +.timeline .chart { + position: relative; + width: 100%; + border-bottom: 1px solid #000; +} +.timeline .startTime, +.timeline .endTime { + position: absolute; + bottom: 0.5em; + font-size: 0.8em; +} +.timeline .startTime { + left: 0em; +} +.timeline .endTime { + right: 0em; +} +.timeline .chartPoints { + display: table; + height: 100px; + width: 99%; + margin: 0 auto; +} +.timeline .interval { + display: table-cell; + position: relative; + height: 100px; + width: 0.5%; +} +.timeline .interval .color { + position: absolute; + bottom: 0; + width: 100%; +} +.timeline div.interval:hover { + background: #9C4274; +} +.timeline .interval:hover .color { + background: #F04DA7; +} +.timeline .domComplete.interval { + background: #ede3ff; +} +.timeline .domComplete .color { + background: #c2a3ff; +} +.timeline .domContentLoadedEnd.interval { + background: #d8f0f0; +} +.timeline .domContentLoadedEnd .color { + background: #7ecccc; +} +.timeline .domContentLoaded.interval { + background: #e0ffd1; +} +.timeline .domContentLoaded .color { + background: #a7e846; +} +.timeline .domInteractive.interval { + background: #fffccc; +} +.timeline .domInteractive .color { + background: #ffe433; +} +.timeline .domCreation.interval { + background: #ffe0cc; +} +.timeline .domCreation .color { + background: #ff6600; +} +.timeline .tooltip.detailsOverlay { + position: absolute; + display: none; + width: auto; + padding: 0.5em 1em; + top: -1.5em; + right: 1em; +} +.timeline .interval:hover .tooltip { + display: block; +} +.timeline .legend { + display: table; + width: 100%; + margin-top: 1em; +} +.timeline .legend > div { + display: table-row; +} +.timeline .legend > div > div { + position: relative; + display: table-cell; + margin-top: 1em; +} +.timeline .titles { + font-weight: bold; +} +.timeline .titles > div { + padding: 0 1em 0 2em; +} +.timeline .tips { + font-size: 0.7em; +} +.timeline .tips > div { + padding: 1em 1em 0 0; +} +.timeline .legend .color { + display: block; + position: absolute; + left: 0; + height: 1.5em; + width: 1.5em; + border-radius: 0.2em; +} +.metrics h4 { + padding-left: 2em; +} +.metrics .module { + padding-left: 4em; + padding-top: 0.5em; +} +.metrics .legend { + font-style: italic; + color: #aaa; +} +.metrics .offenders { + padding-left: 0em; + font-size: 0.8em; +} +.metrics .offenders div { + cursor: pointer; +} +.metrics .offenders ul { + margin-top: 0.5em; +} +.filters { + margin: 1em 0; + padding: 0.5em; + border: 1px dotted #aaa; +} +.slowRequestsLimit { + width: 3em; + font-size: 1em; + text-align: right; + border: 1px solid #aaa; +} +input.textFilter { + box-shadow: none; + font-size: 1em; + padding: 0 0.2em; + border: 1px solid #aaa; + border-radius: none; + width: 15em; +} +.table { + display: table; + width: 100%; + border-spacing: 0.25em; +} +.table > div { + display: table-row; +} +.table > .headers > div { + font-weight: bold; + padding: 0.5em 1em; +} +.table > div > div { + padding: 0.1em 1em; + background: #f2f2f2; + display: table-cell; + text-align: left; +} +.table > div.jsError > .type, +.table > div.jsError > .value { + color: #e74c3c; + font-weight: bold; +} +.table > div.windowPerformance > div, +.table > div.windowPerformance > div.startTime { + background: #EBD8E2; +} +.table > div.showingDetails > div { + background: #f1c40f; +} +.table > div > .index { + color: #bbb; +} +.table > div > .type { + white-space: nowrap; +} +.table > div > .value { + width: 70%; + word-break: break-all; +} +.table > div > .details { + position: relative; +} +.table .details .icon-question { + color: #f1c40f; + cursor: pointer; +} +.table .details .icon-warning { + cursor: pointer; +} +.detailsOverlay { + position: absolute; + right: 3em; + top: -3em; + width: 45em; + min-height: 1em; + padding: 0 1em 1em; + background: #fff; + border: 2px solid #f1c40f; + border-radius: 0.5em; + z-index: 1; +} +@media screen and (max-width: 1024px) { + .detailsOverlay { + width: 25em; + } +} +.detailsOverlay .closeBtn { + position: absolute; + top: 0.5em; + right: 0.5em; + color: #f1c40f; + cursor: pointer; +} +.detailsOverlay .advice { + color: #e74c3c; + font-weight: bold; +} +.detailsOverlay .trace { + word-break: break-all; +} +.table > div > .duration, +.table > div > .startTime { + text-align: center; + white-space: nowrap; +} +.table > div > .startTime.domComplete { + background: #ede3ff; +} +.table > div > .startTime.domContentLoadedEnd { + background: #d8f0f0; +} +.table > div > .startTime.domContentLoaded { + background: #e0ffd1; +} +.table > div > .startTime.domInteractive { + background: #fffccc; +} +.table > div > .startTime.domCreation { + background: #ffe0cc; +} +.table .icon-warning { + color: #e74c3c; +} +/**** NgModal popin (have a look inside bower_components) ****/ +.ng-modal { + position: fixed; + z-index: 9999; + top: 0; + left: 0; + width: 100%; + height: 100%; + text-align: left; +} +.ng-modal-overlay { + position: absolute; + z-index: 9999; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: #000; + opacity: 0.5; +} +.ng-modal-dialog { + z-index: 10000; + position: absolute; + top: 50%; + left: 50%; + width: 50%; + transform: translate(-50%, -50%); + -webkit-transform: translate(-50%, -50%); + background-color: #fff; + padding: 10px; + border: 3px solid #f1c40f; + border-radius: 0.5em; + color: #000; +} +.ng-modal-dialog-content { + overflow-x: hidden; + overflow-y: scroll; + word-wrap: break-word; + max-height: 20em; + font-weight: normal; + white-space: normal; +} +.ng-modal-close { + position: absolute; + top: 3px; + right: 5px; + cursor: pointer; + font-size: 120%; + padding: 5px; + display: inline-block; +} +.ng-modal-close-x { + font-weight: bold; + font-family: Arial, sans-serif; +} +.ng-modal-title { + font-weight: bold; + font-size: 1.5em; + display: block; + margin-bottom: 10px; + padding-bottom: 7px; + border-bottom: solid 1px #999; +} diff --git a/front/src/css/icons.css b/front/src/css/icons.css new file mode 100644 index 0000000..6ebf26b --- /dev/null +++ b/front/src/css/icons.css @@ -0,0 +1,6 @@ +@font-face { + font-family: "fontsmith-icons"; + src: url("/front/fonts/icons.woff") format("woff"); + font-weight: normal; + font-style: normal; +} diff --git a/front/src/css/index.css b/front/src/css/index.css new file mode 100644 index 0000000..d22b867 --- /dev/null +++ b/front/src/css/index.css @@ -0,0 +1,36 @@ +.promess { + padding: 0em 2em 3em; + font-weight: normal; + font-size: 1.2em; +} +.url { + width: 50%; +} +.launchBtn { + background: #e74c3c; + color: #fff; +} +.launchBtn.disabled { + background: #deaca6; +} +input[type=submit], +input.url { + padding: 0 0.5em; + margin: 0.5em; + font-size: 1.2em; + height: 2em; + border: 0 solid; + border-radius: 0.5em; + box-shadow: 0.1em 0.2em 0 0 #5e2846; + outline: none; +} +input[type=submit]:hover { + color: #ddd; +} +input[type=submit].clicked { + color: #ddd; + position: relative; + left: 0.1em; + top: 0.2em; + box-shadow: none; +} diff --git a/front/src/css/main.css b/front/src/css/main.css new file mode 100644 index 0000000..1ef1db3 --- /dev/null +++ b/front/src/css/main.css @@ -0,0 +1,139 @@ +@font-face { + font-family: "fontsmith-icons"; + src: url("/front/fonts/icons.woff") format("woff"); + font-weight: normal; + font-style: normal; +} +html { + margin: 100px 50px; +} +body { + margin: 0 auto; + max-width: 1280px; + background: #9c4274; + color: #fff; + font-size: 16px; + text-align: center; +} +body, +input[type=submit], +input[type=text], +input[type=url], +input[type=number], +button { + font-family: 'Century Gothic', helvetica, arial, sans-serif; +} +input[type=submit] { + cursor: pointer; +} +h1 span { + display: inline-block; + height: 1em; + width: 1em; + color: #ffa319; +} +.footer { + padding: 3em; + color: #4e1836; +} +.footer a { + color: inherit; +} +.footer .star { + font-weight: bold; +} +.footer .star span { + font-size: 1.2em; +} +/* Icons */ +.icon-lab { + font-family: "fontsmith-icons"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} +.icon-lab:before { + content: "\e003"; +} +.icon-question { + font-family: "fontsmith-icons"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} +.icon-question:before { + content: "\e001"; +} +.icon-warning { + font-family: "fontsmith-icons"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} +.icon-warning:before { + content: "\e000"; +} +.icon-back { + font-family: "fontsmith-icons"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} +.icon-back:before { + content: "\e006"; +} +.icon-summary { + font-family: "fontsmith-icons"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} +.icon-summary:before { + content: "\e002"; +} +.icon-spaghetti { + font-family: "fontsmith-icons"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} +.icon-spaghetti:before { + content: "\e005"; +} +.icon-eye { + font-family: "fontsmith-icons"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} +.icon-eye:before { + content: "\e004"; +} diff --git a/front/src/css/queue.css b/front/src/css/queue.css new file mode 100644 index 0000000..76161b3 --- /dev/null +++ b/front/src/css/queue.css @@ -0,0 +1,25 @@ +.status { + margin-top: 2em; + font-size: 2.5em; +} +@-webkit-keyframes rotating { + from { + -webkit-transform: rotate(0deg); + } + to { + -webkit-transform: rotate(360deg); + } +} +@keyframes rotating { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} +.waiting .icon-lab { + -webkit-animation: rotating 3s linear 0s infinite; + -webkit-transform: translateZ(0); + animation: rotating 3s linear 0s infinite; +} diff --git a/front/src/fonts/icons.woff b/front/src/fonts/icons.woff new file mode 100644 index 0000000..dd8c0bd Binary files /dev/null and b/front/src/fonts/icons.woff differ diff --git a/front/src/fonts/svg-icons/arrow-left3.svg b/front/src/fonts/svg-icons/arrow-left3.svg new file mode 100644 index 0000000..d96cc70 --- /dev/null +++ b/front/src/fonts/svg-icons/arrow-left3.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/front/src/fonts/svg-icons/bars.svg b/front/src/fonts/svg-icons/bars.svg new file mode 100644 index 0000000..2e7adca --- /dev/null +++ b/front/src/fonts/svg-icons/bars.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/front/src/fonts/svg-icons/eye.svg b/front/src/fonts/svg-icons/eye.svg new file mode 100644 index 0000000..59ff3c2 --- /dev/null +++ b/front/src/fonts/svg-icons/eye.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/front/src/fonts/svg-icons/lab.svg b/front/src/fonts/svg-icons/lab.svg new file mode 100644 index 0000000..28b3aa8 --- /dev/null +++ b/front/src/fonts/svg-icons/lab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/front/src/fonts/svg-icons/list.svg b/front/src/fonts/svg-icons/list.svg new file mode 100644 index 0000000..403a80a --- /dev/null +++ b/front/src/fonts/svg-icons/list.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/front/src/fonts/svg-icons/question.svg b/front/src/fonts/svg-icons/question.svg new file mode 100644 index 0000000..49e9fc3 --- /dev/null +++ b/front/src/fonts/svg-icons/question.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/front/src/fonts/svg-icons/warning.svg b/front/src/fonts/svg-icons/warning.svg new file mode 100644 index 0000000..85f8300 --- /dev/null +++ b/front/src/fonts/svg-icons/warning.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/front/src/js/controllers/queueCtrl.js b/front/src/js/controllers/queueCtrl.js new file mode 100644 index 0000000..45b8bd4 --- /dev/null +++ b/front/src/js/controllers/queueCtrl.js @@ -0,0 +1,23 @@ +var queueCtrl = angular.module('queueCtrl', ['runsFactory']); + +queueCtrl.controller('QueueCtrl', ['$scope', '$routeParams', '$location', 'Runs', function($scope, $routeParams, $location, Runs) { + $scope.runId = $routeParams.runId; + + function getRunStatus () { + Runs.get({runId: $scope.runId}, function(data) { + $scope.status = data.status; + if (data.status.statusCode === 'running' || data.status.statusCode === 'awaiting') { + // Retrying in 2 seconds + setTimeout(getRunStatus, 2000); + } else if (data.status.statusCode === 'complete') { + $location.path('/result/' + $scope.runId); + } else { + // Handled by the view + } + }); + } + + getRunStatus(); +}]); + + \ No newline at end of file diff --git a/front/src/js/directives/gradeDirective.js b/front/src/js/directives/gradeDirective.js new file mode 100644 index 0000000..f79f2cc --- /dev/null +++ b/front/src/js/directives/gradeDirective.js @@ -0,0 +1,34 @@ +var gradeDirective = angular.module('gradeDirective', []); + +gradeDirective.directive('grade', function() { + + return { + restrict: 'E', + scope: { + score: '=score' + }, + template: '
{{getGrade(score)}}
', + replace: true, + controller : function($scope) { + $scope.getGrade = function(score) { + console.log(score); + if (score >= 85) { + return 'A'; + } + if (score >= 65) { + return 'B'; + } + if (score >= 45) { + return 'C'; + } + if (score >= 30) { + return 'D'; + } + if (score >= 15) { + return 'E'; + } + return 'F'; + } + } + }; +}); \ No newline at end of file diff --git a/front/src/js/models/runsFactory.js b/front/src/js/models/runsFactory.js new file mode 100644 index 0000000..8f4bb8e --- /dev/null +++ b/front/src/js/models/runsFactory.js @@ -0,0 +1,7 @@ +var runsFactory = angular.module('runsFactory', ['ngResource']); + +runsFactory.factory('Runs', ['$resource', function($resource) { + return $resource('/api/runs/:runId', { + + }); +}]); \ No newline at end of file diff --git a/front/src/less/dashboard.less b/front/src/less/dashboard.less new file mode 100644 index 0000000..74a9931 --- /dev/null +++ b/front/src/less/dashboard.less @@ -0,0 +1,507 @@ + +/* Timeline colors, related to Window Performances */ +@domCreationColor: #FF6600; +@domCreationBg: #FFE0CC; +@domContentLoadedColor: #A7E846; +@domContentLoadedBg: #E0FFD1; +@domContentLoadedEndColor: #7ECCCC; +@domContentLoadedEndBg: #D8F0F0; +@domCompleteColor: #C2A3FF; +@domCompleteBg: #EDE3FF; +@domInteractiveColor: #FFE433; +@domInteractiveBg: #FFFCCC; + + +.resultsMenu { + margin-top: 2em; +} + +.resultsMenu .menuItem { + display: inline-block; + margin: 1em; + width: 8em; + height: 7em; + color: #fff; + border: 3px solid #fff; + border-radius: 0.5em; + cursor: pointer; + text-decoration: none; +} +.resultsMenu .back { + color: #5e2846; + border-color: #5e2846; +} +.resultsMenu .menuItem div { + padding-top: 0.5em; + font-size: 3em; +} +.resultsMenu .active, .resultsMenu .menuItem.active:hover { + color: #ffa319; + border-color: #ffa319; +} +.resultsMenu .menuItem:hover { + color: #ffa319; +} + +.resultsMenu span { + position: relative; + top: 0.5em; +} + +.testedUrl { + color: inherit; +} + +h4 { + margin-bottom: 0.5em; +} + +.summary, .metrics, .execution { + margin-top: 2em; + padding: 1em; + background: #fff; + color: #000; + border-radius: 0.5em; + text-align: left; +} + +.notations { + display: table; + width: 90%; + margin: 0 10%; + border-spacing: 1em; +} +.notations > div { + display: table-row; +} +.notations > div > div { + display: table-cell; + height: 2.5em; + vertical-align: middle; +} +.notations .notation { + font-weight: bold; + text-align: center; +} +.notations .criteria { + font-weight: normal; +} +.A, .B, .C, .D, .E, .F, .NA { + .notations & { + width: 2.5em; + font-size: 2em; + text-align: center; + border-radius: 0.5em; + font-weight: bold; + } + .notations .grade & { + width: 1em; + height: 1em; + font-size: 1em; + color: transparent; + position: relative; + top: 0.15em; + } +} +.notations .A { + /* green */ + background: #00DB61; +} +.notations .B { + /* green */ + background: #CAD600; +} +.notations .C { + /* yellow */ + background: #FFD119; +} +.notations .D { + /* orange */ + background: #FFA319; +} +.notations .E { + /* red */ + background: #FF6600; +} +.notations .F { + /* red */ + background: #FF1919; +} +.notations .NA { + /* Non applicable */ + background: #CCC; +} +.notations .icon-eye { + color: #9c4274; + cursor: pointer; +} + +.notations .criteria .table { + width: 75%; +} +.notations .criteria .label { + width: 70%; +} +.notations .criteria .result { + width: 20%; + font-weight: bold; + white-space: nowrap; + text-align: center; +} +.notations .warning .label, .notations .warning .result { + color: #FF1919; +} +.notations .criteria .info { + width: 10%; + text-align: center; +} +.notations .criteria .icon-question { + color: #f1c40f; + cursor: pointer; +} + + +.timeline { + margin: 2em 0 5em; +} +.timeline .chart { + position: relative; + width: 100%; + border-bottom: 1px solid #000; +} +.timeline .startTime, .timeline .endTime { + position: absolute; + bottom: 0.5em; + font-size: 0.8em; +} +.timeline .startTime { + left: 0em; +} +.timeline .endTime { + right: 0em; +} +.timeline .chartPoints { + display: table; + height: 100px; + width: 99%; + margin: 0 auto; +} +.timeline .interval { + display: table-cell; + position: relative; + height: 100px; + width: 0.5%; +} +.timeline .interval .color { + position: absolute; + bottom: 0; + width: 100%; +} +.timeline div.interval:hover { + background: #9C4274; +} +.timeline .interval:hover .color { + background: #F04DA7; +} +.timeline .domComplete.interval { + background: @domCompleteBg; +} +.timeline .domComplete .color { + background: @domCompleteColor; +} +.timeline .domContentLoadedEnd.interval { + background: @domContentLoadedEndBg; +} +.timeline .domContentLoadedEnd .color { + background: @domContentLoadedEndColor; +} +.timeline .domContentLoaded.interval { + background: @domContentLoadedBg; +} +.timeline .domContentLoaded .color { + background: @domContentLoadedColor; +} +.timeline .domInteractive.interval { + background: @domInteractiveBg; +} +.timeline .domInteractive .color { + background: @domInteractiveColor; +} +.timeline .domCreation.interval { + background: @domCreationBg; +} +.timeline .domCreation .color { + background: @domCreationColor; +} +.timeline .tooltip.detailsOverlay { + position: absolute; + display: none; + width: auto; + padding: 0.5em 1em; + top: -1.5em; + right: 1em; +} +.timeline .interval:hover .tooltip { + display: block; +} + +.timeline .legend { + display: table; + width: 100%; + margin-top: 1em; +} +.timeline .legend > div { + display: table-row; +} +.timeline .legend > div > div { + position: relative; + display: table-cell; + margin-top: 1em; +} +.timeline .titles { + font-weight: bold; +} +.timeline .titles > div { + padding: 0 1em 0 2em; +} +.timeline .tips { + font-size: 0.7em; +} +.timeline .tips > div { + padding: 1em 1em 0 0; +} +.timeline .legend .color { + display: block; + position: absolute; + left: 0; + height: 1.5em; + width: 1.5em; + border-radius: 0.2em; +} + + +.metrics h4 { + padding-left: 2em; +} + +.metrics .module { + padding-left: 4em; + padding-top: 0.5em; +} + +.metrics .legend { + font-style: italic; + color: #aaa; +} + +.metrics .offenders { + padding-left: 0em; + font-size: 0.8em; +} + +.metrics .offenders div { + cursor: pointer; +} + +.metrics .offenders ul { + margin-top: 0.5em; +} + +.filters { + margin: 1em 0; + padding: 0.5em; + border: 1px dotted #aaa; +} + +.slowRequestsLimit { + width: 3em; + font-size: 1em; + text-align: right; + border: 1px solid #aaa; +} + +input.textFilter { + box-shadow: none; + font-size: 1em; + padding: 0 0.2em; + border: 1px solid #aaa; + border-radius: none; + width: 15em; +} + +.table { + display: table; + width: 100%; + border-spacing: 0.25em; +} + +.table > div { + display: table-row; +} + +.table > .headers > div { + font-weight: bold; + padding: 0.5em 1em; +} + +.table > div > div { + padding: 0.1em 1em; + background: #f2f2f2; + display: table-cell; + text-align: left; +} +.table > div.jsError > .type, .table > div.jsError > .value { + color: #e74c3c; + font-weight: bold; +} +.table > div.windowPerformance > div, .table > div.windowPerformance > div.startTime { + background: #EBD8E2; +} +.table > div.showingDetails > div { + background: #f1c40f; +} + +.table > div > .index { + color: #bbb; +} + +.table > div > .type { + white-space:nowrap; +} + +.table > div > .value { + width: 70%; + word-break: break-all; +} + +.table > div > .details { + position: relative; +} +.table .details .icon-question { + color: #f1c40f; + cursor: pointer; +} +.table .details .icon-warning { + cursor: pointer; +} + +.detailsOverlay { + position: absolute; + right: 3em; + top: -3em; + width: 45em; + min-height: 1em; + padding: 0 1em 1em; + background: #fff; + border: 2px solid #f1c40f; + border-radius: 0.5em; + z-index: 1; +} +@media screen and (max-width: 1024px) { + .detailsOverlay { + width: 25em; + } +} +.detailsOverlay .closeBtn { + position: absolute; + top: 0.5em; + right: 0.5em; + color: #f1c40f; + cursor: pointer; +} +.detailsOverlay .advice { + color: #e74c3c; + font-weight: bold; +} +.detailsOverlay .trace { + word-break: break-all; +} + +.table > div > .duration, .table > div > .startTime { + text-align: center; + white-space:nowrap; +} +.table > div > .startTime.domComplete { + background: @domCompleteBg; +} +.table > div > .startTime.domContentLoadedEnd { + background: @domContentLoadedEndBg; +} +.table > div > .startTime.domContentLoaded { + background: @domContentLoadedBg; +} +.table > div > .startTime.domInteractive { + background: @domInteractiveBg; +} +.table > div > .startTime.domCreation { + background: @domCreationBg; +} + +.table .icon-warning { + color: #e74c3c; +} + + +/**** NgModal popin (have a look inside bower_components) ****/ +.ng-modal { + position: fixed; + z-index: 9999; + top: 0; + left: 0; + width: 100%; + height: 100%; + text-align: left; +} +.ng-modal-overlay { + position: absolute; + z-index: 9999; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: #000; + opacity: 0.5; +} +.ng-modal-dialog { + z-index: 10000; + position: absolute; + top: 50%; + left: 50%; + width: 50%; + transform: translate(-50%, -50%); + -webkit-transform: translate(-50%, -50%); + background-color: #fff; + padding: 10px; + border: 3px solid #f1c40f; + border-radius: 0.5em; + color: #000; +} +.ng-modal-dialog-content { + overflow-x: hidden; + overflow-y: scroll; + word-wrap: break-word; + max-height: 20em; + font-weight: normal; + white-space: normal; +} +.ng-modal-close { + position: absolute; + top: 3px; + right: 5px; + cursor: pointer; + font-size: 120%; + padding: 5px; + display: inline-block; +} +.ng-modal-close-x { + font-weight: bold; + font-family: Arial, sans-serif; +} +.ng-modal-title { + font-weight: bold; + font-size: 1.5em; + display: block; + margin-bottom: 10px; + padding-bottom: 7px; + border-bottom: solid 1px #999; +} diff --git a/front/src/less/icons.less b/front/src/less/icons.less new file mode 100644 index 0000000..8a2c12a --- /dev/null +++ b/front/src/less/icons.less @@ -0,0 +1,56 @@ +@arrow-left3-font-family: "fontsmith-icons"; +@arrow-left3-value: "\e006"; +@arrow-left3: '"fontsmith-icons"' '"\\e006"'; +@lab-font-family: "fontsmith-icons"; +@lab-value: "\e003"; +@lab: '"fontsmith-icons"' '"\\e003"'; +@warning-font-family: "fontsmith-icons"; +@warning-value: "\e000"; +@warning: '"fontsmith-icons"' '"\\e000"'; +@list-font-family: "fontsmith-icons"; +@list-value: "\e002"; +@list: '"fontsmith-icons"' '"\\e002"'; +@eye-font-family: "fontsmith-icons"; +@eye-value: "\e004"; +@eye: '"fontsmith-icons"' '"\\e004"'; +@bars-font-family: "fontsmith-icons"; +@bars-value: "\e005"; +@bars: '"fontsmith-icons"' '"\\e005"'; +@question-font-family: "fontsmith-icons"; +@question-value: "\e001"; +@question: '"fontsmith-icons"' '"\\e001"'; + +.icon-font-family(@char) { + font-family: ~`@{char}[0]`; +} + +.icon-font() { + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} + +.icon-content(@char) { + content: ~`@{char}[1]`; +} + +.icon(@char) { + .icon-font-family(@char); + .icon-font(); + + &:before { + .icon-content(@char); + } +} + +@font-face { + font-family: "fontsmith-icons"; + src:url("/front/fonts/icons.woff") format("woff"), + ; + font-weight: normal; + font-style: normal; +} \ No newline at end of file diff --git a/front/src/less/index.less b/front/src/less/index.less new file mode 100644 index 0000000..5bbd573 --- /dev/null +++ b/front/src/less/index.less @@ -0,0 +1,38 @@ +.promess { + padding: 0em 2em 3em; + font-weight: normal; + font-size: 1.2em; +} + +.url { + width: 50%; +} + +.launchBtn { + background: #e74c3c; + color: #fff; + &.disabled { + background: #deaca6; + } +} + +input[type=submit], input.url { + padding: 0 0.5em; + margin: 0.5em; + font-size: 1.2em; + height: 2em; + border: 0 solid; + border-radius: 0.5em; + box-shadow: 0.1em 0.2em 0 0 #5e2846; + outline: none; +} +input[type=submit]:hover { + color: #ddd; +} +input[type=submit].clicked { + color: #ddd; + position: relative; + left: 0.1em; + top: 0.2em; + box-shadow: none; +} \ No newline at end of file diff --git a/front/src/less/main.less b/front/src/less/main.less new file mode 100644 index 0000000..79f6dd2 --- /dev/null +++ b/front/src/less/main.less @@ -0,0 +1,66 @@ +@import "icons.less"; + +html { + margin: 100px 50px; +} + +body { + margin: 0 auto; + max-width: 1280px; + background: #9c4274; + color: #fff; + font-size: 16px; + text-align: center; +} + +body, input[type=submit], input[type=text], input[type=url], input[type=number], button { + font-family: 'Century Gothic', helvetica, arial, sans-serif; +} + +input[type=submit] { + cursor: pointer; +} + +h1 span { + display: inline-block; + height: 1em; + width: 1em; + color: #ffa319; +} + +.footer { + padding: 3em; + color: #4e1836; + a { + color: inherit; + } + .star { + font-weight: bold; + span { + font-size: 1.2em; + } + } +} + +/* Icons */ +.icon-lab { + .icon(@lab); +} +.icon-question { + .icon(@question); +} +.icon-warning { + .icon(@warning); +} +.icon-back { + .icon(@arrow-left3); +} +.icon-summary { + .icon(@list); +} +.icon-spaghetti { + .icon(@bars); +} +.icon-eye { + .icon(@eye); +} \ No newline at end of file diff --git a/front/src/less/queue.less b/front/src/less/queue.less new file mode 100644 index 0000000..57a52f6 --- /dev/null +++ b/front/src/less/queue.less @@ -0,0 +1,19 @@ +.status { + margin-top: 2em; + font-size: 2.5em; +} + +@-webkit-keyframes rotating { + from { -webkit-transform: rotate(0deg); } + to { -webkit-transform: rotate(360deg); } +} +@keyframes rotating { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} + +.waiting .icon-lab { + -webkit-animation: rotating 3s linear 0s infinite; + -webkit-transform: translateZ(0); + animation: rotating 3s linear 0s infinite; +} \ No newline at end of file diff --git a/front/src/views/queue.html b/front/src/views/queue.html new file mode 100644 index 0000000..dcd631b --- /dev/null +++ b/front/src/views/queue.html @@ -0,0 +1,8 @@ +
Test failed
+
+ +
+
Test is running...
+
Test complete
\ No newline at end of file diff --git a/src b/src new file mode 100644 index 0000000..36a8a55 --- /dev/null +++ b/src @@ -0,0 +1,672 @@ +/* Timeline colors, related to Window Performances */ +.resultsMenu { + margin-top: 2em; +} +.resultsMenu .menuItem { + display: inline-block; + margin: 1em; + width: 8em; + height: 7em; + color: #fff; + border: 3px solid #fff; + border-radius: 0.5em; + cursor: pointer; + text-decoration: none; +} +.resultsMenu .back { + color: #5e2846; + border-color: #5e2846; +} +.resultsMenu .menuItem div { + padding-top: 0.5em; + font-size: 3em; +} +.resultsMenu .active, +.resultsMenu .menuItem.active:hover { + color: #ffa319; + border-color: #ffa319; +} +.resultsMenu .menuItem:hover { + color: #ffa319; +} +.resultsMenu span { + position: relative; + top: 0.5em; +} +.testedUrl { + color: inherit; +} +h4 { + margin-bottom: 0.5em; +} +.summary, +.metrics, +.execution { + margin-top: 2em; + padding: 1em; + background: #fff; + color: #000; + border-radius: 0.5em; + text-align: left; +} +.notations { + display: table; + width: 90%; + margin: 0 10%; + border-spacing: 1em; +} +.notations > div { + display: table-row; +} +.notations > div > div { + display: table-cell; + height: 2.5em; + vertical-align: middle; +} +.notations .notation { + font-weight: bold; + text-align: center; +} +.notations .criteria { + font-weight: normal; +} +.notations .A, +.notations .B, +.notations .C, +.notations .D, +.notations .E, +.notations .F, +.notations .NA { + width: 2.5em; + font-size: 2em; + text-align: center; + border-radius: 0.5em; + font-weight: bold; +} +.notations .A { + /* green */ + background: #00DB61; +} +.notations .B { + /* green */ + background: #CAD63D; +} +.notations .C { + /* yellow */ + background: #FFD119; +} +.notations .D { + /* orange */ + background: #FFA319; +} +.notations .E { + /* red */ + background: #FF6600; +} +.notations .F { + /* red */ + background: #FF1919; +} +.notations .NA { + /* Non applicable */ + background: #CCC; +} +.notations .icon-eye { + color: #9c4274; + cursor: pointer; +} +.notations .criteria .table { + width: 75%; +} +.notations .criteria .label { + width: 70%; +} +.notations .criteria .result { + width: 20%; + font-weight: bold; + white-space: nowrap; + text-align: center; +} +.notations .warning .label, +.notations .warning .result { + color: #FF1919; +} +.notations .criteria .info { + width: 10%; + text-align: center; +} +.notations .criteria .icon-question { + color: #f1c40f; + cursor: pointer; +} +.timeline { + margin: 2em 0 5em; +} +.timeline .chart { + position: relative; + width: 100%; + border-bottom: 1px solid #000; +} +.timeline .startTime, +.timeline .endTime { + position: absolute; + bottom: 0.5em; + font-size: 0.8em; +} +.timeline .startTime { + left: 0em; +} +.timeline .endTime { + right: 0em; +} +.timeline .chartPoints { + display: table; + height: 100px; + width: 99%; + margin: 0 auto; +} +.timeline .interval { + display: table-cell; + position: relative; + height: 100px; + width: 0.5%; +} +.timeline .interval .color { + position: absolute; + bottom: 0; + width: 100%; +} +.timeline div.interval:hover { + background: #9C4274; +} +.timeline .interval:hover .color { + background: #F04DA7; +} +.timeline .domComplete.interval { + background: #ede3ff; +} +.timeline .domComplete .color { + background: #c2a3ff; +} +.timeline .domContentLoadedEnd.interval { + background: #d8f0f0; +} +.timeline .domContentLoadedEnd .color { + background: #7ecccc; +} +.timeline .domContentLoaded.interval { + background: #e0ffd1; +} +.timeline .domContentLoaded .color { + background: #a7e846; +} +.timeline .domInteractive.interval { + background: #fffccc; +} +.timeline .domInteractive .color { + background: #ffe433; +} +.timeline .domCreation.interval { + background: #ffe0cc; +} +.timeline .domCreation .color { + background: #ff6600; +} +.timeline .tooltip.detailsOverlay { + position: absolute; + display: none; + width: auto; + padding: 0.5em 1em; + top: -1.5em; + right: 1em; +} +.timeline .interval:hover .tooltip { + display: block; +} +.timeline .legend { + display: table; + width: 100%; + margin-top: 1em; +} +.timeline .legend > div { + display: table-row; +} +.timeline .legend > div > div { + position: relative; + display: table-cell; + margin-top: 1em; +} +.timeline .titles { + font-weight: bold; +} +.timeline .titles > div { + padding: 0 1em 0 2em; +} +.timeline .tips { + font-size: 0.7em; +} +.timeline .tips > div { + padding: 1em 1em 0 0; +} +.timeline .legend .color { + display: block; + position: absolute; + left: 0; + height: 1.5em; + width: 1.5em; + border-radius: 0.2em; +} +.metrics h4 { + padding-left: 2em; +} +.metrics .module { + padding-left: 4em; + padding-top: 0.5em; +} +.metrics .legend { + font-style: italic; + color: #aaa; +} +.metrics .offenders { + padding-left: 0em; + font-size: 0.8em; +} +.metrics .offenders div { + cursor: pointer; +} +.metrics .offenders ul { + margin-top: 0.5em; +} +.filters { + margin: 1em 0; + padding: 0.5em; + border: 1px dotted #aaa; +} +.slowRequestsLimit { + width: 3em; + font-size: 1em; + text-align: right; + border: 1px solid #aaa; +} +input.textFilter { + box-shadow: none; + font-size: 1em; + padding: 0 0.2em; + border: 1px solid #aaa; + border-radius: none; + width: 15em; +} +.table { + display: table; + width: 100%; + border-spacing: 0.25em; +} +.table > div { + display: table-row; +} +.table > .headers > div { + font-weight: bold; + padding: 0.5em 1em; +} +.table > div > div { + padding: 0.1em 1em; + background: #f2f2f2; + display: table-cell; + text-align: left; +} +.table > div.jsError > .type, +.table > div.jsError > .value { + color: #e74c3c; + font-weight: bold; +} +.table > div.windowPerformance > div, +.table > div.windowPerformance > div.startTime { + background: #EBD8E2; +} +.table > div.showingDetails > div { + background: #f1c40f; +} +.table > div > .index { + color: #bbb; +} +.table > div > .type { + white-space: nowrap; +} +.table > div > .value { + width: 70%; + word-break: break-all; +} +.table > div > .details { + position: relative; +} +.table .details .icon-question { + color: #f1c40f; + cursor: pointer; +} +.table .details .icon-warning { + cursor: pointer; +} +.detailsOverlay { + position: absolute; + right: 3em; + top: -3em; + width: 45em; + min-height: 1em; + padding: 0 1em 1em; + background: #fff; + border: 2px solid #f1c40f; + border-radius: 0.5em; + z-index: 1; +} +@media screen and (max-width: 1024px) { + .detailsOverlay { + width: 25em; + } +} +.detailsOverlay .closeBtn { + position: absolute; + top: 0.5em; + right: 0.5em; + color: #f1c40f; + cursor: pointer; +} +.detailsOverlay .advice { + color: #e74c3c; + font-weight: bold; +} +.detailsOverlay .trace { + word-break: break-all; +} +.table > div > .duration, +.table > div > .startTime { + text-align: center; + white-space: nowrap; +} +.table > div > .startTime.domComplete { + background: #ede3ff; +} +.table > div > .startTime.domContentLoadedEnd { + background: #d8f0f0; +} +.table > div > .startTime.domContentLoaded { + background: #e0ffd1; +} +.table > div > .startTime.domInteractive { + background: #fffccc; +} +.table > div > .startTime.domCreation { + background: #ffe0cc; +} +.table .icon-warning { + color: #e74c3c; +} +/**** NgModal popin (have a look inside bower_components) ****/ +.ng-modal { + position: fixed; + z-index: 9999; + top: 0; + left: 0; + width: 100%; + height: 100%; + text-align: left; +} +.ng-modal-overlay { + position: absolute; + z-index: 9999; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: #000; + opacity: 0.5; +} +.ng-modal-dialog { + z-index: 10000; + position: absolute; + top: 50%; + left: 50%; + width: 50%; + transform: translate(-50%, -50%); + -webkit-transform: translate(-50%, -50%); + background-color: #fff; + padding: 10px; + border: 3px solid #f1c40f; + border-radius: 0.5em; + color: #000; +} +.ng-modal-dialog-content { + overflow-x: hidden; + overflow-y: scroll; + word-wrap: break-word; + max-height: 20em; + font-weight: normal; + white-space: normal; +} +.ng-modal-close { + position: absolute; + top: 3px; + right: 5px; + cursor: pointer; + font-size: 120%; + padding: 5px; + display: inline-block; +} +.ng-modal-close-x { + font-weight: bold; + font-family: Arial, sans-serif; +} +.ng-modal-title { + font-weight: bold; + font-size: 1.5em; + display: block; + margin-bottom: 10px; + padding-bottom: 7px; + border-bottom: solid 1px #999; +} + +@font-face { + font-family: "fontsmith-icons"; + src: url("/public/fonts/icons.woff") format("woff"); + font-weight: normal; + font-style: normal; +} + +.promess { + padding: 0em 2em 3em; + font-weight: normal; + font-size: 1.2em; +} +.url { + width: 50%; +} +.launchBtn { + background: #e74c3c; + color: #fff; +} +input[type=submit], +input.url { + padding: 0 0.5em; + margin: 0.5em; + font-size: 1.2em; + height: 2em; + border: 0 solid; + border-radius: 0.5em; + box-shadow: 0.1em 0.2em 0 0 #5e2846; + outline: none; +} +input[type=submit]:hover { + color: #ddd; +} +input[type=submit].clicked { + color: #ddd; + position: relative; + left: 0.1em; + top: 0.2em; + box-shadow: none; +} + +#status { + margin-top: 2em; + font-size: 2.5em; +} +@-webkit-keyframes rotating { + from { + -webkit-transform: rotate(0deg); + } + to { + -webkit-transform: rotate(360deg); + } +} +@keyframes rotating { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} +.waiting .icon-lab { + -webkit-animation: rotating 3s linear 0s infinite; + -webkit-transform: translateZ(0); + animation: rotating 3s linear 0s infinite; +} + +@font-face { + font-family: "fontsmith-icons"; + src: url("/public/fonts/icons.woff") format("woff"); + font-weight: normal; + font-style: normal; +} +html { + margin: 100px 50px; +} +body { + margin: 0 auto; + max-width: 1280px; + background: #9c4274; + color: #fff; + font-size: 16px; + text-align: center; +} +body, +input[type=submit], +input[type=text], +input[type=url], +input[type=number], +button { + font-family: 'Century Gothic', helvetica, arial, sans-serif; +} +input[type=submit] { + cursor: pointer; +} +h1 span { + display: inline-block; + height: 1em; + width: 1em; + color: #ffa319; +} +.footer { + padding: 3em; + color: #4e1836; +} +.footer a { + color: inherit; +} +.footer .star { + font-weight: bold; +} +.footer .star span { + font-size: 1.2em; +} +/* Icons */ +.icon-lab { + font-family: "fontsmith-icons"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} +.icon-lab:before { + content: "\e003"; +} +.icon-question { + font-family: "fontsmith-icons"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} +.icon-question:before { + content: "\e001"; +} +.icon-warning { + font-family: "fontsmith-icons"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} +.icon-warning:before { + content: "\e000"; +} +.icon-back { + font-family: "fontsmith-icons"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} +.icon-back:before { + content: "\e006"; +} +.icon-summary { + font-family: "fontsmith-icons"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} +.icon-summary:before { + content: "\e002"; +} +.icon-spaghetti { + font-family: "fontsmith-icons"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} +.icon-spaghetti:before { + content: "\e005"; +} +.icon-eye { + font-family: "fontsmith-icons"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} +.icon-eye:before { + content: "\e004"; +}