diff --git a/.angular-cli.json b/.angular-cli.json
index 8600971..755e33d 100644
--- a/.angular-cli.json
+++ b/.angular-cli.json
@@ -22,7 +22,9 @@
"../node_modules/semantic-ui-css/semantic.css",
"styles.css"
],
- "scripts": [],
+ "scripts": [
+ "../node_modules/marked/lib/marked.js"
+ ],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
diff --git a/package-lock.json b/package-lock.json
index ff86de6..e52105e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -290,6 +290,11 @@
"@types/jasmine": "2.8.6"
}
},
+ "@types/marked": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.3.0.tgz",
+ "integrity": "sha512-CSf9YWJdX1DkTNu9zcNtdCcn6hkRtB5ILjbhRId4ZOQqx30fXmdecuaXhugQL6eyrhuXtaHJ7PHI+Vm7k9ZJjg=="
+ },
"@types/node": {
"version": "6.0.102",
"resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.102.tgz",
@@ -6836,6 +6841,11 @@
"object-visit": "1.0.1"
}
},
+ "marked": {
+ "version": "0.3.19",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz",
+ "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg=="
+ },
"md5.js": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz",
diff --git a/package.json b/package.json
index 0b8fd0f..6454df0 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,9 @@
"@angular/platform-browser": "^5.2.0",
"@angular/platform-browser-dynamic": "^5.2.0",
"@angular/router": "^5.2.0",
+ "@types/marked": "^0.3.0",
"core-js": "^2.4.1",
+ "marked": "^0.3.19",
"ng2-semantic-ui": "^0.9.7",
"rxjs": "^5.5.6",
"semantic-ui-css": "^2.3.1",
diff --git a/src/app/admin/admin-routing.module.ts b/src/app/admin/admin-routing.module.ts
index cca431d..414e388 100644
--- a/src/app/admin/admin-routing.module.ts
+++ b/src/app/admin/admin-routing.module.ts
@@ -5,22 +5,57 @@ import { TeamListComponent} from './team-list/team-list.component';
import { TeamService } from '../shared/service/team.service';
import { TeamResolverService } from './team-resolver.service';
import { TeamEditorComponent } from './team-editor/team-editor.component';
+import { SlideEditorComponent } from './slide-editor/slide-editor.component';
+import { SlideListComponent } from './slide-list/slide-list.component';
+import { SlideResolverService } from './slide-resolver.service';
+import { SlideService } from '../shared/service/slide.service';
+import { DashboardComponent } from './dashboard/dashboard.component';
const routes: Routes = [
{
- path: 'admin/teams/list',
+ path: 'admin',
+ 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,
+ }
+ }, {
+ 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,
+ }
}
];
diff --git a/src/app/admin/admin.module.ts b/src/app/admin/admin.module.ts
index ca96824..f6a64bc 100644
--- a/src/app/admin/admin.module.ts
+++ b/src/app/admin/admin.module.ts
@@ -8,14 +8,20 @@ import { TeamEditorComponent } from './team-editor/team-editor.component';
import { SlideEditorComponent } from './slide-editor/slide-editor.component';
import { SlideListComponent } from './slide-list/slide-list.component';
import { TeamResolverService } from './team-resolver.service';
+import { SlideResolverService } from './slide-resolver.service';
+import { SuiModule } from 'ng2-semantic-ui';
+import { DashboardComponent } from './dashboard/dashboard.component';
+import { DisplayModule } from '../display/display.module';
@NgModule({
imports: [
CommonModule,
FormsModule,
- AdminRoutingModule
+ SuiModule,
+ AdminRoutingModule,
+ DisplayModule
],
- declarations: [TeamListComponent, TeamEditorComponent, SlideEditorComponent, SlideListComponent],
- providers: [TeamResolverService]
+ declarations: [TeamListComponent, TeamEditorComponent, SlideEditorComponent, SlideListComponent, DashboardComponent],
+ providers: [TeamResolverService, SlideResolverService]
})
export class AdminModule { }
diff --git a/src/app/admin/dashboard/dashboard.component.css b/src/app/admin/dashboard/dashboard.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/admin/dashboard/dashboard.component.html b/src/app/admin/dashboard/dashboard.component.html
new file mode 100644
index 0000000..3b92002
--- /dev/null
+++ b/src/app/admin/dashboard/dashboard.component.html
@@ -0,0 +1,50 @@
+
diff --git a/src/app/admin/dashboard/dashboard.component.spec.ts b/src/app/admin/dashboard/dashboard.component.spec.ts
new file mode 100644
index 0000000..9c996c3
--- /dev/null
+++ b/src/app/admin/dashboard/dashboard.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DashboardComponent } from './dashboard.component';
+
+describe('DashboardComponent', () => {
+ let component: DashboardComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ DashboardComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(DashboardComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/admin/dashboard/dashboard.component.ts b/src/app/admin/dashboard/dashboard.component.ts
new file mode 100644
index 0000000..c611a7e
--- /dev/null
+++ b/src/app/admin/dashboard/dashboard.component.ts
@@ -0,0 +1,17 @@
+import { Component, OnInit } from '@angular/core';
+import { Title } from '@angular/platform-browser';
+
+@Component({
+ selector: 'app-dashboard',
+ templateUrl: './dashboard.component.html',
+ styleUrls: ['./dashboard.component.css']
+})
+export class DashboardComponent implements OnInit {
+
+ constructor(private titleService: Title) { }
+
+ ngOnInit() {
+ this.titleService.setTitle('Dashboard : MTAStv');
+ }
+
+}
diff --git a/src/app/admin/slide-editor/slide-editor.component.html b/src/app/admin/slide-editor/slide-editor.component.html
index cdca987..c51d636 100644
--- a/src/app/admin/slide-editor/slide-editor.component.html
+++ b/src/app/admin/slide-editor/slide-editor.component.html
@@ -1,3 +1,54 @@
-
- slide-editor works!
-
+
diff --git a/src/app/admin/slide-editor/slide-editor.component.ts b/src/app/admin/slide-editor/slide-editor.component.ts
index 6c6bb23..5f5eb51 100644
--- a/src/app/admin/slide-editor/slide-editor.component.ts
+++ b/src/app/admin/slide-editor/slide-editor.component.ts
@@ -1,4 +1,11 @@
import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { Title } from '@angular/platform-browser';
+
+import * as marked from 'marked';
+import { Slide } from '../../shared/slide';
+import { SlideService } from '../../shared/service/slide.service';
+import { Team } from '../../shared/team';
@Component({
selector: 'app-slide-editor',
@@ -6,10 +13,56 @@ import { Component, OnInit } from '@angular/core';
styleUrls: ['./slide-editor.component.css']
})
export class SlideEditorComponent implements OnInit {
+ private md;
+ public emptyTeam: Team = new Team();
+ public slide: Slide;
+ public teams: Array = [];
+ public renderedPreview: String = '';
+ public previewVisible = false;
- constructor() { }
-
- ngOnInit() {
+ constructor(private slideService: SlideService,
+ private titleService: Title,
+ private route: ActivatedRoute,
+ private router: Router) {
+ this.md = marked.setOptions({});
+ this.emptyTeam.name = 'All teams';
}
+ ngOnInit() {
+ this.titleService.setTitle('Edit slide : MTAStv');
+ this.route.data.subscribe((data: {
+ slide: Slide,
+ teams: Array
+ }) => {
+ this.teams = data.teams;
+ this.slide = data.slide ? data.slide : new Slide;
+ this.slide.team = this.slide.team === null
+ ? this.emptyTeam
+ : this.teams.find(team => team.id === this.slide.team.id);
+ });
+ }
+
+ public saveSlide() {
+ if (this.canSave) {
+ this.slideService
+ .persist(this.slide)
+ .subscribe(result => this.router.navigate(['/admin/slides']));
+ }
+ }
+
+ get canSave(): boolean {
+ return [
+ this.slide.title,
+ this.slide.slideData
+ ].every(field => field.trim().length > 0);
+ }
+
+ get canPreview(): boolean {
+ return this.slide.slideData.trim().length > 0;
+ }
+
+ public preview() {
+ this.previewVisible = true;
+ this.renderedPreview = this.md.parse(this.slide.slideData);
+ }
}
diff --git a/src/app/admin/slide-list/slide-list.component.html b/src/app/admin/slide-list/slide-list.component.html
index a7c5219..8953079 100644
--- a/src/app/admin/slide-list/slide-list.component.html
+++ b/src/app/admin/slide-list/slide-list.component.html
@@ -1,3 +1,30 @@
-
- slide-list works!
-
+
+
+
New slide
+
Back to dashboard
+
+
+
+ |
+ Slide title |
+ Owner team |
+ Visible |
+
+
+
+
+ |
+
+
+ |
+ {{slide.title}} |
+ {{slideTeam(slide.team)}} |
+ |
+
+
+
+
diff --git a/src/app/admin/slide-list/slide-list.component.ts b/src/app/admin/slide-list/slide-list.component.ts
index fe12c15..489a00d 100644
--- a/src/app/admin/slide-list/slide-list.component.ts
+++ b/src/app/admin/slide-list/slide-list.component.ts
@@ -1,4 +1,10 @@
import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { Title } from '@angular/platform-browser';
+
+import { SlideService } from '../../shared/service/slide.service';
+import { Slide } from '../../shared/slide';
+import { Team } from '../../shared/team';
@Component({
selector: 'app-slide-list',
@@ -7,9 +13,42 @@ import { Component, OnInit } from '@angular/core';
})
export class SlideListComponent implements OnInit {
- constructor() { }
-
- ngOnInit() {
+ constructor(private slideService: SlideService,
+ private titleService: Title,
+ private route: ActivatedRoute) {
}
+ ngOnInit() {
+ this.titleService.setTitle('Slides : MTAStv');
+ this.route.data.subscribe((data: {slides: Array}) => this.slides = data.slides);
+ }
+
+ get slides(): Array {
+ return this.slideService.slides;
+ }
+
+ set slides(slides: Array) {
+ this.slideService.slides = slides;
+ }
+
+ public slideTeam(team: Team): String {
+ return team === null ? 'All teams' : team.name;
+ }
+
+ public delete(slide: Slide) {
+ if (confirm(`Are you sure you want to delete the slide '${slide.title}'`)) {
+ this.slideService.delete(slide).subscribe(result => {
+ if (result) {
+ this.slides = this.slides.filter(slideItem => slideItem !== slide);
+ }
+ });
+ }
+ }
+
+ public visibleClass(slide: Slide) {
+ return {
+ 'green check': slide.isVisible,
+ 'red times': !slide.isVisible
+ };
+ }
}
diff --git a/src/app/admin/slide-resolver.service.spec.ts b/src/app/admin/slide-resolver.service.spec.ts
new file mode 100644
index 0000000..56b541f
--- /dev/null
+++ b/src/app/admin/slide-resolver.service.spec.ts
@@ -0,0 +1,15 @@
+import { TestBed, inject } from '@angular/core/testing';
+
+import { SlideResolverService } from './slide-resolver.service';
+
+describe('SlideResolverService', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ providers: [SlideResolverService]
+ });
+ });
+
+ it('should be created', inject([SlideResolverService], (service: SlideResolverService) => {
+ expect(service).toBeTruthy();
+ }));
+});
diff --git a/src/app/admin/slide-resolver.service.ts b/src/app/admin/slide-resolver.service.ts
new file mode 100644
index 0000000..0fab2c2
--- /dev/null
+++ b/src/app/admin/slide-resolver.service.ts
@@ -0,0 +1,22 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
+import { Observable } from 'rxjs/Observable';
+
+import { environment } from '../../environments/environment';
+import { Slide } from '../shared/slide';
+
+@Injectable()
+export class SlideResolverService implements Resolve {
+ private apiEndPoint = environment.apiUrl + '/api/slide';
+
+ constructor(private httpClient: HttpClient) {}
+
+ public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise {
+ return this.getSlide(route.params['id']).toPromise();
+ }
+
+ public getSlide(id: Number): Observable {
+ return this.httpClient.get(`${this.apiEndPoint}/${id}`);
+ }
+}
diff --git a/src/app/admin/team-editor/team-editor.component.html b/src/app/admin/team-editor/team-editor.component.html
index e87c10c..e2b057b 100644
--- a/src/app/admin/team-editor/team-editor.component.html
+++ b/src/app/admin/team-editor/team-editor.component.html
@@ -1,12 +1,18 @@
-
+
+
+ Back to teams list
diff --git a/src/app/admin/team-editor/team-editor.component.ts b/src/app/admin/team-editor/team-editor.component.ts
index fc86668..d8d6fcb 100644
--- a/src/app/admin/team-editor/team-editor.component.ts
+++ b/src/app/admin/team-editor/team-editor.component.ts
@@ -1,10 +1,11 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, ElementRef, HostBinding, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Title } from '@angular/platform-browser';
import { TeamService } from '../../shared/service/team.service';
import { Team } from '../../shared/team';
import { Member } from '../../shared/member';
+import { slideInOutAnimation } from '../../shared/slide-in-out-animation';
@Component({
selector: 'app-team-editor',
@@ -12,7 +13,8 @@ import { Member } from '../../shared/member';
styleUrls: ['./team-editor.component.css']
})
export class TeamEditorComponent implements OnInit {
- public team: Team = new Team();
+ @ViewChild('signumInput') signumInputElement: ElementRef;
+ public team: Team;
public member: Member = new Member();
constructor(private teamService: TeamService,
@@ -23,31 +25,55 @@ export class TeamEditorComponent implements OnInit {
ngOnInit() {
this.titleService.setTitle('Team editor : MTAStv');
- this.route.data.subscribe((data: { team: Team }) => this.team = data.team);
+ this.route.data.subscribe((data: { team: Team }) => this.team = data.team ? data.team : new Team());
}
get canAddMember(): boolean {
try {
- return [this.member.name, this.member.signum].every(field => field.length !== 0);
+ return [this.member.name, this.member.signum].every(field => field.length !== 0)
+ && this.team.members.every(member => member.signum !== this.member.signum);
} catch (e) {
return false;
}
}
public addMember() {
- this.team.members = this.team.members.concat(Object.assign({}, this.member));
+ this.team.members = this.team.members
+ .concat(Object.assign({}, this.member))
+ .sort((a: Member, b: Member) => a.signum < b.signum ? -1 : 1);
this.member = new Member();
}
+ public handleEnter(ev: KeyboardEvent) {
+ ev.preventDefault();
+ if (this.canAddMember) {
+ this.addMember();
+ this.focusSignumField();
+ }
+ }
+
+ public focusSignumField() {
+ this.signumInputElement.nativeElement.focus();
+ }
+
public removeMember(signum: String) {
if (confirm(`Remove the member with signum ${signum}?`)) {
this.team.members = this.team.members.filter(member => member.signum !== signum);
}
}
+ get canSave(): boolean {
+ return [
+ this.team.name.trim(),
+ this.team.members
+ ].every(field => field.length > 0);
+ }
+
public saveTeam() {
- this.teamService.update(this.team).subscribe(
- () => this.router.navigate(['/admin/teams/list'])
- );
+ if (this.canSave) {
+ this.teamService.persist(this.team).subscribe(
+ () => this.router.navigate(['/admin/teams'])
+ );
+ }
}
}
diff --git a/src/app/admin/team-list/team-list.component.html b/src/app/admin/team-list/team-list.component.html
index b2d3cf8..21a36a8 100644
--- a/src/app/admin/team-list/team-list.component.html
+++ b/src/app/admin/team-list/team-list.component.html
@@ -1,22 +1,30 @@
+
New team
+
Back to dashboard
- |
- Team |
- Members |
+ |
+ Team |
+ Members |
+ Active |
|
+ class="large pencil alternate icon">
+
|
{{team.name}} |
{{fancyMemberNames(team)}} |
+ |
-
\ No newline at end of file
+
diff --git a/src/app/admin/team-list/team-list.component.ts b/src/app/admin/team-list/team-list.component.ts
index 117949d..6d2f485 100644
--- a/src/app/admin/team-list/team-list.component.ts
+++ b/src/app/admin/team-list/team-list.component.ts
@@ -2,8 +2,8 @@ import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Title } from '@angular/platform-browser';
-import { Team } from '../../shared/team';
import { TeamService } from '../../shared/service/team.service';
+import { Team } from '../../shared/team';
@Component({
selector: 'app-team-list',
@@ -33,4 +33,21 @@ export class TeamListComponent implements OnInit {
public fancyMemberNames(team: Team): String {
return team.members.map(member => member.name).join(', ');
}
+
+ public delete(team: Team) {
+ if (confirm(`Remove the team '${team.name}'?`)) {
+ this.teamService.delete(team).subscribe(result => {
+ if (result) {
+ this.teams = this.teams.filter(teamItem => teamItem !== team);
+ }
+ });
+ }
+ }
+
+ public activeClass(team: Team) {
+ return {
+ 'green check': team.isActive,
+ 'red times': !team.isActive
+ };
+ }
}
diff --git a/src/app/admin/team-resolver.service.ts b/src/app/admin/team-resolver.service.ts
index cecd095..0d6c083 100644
--- a/src/app/admin/team-resolver.service.ts
+++ b/src/app/admin/team-resolver.service.ts
@@ -1,9 +1,10 @@
import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
+import { Observable } from 'rxjs/Observable';
+
import { Team } from '../shared/team';
import { environment } from '../../environments/environment';
-import { HttpClient } from '@angular/common/http';
-import { Observable } from 'rxjs/Observable';
@Injectable()
export class TeamResolverService implements Resolve {
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 7b0f672..58e1a52 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -1,10 +1,70 @@
-import { Component } from '@angular/core';
+import { Component, OnDestroy, OnInit } from '@angular/core';
+import { Subscription } from 'rxjs/Subscription';
+import { CommitTrackerService } from './shared/service/commit-tracker.service';
+import { SettingsService } from './shared/service/settings.service';
+import { SelfUpdaterService } from './shared/service/self-updater.service';
+import { ActivationEnd, Router } from '@angular/router';
+import { Subject } from 'rxjs/Subject';
+import { TimerObservable } from 'rxjs/observable/TimerObservable';
+import 'rxjs/add/operator/filter';
+import 'rxjs/add/operator/switchMap';
+
+
+const TIMER_UPDATE_POLL_INTERVAL = 30000;
+const TIMER_COMMITTRACKER_REFRESH = 5000;
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
-export class AppComponent {
- title = 'app';
+export class AppComponent implements OnInit, OnDestroy {
+ private selfUpdateCheckerTimer: Subscription;
+ private refreshCommitTrackerTimer: Subscription;
+ private slideshowTimer: Subscription;
+ private autoSwitch = false;
+
+ constructor(private commitTrackerService: CommitTrackerService,
+ private settings: SettingsService,
+ private selfUpdaterService: SelfUpdaterService,
+ private router: Router) {}
+
+ public ngOnInit() {
+ const timerSUC = TimerObservable.create(TIMER_UPDATE_POLL_INTERVAL, TIMER_UPDATE_POLL_INTERVAL);
+ this.selfUpdateCheckerTimer = timerSUC.subscribe(() => {
+ this.selfUpdaterService.checkAndReloadIfNecessary();
+ });
+
+ const timerCT = TimerObservable.create(TIMER_COMMITTRACKER_REFRESH, TIMER_COMMITTRACKER_REFRESH);
+ this.refreshCommitTrackerTimer = timerCT.subscribe(() => {
+ this.commitTrackerService.getTeamCommits(this.settings.team.members.map(member => member.signum));
+ });
+
+ const timerSS = new Subject();
+ this.slideshowTimer = timerSS.switchMap(period => TimerObservable.create(period))
+ .subscribe(() => {
+ this.changeSlide(timerSS);
+ });
+ timerSS.next(this.settings.slideInterval);
+
+ this.autoSwitch = false;
+ this.router.events
+ .filter(event => event instanceof ActivationEnd)
+ .subscribe(event => {
+ this.autoSwitch = !!event.snapshot.data.autoSwitchable;
+ });
+ }
+
+ public ngOnDestroy() {
+ this.refreshCommitTrackerTimer.unsubscribe();
+ this.selfUpdateCheckerTimer.unsubscribe();
+ this.slideshowTimer.unsubscribe();
+ }
+
+ private changeSlide(timer: Subject) {
+ if (this.autoSwitch) {
+ console.log('Slide should have changed here');
+ }
+ timer.next(this.settings.slideInterval);
+ }
}
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 508cbf8..07339e7 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -1,5 +1,6 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
import { SuiModule } from 'ng2-semantic-ui';
@@ -11,6 +12,8 @@ import { SlideService } from './shared/service/slide.service';
import { AdminModule } from './admin/admin.module';
import { DisplayModule } from './display/display.module';
import { CommitTrackerService } from './shared/service/commit-tracker.service';
+import { SettingsService } from './shared/service/settings.service';
+import { SelfUpdaterService } from './shared/service/self-updater.service';
@NgModule({
declarations: [
@@ -18,6 +21,7 @@ import { CommitTrackerService } from './shared/service/commit-tracker.service';
],
imports: [
BrowserModule,
+ BrowserAnimationsModule,
HttpClientModule,
FormsModule,
SuiModule,
@@ -25,7 +29,7 @@ import { CommitTrackerService } from './shared/service/commit-tracker.service';
AdminModule,
AppRoutingModule, // must be last RouterModule import for ** route to work
],
- providers: [TeamService, SlideService, CommitTrackerService],
+ providers: [TeamService, SlideService, CommitTrackerService, SettingsService, SelfUpdaterService],
bootstrap: [AppComponent]
})
export class AppModule {
diff --git a/src/app/display/display-routing.module.ts b/src/app/display/display-routing.module.ts
index ff69e15..5d6c6a6 100644
--- a/src/app/display/display-routing.module.ts
+++ b/src/app/display/display-routing.module.ts
@@ -3,15 +3,39 @@ import { Routes, RouterModule } from '@angular/router';
import { CommitTrackerComponent } from './commit-tracker/commit-tracker.component';
import { CommitTrackerService } from '../shared/service/commit-tracker.service';
+import { SettingsComponent } from './settings/settings.component';
+import { TeamService } from '../shared/service/team.service';
+import { SlideShowComponent } from './slide-show/slide-show.component';
+import { SlideResolverService } from '../admin/slide-resolver.service';
const routes: Routes = [
{
+ path: 'slideshow/:id',
+ component: SlideShowComponent,
+ // canActivate: [AuthGuardService, RoleGuardService],
+ resolve: {
+ slide: SlideResolverService,
+ },
+ data: {
+ autoSwitchable: true
+ }
+ }, {
path: 'commit-tracker',
component: CommitTrackerComponent,
// canActivate: [AuthGuardService, RoleGuardService],
resolve: {
commits: CommitTrackerService,
},
+ data: {
+ autoSwitchable: true
+ }
+ }, {
+ path: 'settings',
+ component: SettingsComponent,
+ // canActivate: [AuthGuardService, RoleGuardService],
+ resolve: {
+ teams: TeamService,
+ },
}
];
diff --git a/src/app/display/display.module.ts b/src/app/display/display.module.ts
index dad6dc0..8d68310 100644
--- a/src/app/display/display.module.ts
+++ b/src/app/display/display.module.ts
@@ -1,14 +1,22 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
import { DisplayRoutingModule } from './display-routing.module';
import { CommitTrackerComponent } from './commit-tracker/commit-tracker.component';
+import { SettingsComponent } from './settings/settings.component';
+import { SuiModule } from 'ng2-semantic-ui';
+import { SlideComponent } from './slide/slide.component';
+import { SlideShowComponent } from './slide-show/slide-show.component';
@NgModule({
imports: [
CommonModule,
+ FormsModule,
+ SuiModule,
DisplayRoutingModule
],
- declarations: [CommitTrackerComponent]
+ exports: [SlideComponent],
+ declarations: [CommitTrackerComponent, SettingsComponent, SlideComponent, SlideShowComponent]
})
export class DisplayModule { }
diff --git a/src/app/display/settings/settings.component.css b/src/app/display/settings/settings.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/display/settings/settings.component.html b/src/app/display/settings/settings.component.html
new file mode 100644
index 0000000..d451423
--- /dev/null
+++ b/src/app/display/settings/settings.component.html
@@ -0,0 +1,30 @@
+
+
+
+
+
diff --git a/src/app/display/settings/settings.component.spec.ts b/src/app/display/settings/settings.component.spec.ts
new file mode 100644
index 0000000..91588f3
--- /dev/null
+++ b/src/app/display/settings/settings.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SettingsComponent } from './settings.component';
+
+describe('SettingsComponent', () => {
+ let component: SettingsComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ SettingsComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SettingsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/display/settings/settings.component.ts b/src/app/display/settings/settings.component.ts
new file mode 100644
index 0000000..fd9186d
--- /dev/null
+++ b/src/app/display/settings/settings.component.ts
@@ -0,0 +1,34 @@
+import { Component, OnInit } from '@angular/core';
+import { Team } from '../../shared/team';
+import { ActivatedRoute, Router } from '@angular/router';
+import { SettingsService } from '../../shared/service/settings.service';
+
+@Component({
+ selector: 'app-settings',
+ templateUrl: './settings.component.html',
+ styleUrls: ['./settings.component.css']
+})
+export class SettingsComponent implements OnInit {
+
+ public teams: Array = [];
+ public selectedTeam: Team;
+ public slideInterval: Number;
+
+ constructor(private route: ActivatedRoute,
+ private settingsService: SettingsService,
+ private router: Router) {}
+
+ ngOnInit() {
+ this.route.data.subscribe((data: {teams: Array}) => {
+ this.teams = data.teams;
+ this.selectedTeam = this.teams.find(team => team.id === this.settingsService.team.id);
+ this.slideInterval = this.settingsService.slideInterval;
+ });
+ }
+
+ public saveSettings() {
+ this.settingsService.team = this.selectedTeam;
+ this.settingsService.slideInterval = this.slideInterval;
+ this.router.navigate(['/admin']);
+ }
+}
diff --git a/src/app/display/slide-show/slide-show.component.css b/src/app/display/slide-show/slide-show.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/display/slide-show/slide-show.component.html b/src/app/display/slide-show/slide-show.component.html
new file mode 100644
index 0000000..88cebed
--- /dev/null
+++ b/src/app/display/slide-show/slide-show.component.html
@@ -0,0 +1 @@
+
diff --git a/src/app/display/slide-show/slide-show.component.spec.ts b/src/app/display/slide-show/slide-show.component.spec.ts
new file mode 100644
index 0000000..abcc1b7
--- /dev/null
+++ b/src/app/display/slide-show/slide-show.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SlideShowComponent } from './slide-show.component';
+
+describe('SlideShowComponent', () => {
+ let component: SlideShowComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ SlideShowComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SlideShowComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/display/slide-show/slide-show.component.ts b/src/app/display/slide-show/slide-show.component.ts
new file mode 100644
index 0000000..c2b10f0
--- /dev/null
+++ b/src/app/display/slide-show/slide-show.component.ts
@@ -0,0 +1,39 @@
+import { Component, HostBinding, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { Title } from '@angular/platform-browser';
+
+import * as marked from 'marked';
+import { slideInOutAnimation } from '../../shared/slide-in-out-animation';
+import { Slide } from '../../shared/slide';
+
+@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')
+ get slideIn() {
+ return '';
+ }
+
+ constructor(private route: ActivatedRoute,
+ private titleService: Title) {
+ this.md = marked.setOptions({});
+ }
+
+ ngOnInit() {
+ this.route.data.subscribe((data: {slide: Slide}) => {
+ this.slide = data.slide;
+ this.titleService.setTitle(`${this.slide.title} : MTAStv`);
+ });
+ }
+
+ get renderedSlide(): String {
+ return this.md.parse(this.slide.slideData);
+ }
+}
diff --git a/src/app/display/slide/slide.component.css b/src/app/display/slide/slide.component.css
new file mode 100644
index 0000000..3703d02
--- /dev/null
+++ b/src/app/display/slide/slide.component.css
@@ -0,0 +1,244 @@
+:host {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 1;
+ background: #222;
+ font-family: "Source Sans Pro", Helvetica, sans-serif;
+ font-size: 42px;
+ font-weight: normal;
+ color: #fff; }
+
+section {
+ line-height: 1.3;
+ font-weight: inherit; }
+
+/*********************************************
+ * HEADERS
+ *********************************************/
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ margin: 0 0 20px 0;
+ color: #fff;
+ font-family: "Source Sans Pro", Helvetica, sans-serif;
+ font-weight: 600;
+ line-height: 1.2;
+ letter-spacing: normal;
+ text-transform: uppercase;
+ text-shadow: none;
+ word-wrap: break-word; }
+
+h1 {
+ font-size: 2.5em; }
+
+h2 {
+ font-size: 1.6em; }
+
+h3 {
+ font-size: 1.3em; }
+
+h4 {
+ font-size: 1em; }
+
+h1 {
+ text-shadow: none; }
+
+/*********************************************
+ * OTHER
+ *********************************************/
+p {
+ margin: 20px 0;
+ line-height: 1.3; }
+
+/* Ensure certain elements are never larger than the slide itself */
+img,
+video,
+iframe {
+ max-width: 95%;
+ max-height: 95%; }
+
+strong,
+b {
+ font-weight: bold; }
+
+em {
+ font-style: italic; }
+
+ol,
+dl,
+ul {
+ display: inline-block;
+ text-align: left;
+ margin: 0 0 0 1em; }
+
+ol {
+ list-style-type: decimal; }
+
+ul {
+ list-style-type: disc; }
+
+ul ul {
+ list-style-type: square; }
+
+ul ul ul {
+ list-style-type: circle; }
+
+ul ul,
+ul ol,
+ol ol,
+ol ul {
+ display: block;
+ margin-left: 40px; }
+
+dt {
+ font-weight: bold; }
+
+dd {
+ margin-left: 40px; }
+
+blockquote {
+ display: block;
+ position: relative;
+ width: 70%;
+ margin: 20px auto;
+ padding: 5px;
+ font-style: italic;
+ background: rgba(255, 255, 255, 0.05);
+ box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.2); }
+
+blockquote p:first-child,
+blockquote p:last-child {
+ display: inline-block; }
+
+q {
+ font-style: italic; }
+
+pre {
+ display: block;
+ position: relative;
+ width: 90%;
+ margin: 20px auto;
+ text-align: left;
+ font-size: 0.55em;
+ font-family: monospace;
+ line-height: 1.2em;
+ word-wrap: break-word;
+ box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.3); }
+
+code {
+ font-family: monospace;
+ text-transform: none; }
+
+pre code {
+ display: block;
+ padding: 5px;
+ overflow: auto;
+ max-height: 400px;
+ word-wrap: normal; }
+
+table {
+ margin: auto;
+ border-collapse: collapse;
+ border-spacing: 0; }
+
+table th {
+ font-weight: bold; }
+
+table th,
+table td {
+ text-align: left;
+ padding: 0.2em 0.5em 0.2em 0.5em;
+ border-bottom: 1px solid; }
+
+table th[align="center"],
+table td[align="center"] {
+ text-align: center; }
+
+table th[align="right"],
+table td[align="right"] {
+ text-align: right; }
+
+table tbody tr:last-child th,
+table tbody tr:last-child td {
+ border-bottom: none; }
+
+sup {
+ vertical-align: super; }
+
+sub {
+ vertical-align: sub; }
+
+small {
+ display: inline-block;
+ font-size: 0.6em;
+ line-height: 1.2em;
+ vertical-align: top; }
+
+small * {
+ vertical-align: top; }
+
+/*********************************************
+ * LINKS
+ *********************************************/
+a {
+ color: #42affa;
+ text-decoration: none;
+ -webkit-transition: color .15s ease;
+ -moz-transition: color .15s ease;
+ transition: color .15s ease; }
+
+a:hover {
+ color: #8dcffc;
+ text-shadow: none;
+ border: none; }
+
+.roll span:after {
+ color: #fff;
+ background: #068de9; }
+
+/*********************************************
+ * IMAGES
+ *********************************************/
+section img {
+ margin: 15px 0px;
+ background: rgba(255, 255, 255, 0.12);
+ border: 4px solid #fff;
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); }
+
+section img.plain {
+ border: 0;
+ box-shadow: none; }
+
+a img {
+ -webkit-transition: all .15s linear;
+ -moz-transition: all .15s linear;
+ transition: all .15s linear; }
+
+a:hover img {
+ background: rgba(255, 255, 255, 0.2);
+ border-color: #42affa;
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); }
+
+/*********************************************
+ * NAVIGATION CONTROLS
+ *********************************************/
+.controls {
+ color: #42affa; }
+
+/*********************************************
+ * PROGRESS BAR
+ *********************************************/
+.progress {
+ background: rgba(0, 0, 0, 0.2);
+ color: #42affa; }
+
+.progress span {
+ -webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
+ -moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
+ transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); }
\ No newline at end of file
diff --git a/src/app/display/slide/slide.component.html b/src/app/display/slide/slide.component.html
new file mode 100644
index 0000000..67745c7
--- /dev/null
+++ b/src/app/display/slide/slide.component.html
@@ -0,0 +1 @@
+
diff --git a/src/app/display/slide/slide.component.spec.ts b/src/app/display/slide/slide.component.spec.ts
new file mode 100644
index 0000000..c82efb6
--- /dev/null
+++ b/src/app/display/slide/slide.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SlideComponent } from './slide.component';
+
+describe('SlideComponent', () => {
+ let component: SlideComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ SlideComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SlideComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/display/slide/slide.component.ts b/src/app/display/slide/slide.component.ts
new file mode 100644
index 0000000..6db9cc8
--- /dev/null
+++ b/src/app/display/slide/slide.component.ts
@@ -0,0 +1,25 @@
+import { Component, EventEmitter, HostListener, Input, OnInit, Output } from '@angular/core';
+
+@Component({
+ selector: 'app-slide',
+ templateUrl: './slide.component.html',
+ styleUrls: ['./slide.component.css']
+})
+export class SlideComponent implements OnInit {
+ @Input() data: String = '';
+ @Input() preview = false;
+
+ @Input() visible = true;
+ @Output() visibleChange = new EventEmitter();
+
+
+ constructor() {}
+ ngOnInit() {}
+
+ @HostListener('click')
+ public hide() {
+ if (this.preview) {
+ this.visibleChange.emit(false);
+ }
+ }
+}
diff --git a/src/app/shared/service/sommit-tracker.service.spec.ts b/src/app/shared/service/commit-tracker.service.spec.ts
similarity index 100%
rename from src/app/shared/service/sommit-tracker.service.spec.ts
rename to src/app/shared/service/commit-tracker.service.spec.ts
diff --git a/src/app/shared/service/commit-tracker.service.ts b/src/app/shared/service/commit-tracker.service.ts
index dd1511d..3271e47 100644
--- a/src/app/shared/service/commit-tracker.service.ts
+++ b/src/app/shared/service/commit-tracker.service.ts
@@ -1,11 +1,11 @@
import { Injectable } from '@angular/core';
-import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
+import { HttpClient, HttpParams } from '@angular/common/http';
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { environment } from '../../../environments/environment';
import { Commit } from '../commit';
-import { TeamService } from './team.service';
+import { SettingsService } from './settings.service';
@Injectable()
export class CommitTrackerService implements Resolve> {
@@ -14,10 +14,13 @@ export class CommitTrackerService implements Resolve> {
private cachedCommits: Array = [];
constructor(private httpClient: HttpClient,
- private teamService: TeamService) { }
+ private settingsService: SettingsService) { }
public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise> {
- return this.getTeamCommits(this.teamService.teamMembers).toPromise();
+ const signums = this.settingsService.team
+ ? this.settingsService.team.members.map(member => member.signum)
+ : [];
+ return this.getTeamCommits(signums).toPromise();
}
public getTeamCommits(signums: Array): Observable> {
diff --git a/src/app/shared/service/self-updater.service.spec.ts b/src/app/shared/service/self-updater.service.spec.ts
new file mode 100644
index 0000000..8be1bb2
--- /dev/null
+++ b/src/app/shared/service/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/shared/service/self-updater.service.ts b/src/app/shared/service/self-updater.service.ts
new file mode 100644
index 0000000..f76ae2f
--- /dev/null
+++ b/src/app/shared/service/self-updater.service.ts
@@ -0,0 +1,39 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { Observable } from 'rxjs/Observable';
+import { Location } from '@angular/common';
+
+@Injectable()
+export class SelfUpdaterService {
+
+ private appRevision: Number = 0;
+ private initFailed = false;
+
+ constructor(private httpClient: HttpClient,
+ private locationService: Location) {
+ this.getDeployedRevision().subscribe(
+ revision => this.appRevision = revision,
+ () => {
+ 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.httpClient.get(this.locationService.prepareExternalUrl('/revision.json'));
+ }
+
+ public checkAndReloadIfNecessary() {
+ if (!this.initFailed) {
+ this.getDeployedRevision().subscribe(revision => {
+ if (revision > this.appRevision) {
+ this.locationService.go('/');
+ }
+ });
+ }
+ }
+}
diff --git a/src/app/shared/service/settings.service.spec.ts b/src/app/shared/service/settings.service.spec.ts
new file mode 100644
index 0000000..b7a9bdf
--- /dev/null
+++ b/src/app/shared/service/settings.service.spec.ts
@@ -0,0 +1,15 @@
+import { TestBed, inject } from '@angular/core/testing';
+
+import { SettingsService } from './settings.service';
+
+describe('SettingsService', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ providers: [SettingsService]
+ });
+ });
+
+ it('should be created', inject([SettingsService], (service: SettingsService) => {
+ expect(service).toBeTruthy();
+ }));
+});
diff --git a/src/app/shared/service/settings.service.ts b/src/app/shared/service/settings.service.ts
new file mode 100644
index 0000000..8bedb18
--- /dev/null
+++ b/src/app/shared/service/settings.service.ts
@@ -0,0 +1,40 @@
+import { Injectable } from '@angular/core';
+import { Team } from '../team';
+
+const DEFAULT_SLIDE_INTERVAL = 30000;
+
+const SLIDE_INTERVAL_KEY = 'slide_interval';
+const SELECTED_TEAM_KEY = 'team';
+
+@Injectable()
+export class SettingsService {
+
+ constructor() {
+ }
+
+ get team(): Team {
+ try {
+ const team = JSON.parse(localStorage.getItem(SELECTED_TEAM_KEY));
+ return team !== null ? team : new Team;
+ } catch (e) {
+ return new Team;
+ }
+ }
+
+ set team(team: Team) {
+ localStorage.setItem(SELECTED_TEAM_KEY, JSON.stringify(team));
+ }
+
+ get slideInterval(): Number {
+ try {
+ const interval = JSON.parse(localStorage.getItem(SLIDE_INTERVAL_KEY));
+ return interval !== null ? interval : DEFAULT_SLIDE_INTERVAL;
+ } catch (e) {
+ return DEFAULT_SLIDE_INTERVAL;
+ }
+ }
+
+ set slideInterval(interval: Number) {
+ localStorage.setItem(SLIDE_INTERVAL_KEY, JSON.stringify(interval));
+ }
+}
diff --git a/src/app/shared/service/slide.service.ts b/src/app/shared/service/slide.service.ts
index 8bdb738..c89551e 100644
--- a/src/app/shared/service/slide.service.ts
+++ b/src/app/shared/service/slide.service.ts
@@ -1,8 +1,58 @@
import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
+import { Observable } from 'rxjs/Observable';
+
+import { environment } from '../../../environments/environment';
+import { Slide } from '../slide';
@Injectable()
-export class SlideService {
+export class SlideService implements Resolve>{
- constructor() { }
+ private apiEndPoint = environment.apiUrl + '/api/slide';
+ private cachedSlides: Array = [];
+ constructor(private httpClient: HttpClient) {}
+
+ private static prepareSlideData(slide: Slide) {
+ const slideToSave = Object.assign({}, slide);
+ slideToSave.team = slideToSave.team.id === null
+ ? null
+ : slideToSave.team.id;
+ return slideToSave;
+ }
+
+ public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise> {
+ return this.list().toPromise();
+ }
+
+ public list(): Observable> {
+ return this.httpClient.get>(this.apiEndPoint);
+ }
+
+ public persist(slide: Slide): Observable {
+ return slide.id === null
+ ? this.create(slide)
+ : this.update(slide);
+ }
+
+ public create(slide: Slide): Observable {
+ return this.httpClient.post(this.apiEndPoint, SlideService.prepareSlideData(slide));
+ }
+
+ public update(slide: Slide): Observable {
+ return this.httpClient.put(`${this.apiEndPoint}/${slide.id.toString()}`, SlideService.prepareSlideData(slide));
+ }
+
+ public delete(slide: Slide): Observable {
+ return this.httpClient.delete(`${this.apiEndPoint}/${slide.id.toString()}`);
+ }
+
+ get slides(): Array {
+ return this.cachedSlides;
+ }
+
+ set slides(slides: Array) {
+ this.cachedSlides = slides;
+ }
}
diff --git a/src/app/shared/service/team.service.ts b/src/app/shared/service/team.service.ts
index 83446ee..4c5b6d0 100644
--- a/src/app/shared/service/team.service.ts
+++ b/src/app/shared/service/team.service.ts
@@ -22,6 +22,12 @@ export class TeamService implements Resolve> {
return this.httpClient.get>(this.apiEndPoint);
}
+ public persist(team: Team): Observable {
+ return team.id === null
+ ? this.create(team)
+ : this.update(team);
+ }
+
public create(team: Team) {
return this.httpClient.post(this.apiEndPoint, team);
}
@@ -41,8 +47,4 @@ export class TeamService implements Resolve> {
set teams(teams: Array) {
this.cachedTeams = teams;
}
-
- get teamMembers(): Array {
- return ['eztoli', 'etamecs', 'esteist', 'emrtsis', 'erudvel'];
- }
}
diff --git a/src/app/shared/slide-in-out-animation.ts b/src/app/shared/slide-in-out-animation.ts
new file mode 100644
index 0000000..a0dfcc2
--- /dev/null
+++ b/src/app/shared/slide-in-out-animation.ts
@@ -0,0 +1,43 @@
+// import the required animation functions from the angular animations module
+import { animate, 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
+ right: '-400%'
+ }),
+
+ // animation and styles at end of transition
+ animate('.5s ease-in-out', style({
+ // transition the right position to 0 which slides the content into view
+ right: 0
+ }))
+ ]),
+
+ // route 'leave' transition
+ transition(':leave', [
+ // animation and styles at end of transition
+ animate('.5s ease-in-out', style({
+ // transition the right position to -400% which slides the content out of view
+ right: '-400%'
+ }))
+ ])
+ ]);
diff --git a/src/app/shared/slide.ts b/src/app/shared/slide.ts
index 73abaec..59fa9a7 100644
--- a/src/app/shared/slide.ts
+++ b/src/app/shared/slide.ts
@@ -1,11 +1,11 @@
import { Team } from './team';
export class Slide {
- id: Number;
- title: String;
- team: Team;
- slideData: String;
- isVisible: boolean;
- createdAt: String;
- updatedAt: String;
+ id: Number = null;
+ title: String = '';
+ team: Team = null;
+ slideData: String = '';
+ isVisible = true;
+ createdAt: String = null;
+ updatedAt: String = null;
}
diff --git a/src/styles.css b/src/styles.css
index 7377efb..1ae6850 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -1,4 +1,9 @@
/* You can add global styles to this file, and also import other style files */
+html,
+body {
+ height: calc(100% - 2em);
+}
+
.main.container {
margin-top: 2em;
}