From: Chocobozzz Date: Fri, 27 Jan 2017 15:14:11 +0000 (+0100) Subject: Client: better notifications for a beautiful world X-Git-Tag: v0.0.1-alpha~540 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=7ddd02c9b8c1e088f6679a2227f105e6439fc992;p=oweals%2Fpeertube.git Client: better notifications for a beautiful world --- diff --git a/client/package.json b/client/package.json index 1a04be5bc..bd6cb03e7 100644 --- a/client/package.json +++ b/client/package.json @@ -36,6 +36,7 @@ "@types/videojs": "0.0.30", "@types/webpack": "^2.0.0", "angular-pipes": "^5.0.0", + "angular2-notifications": "^0.4.49", "angular2-template-loader": "^0.6.0", "assets-webpack-plugin": "^3.4.0", "awesome-typescript-loader": "~3.0.0-beta.17", diff --git a/client/src/app/+admin/friends/friend-add/friend-add.component.ts b/client/src/app/+admin/friends/friend-add/friend-add.component.ts index 014252011..a271970ae 100644 --- a/client/src/app/+admin/friends/friend-add/friend-add.component.ts +++ b/client/src/app/+admin/friends/friend-add/friend-add.component.ts @@ -2,6 +2,8 @@ import { Component, OnInit } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; import { Router } from '@angular/router'; +import { NotificationsService } from 'angular2-notifications'; + import { validateHost } from '../../../shared'; import { FriendService } from '../shared'; @@ -15,7 +17,11 @@ export class FriendAddComponent implements OnInit { hosts = [ ]; error: string = null; - constructor(private router: Router, private friendService: FriendService) {} + constructor( + private router: Router, + private notificationsService: NotificationsService, + private friendService: FriendService + ) {} ngOnInit() { this.form = new FormGroup({}); @@ -83,10 +89,11 @@ export class FriendAddComponent implements OnInit { this.friendService.makeFriends(notEmptyHosts).subscribe( status => { - alert('Make friends request sent!'); + this.notificationsService.success('Sucess', 'Make friends request sent!'); this.router.navigate([ '/admin/friends/list' ]); }, - error => alert(error.text) + + err => this.notificationsService.error('Error', err.text) ); } diff --git a/client/src/app/+admin/friends/friend-list/friend-list.component.ts b/client/src/app/+admin/friends/friend-list/friend-list.component.ts index bec10162c..700ea7a69 100644 --- a/client/src/app/+admin/friends/friend-list/friend-list.component.ts +++ b/client/src/app/+admin/friends/friend-list/friend-list.component.ts @@ -1,5 +1,7 @@ import { Component, OnInit } from '@angular/core'; +import { NotificationsService } from 'angular2-notifications'; + import { Friend, FriendService } from '../shared'; @Component({ @@ -10,7 +12,10 @@ import { Friend, FriendService } from '../shared'; export class FriendListComponent implements OnInit { friends: Friend[]; - constructor(private friendService: FriendService) { } + constructor( + private notificationsService: NotificationsService, + private friendService: FriendService + ) { } ngOnInit() { this.getFriends(); @@ -21,10 +26,12 @@ export class FriendListComponent implements OnInit { this.friendService.quitFriends().subscribe( status => { - alert('Quit friends!'); + this.notificationsService.success('Sucess', 'Friends left!'); + this.getFriends(); }, - error => alert(error.text) + + err => this.notificationsService.error('Error', err.text) ); } @@ -32,7 +39,7 @@ export class FriendListComponent implements OnInit { this.friendService.getFriends().subscribe( res => this.friends = res.friends, - err => alert(err.text) + err => this.notificationsService.error('Error', err.text) ); } } diff --git a/client/src/app/+admin/requests/request-stats/request-stats.component.ts b/client/src/app/+admin/requests/request-stats/request-stats.component.ts index 23b836779..18855a5f8 100644 --- a/client/src/app/+admin/requests/request-stats/request-stats.component.ts +++ b/client/src/app/+admin/requests/request-stats/request-stats.component.ts @@ -1,6 +1,7 @@ -import { setInterval } from 'timers' import { Component, OnInit, OnDestroy } from '@angular/core'; +import { NotificationsService } from 'angular2-notifications'; + import { RequestService, RequestStats } from '../shared'; @Component({ @@ -11,9 +12,13 @@ import { RequestService, RequestStats } from '../shared'; export class RequestStatsComponent implements OnInit, OnDestroy { stats: RequestStats = null; - private interval: NodeJS.Timer = null; + private interval: number = null; + private timeout: number = null; - constructor(private requestService: RequestService) { } + constructor( + private notificationsService: NotificationsService, + private requestService: RequestService + ) { } ngOnInit() { this.getStats(); @@ -21,8 +26,12 @@ export class RequestStatsComponent implements OnInit, OnDestroy { } ngOnDestroy() { - if (this.stats !== null && this.stats.secondsInterval !== null) { - clearInterval(this.interval); + if (this.interval !== null) { + window.clearInterval(this.interval); + } + + if (this.timeout !== null) { + window.clearTimeout(this.timeout); } } @@ -30,16 +39,16 @@ export class RequestStatsComponent implements OnInit, OnDestroy { this.requestService.getStats().subscribe( stats => this.stats = stats, - err => alert(err.text) + err => this.notificationsService.error('Error', err.text) ); } private runInterval() { - this.interval = setInterval(() => { + this.interval = window.setInterval(() => { this.stats.remainingMilliSeconds -= 1000; if (this.stats.remainingMilliSeconds <= 0) { - setTimeout(() => this.getStats(), this.stats.remainingMilliSeconds + 100); + this.timeout = window.setTimeout(() => this.getStats(), this.stats.remainingMilliSeconds + 100); } }, 1000); } diff --git a/client/src/app/+admin/users/user-add/user-add.component.ts b/client/src/app/+admin/users/user-add/user-add.component.ts index ab96fb01d..a851fee44 100644 --- a/client/src/app/+admin/users/user-add/user-add.component.ts +++ b/client/src/app/+admin/users/user-add/user-add.component.ts @@ -2,6 +2,8 @@ import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; import { Router } from '@angular/router'; +import { NotificationsService } from 'angular2-notifications'; + import { UserService } from '../shared'; import { FormReactive, USER_USERNAME, USER_PASSWORD } from '../../../shared'; @@ -25,6 +27,7 @@ export class UserAddComponent extends FormReactive implements OnInit { constructor( private formBuilder: FormBuilder, private router: Router, + private notificationsService: NotificationsService, private userService: UserService ) { super(); @@ -49,7 +52,10 @@ export class UserAddComponent extends FormReactive implements OnInit { const { username, password } = this.form.value; this.userService.addUser(username, password).subscribe( - ok => this.router.navigate([ '/admin/users/list' ]), + () => { + this.notificationsService.success('Success', `User ${username} created.`); + this.router.navigate([ '/admin/users/list' ]); + }, err => this.error = err.text ); diff --git a/client/src/app/+admin/users/user-list/user-list.component.ts b/client/src/app/+admin/users/user-list/user-list.component.ts index 03f4e5c0a..ca08ed305 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.ts +++ b/client/src/app/+admin/users/user-list/user-list.component.ts @@ -1,5 +1,7 @@ import { Component, OnInit } from '@angular/core'; +import { NotificationsService } from 'angular2-notifications'; + import { User } from '../../../shared'; import { UserService } from '../shared'; @@ -12,7 +14,10 @@ export class UserListComponent implements OnInit { totalUsers: number; users: User[]; - constructor(private userService: UserService) {} + constructor( + private notificationsService: NotificationsService, + private userService: UserService + ) {} ngOnInit() { this.getUsers(); @@ -25,7 +30,7 @@ export class UserListComponent implements OnInit { this.totalUsers = totalUsers; }, - err => alert(err.text) + err => this.notificationsService.error('Error', err.text) ); } @@ -33,9 +38,12 @@ export class UserListComponent implements OnInit { removeUser(user: User) { if (confirm('Are you sure?')) { this.userService.removeUser(user).subscribe( - () => this.getUsers(), + () => { + this.notificationsService.success('Success', `User ${user.username} deleted.`); + this.getUsers(); + }, - err => alert(err.text) + err => this.notificationsService.error('Error', err.text) ); } } diff --git a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts index de58bba3d..cfd9151b0 100644 --- a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts +++ b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts @@ -1,6 +1,7 @@ -import { setInterval } from 'timers' import { Component, OnInit } from '@angular/core'; +import { NotificationsService } from 'angular2-notifications'; + import { VideoAbuseService, VideoAbuse} from '../../../shared'; @Component({ @@ -11,7 +12,10 @@ import { VideoAbuseService, VideoAbuse} from '../../../shared'; export class VideoAbuseListComponent implements OnInit { videoAbuses: VideoAbuse[]; - constructor(private videoAbuseService: VideoAbuseService) { } + constructor( + private notificationsService: NotificationsService, + private videoAbuseService: VideoAbuseService + ) { } ngOnInit() { this.getVideoAbuses(); @@ -25,7 +29,7 @@ export class VideoAbuseListComponent implements OnInit { this.videoAbuseService.getVideoAbuses().subscribe( res => this.videoAbuses = res.videoAbuses, - err => alert(err.text) + err => this.notificationsService.error('Error', err.text) ); } } diff --git a/client/src/app/account/account.component.html b/client/src/app/account/account.component.html index 5a8847acd..2fbb5a908 100644 --- a/client/src/app/account/account.component.html +++ b/client/src/app/account/account.component.html @@ -1,6 +1,5 @@

Account

-
{{ information }}
{{ error }}
diff --git a/client/src/app/account/account.component.ts b/client/src/app/account/account.component.ts index 851eaf198..9b6b5fbf4 100644 --- a/client/src/app/account/account.component.ts +++ b/client/src/app/account/account.component.ts @@ -1,8 +1,9 @@ -import { } from '@angular/common'; import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; import { Router } from '@angular/router'; +import { NotificationsService } from 'angular2-notifications'; + import { AccountService } from './account.service'; import { FormReactive, USER_PASSWORD } from '../shared'; @@ -12,7 +13,6 @@ import { FormReactive, USER_PASSWORD } from '../shared'; }) export class AccountComponent extends FormReactive implements OnInit { - information: string = null; error: string = null; form: FormGroup; @@ -26,9 +26,10 @@ export class AccountComponent extends FormReactive implements OnInit { }; constructor( - private accountService: AccountService, private formBuilder: FormBuilder, - private router: Router + private router: Router, + private notificationsService: NotificationsService, + private accountService: AccountService ) { super(); } @@ -50,7 +51,6 @@ export class AccountComponent extends FormReactive implements OnInit { const newPassword = this.form.value['new-password']; const newConfirmedPassword = this.form.value['new-confirmed-password']; - this.information = null; this.error = null; if (newPassword !== newConfirmedPassword) { @@ -59,7 +59,7 @@ export class AccountComponent extends FormReactive implements OnInit { } this.accountService.changePassword(newPassword).subscribe( - ok => this.information = 'Password updated.', + () => this.notificationsService.success('Success', 'Password updated.'), err => this.error = err ); diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html index 04c32f596..95a025832 100644 --- a/client/src/app/app.component.html +++ b/client/src/app/app.component.html @@ -22,6 +22,8 @@ + + diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index ce4fc04ff..f487e6c48 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts @@ -9,6 +9,19 @@ import { MetaService } from 'ng2-meta'; }) export class AppComponent { + notificationOptions = { + timeOut: 3000, + lastOnBottom: true, + clickToClose: true, + maxLength: 0, + maxStack: 7, + showProgressBar: false, + pauseOnHover: false, + preventDuplicates: false, + preventLastDuplicates: 'visible', + rtl: false + }; + constructor( private router: Router, private metaService: MetaService, diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts index 06ffa1a42..a56adbbad 100644 --- a/client/src/app/core/auth/auth.service.ts +++ b/client/src/app/core/auth/auth.service.ts @@ -7,6 +7,8 @@ import 'rxjs/add/operator/map'; import 'rxjs/add/operator/mergeMap'; import 'rxjs/add/observable/throw'; +import { NotificationsService } from 'angular2-notifications'; + // Do not use the barrel (dependency loop) import { AuthStatus } from '../../shared/auth/auth-status.model'; import { AuthUser } from '../../shared/auth/auth-user.model'; @@ -27,6 +29,7 @@ export class AuthService { constructor( private http: Http, + private notificationsService: NotificationsService, private restExtractor: RestExtractor, private router: Router ) { @@ -44,11 +47,14 @@ export class AuthService { this.clientSecret = result.client_secret; console.log('Client credentials loaded.'); }, + error => { - alert( - `Cannot retrieve OAuth Client credentials: ${error.text}. \n` + - 'Ensure you have correctly configured PeerTube (config/ directory), in particular the "webserver" section.' - ); + let errorMessage = `Cannot retrieve OAuth Client credentials: ${error.text}. \n`; + errorMessage += 'Ensure you have correctly configured PeerTube (config/ directory), in particular the "webserver" section.'; + + // We put a bigger timeout + // This is an important message + this.notificationsService.error('Error', errorMessage, { timeOut: 7000 }); } ); diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts index 09a6f92f5..48fec2d43 100644 --- a/client/src/app/core/core.module.ts +++ b/client/src/app/core/core.module.ts @@ -3,6 +3,8 @@ import { CommonModule } from '@angular/common'; import { HttpModule } from '@angular/http'; import { RouterModule } from '@angular/router'; +import { SimpleNotificationsModule } from 'angular2-notifications'; + import { AuthService } from './auth'; import { MenuComponent, MenuAdminComponent } from './menu'; import { throwIfAlreadyLoaded } from './module-import-guard'; @@ -11,13 +13,17 @@ import { throwIfAlreadyLoaded } from './module-import-guard'; imports: [ CommonModule, HttpModule, - RouterModule + RouterModule, + + SimpleNotificationsModule ], declarations: [ MenuComponent, MenuAdminComponent ], exports: [ + SimpleNotificationsModule, + MenuComponent, MenuAdminComponent ], diff --git a/client/src/app/videos/video-add/video-add.component.ts b/client/src/app/videos/video-add/video-add.component.ts index 1e700ae48..cd6bb9989 100644 --- a/client/src/app/videos/video-add/video-add.component.ts +++ b/client/src/app/videos/video-add/video-add.component.ts @@ -3,6 +3,7 @@ import { FormBuilder, FormGroup } from '@angular/forms'; import { Router } from '@angular/router'; import { FileUploader } from 'ng2-file-upload/ng2-file-upload'; +import { NotificationsService } from 'angular2-notifications'; import { AuthService } from '../../core'; import { FormReactive, VIDEO_NAME, VIDEO_DESCRIPTION, VIDEO_TAGS } from '../../shared'; @@ -38,7 +39,8 @@ export class VideoAddComponent extends FormReactive implements OnInit { private authService: AuthService, private elementRef: ElementRef, private formBuilder: FormBuilder, - private router: Router + private router: Router, + private notificationsService: NotificationsService ) { super(); } @@ -151,6 +153,8 @@ export class VideoAddComponent extends FormReactive implements OnInit { clearInterval(interval); console.log('Video uploaded.'); + this.notificationsService.success('Success', 'Video uploaded.'); + // Print all the videos once it's finished this.router.navigate(['/videos/list']); diff --git a/client/src/app/videos/video-list/video-list.component.ts b/client/src/app/videos/video-list/video-list.component.ts index 6c42ba5be..b3780f8b6 100644 --- a/client/src/app/videos/video-list/video-list.component.ts +++ b/client/src/app/videos/video-list/video-list.component.ts @@ -2,6 +2,8 @@ import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; +import { NotificationsService } from 'angular2-notifications'; + import { SortField, Video, @@ -33,6 +35,7 @@ export class VideoListComponent implements OnInit, OnDestroy { private subSearch: any; constructor( + private notificationsService: NotificationsService, private authService: AuthService, private changeDetector: ChangeDetectorRef, private router: Router, @@ -91,7 +94,7 @@ export class VideoListComponent implements OnInit, OnDestroy { this.loading.next(false); }, - error => alert(error.text) + error => this.notificationsService.error('Error', error.text) ); } @@ -107,6 +110,7 @@ export class VideoListComponent implements OnInit, OnDestroy { } onRemoved(video: Video) { + this.notificationsService.success('Success', `Video ${video.name} deleted.`); this.getVideos(); } diff --git a/client/src/app/videos/video-list/video-miniature.component.ts b/client/src/app/videos/video-list/video-miniature.component.ts index 398d2db75..ca4afc451 100644 --- a/client/src/app/videos/video-list/video-miniature.component.ts +++ b/client/src/app/videos/video-list/video-miniature.component.ts @@ -1,5 +1,7 @@ import { Component, Input, Output, EventEmitter } from '@angular/core'; +import { NotificationsService } from 'angular2-notifications'; + import { SortField, Video, VideoService } from '../shared'; import { User } from '../../shared'; @@ -18,7 +20,10 @@ export class VideoMiniatureComponent { hovering = false; - constructor(private videoService: VideoService) {} + constructor( + private notificationsService: NotificationsService, + private videoService: VideoService + ) {} displayRemoveIcon() { return this.hovering && this.video.isRemovableBy(this.user); @@ -36,7 +41,8 @@ export class VideoMiniatureComponent { if (confirm('Do you really want to remove this video?')) { this.videoService.removeVideo(id).subscribe( status => this.removed.emit(true), - error => alert(error.text) + + error => this.notificationsService.error('Error', error.text) ); } } diff --git a/client/src/app/videos/video-watch/video-report.component.ts b/client/src/app/videos/video-watch/video-report.component.ts index 7a125f53e..19a7af148 100644 --- a/client/src/app/videos/video-watch/video-report.component.ts +++ b/client/src/app/videos/video-watch/video-report.component.ts @@ -2,6 +2,7 @@ import { Component, Input, OnInit, ViewChild } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; import { ModalDirective } from 'ng2-bootstrap/modal'; +import { NotificationsService } from 'angular2-notifications'; import { FormReactive, VideoAbuseService, VIDEO_ABUSE_REASON } from '../../shared'; import { Video, VideoService } from '../shared'; @@ -26,7 +27,8 @@ export class VideoReportComponent extends FormReactive implements OnInit { constructor( private formBuilder: FormBuilder, - private videoAbuseService: VideoAbuseService + private videoAbuseService: VideoAbuseService, + private notificationsService: NotificationsService ) { super(); } @@ -56,13 +58,12 @@ export class VideoReportComponent extends FormReactive implements OnInit { this.videoAbuseService.reportVideo(this.video.id, reason) .subscribe( - // TODO: move alert to beautiful notifications - ok => { - alert('Video reported.'); + () => { + this.notificationsService.success('Success', 'Video reported.'); this.hide(); }, - err => alert(err.text) + err => this.notificationsService.error('Error', err.text); ) } } diff --git a/client/src/app/videos/video-watch/video-watch.component.ts b/client/src/app/videos/video-watch/video-watch.component.ts index 5cd7550be..c27133f74 100644 --- a/client/src/app/videos/video-watch/video-watch.component.ts +++ b/client/src/app/videos/video-watch/video-watch.component.ts @@ -1,8 +1,9 @@ import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { MetaService } from 'ng2-meta'; import * as videojs from 'video.js'; +import { MetaService } from 'ng2-meta'; +import { NotificationsService } from 'angular2-notifications'; import { AuthService } from '../../core'; import { VideoMagnetComponent } from './video-magnet.component'; @@ -45,7 +46,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy { private videoService: VideoService, private metaService: MetaService, private webTorrentService: WebTorrentService, - private authService: AuthService + private authService: AuthService, + private notificationsService: NotificationsService ) {} ngOnInit() { @@ -117,7 +119,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { console.log('Added ' + this.video.magnetUri + '.'); torrent.files[0].renderTo(this.playerElement, { autoplay: true }, (err) => { if (err) { - alert('Cannot append the file.'); + this.notificationsService.error('Error', 'Cannot append the file in the video element.'); console.error(err); } });