diff --git a/package-lock.json b/package-lock.json index 57dcdf4..8e15fe6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3246,6 +3246,15 @@ } } }, + "gify-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/gify-parse/-/gify-parse-1.0.6.tgz", + "integrity": "sha1-NHRHheiiBLUhtJNtMFBwpqU0fos=", + "requires": { + "commander": "2.11.0", + "jdataview": "2.5.0" + } + }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", @@ -5560,6 +5569,11 @@ "integrity": "sha1-2llSddGuYx3nNqwKfH2Fyfc+9lI=", "dev": true }, + "jdataview": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/jdataview/-/jdataview-2.5.0.tgz", + "integrity": "sha1-MIGz/qZR+TF+xr1P6y3cmKpB1ZU=" + }, "jquery": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz", diff --git a/package.json b/package.json index 59685ef..3e6489a 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "@angular/platform-browser-dynamic": "^4.0.0", "@angular/router": "^4.0.0", "core-js": "^2.4.1", + "gify-parse": "^1.0.6", "rxjs": "^5.4.1", "semantic-ui": "^2.2.11", "zone.js": "^0.8.14" diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 97face8..56be8ad 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -3,13 +3,23 @@ import {Subscription} from "rxjs/Subscription"; import {TimerObservable} from "rxjs/observable/TimerObservable"; import {KanbanService} from "./kanban/shared/kanban.service"; -import {Router} from "@angular/router"; +import {ActivatedRoute, Router} from "@angular/router"; import {SelfUpdaterService} from "./kanban/shared/self-updater.service"; + const TIMER_DEPLOY_REFRESH = 30000; const TIMER_JIRA_REFRESH = 60000; -const TIMER_PAGE_SWITCH = 300000; +const TIMER_PAGE_SWITCH_TICK = 1000; +/** + * Page switch timer in seconds + * @type {number} + */ +const TIMESPENT_KANBAN = 120000; +const TIMESPENT_TSPINFO = 60000; + +const PAGE_KANBAN = '/kanban'; +const PAGE_TSPINFO = '/tsp-info-page'; @Component({ selector: 'app-root', @@ -17,23 +27,25 @@ const TIMER_PAGE_SWITCH = 300000; styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit, OnDestroy { + private currentPage: string = PAGE_KANBAN; + private lastNavOccured: number = Date.now(); + private autoSwitchEnabled: boolean = true; - selfUpdateCheckerTimer: Subscription; - reloadJiraIssueTimer: Subscription; - pageSwitchTimer: Subscription; + private selfUpdateCheckerTimer: Subscription; + private reloadJiraIssueTimer: Subscription; + private pageSwitchTimer: Subscription; - constructor( - private selfUpdaterService: SelfUpdaterService, - private kanbanService: KanbanService, - private router: Router - ) {} + constructor(private selfUpdaterService: SelfUpdaterService, + private kanbanService: KanbanService, + private router: Router, + private activatedRoute: ActivatedRoute) { + } /** * Initialize application timers: * - selfUpdateCheckerTimer is used to see if there is a newer revision deployed on the server * - reloadJiraIssueTimer is used to refresh the status of the jira board * - pageSwitchTimer handles switching back and forth between page views - * @todo: pageSwitchTimer */ public ngOnInit() { let timer0 = TimerObservable.create(TIMER_DEPLOY_REFRESH, TIMER_JIRA_REFRESH); @@ -44,17 +56,63 @@ export class AppComponent implements OnInit, OnDestroy { this.reloadJiraIssueTimer = timer1.subscribe(() => { this.kanbanService.reload(); }); - let timer2 = TimerObservable.create(TIMER_PAGE_SWITCH, TIMER_PAGE_SWITCH); - this.pageSwitchTimer = timer2.subscribe(() => { - // navigate to next page - // this.router.navigate(); - console.log("pageSwitch"); + this.activatedRoute.queryParamMap.subscribe(params => { + if (!params.has("disableAutoSwitch")) { + let timer2 = TimerObservable.create(TIMER_PAGE_SWITCH_TICK, TIMER_PAGE_SWITCH_TICK); + // this.pageSwitchTimer = timer2.subscribe(this.switchSubscriber.bind(this)); + } }); } public ngOnDestroy() { this.selfUpdateCheckerTimer.unsubscribe(); this.reloadJiraIssueTimer.unsubscribe(); - this.pageSwitchTimer.unsubscribe(); + if (this.pageSwitchTimer) { + // this.pageSwitchTimer.unsubscribe(); + } + } + + private switchSubscriber() { + let now = new Date(); + let weekDay = now.getDay(); + // on weekdays + if (weekDay > 0 && weekDay < 6) { + if (now.getHours() == 9 && now.getMinutes() >= 14 && this.autoSwitchEnabled) { + this.navigateToPage(PAGE_KANBAN); + this.autoSwitchEnabled = false; + } + if (now.getHours() == 9 && now.getMinutes() >= 29 && !this.autoSwitchEnabled) { + this.navigateToPage(PAGE_TSPINFO); + this.autoSwitchEnabled = true; + } + } + if (this.autoSwitchEnabled) { + let compareTimer: number = 0; + let switchTo: string = ''; + switch (this.currentPage) { + case PAGE_KANBAN: + compareTimer = TIMESPENT_KANBAN; + switchTo = PAGE_TSPINFO; + break; + case PAGE_TSPINFO: + compareTimer = TIMESPENT_TSPINFO; + switchTo = PAGE_KANBAN; + break; + default: + console.error("Unknown page in pageSwitcherTimer"); + return false; + } + if ((Date.now() - this.lastNavOccured) > compareTimer) { + this.navigateToPage(switchTo); + } + } + } + + private navigateToPage(page: string) { + if (page != this.currentPage) { + this.router.navigate([page]); + this.currentPage = page; + this.lastNavOccured = Date.now(); + } } } diff --git a/src/app/tsp-info/animgif/animgif.component.css b/src/app/tsp-info/animgif/animgif.component.css index e69de29..f58749a 100644 --- a/src/app/tsp-info/animgif/animgif.component.css +++ b/src/app/tsp-info/animgif/animgif.component.css @@ -0,0 +1,3 @@ +.widget.camera { + padding: 0; +} diff --git a/src/app/tsp-info/animgif/animgif.component.html b/src/app/tsp-info/animgif/animgif.component.html index 384a806..da25e26 100644 --- a/src/app/tsp-info/animgif/animgif.component.html +++ b/src/app/tsp-info/animgif/animgif.component.html @@ -1,3 +1,4 @@ -

