From f51b8090aab079a132a4d02c527a2eb20ecc56c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Danyi?= Date: Wed, 23 Aug 2017 19:06:55 +0200 Subject: [PATCH] * deploy config updated to deployer v4 * auto redirect to /kanban on page load * priority separator implemented * auto version reloader initial implementation --- .gitignore | 3 ++ deploy.php | 7 +++- src/app/app-routing.module.ts | 3 +- src/app/app.component.ts | 9 ++++ .../kanban-entry-item.component.css | 30 +++++++++++-- .../kanban-entry-item.component.html | 2 +- .../kanban-entry-item.component.ts | 6 +++ src/app/kanban/kanban.module.ts | 2 + src/app/kanban/shared/kanban-entry.model.ts | 3 +- src/app/kanban/shared/kanban.service.ts | 23 +++++++++- .../shared/self-updater.service.spec.ts | 15 +++++++ src/app/kanban/shared/self-updater.service.ts | 42 +++++++++++++++++++ 12 files changed, 136 insertions(+), 9 deletions(-) create mode 100644 src/app/kanban/shared/self-updater.service.spec.ts create mode 100644 src/app/kanban/shared/self-updater.service.ts diff --git a/.gitignore b/.gitignore index 8f746f0..a96070b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ # See http://help.github.com/ignore-files/ for more about ignoring files. +# dynamic generated by deployer on remote host +revision.json + # compiled output /semantic /dist diff --git a/deploy.php b/deploy.php index 3de6e74..82cd47f 100644 --- a/deploy.php +++ b/deploy.php @@ -16,7 +16,7 @@ set('keep_releases', 3); set('default_stage', 'production'); // Servers -server('vasgyuro', 'vasgyuro.tsp') +host('vasgyuro.tsp') ->stage('production') ->user('edvidan') ->forwardAgent() @@ -40,6 +40,11 @@ task('deploy:ng-upload', function() { run("rm -f {{release_path}}/dist.tar.xz"); runLocally("rm -rf dist.tar.xz dist"); upload("htaccess", "{{release_path}}/dist/.htaccess"); + + $revision = get("release_name"); + within('{{release_path}}', function () use ($revision){ + run("echo $revision > dist/revision.json"); + }); }); desc('Deploy your project'); diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 739284f..ac290af 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -7,7 +7,8 @@ import { KanbanBoardComponent } from "./kanban/kanban-board/kanban-board.compone const routes: Routes = [ { path: '', - children: [] + redirectTo: '/kanban', + pathMatch: 'full', },{ path: 'kanban', children: [], diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 3fa81f4..bd8215f 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -4,7 +4,9 @@ import {TimerObservable} from "rxjs/observable/TimerObservable"; import {KanbanService} from "./kanban/shared/kanban.service"; import {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; @@ -16,15 +18,21 @@ const TIMER_PAGE_SWITCH = 300000; }) export class AppComponent implements OnInit, OnDestroy { + selfUpdateCheckerTimer: Subscription; reloadJiraIssueTimer: Subscription; pageSwitchTimer: Subscription; constructor( + private selfUpdaterService: SelfUpdaterService, private kanbanService: KanbanService, private router: Router ) {} public ngOnInit() { + let timer0 = TimerObservable.create(TIMER_DEPLOY_REFRESH, TIMER_JIRA_REFRESH); + this.selfUpdateCheckerTimer = timer0.subscribe(() => { + this.selfUpdaterService.checkAndReloadIfNecessary(); + }); let timer1 = TimerObservable.create(TIMER_JIRA_REFRESH, TIMER_JIRA_REFRESH); this.reloadJiraIssueTimer = timer1.subscribe(() => { this.kanbanService.reload(); @@ -38,6 +46,7 @@ export class AppComponent implements OnInit, OnDestroy { } public ngOnDestroy() { + this.selfUpdateCheckerTimer.unsubscribe(); this.reloadJiraIssueTimer.unsubscribe(); this.pageSwitchTimer.unsubscribe(); } diff --git a/src/app/kanban/kanban-entry-item/kanban-entry-item.component.css b/src/app/kanban/kanban-entry-item/kanban-entry-item.component.css index 8d58736..cf5a185 100644 --- a/src/app/kanban/kanban-entry-item/kanban-entry-item.component.css +++ b/src/app/kanban/kanban-entry-item/kanban-entry-item.component.css @@ -16,14 +16,36 @@ border-radius: 4px; } -.ui.divided.items > .item:first-child { - border-top: 0; +.ui.divided.items > .item:last-child { + border-bottom: 0 !important; } .ui.divided.items > .item { - border-top: 1px solid rgba(250, 250, 250, 0.25); + border-bottom: 1px solid rgba(250, 250, 250, 0.25); } .ui.label { opacity: 0.85; -} \ No newline at end of file + font-weight: bold; +} + +.ui.divided.items > .item.blocker.bottom-separator { + border-bottom: 1px solid rgba(219, 40, 40, 0.5); +} + +.ui.divided.items > .item.critical.bottom-separator { + border-bottom: 1px solid rgba(242, 113, 28, 0.5); +} + +.ui.divided.items > .item.major.bottom-separator { + border-bottom: 1px solid rgba(181, 204, 24, 0.5); +} + +.ui.divided.items > .item.minor.bottom-separator { + border-bottom: 1px solid rgba(0, 181, 173, 0.5); +} + +/*Nothing below trivial, no separator needed*/ +/*.ui.divided.items > .item.trivial.bottom-separator {*/ + /*border-bottom: 1px solid rgba(181, 204, 24, 0.5);*/ +/*}*/ diff --git a/src/app/kanban/kanban-entry-item/kanban-entry-item.component.html b/src/app/kanban/kanban-entry-item/kanban-entry-item.component.html index 64892df..23209af 100644 --- a/src/app/kanban/kanban-entry-item/kanban-entry-item.component.html +++ b/src/app/kanban/kanban-entry-item/kanban-entry-item.component.html @@ -1,6 +1,6 @@

