* widget layout implemented
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.widget.camera {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<p>
|
||||
animgif works!
|
||||
</p>
|
||||
<div class="widget camera">
|
||||
<img [src]="cameraUrls[0]">
|
||||
<img [src]="cameraUrls[1]">
|
||||
</div>
|
||||
|
||||
@@ -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<AnimGif> = [];
|
||||
@Input() cameraUrls: Array<string> = [];
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
constructor() {
|
||||
super();
|
||||
// gifyParse.getInfo();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
// @todo subscriber
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
|
||||
}
|
||||
|
||||
get imgHref(): string {
|
||||
return this.cameraUrls[1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
<h1>{{title}}</h1>
|
||||
<h2>{{data.all}}</h2>
|
||||
<h3>{{data.unassigned}}</h3>
|
||||
<p>unassigned</p>
|
||||
<div class="widget {{widgetClass}}">
|
||||
<h1>{{title}}</h1>
|
||||
<h2>{{data.all}}</h2>
|
||||
<h3>{{data.unassigned}}</h3>
|
||||
<p>unassigned</p>
|
||||
<i class="warning sign icon icon-background"></i>
|
||||
</div>
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
<p>
|
||||
info-box works!
|
||||
</p>
|
||||
<p>info-box works!</p>
|
||||
|
||||
@@ -15,4 +15,7 @@ export class InfoBoxComponent implements OnInit {
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
get widgetClass(): string {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,22 @@
|
||||
<p>
|
||||
<app-tr-progress
|
||||
title="OVERDUE PROGRESS INFOS (DAYS)"
|
||||
[data]="tspInfo.trProgressInfo"></app-tr-progress>
|
||||
<app-tr-flow-errors
|
||||
title="TR FLOW ERRORS"
|
||||
[data]="tspInfo.trFlowErrors"></app-tr-flow-errors>
|
||||
class="sizex2 col1 row1"
|
||||
title="TR INFO"
|
||||
[data]="{
|
||||
topData: tspInfo.trProgressInfo,
|
||||
bottomData: tspInfo.trFlowErrors
|
||||
}"></app-tr-progress>
|
||||
<app-pra-goals
|
||||
title="PRA TR GOALS(A,B,C PRIO)"
|
||||
class="sizey2 col4 row1"
|
||||
title="PRA TR GOALS (A,B,C PRIO)"
|
||||
[data]="tspInfo.praGoals"></app-pra-goals>
|
||||
<app-expedites
|
||||
class="col3 row1"
|
||||
title="NUMBER OF EXPEDITES (W/O PA)"
|
||||
[data]="tspInfo.expedites"></app-expedites>
|
||||
<app-animgif
|
||||
title=""
|
||||
[data]="tspInfo.animGifs"></app-animgif>
|
||||
class="col3 row2"
|
||||
title="ANIMATED IMPORTANCE"
|
||||
[data]="tspInfo.animGifs"
|
||||
[cameraUrls]="tspInfo.cameraUrls"></app-animgif>
|
||||
</p>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,24 +1,27 @@
|
||||
<h1>{{title}}</h1>
|
||||
<p>
|
||||
<span class="heading">CORE</span>
|
||||
<span class="heading">SIG</span>
|
||||
<span class="heading">TADE</span>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">{{data.core.A}}</span>
|
||||
<span class="heading">{{data.sig.A}}</span>
|
||||
<span class="heading">{{data.tade.A}}</span>
|
||||
</p>
|
||||
<h2>{{sumA}}</h2>
|
||||
<p>
|
||||
<span class="heading">{{data.core.B}}</span>
|
||||
<span class="heading">{{data.sig.B}}</span>
|
||||
<span class="heading">{{data.tade.B}}</span>
|
||||
</p>
|
||||
<h2>{{sumB}}</h2>
|
||||
<p>
|
||||
<span class="heading">{{data.core.C}}</span>
|
||||
<span class="heading">{{data.sig.C}}</span>
|
||||
<span class="heading">{{data.tade.C}}</span>
|
||||
</p>
|
||||
<h2>{{sumC}}</h2>
|
||||
<div class="widget">
|
||||
<h1>{{title}}</h1>
|
||||
<p class="header">
|
||||
<span>CORE</span>
|
||||
<span>SIG</span>
|
||||
<span>TADE</span>
|
||||
</p>
|
||||
<p class="smallnum">
|
||||
<span [class]="getClass(data.core.A)">{{data.core.A}}</span>
|
||||
<span [class]="getClass(data.sig.A)">{{data.sig.A}}</span>
|
||||
<span [class]="getClass(data.tade.A)">{{data.tade.A}}</span>
|
||||
</p>
|
||||
<h2 class="bignum {{getClass(sumA)}}">{{sumA}}</h2>
|
||||
<p class="smallnum">
|
||||
<span [class]="getClass(data.core.B)">{{data.core.B}}</span>
|
||||
<span [class]="getClass(data.sig.B)">{{data.sig.B}}</span>
|
||||
<span [class]="getClass(data.tade.B)">{{data.tade.B}}</span>
|
||||
</p>
|
||||
<h2 class="bignum {{getClass(sumB)}}">{{sumB}}</h2>
|
||||
<p class="smallnum">
|
||||
<span [class]="getClass(data.core.C)">{{data.core.C}}</span>
|
||||
<span [class]="getClass(data.sig.C)">{{data.sig.C}}</span>
|
||||
<span [class]="getClass(data.tade.C)">{{data.tade.C}}</span>
|
||||
</p>
|
||||
<h2 class="bignum {{getClass(sumC)}}">{{sumC}}</h2>
|
||||
<i class="cocktail icon icon-background"></i>
|
||||
</div>
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
<h1>{{title}} ({{errorSum}})</h1>
|
||||
<ul>
|
||||
<li *ngFor="let flowError of data">
|
||||
<span class="label">{{flowError.label}}</span>
|
||||
<span class="value">{{flowError.value}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="widget {{widgetClass}}">
|
||||
<h1>{{title}} ({{errorSum}})</h1>
|
||||
<ul>
|
||||
<li *ngFor="let flowError of data">
|
||||
<span class="label">{{flowError.label}}</span>
|
||||
<span class="value">{{flowError.value}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<i class="fire icon icon-background"></i>
|
||||
</div>
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.separator {
|
||||
margin-top: 65px;
|
||||
}
|
||||
@@ -1,7 +1,17 @@
|
||||
<h1>THE MOST OVERDUE PROGRESS INFOS (DAYS)</h1>
|
||||
<ul>
|
||||
<li *ngFor="let progress of data">
|
||||
<span class="label">{{progress.eriref}} {{progress.heading}}</span>
|
||||
<span class="value">{{progress.lastProgressInDays}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="widget {{widgetClass}}">
|
||||
<h1>THE MOST OVERDUE PROGRESS INFOS (DAYS)</h1>
|
||||
<ul>
|
||||
<li *ngFor="let progress of data.topData">
|
||||
<span class="label">{{progress.eriref}} {{progress.heading}}</span>
|
||||
<span class="value">{{progress.lastProgressInDays}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<h1 class="separator">TR FLOW ERRORS ({{errorSum}})</h1>
|
||||
<ul>
|
||||
<li *ngFor="let flowError of data.bottomData">
|
||||
<span class="label">{{flowError.label}}</span>
|
||||
<span class="value">{{flowError.value}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<i class="warning sign icon icon-background"></i>
|
||||
</div>
|
||||
|
||||
@@ -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<TrProgress> = [];
|
||||
@Input() data: {
|
||||
topData: Array<TrProgress>,
|
||||
bottomData: Array<TrFlowError>,
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user