- animgif works! -

+
+ + +
diff --git a/src/app/tsp-info/animgif/animgif.component.ts b/src/app/tsp-info/animgif/animgif.component.ts index 264e975..7807dad 100644 --- a/src/app/tsp-info/animgif/animgif.component.ts +++ b/src/app/tsp-info/animgif/animgif.component.ts @@ -1,21 +1,37 @@ -import { Component, OnInit } from '@angular/core'; +import {Component, Input, OnDestroy, OnInit} from '@angular/core'; import {InfoBoxComponent} from "../info-box/info-box.component"; +import {AnimGif} from "../shared/anim-gif.model"; + +// import gifyParse from "gify-parse/gify-parse"; @Component({ - selector: 'app-animgif', - templateUrl: './animgif.component.html', - styleUrls: [ - '../info-box/info-box.component.css', - './animgif.component.css' - ] + selector: 'app-animgif', + templateUrl: './animgif.component.html', + styleUrls: [ + '../info-box/info-box.component.css', + './animgif.component.css' + ] }) -export class AnimgifComponent extends InfoBoxComponent implements OnInit { +export class AnimgifComponent extends InfoBoxComponent implements OnInit, OnDestroy { - constructor() { - super(); - } + @Input() data: Array = []; + @Input() cameraUrls: Array = []; - ngOnInit() { - } + constructor() { + super(); + // gifyParse.getInfo(); + } + + ngOnInit() { + // @todo subscriber + } + + ngOnDestroy() { + + } + + get imgHref(): string { + return this.cameraUrls[1]; + } } diff --git a/src/app/tsp-info/expedites/expedites.component.css b/src/app/tsp-info/expedites/expedites.component.css index e69de29..a9ec512 100644 --- a/src/app/tsp-info/expedites/expedites.component.css +++ b/src/app/tsp-info/expedites/expedites.component.css @@ -0,0 +1,16 @@ +h2 { + text-transform: uppercase; + font-size: 76px; + font-weight: 700 +} + +h3 { + font-weight: 500; + font-size: 30px; + color: white; +} + +p { + font-size: 15px; + color: rgba(255, 255, 255, 0.7); +} \ No newline at end of file diff --git a/src/app/tsp-info/expedites/expedites.component.html b/src/app/tsp-info/expedites/expedites.component.html index dc98698..b6bef4b 100644 --- a/src/app/tsp-info/expedites/expedites.component.html +++ b/src/app/tsp-info/expedites/expedites.component.html @@ -1,4 +1,7 @@ -

{{title}}

-

{{data.all}}

