* Home key added to navigation, navigates to dashboard

* route animation reworked into routeTransition to avoid memory leaks
This commit is contained in:
Dávid Danyi 2018-09-24 15:54:27 +02:00
parent 41ad9d9a28
commit 8aa0828701
14 changed files with 138 additions and 137 deletions

23
src/app/admin/admin-routing.module.ts Normal file → Executable file
View File

@ -11,63 +11,56 @@ import { SlideResolverService } from './slide-resolver.service';
import { SlideService } from '../shared/service/slide.service';
import { DashboardComponent } from './dashboard/dashboard.component';
const routes: Routes = [
{
path: 'admin',
redirectTo: '/dashboard',
pathMatch: 'full'
// canActivate: [AuthGuardService, RoleGuardService],
pathMatch: 'full',
}, {
path: 'dashboard',
component: DashboardComponent,
// canActivate: [AuthGuardService, RoleGuardService],
}, {
path: 'admin/teams',
component: TeamListComponent,
// canActivate: [AuthGuardService, RoleGuardService],
resolve: {
teams: TeamService,
}
}, {
path: 'admin/team/new',
component: TeamEditorComponent,
// canActivate: [AuthGuardService, RoleGuardService],
}, {
path: 'admin/team/edit/:id',
component: TeamEditorComponent,
// canActivate: [AuthGuardService, RoleGuardService],
resolve: {
team: TeamResolverService,
}
},
}, {
path: 'admin/slides',
component: SlideListComponent,
// canActivate: [AuthGuardService, RoleGuardService],
resolve: {
slides: SlideService,
teams: TeamService,
}
},
}, {
path: 'admin/slide/new',
component: SlideEditorComponent,
// canActivate: [AuthGuardService, RoleGuardService],
resolve: {
teams: TeamService,
}
},
}, {
path: 'admin/slide/edit/:id',
component: SlideEditorComponent,
// canActivate: [AuthGuardService, RoleGuardService],
resolve: {
slide: SlideResolverService,
teams: TeamService,
}
},
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class AdminRoutingModule {
}
export class AdminRoutingModule {}

View File

@ -1,2 +1,4 @@
<div class="pause-indicator" *ngIf="paused">Slideshow is paused</div>
<router-outlet></router-outlet>
<main [@routerTransition]="getAnimationData(o)">
<router-outlet #o="outlet"></router-outlet>
</main>

View File