{{rowHeading}}

-
+
diff --git a/src/app/kanban/kanban-entry-item/kanban-entry-item.component.ts b/src/app/kanban/kanban-entry-item/kanban-entry-item.component.ts index 388ce28..969b3f5 100644 --- a/src/app/kanban/kanban-entry-item/kanban-entry-item.component.ts +++ b/src/app/kanban/kanban-entry-item/kanban-entry-item.component.ts @@ -40,4 +40,10 @@ export class KanbanEntryItemComponent implements OnInit { return 'white'; } } + + public entryClass(entry: KanbanEntry) { + return { + 'bottom-separator': entry.isLastOfPriority, + }; + } } diff --git a/src/app/kanban/kanban.module.ts b/src/app/kanban/kanban.module.ts index 8bc89b0..8da0a94 100644 --- a/src/app/kanban/kanban.module.ts +++ b/src/app/kanban/kanban.module.ts @@ -8,6 +8,7 @@ import { KanbanService } from './shared/kanban.service'; import { KanbanEntryItemComponent } from './kanban-entry-item/kanban-entry-item.component'; import { PriorityColorPipe } from './shared/priority-color.pipe'; import { ShortenTextPipe } from './shared/shorten-text.pipe'; +import { SelfUpdaterService } from './shared/self-updater.service'; @NgModule({ imports: [ @@ -22,6 +23,7 @@ import { ShortenTextPipe } from './shared/shorten-text.pipe'; ], providers: [ KanbanService, + SelfUpdaterService, ], exports: [], }) diff --git a/src/app/kanban/shared/kanban-entry.model.ts b/src/app/kanban/shared/kanban-entry.model.ts index e4bcb64..e9fef74 100644 --- a/src/app/kanban/shared/kanban-entry.model.ts +++ b/src/app/kanban/shared/kanban-entry.model.ts @@ -9,7 +9,7 @@ export class KanbanEntry { public issueType: JiraIssueType; public status: JiraStatus; public assignee: JiraAssignee; - public issuePriority: string + public issuePriority: string; public issuePriorityIcon: string; public labels: Array; public prio: number; @@ -22,4 +22,5 @@ export class KanbanEntry { public mhwebExternal: boolean; public team: string; public answerCode: string; + public isLastOfPriority: boolean; } diff --git a/src/app/kanban/shared/kanban.service.ts b/src/app/kanban/shared/kanban.service.ts index 0ecaaa9..9ededfa 100644 --- a/src/app/kanban/shared/kanban.service.ts +++ b/src/app/kanban/shared/kanban.service.ts @@ -18,7 +18,7 @@ export class KanbanService { constructor(private httpService: Http) {} public getList(): Observable { - return this.httpService.get(this.url).map(res => res.json()) + return this.httpService.get(this.url).map(res => this.preprocessPriorities(res.json())); } public resolve(route: ActivatedRouteSnapshot): Promise { @@ -37,4 +37,25 @@ export class KanbanService { this.cachedKanbanBoard = kanbanBoard; } + private preprocessPriorities(kanbanBoard: KanbanBoard): KanbanBoard { + ['inbox','inProgress','verification','done'].map(progress => { + kanbanBoard[progress].map(entry => entry.isLastOfPriority = false); + ['Trivial', + 'Minor', + 'Major', + 'Critical', + 'Blocker'].map(prio => { + let prioLastIndex = -1; + kanbanBoard[progress].map( (entry, idx) => { + if(entry.issuePriority == prio) { + prioLastIndex = idx; + } + }); + try { + kanbanBoard[progress][prioLastIndex].isLastOfPriority = true; + } catch(e) {} + }); + }); + return kanbanBoard; + } } diff --git a/src/app/kanban/shared/self-updater.service.spec.ts b/src/app/kanban/shared/self-updater.service.spec.ts new file mode 100644 index 0000000..8be1bb2 --- /dev/null +++ b/src/app/kanban/shared/self-updater.service.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { SelfUpdaterService } from './self-updater.service'; + +describe('SelfUpdaterService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [SelfUpdaterService] + }); + }); + + it('should be created', inject([SelfUpdaterService], (service: SelfUpdaterService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/src/app/kanban/shared/self-updater.service.ts b/src/app/kanban/shared/self-updater.service.ts new file mode 100644 index 0000000..a1f3899 --- /dev/null +++ b/src/app/kanban/shared/self-updater.service.ts @@ -0,0 +1,42 @@ +import {Injectable} from '@angular/core'; +import {Http} from "@angular/http"; +import {Observable} from "rxjs/Observable"; + + +@Injectable() +export class SelfUpdaterService { + + private appRevision: number = 0; + private initFailed: boolean = false; + + constructor(private httpService: Http) { + console.log("init"); + this.getDeployedRevision().subscribe( + result => this.appRevision = result, + () => { + console.log( + "%c Couldn't load initial revision data from server. Self update disabled.", + "background: #222; color: #bada55;" + ); + this.initFailed = true; + } + ); + } + + private getDeployedRevision(): Observable { + return this.httpService.get("/revision.json").map(result => result.json()); + } + + public checkAndReloadIfNecessary() { + if (!this.initFailed) { + this.getDeployedRevision().subscribe( + result => { + if (result > this.appRevision) { + document.location.reload(true); + } + }, + () => {} + ); + } + } +}