* deploy config updated to deployer v4

* auto redirect to /kanban on page load
* priority separator implemented
* auto version reloader initial implementation
This commit is contained in:
Dávid Danyi 2017-08-23 19:06:55 +02:00
parent 935af4c533
commit f51b8090aa
12 changed files with 136 additions and 9 deletions

3
.gitignore vendored
View File

@ -1,5 +1,8 @@
# See http://help.github.com/ignore-files/ for more about ignoring files. # See http://help.github.com/ignore-files/ for more about ignoring files.
# dynamic generated by deployer on remote host
revision.json
# compiled output # compiled output
/semantic /semantic
/dist /dist

View File

@ -16,7 +16,7 @@ set('keep_releases', 3);
set('default_stage', 'production'); set('default_stage', 'production');
// Servers // Servers
server('vasgyuro', 'vasgyuro.tsp') host('vasgyuro.tsp')
->stage('production') ->stage('production')
->user('edvidan') ->user('edvidan')
->forwardAgent() ->forwardAgent()
@ -40,6 +40,11 @@ task('deploy:ng-upload', function() {
run("rm -f {{release_path}}/dist.tar.xz"); run("rm -f {{release_path}}/dist.tar.xz");
runLocally("rm -rf dist.tar.xz dist"); runLocally("rm -rf dist.tar.xz dist");
upload("htaccess", "{{release_path}}/dist/.htaccess"); 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'); desc('Deploy your project');

View File

@ -7,7 +7,8 @@ import { KanbanBoardComponent } from "./kanban/kanban-board/kanban-board.compone
const routes: Routes = [ const routes: Routes = [
{ {
path: '', path: '',
children: [] redirectTo: '/kanban',
pathMatch: 'full',
},{ },{
path: 'kanban', path: 'kanban',
children: [], children: [],

View File

@ -4,7 +4,9 @@ import {TimerObservable} from "rxjs/observable/TimerObservable";
import {KanbanService} from "./kanban/shared/kanban.service"; import {KanbanService} from "./kanban/shared/kanban.service";
import {Router} from "@angular/router"; 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_JIRA_REFRESH = 60000;
const TIMER_PAGE_SWITCH = 300000; const TIMER_PAGE_SWITCH = 300000;
@ -16,15 +18,21 @@ const TIMER_PAGE_SWITCH = 300000;
}) })
export class AppComponent implements OnInit, OnDestroy { export class AppComponent implements OnInit, OnDestroy {
selfUpdateCheckerTimer: Subscription;
reloadJiraIssueTimer: Subscription; reloadJiraIssueTimer: Subscription;
pageSwitchTimer: Subscription; pageSwitchTimer: Subscription;
constructor( constructor(
private selfUpdaterService: SelfUpdaterService,
private kanbanService: KanbanService, private kanbanService: KanbanService,
private router: Router private router: Router
) {} ) {}
public ngOnInit() { 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); let timer1 = TimerObservable.create(TIMER_JIRA_REFRESH, TIMER_JIRA_REFRESH);
this.reloadJiraIssueTimer = timer1.subscribe(() => { this.reloadJiraIssueTimer = timer1.subscribe(() => {
this.kanbanService.reload(); this.kanbanService.reload();
@ -38,6 +46,7 @@ export class AppComponent implements OnInit, OnDestroy {
} }
public ngOnDestroy() { public ngOnDestroy() {
this.selfUpdateCheckerTimer.unsubscribe();
this.reloadJiraIssueTimer.unsubscribe(); this.reloadJiraIssueTimer.unsubscribe();
this.pageSwitchTimer.unsubscribe(); this.pageSwitchTimer.unsubscribe();
} }

View File

@ -16,14 +16,36 @@
border-radius: 4px; border-radius: 4px;
} }
.ui.divided.items > .item:first-child { .ui.divided.items > .item:last-child {
border-top: 0; border-bottom: 0 !important;
} }
.ui.divided.items > .item { .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 { .ui.label {
opacity: 0.85; opacity: 0.85;
} 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);*/
/*}*/

View File

@ -1,6 +1,6 @@
<h1>{{rowHeading}}</h1> <h1>{{rowHeading}}</h1>
<div class="ui divided items"> <div class="ui divided items">
<div class="item" *ngFor="let kanbanEntry of kanbanEntries"> <div class="item {{kanbanEntry.issuePriority|lowercase}}" [ngClass]="entryClass(kanbanEntry)" *ngFor="let kanbanEntry of kanbanEntries">
<div class="content"> <div class="content">
<div class="task-description"> <div class="task-description">
<ng-template [ngIf]="hasLabels(kanbanEntry)"> <ng-template [ngIf]="hasLabels(kanbanEntry)">

View File

@ -40,4 +40,10 @@ export class KanbanEntryItemComponent implements OnInit {
return 'white'; return 'white';
} }
} }
public entryClass(entry: KanbanEntry) {
return {
'bottom-separator': entry.isLastOfPriority,
};
}
} }

View File

@ -8,6 +8,7 @@ import { KanbanService } from './shared/kanban.service';
import { KanbanEntryItemComponent } from './kanban-entry-item/kanban-entry-item.component'; import { KanbanEntryItemComponent } from './kanban-entry-item/kanban-entry-item.component';
import { PriorityColorPipe } from './shared/priority-color.pipe'; import { PriorityColorPipe } from './shared/priority-color.pipe';
import { ShortenTextPipe } from './shared/shorten-text.pipe'; import { ShortenTextPipe } from './shared/shorten-text.pipe';
import { SelfUpdaterService } from './shared/self-updater.service';
@NgModule({ @NgModule({
imports: [ imports: [
@ -22,6 +23,7 @@ import { ShortenTextPipe } from './shared/shorten-text.pipe';
], ],
providers: [ providers: [
KanbanService, KanbanService,
SelfUpdaterService,
], ],
exports: [], exports: [],
}) })

View File

@ -9,7 +9,7 @@ export class KanbanEntry {
public issueType: JiraIssueType; public issueType: JiraIssueType;
public status: JiraStatus; public status: JiraStatus;
public assignee: JiraAssignee; public assignee: JiraAssignee;
public issuePriority: string public issuePriority: string;
public issuePriorityIcon: string; public issuePriorityIcon: string;
public labels: Array<string>; public labels: Array<string>;
public prio: number; public prio: number;
@ -22,4 +22,5 @@ export class KanbanEntry {
public mhwebExternal: boolean; public mhwebExternal: boolean;
public team: string; public team: string;
public answerCode: string; public answerCode: string;
public isLastOfPriority: boolean;
} }

View File

@ -18,7 +18,7 @@ export class KanbanService {
constructor(private httpService: Http) {} constructor(private httpService: Http) {}
public getList(): Observable<KanbanBoard> { public getList(): Observable<KanbanBoard> {
return this.httpService.get(this.url).map(res => <KanbanBoard>res.json()) return this.httpService.get(this.url).map(res => this.preprocessPriorities(<KanbanBoard>res.json()));
} }
public resolve(route: ActivatedRouteSnapshot): Promise<KanbanBoard> { public resolve(route: ActivatedRouteSnapshot): Promise<KanbanBoard> {
@ -37,4 +37,25 @@ export class KanbanService {
this.cachedKanbanBoard = kanbanBoard; 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;
}
} }

View File

@ -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();
}));
});

View File

@ -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<number> {
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);
}
},
() => {}
);
}
}
}