-

{{data.unassigned}}

-

unassigned

+
+

{{title}}

+

{{data.all}}

+

{{data.unassigned}}

+

unassigned

+ +
\ No newline at end of file diff --git a/src/app/tsp-info/expedites/expedites.component.ts b/src/app/tsp-info/expedites/expedites.component.ts index b4ad29a..f3c4070 100644 --- a/src/app/tsp-info/expedites/expedites.component.ts +++ b/src/app/tsp-info/expedites/expedites.component.ts @@ -20,4 +20,11 @@ export class ExpeditesComponent extends InfoBoxComponent implements OnInit { ngOnInit() {} + get widgetClass(): string { + return this.data.unassigned > 0 + ? 'critical' + : this.data.all > 0 + ? 'warn' + : 'ok'; + } } diff --git a/src/app/tsp-info/info-box/info-box.component.css b/src/app/tsp-info/info-box/info-box.component.css index 39daac2..807450c 100644 --- a/src/app/tsp-info/info-box/info-box.component.css +++ b/src/app/tsp-info/info-box/info-box.component.css @@ -1,5 +1,107 @@ :host { - display: inline-block; - padding: 1.25em; - background-color: #0E566C; + position: absolute; + z-index: 2; + display: table; + width: 468px; + height: 525px; + background-color: #00285F; + color: rgba(255, 255, 255, 0.7); + font-family: 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 20px; + box-shadow: 5px 5px 10px #222; +} + +:host-context(.sizex2) { + width: 946px; +} + +:host-context(.sizey2) { + height: 1060px; +} + +:host-context(.col1) { + left: 10px; +} + +:host-context(.col2) { + left: 488px; +} + +:host-context(.col3) { + left: 966px; +} + +:host-context(.col4) { + left: 1444px; +} + +:host-context(.row1) { + top: 10px; +} + +:host-context(.row2) { + top: 545px; +} + +h1 { + font-family: 'EricssonCapital', "Helvetica Neue", Helvetica, Arial, sans-serif; + margin-bottom: 12px; + text-align: center; + font-size: 30px; + font-weight: bold; + padding: 0; +} + +ul { + list-style: none; + margin: 0 15px; + padding: 0; + overflow: hidden; +} + +ul > li { + margin: 0 0 5px; + overflow: hidden; +} + +ul > li > span.label { + float: left; +} + +ul > li > span.value { + float: right; +} + +.widget { + width: 100%; + height: 100%; + padding: 52px 12px; + display: table-cell; + vertical-align: middle; + text-align: center; + position: relative; +} + +.icon-background { + width: 100% !important; + height: 100%; + position: absolute; + left: 0; + top: 0; + opacity: 0.1; + font-size: 300px; + text-align: center; + margin-top: 255px; +} + +.ok { + background-color: rgb(137, 186, 23); +} + +.warn { + background-color: #E95C38; +} + +.critical { + background-color: rgb(227, 33, 25); } diff --git a/src/app/tsp-info/info-box/info-box.component.html b/src/app/tsp-info/info-box/info-box.component.html index b3fa334..9eb7d13 100644 --- a/src/app/tsp-info/info-box/info-box.component.html +++ b/src/app/tsp-info/info-box/info-box.component.html @@ -1,3 +1 @@ -

- info-box works! -

+

info-box works!

diff --git a/src/app/tsp-info/info-box/info-box.component.ts b/src/app/tsp-info/info-box/info-box.component.ts index f317132..a490651 100644 --- a/src/app/tsp-info/info-box/info-box.component.ts +++ b/src/app/tsp-info/info-box/info-box.component.ts @@ -15,4 +15,7 @@ export class InfoBoxComponent implements OnInit { ngOnInit() { } + get widgetClass(): string { + return ''; + } } diff --git a/src/app/tsp-info/info-page/info-page.component.html b/src/app/tsp-info/info-page/info-page.component.html index f56b2eb..a36e504 100644 --- a/src/app/tsp-info/info-page/info-page.component.html +++ b/src/app/tsp-info/info-page/info-page.component.html @@ -1,17 +1,22 @@

- + class="sizex2 col1 row1" + title="TR INFO" + [data]="{ + topData: tspInfo.trProgressInfo, + bottomData: tspInfo.trFlowErrors + }"> + class="col3 row2" + title="ANIMATED IMPORTANCE" + [data]="tspInfo.animGifs" + [cameraUrls]="tspInfo.cameraUrls">

diff --git a/src/app/tsp-info/pra-goals/pra-goals.component.css b/src/app/tsp-info/pra-goals/pra-goals.component.css index e69de29..349fc03 100644 --- a/src/app/tsp-info/pra-goals/pra-goals.component.css +++ b/src/app/tsp-info/pra-goals/pra-goals.component.css @@ -0,0 +1,28 @@ +p > span { + margin: 0 30px; +} + +.header { + margin: 0 20px 0; + font-size: 20px; + font-weight: 200; +} + +.smallnum { + font-size: 30px; + font-weight: 500; +} + +.bignum { + text-transform: uppercase; + font-size: 76px; + font-weight: 700; +} + +.numok { + color: rgb(137, 186, 23); +} + +.numbad { + color: rgb(227, 33, 25); +} \ No newline at end of file diff --git a/src/app/tsp-info/pra-goals/pra-goals.component.html b/src/app/tsp-info/pra-goals/pra-goals.component.html index 43f5f2b..2930e2e 100644 --- a/src/app/tsp-info/pra-goals/pra-goals.component.html +++ b/src/app/tsp-info/pra-goals/pra-goals.component.html @@ -1,24 +1,27 @@ -

{{title}}

-

- CORE - SIG - TADE -

-

- {{data.core.A}} - {{data.sig.A}} - {{data.tade.A}} -

-

{{sumA}}

-

- {{data.core.B}} - {{data.sig.B}} - {{data.tade.B}} -

-

{{sumB}}

-

- {{data.core.C}} - {{data.sig.C}} - {{data.tade.C}} -

-

{{sumC}}

+
+

{{title}}

+

+ CORE + SIG + TADE +

+

+ {{data.core.A}} + {{data.sig.A}} + {{data.tade.A}} +

+

{{sumA}}

+

+ {{data.core.B}} + {{data.sig.B}} + {{data.tade.B}} +

+

{{sumB}}

+

+ {{data.core.C}} + {{data.sig.C}} + {{data.tade.C}} +

+

{{sumC}}

+ +
diff --git a/src/app/tsp-info/pra-goals/pra-goals.component.ts b/src/app/tsp-info/pra-goals/pra-goals.component.ts index 681678c..b85736c 100644 --- a/src/app/tsp-info/pra-goals/pra-goals.component.ts +++ b/src/app/tsp-info/pra-goals/pra-goals.component.ts @@ -40,4 +40,8 @@ export class PraGoalsComponent extends InfoBoxComponent implements OnInit { public sum(prio: string) { return ['core', 'sig', 'tade'].reduce((sum,unit) => sum + this.data[unit][prio], 0); } + + public getClass(value: number) { + return value < 1 ? 'numok' : 'numbad'; + } } diff --git a/src/app/tsp-info/tr-flow-errors/tr-flow-errors.component.html b/src/app/tsp-info/tr-flow-errors/tr-flow-errors.component.html index 8a37b95..e12ca18 100644 --- a/src/app/tsp-info/tr-flow-errors/tr-flow-errors.component.html +++ b/src/app/tsp-info/tr-flow-errors/tr-flow-errors.component.html @@ -1,7 +1,10 @@ -

{{title}} ({{errorSum}})

- +
+

{{title}} ({{errorSum}})

+
    +
  • + {{flowError.label}} + {{flowError.value}} +
  • +
+ +
\ No newline at end of file diff --git a/src/app/tsp-info/tr-flow-errors/tr-flow-errors.component.ts b/src/app/tsp-info/tr-flow-errors/tr-flow-errors.component.ts index ab1212c..70eb768 100644 --- a/src/app/tsp-info/tr-flow-errors/tr-flow-errors.component.ts +++ b/src/app/tsp-info/tr-flow-errors/tr-flow-errors.component.ts @@ -24,4 +24,8 @@ export class TrFlowErrorsComponent extends InfoBoxComponent implements OnInit { get errorSum(): number { return this.data.reduce((sum: number, flowError: TrFlowError) => sum + flowError.value, 0); } + + get widgetClass(): string { + return this.data.length ? 'warn' : 'ok'; + } } diff --git a/src/app/tsp-info/tr-progress/tr-progress.component.css b/src/app/tsp-info/tr-progress/tr-progress.component.css index e69de29..7017376 100644 --- a/src/app/tsp-info/tr-progress/tr-progress.component.css +++ b/src/app/tsp-info/tr-progress/tr-progress.component.css @@ -0,0 +1,3 @@ +.separator { + margin-top: 65px; +} \ No newline at end of file diff --git a/src/app/tsp-info/tr-progress/tr-progress.component.html b/src/app/tsp-info/tr-progress/tr-progress.component.html index 28beb66..e90307e 100644 --- a/src/app/tsp-info/tr-progress/tr-progress.component.html +++ b/src/app/tsp-info/tr-progress/tr-progress.component.html @@ -1,7 +1,17 @@ -

THE MOST OVERDUE PROGRESS INFOS (DAYS)

- +
+

THE MOST OVERDUE PROGRESS INFOS (DAYS)

+
    +
  • + {{progress.eriref}} {{progress.heading}} + {{progress.lastProgressInDays}} +
  • +
+

TR FLOW ERRORS ({{errorSum}})

+
    +
  • + {{flowError.label}} + {{flowError.value}} +
  • +
+ +
diff --git a/src/app/tsp-info/tr-progress/tr-progress.component.ts b/src/app/tsp-info/tr-progress/tr-progress.component.ts index 5b412f2..fc7b61c 100644 --- a/src/app/tsp-info/tr-progress/tr-progress.component.ts +++ b/src/app/tsp-info/tr-progress/tr-progress.component.ts @@ -1,24 +1,38 @@ import {Component, Input, OnInit} from '@angular/core'; import {InfoBoxComponent} from "../info-box/info-box.component"; import {TrProgress} from "../shared/tr-progress.model"; +import {TrFlowError} from "../shared/tr-flow-error.model"; @Component({ - selector: 'app-tr-progress', - templateUrl: './tr-progress.component.html', - styleUrls: [ - '../info-box/info-box.component.css', - './tr-progress.component.css' - ] + selector: 'app-tr-progress', + templateUrl: './tr-progress.component.html', + styleUrls: [ + '../info-box/info-box.component.css', + './tr-progress.component.css' + ] }) export class TrProgressComponent extends InfoBoxComponent implements OnInit { - @Input() data: Array = []; + @Input() data: { + topData: Array, + bottomData: Array, + }; - constructor() { - super(); - } + constructor() { + super(); + } - ngOnInit() { - } + ngOnInit() { + } + get widgetClass(): string { + return [ + this.data.topData, + this.data.bottomData + ].every(data => data.length > 0) ? 'critical' : 'ok'; + } + + get errorSum(): number { + return this.data.bottomData.reduce((sum: number, flowError: TrFlowError) => sum + flowError.value, 0); + } } diff --git a/src/assets/font/impact.ttf b/src/assets/font/impact.ttf new file mode 100644 index 0000000..114e6c1 Binary files /dev/null and b/src/assets/font/impact.ttf differ diff --git a/src/assets/font/utm-ericsson-capital.ttf b/src/assets/font/utm-ericsson-capital.ttf new file mode 100644 index 0000000..7f02fa8 Binary files /dev/null and b/src/assets/font/utm-ericsson-capital.ttf differ diff --git a/src/styles.css b/src/styles.css index 4378392..27b075a 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1,57 +1,73 @@ /* You can add global styles to this file, and also import other style files */ +@import "//fonts.googleapis.com/css?family=Open+Sans:300,400,600,700"; + +@font-face { + font-family: 'EricssonCapital'; + src: url("./assets/font/utm-ericsson-capital.ttf"); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'Impact'; + src: url("./assets/font/impact.ttf"); + font-weight: normal; + font-style: normal; +} + html, body { - height: 100% !important; - overflow: hidden; + height: 100% !important; + overflow: hidden; } body { - background-color: #303030 !important; - color: #eeeeee !important; - margin-top: 1em !important; - margin-bottom: 1em !important; - font-weight: bold !important; + background-color: #303030 !important; + color: #eeeeee !important; + margin-top: 1em !important; + margin-bottom: 1em !important; + font-weight: bold !important; } app-kanban-board { - overflow: hidden; + overflow: hidden; } .ui.fullwide-container { - margin-left: 1em; - margin-right: 1em; + margin-left: 1em; + margin-right: 1em; } .match-mhr { - text-justify: none; - color: mediumpurple; + text-justify: none; + color: mediumpurple; } .match-s { - text-justify: none; - color: #00b5ad; + text-justify: none; + color: #00b5ad; } .match-m { - text-justify: none; - color: #0ea432; + text-justify: none; + color: #0ea432; } .match-l { - text-justify: none; - color: #ffbf00; + text-justify: none; + color: #ffbf00; } .match-xl { - text-justify: none; - color: coral; + text-justify: none; + color: coral; } .over-wip { - background-color: rgba(194,59,34, 0.3); + background-color: rgba(194, 59, 34, 0.3); } .prio-icon { - display: inline-block; - vertical-align: middle; + display: inline-block; + vertical-align: middle; }