Client: better notifications for a beautiful world

pull/40/head
Chocobozzz 2017-01-27 16:14:11 +01:00
parent cddadde81f
commit 7ddd02c9b8
18 changed files with 132 additions and 47 deletions

View File

@ -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",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,5 @@
<h3>Account</h3>
<div *ngIf="information" class="alert alert-success">{{ information }}</div>
<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
<form role="form" (ngSubmit)="changePassword()" [formGroup]="form">

View File

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

View File

@ -22,6 +22,8 @@
</div>
</div>
<simple-notifications [options]="notificationOptions"></simple-notifications>
<footer>
PeerTube, CopyLeft 2015-2016
</footer>

View File

@ -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,

View File

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

View File

@ -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
],

View File

@ -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']);

View File

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

View File

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

View File

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

View File

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