@ -1,15 +1,21 @@
import { Component, HostListener, OnInit } from '@angular/core';
import { TimerService } from './shared/service/timer.service';
import { SlideShowService } from './display/slide-show.service';
import { Router, RouterOutlet } from '@angular/router';
import { slideInOutAnimation } from './shared/slide-in-out-animation';
import { AnimationDirection, SettingsService } from './shared/service/settings.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
styleUrls: ['./app.component.css'],
animations: [slideInOutAnimation],
})
export class AppComponent implements OnInit {
constructor(private timerService: TimerService,
private slideShowService: SlideShowService) {}
private slideShowService: SlideShowService,
private settings: SettingsService,
private router: Router) {}
public ngOnInit() {}
@ -17,6 +23,9 @@ export class AppComponent implements OnInit {
private keyPressed(key: string) {
if (this.timerService.autoSwitch) {
switch (key) {
case 'Home':
this.router.navigate(['/dashboard']);
break;
case ' ':
this.timerService.togglePause();
break;
@ -35,4 +44,14 @@ export class AppComponent implements OnInit {
public get paused(): boolean {
return this.timerService.paused;
}
public getAnimationData(outlet: RouterOutlet) {
return {
value: outlet.activatedRouteData.state ? outlet.activatedRouteData.state : false,
params: {
offsetEnter: this.settings.animationDirection === AnimationDirection.LEFT ? -100 : 100,
offsetLeave: this.settings.animationDirection === AnimationDirection.LEFT ? 100 : -100,
}
};
}
}

View File

@ -1,5 +1,11 @@
:host {
background-color: #444;
position: fixed;
display: block;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.ui.label.inprogress {

View File

@ -1,11 +1,10 @@
import {Component, HostBinding, OnDestroy, OnInit} from '@angular/core';
import {Component, OnDestroy, OnInit} from '@angular/core';
import {Title} from '@angular/platform-browser';
import {ActivatedRoute} from '@angular/router';
import {Subscription, timer} from 'rxjs';
import {slideInOutAnimation} from '../../shared/slide-in-out-animation';
import {CommitTrackerService} from '../../shared/service/commit-tracker.service';
import {AnimationDirection, SettingsService} from '../../shared/service/settings.service';
import {SettingsService} from '../../shared/service/settings.service';
import {Commit} from '../../shared/commit';
import {CommitStatus} from '../../shared/commit-status.enum';
import {Result} from '../../shared/result.enum';
@ -19,20 +18,12 @@ const DEFAULT_AVATAR = '/assets/riddler.png';
selector: 'app-commit-tracker',
templateUrl: './commit-tracker.component.html',
styleUrls: ['./commit-tracker.component.css'],
animations: [slideInOutAnimation]
})
export class CommitTrackerComponent implements OnInit, OnDestroy {
public CommitStatus = CommitStatus;
private refreshCommitTrackerTimer: Subscription;
@HostBinding('@slideInOutAnimation')
public get slideInOutAnimation() {
return this.settings.animationDirection === AnimationDirection.RIGHT
? {value: 'right', params: {offsetEnter: 100, offsetLeave: -100}}
: {value: 'left', params: {offsetEnter: -100, offsetLeave: 100}};
}
constructor(private commitTrackerService: CommitTrackerService,
private settings: SettingsService,
private titleService: Title,

View File

@ -9,109 +9,117 @@ import { SlideShowComponent } from './slide-show/slide-show.component';
import { SlideResolverService } from '../admin/slide-resolver.service';
import { KanbanBoardComponent } from './kanban-board/kanban-board.component';
import { KanbanService } from './shared';
import {WatchersComponent} from './watchers/watchers.component';
import {WatcherService} from './shared/watcher.service';
import { WatchersComponent } from './watchers/watchers.component';
import { WatcherService } from './shared/watcher.service';
const routes: Routes = [
{
path: 'slideshow/:id',
component: SlideShowComponent,
// canActivate: [AuthGuardService, RoleGuardService],
resolve: {
slide: SlideResolverService,
},
data: {
autoSwitchable: false
autoSwitchable: false,
state: 'slideshow',
}
}, {
path: 'slideshow-odd/:id',
component: SlideShowComponent,
// canActivate: [AuthGuardService, RoleGuardService],
resolve: {
slide: SlideResolverService,
},
data: {
autoSwitchable: true
autoSwitchable: true,
state: 'slideshow-odd',
}
}, {
path: 'slideshow-even/:id',
component: SlideShowComponent,
// canActivate: [AuthGuardService, RoleGuardService],
resolve: {
slide: SlideResolverService,
},
data: {
autoSwitchable: true
autoSwitchable: true,
state: 'slideshow-even',
}
}, {
path: 'commit-tracker',
component: CommitTrackerComponent,
// canActivate: [AuthGuardService, RoleGuardService],
resolve: {
commits: CommitTrackerService,
},
data: {
autoSwitchable: true
autoSwitchable: true,
state: 'commit-tracker',
}
}, {
path: 'commit-tracker-fixed',
component: CommitTrackerComponent,
// canActivate: [AuthGuardService, RoleGuardService],
resolve: {
commits: CommitTrackerService,
},
data: {
autoSwitchable: false,
state: 'commit-tracker-fixed',
}
}, {
path: 'kanban',
component: KanbanBoardComponent,
// canActivate: [AuthGuardService, RoleGuardService],
resolve: {
kanbanBoard: KanbanService,
},
data: {
autoSwitchable: true
autoSwitchable: true,
state: 'kanban',
}
}, {
path: 'kanban-fixed',
component: KanbanBoardComponent,
// canActivate: [AuthGuardService, RoleGuardService],
resolve: {
kanbanBoard: KanbanService,
},
data: {
autoSwitchable: false
autoSwitchable: false,
state: 'kanban-fixed',
}
}, {
path: 'watchers',
component: WatchersComponent,
// canActivate: [AuthGuardService, RoleGuardService],
resolve: {
watchers: WatcherService,
},
data: {
autoSwitchable: true
autoSwitchable: true,
state: 'watchers',
}
}, {
path: 'watchers-fixed',
component: WatchersComponent,
// canActivate: [AuthGuardService, RoleGuardService],
resolve: {
watchers: WatcherService,
},
data: {
autoSwitchable: false
autoSwitchable: false,
state: 'watchers-fixed',
}
}, {
path: 'settings',
component: SettingsComponent,
// canActivate: [AuthGuardService, RoleGuardService],
resolve: {
teams: TeamService,
},
data: {
autoSwitchable: true,
// state: 'settings',
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class DisplayRoutingModule { }
export class DisplayRoutingModule {}

View File

@ -1,5 +1,10 @@
:host {
display: inline-block;
position: fixed;
display: block;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: 100vh;
overflow-x: hidden;
overflow-y: scroll;

View File

@ -1,37 +1,28 @@
import {Component, HostBinding, OnInit} from '@angular/core';
import {Component, OnInit} from '@angular/core';
import {Title} from '@angular/platform-browser';
import {ActivatedRoute} from '@angular/router';
import {KanbanBoard, KanbanEntry, KanbanService,} from '../shared';
import {slideInOutAnimation} from '../../shared/slide-in-out-animation';
import {AnimationDirection, SettingsService} from '../../shared/service/settings.service';
import {SettingsService} from '../../shared/service/settings.service';
@Component({
selector: 'app-kanban-board',
templateUrl: './kanban-board.component.html',
styleUrls: ['./kanban-board.component.css'],
animations: [slideInOutAnimation]
})
export class KanbanBoardComponent implements OnInit {
@HostBinding('@slideInOutAnimation')
public get slideInOutAnimation() {
return this.settingService.animationDirection === AnimationDirection.RIGHT
? {value: 'right', params: {offsetEnter: 100, offsetLeave: -100}}
: {value: 'left', params: {offsetEnter: -100, offsetLeave: 100}};
}
constructor(private titleService: Title,
private route: ActivatedRoute,
private kanbanService: KanbanService,
private settingService: SettingsService) {
private settings: SettingsService) {
}
/**
* Set page title, and handle preloaded kanbanBoard data
*/
ngOnInit() {
this.titleService.setTitle(`${this.settingService.team.name} : Kanban board`);
this.titleService.setTitle(`${this.settings.team.name} : Kanban board`);
this.route.data.subscribe((data: {
kanbanBoard: KanbanBoard,
}) => {
@ -48,7 +39,7 @@ export class KanbanBoardComponent implements OnInit {
}
get inprogressWipLimit(): number {
return this.settingService.team.inprogressColumn.wipLimit;
return this.settings.team.inprogressColumn.wipLimit;
}
get inprogressWipCount(): number {
@ -67,12 +58,12 @@ export class KanbanBoardComponent implements OnInit {
*/
get inprogressWipClass() {
return {
'over-wip': this.inprogressWipCount > this.settingService.team.inprogressColumn.wipLimit,
'over-wip': this.inprogressWipCount > this.settings.team.inprogressColumn.wipLimit,
};
}
get verificationWipLimit(): number {
return this.settingService.team.verificationColumn.wipLimit;
return this.settings.team.verificationColumn.wipLimit;
}
get verificationWipCount(): number {
@ -91,23 +82,23 @@ export class KanbanBoardComponent implements OnInit {
*/
get verificationWipClass() {
return {
'over-wip': this.verificationWipCount > this.settingService.team.verificationColumn.wipLimit,
'over-wip': this.verificationWipCount > this.settings.team.verificationColumn.wipLimit,
};
}
get backlogLabel(): string {
return this.settingService.team.backlogColumn.label;
return this.settings.team.backlogColumn.label;
}
get inProgressLabel(): string {
return this.settingService.team.inprogressColumn.label;
return this.settings.team.inprogressColumn.label;
}
get verificationLabel(): string {
return this.settingService.team.verificationColumn.label;
return this.settings.team.verificationColumn.label;
}
get doneLabel(): string {
return this.settingService.team.doneColumn.label;
return this.settings.team.doneColumn.label;
}
}

10
src/app/display/settings/settings.component.ts Normal file → Executable file
View File

@ -15,20 +15,20 @@ export class SettingsComponent implements OnInit {
public slideInterval: number;
constructor(private route: ActivatedRoute,
private settingsService: SettingsService,
private settings: SettingsService,
private router: Router) {}
ngOnInit() {
this.route.data.subscribe((data: {teams: Array<Team>}) => {
this.teams = data.teams;
this.selectedTeam = this.teams.find(team => team.id === this.settingsService.team.id);
this.slideInterval = this.settingsService.slideInterval;
this.selectedTeam = this.teams.find(team => team.id === this.settings.team.id);
this.slideInterval = this.settings.slideInterval;
});
}
public saveSettings() {
this.settingsService.team = this.selectedTeam;
this.settingsService.slideInterval = this.slideInterval;
this.settings.team = this.selectedTeam;
this.settings.slideInterval = this.slideInterval;
this.router.navigate(['/admin']);
}
}

8
src/app/display/slide-show/slide-show.component.css Normal file → Executable file
View File

@ -0,0 +1,8 @@
:host {
position: fixed;
display: block;
top: 0;
left: 0;
right: 0;
bottom: 0;
}

View File

@ -1,32 +1,21 @@
import {Component, HostBinding, OnInit} from '@angular/core';
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {Title} from '@angular/platform-browser';
import * as marked from 'marked';
import {Slide, SlideType} from '../../shared/slide';
import {slideInOutAnimation} from '../../shared/slide-in-out-animation';
import {AnimationDirection, SettingsService} from '../../shared/service/settings.service';
@Component({
selector: 'app-slide-show',
templateUrl: './slide-show.component.html',
styleUrls: ['./slide-show.component.css'],
animations: [slideInOutAnimation]
})
export class SlideShowComponent implements OnInit {
private md;
public slide: Slide;
@HostBinding('@slideInOutAnimation')
public get slideInOutAnimation() {
return this.settings.animationDirection === AnimationDirection.RIGHT
? {value: 'right', params: {offsetEnter: 100, offsetLeave: -100}}
: {value: 'left', params: {offsetEnter: -100, offsetLeave: 100}};
}
constructor(private route: ActivatedRoute,
private titleService: Title,
private settings: SettingsService) {
private titleService: Title) {
this.md = marked.setOptions({});
}

View File

@ -1,5 +1,11 @@
:host {
background-color: #444;
position: fixed;
display: block;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
/* avatar */

View File

@ -1,8 +1,7 @@
import {Component, HostBinding, OnInit} from '@angular/core';
import {Component, OnInit} from '@angular/core';
import {Title} from '@angular/platform-browser';
import {ActivatedRoute} from '@angular/router';
import {AnimationDirection, SettingsService} from '../../shared/service/settings.service';
import {slideInOutAnimation} from '../../shared/slide-in-out-animation';
import {SettingsService} from '../../shared/service/settings.service';
import {WatcherService} from '../shared/watcher.service';
import {WatchedIssue} from '../shared/watched-issue.model';
import {environment} from '../../../environments/environment';
@ -13,17 +12,9 @@ const DEFAULT_AVATAR = '/assets/riddler.png';
selector: 'app-watchers',
templateUrl: './watchers.component.html',
styleUrls: ['./watchers.component.css'],
animations: [slideInOutAnimation]
})
export class WatchersComponent implements OnInit {
@HostBinding('@slideInOutAnimation')
public get slideInOutAnimation() {
return this.settingService.animationDirection === AnimationDirection.RIGHT
? {value: 'right', params: {offsetEnter: 100, offsetLeave: -100}}
: {value: 'left', params: {offsetEnter: -100, offsetLeave: 100}};
}
constructor(private titleService: Title,
private route: ActivatedRoute,
private watcherService: WatcherService,

View File

@ -1,42 +1,34 @@
// import the required animation functions from the angular animations module
import { animate, state, style, transition, trigger } from '@angular/animations';
import {animate, group, query, state, style, transition, trigger} from '@angular/animations';
export const slideInOutAnimation =
// trigger name for attaching this animation to an element using the [@triggerName] syntax
trigger('slideInOutAnimation', [
// end state styles for route container (host)
state('*', style({
// the view covers the whole screen with a semi tranparent background
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0
})),
// route 'enter' transition
transition(':enter', [
// styles at start of transition
style({
// start with the content positioned off the right of the screen,
// -400% is required instead of -100% because the negative position adds to the width of the element
transform: 'translateX({{offsetEnter}}%)'
trigger('routerTransition', [
transition('* <=> *', [
query(':enter, :leave', style({
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0
}), {
optional: true
}),
// animation and styles at end of transition
animate('.75s cubic-bezier(0.175, 0.885, 0.32, 1.275)', style({
// transition the right position to 0 which slides the content into view
transform: 'translateX(0)'
}))
]),
// route 'leave' transition
transition(':leave', [
// animation and styles at end of transition
animate('.75s cubic-bezier(0.175, 0.885, 0.32, 1.275)', style({
// transition the right position to -400% which slides the content out of view
transform: 'translateX({{offsetLeave}}%)'
}))
group([
query(':enter', [
style({ transform: 'translateX({{offsetEnter}}%)'}),
animate('.75s cubic-bezier(0.175, 0.885, 0.32, 1.275)', style({
transform: 'translateX(0%)'
}))
], {
optional: true
}),
query(':leave', [
style({ transform: 'translateX(0%)' }),
animate('.75s cubic-bezier(0.175, 0.885, 0.32, 1.275)', style({
transform: 'translateX({{offsetLeave}}%)'
}))
], { optional: true })
])
])
]);