diff options
Diffstat (limited to 'client')
16 files changed, 428 insertions, 11 deletions
diff --git a/client/src/app/+admin/admin-routing.module.ts b/client/src/app/+admin/admin-routing.module.ts index 7ef5c6105..0301d7601 100644 --- a/client/src/app/+admin/admin-routing.module.ts +++ b/client/src/app/+admin/admin-routing.module.ts | |||
@@ -1,14 +1,15 @@ | |||
1 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
2 | import { RouterModule, Routes } from '@angular/router' | 2 | import { RouterModule, Routes } from '@angular/router' |
3 | import { ConfigRoutes } from '@app/+admin/config' | ||
3 | 4 | ||
4 | import { MetaGuard } from '@ngx-meta/core' | 5 | import { MetaGuard } from '@ngx-meta/core' |
5 | 6 | ||
6 | import { AdminComponent } from './admin.component' | 7 | import { AdminComponent } from './admin.component' |
7 | import { FollowsRoutes } from './follows' | 8 | import { FollowsRoutes } from './follows' |
9 | import { JobsRoutes } from './jobs/job.routes' | ||
8 | import { UsersRoutes } from './users' | 10 | import { UsersRoutes } from './users' |
9 | import { VideoAbusesRoutes } from './video-abuses' | 11 | import { VideoAbusesRoutes } from './video-abuses' |
10 | import { VideoBlacklistRoutes } from './video-blacklist' | 12 | import { VideoBlacklistRoutes } from './video-blacklist' |
11 | import { JobsRoutes } from './jobs/job.routes' | ||
12 | 13 | ||
13 | const adminRoutes: Routes = [ | 14 | const adminRoutes: Routes = [ |
14 | { | 15 | { |
@@ -26,7 +27,8 @@ const adminRoutes: Routes = [ | |||
26 | ...UsersRoutes, | 27 | ...UsersRoutes, |
27 | ...VideoAbusesRoutes, | 28 | ...VideoAbusesRoutes, |
28 | ...VideoBlacklistRoutes, | 29 | ...VideoBlacklistRoutes, |
29 | ...JobsRoutes | 30 | ...JobsRoutes, |
31 | ...ConfigRoutes | ||
30 | ] | 32 | ] |
31 | } | 33 | } |
32 | ] | 34 | ] |
diff --git a/client/src/app/+admin/admin.component.html b/client/src/app/+admin/admin.component.html index 0bf4c8aac..e4644498b 100644 --- a/client/src/app/+admin/admin.component.html +++ b/client/src/app/+admin/admin.component.html | |||
@@ -19,6 +19,10 @@ | |||
19 | <a *ngIf="hasJobsRight()" routerLink="/admin/jobs" routerLinkActive="active" class="title-page"> | 19 | <a *ngIf="hasJobsRight()" routerLink="/admin/jobs" routerLinkActive="active" class="title-page"> |
20 | Jobs | 20 | Jobs |
21 | </a> | 21 | </a> |
22 | |||
23 | <a *ngIf="hasConfigRight()" routerLink="/admin/config" routerLinkActive="active" class="title-page"> | ||
24 | Configuration | ||
25 | </a> | ||
22 | </div> | 26 | </div> |
23 | 27 | ||
24 | <div class="margin-content"> | 28 | <div class="margin-content"> |
diff --git a/client/src/app/+admin/admin.component.ts b/client/src/app/+admin/admin.component.ts index 75cd50cc7..1a4dd6786 100644 --- a/client/src/app/+admin/admin.component.ts +++ b/client/src/app/+admin/admin.component.ts | |||
@@ -28,4 +28,8 @@ export class AdminComponent { | |||
28 | hasJobsRight () { | 28 | hasJobsRight () { |
29 | return this.auth.getUser().hasRight(UserRight.MANAGE_JOBS) | 29 | return this.auth.getUser().hasRight(UserRight.MANAGE_JOBS) |
30 | } | 30 | } |
31 | |||
32 | hasConfigRight () { | ||
33 | return this.auth.getUser().hasRight(UserRight.MANAGE_CONFIGURATION) | ||
34 | } | ||
31 | } | 35 | } |
diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts index 74ceb25ef..1d9120490 100644 --- a/client/src/app/+admin/admin.module.ts +++ b/client/src/app/+admin/admin.module.ts | |||
@@ -1,4 +1,6 @@ | |||
1 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
2 | import { ConfigComponent, EditCustomConfigComponent } from '@app/+admin/config' | ||
3 | import { ConfigService } from '@app/+admin/config/shared/config.service' | ||
2 | import { TabsModule } from 'ngx-bootstrap/tabs' | 4 | import { TabsModule } from 'ngx-bootstrap/tabs' |
3 | import { DataTableModule } from 'primeng/components/datatable/datatable' | 5 | import { DataTableModule } from 'primeng/components/datatable/datatable' |
4 | import { SharedModule } from '../shared' | 6 | import { SharedModule } from '../shared' |
@@ -41,7 +43,10 @@ import { VideoBlacklistComponent, VideoBlacklistListComponent } from './video-bl | |||
41 | VideoAbuseListComponent, | 43 | VideoAbuseListComponent, |
42 | 44 | ||
43 | JobsComponent, | 45 | JobsComponent, |
44 | JobsListComponent | 46 | JobsListComponent, |
47 | |||
48 | ConfigComponent, | ||
49 | EditCustomConfigComponent | ||
45 | ], | 50 | ], |
46 | 51 | ||
47 | exports: [ | 52 | exports: [ |
@@ -51,7 +56,8 @@ import { VideoBlacklistComponent, VideoBlacklistListComponent } from './video-bl | |||
51 | providers: [ | 56 | providers: [ |
52 | FollowService, | 57 | FollowService, |
53 | UserService, | 58 | UserService, |
54 | JobService | 59 | JobService, |
60 | ConfigService | ||
55 | ] | 61 | ] |
56 | }) | 62 | }) |
57 | export class AdminModule { } | 63 | export class AdminModule { } |
diff --git a/client/src/app/+admin/config/config.component.ts b/client/src/app/+admin/config/config.component.ts new file mode 100644 index 000000000..e0eb77278 --- /dev/null +++ b/client/src/app/+admin/config/config.component.ts | |||
@@ -0,0 +1,7 @@ | |||
1 | import { Component } from '@angular/core' | ||
2 | |||
3 | @Component({ | ||
4 | template: '<router-outlet></router-outlet>' | ||
5 | }) | ||
6 | export class ConfigComponent { | ||
7 | } | ||
diff --git a/client/src/app/+admin/config/config.routes.ts b/client/src/app/+admin/config/config.routes.ts new file mode 100644 index 000000000..a46b0ddfd --- /dev/null +++ b/client/src/app/+admin/config/config.routes.ts | |||
@@ -0,0 +1,32 @@ | |||
1 | import { Routes } from '@angular/router' | ||
2 | import { EditCustomConfigComponent } from '@app/+admin/config/edit-custom-config' | ||
3 | import { UserRightGuard } from '@app/core' | ||
4 | import { UserRight } from '../../../../../shared/models/users' | ||
5 | import { ConfigComponent } from './config.component' | ||
6 | |||
7 | export const ConfigRoutes: Routes = [ | ||
8 | { | ||
9 | path: 'config', | ||
10 | component: ConfigComponent, | ||
11 | canActivate: [ UserRightGuard ], | ||
12 | data: { | ||
13 | userRight: UserRight.MANAGE_CONFIGURATION | ||
14 | }, | ||
15 | children: [ | ||
16 | { | ||
17 | path: '', | ||
18 | redirectTo: 'edit-custom', | ||
19 | pathMatch: 'full' | ||
20 | }, | ||
21 | { | ||
22 | path: 'edit-custom', | ||
23 | component: EditCustomConfigComponent, | ||
24 | data: { | ||
25 | meta: { | ||
26 | title: 'Following list' | ||
27 | } | ||
28 | } | ||
29 | } | ||
30 | ] | ||
31 | } | ||
32 | ] | ||
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html new file mode 100644 index 000000000..c568a43b4 --- /dev/null +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html | |||
@@ -0,0 +1,97 @@ | |||
1 | <div class="admin-sub-title">Update PeerTube configuration</div> | ||
2 | |||
3 | <form role="form" (ngSubmit)="formValidated()" [formGroup]="form"> | ||
4 | |||
5 | <div class="inner-form-title">Cache</div> | ||
6 | |||
7 | <div class="form-group"> | ||
8 | <label for="cachePreviewsSize">Preview cache size</label> | ||
9 | <input | ||
10 | type="text" id="cachePreviewsSize" | ||
11 | formControlName="cachePreviewsSize" [ngClass]="{ 'input-error': formErrors['cachePreviewsSize'] }" | ||
12 | > | ||
13 | <div *ngIf="formErrors.cachePreviewsSize" class="form-error"> | ||
14 | {{ formErrors.cachePreviewsSize }} | ||
15 | </div> | ||
16 | </div> | ||
17 | |||
18 | <div class="inner-form-title">Signup</div> | ||
19 | |||
20 | <div class="form-group"> | ||
21 | <input type="checkbox" id="signupEnabled" formControlName="signupEnabled"> | ||
22 | |||
23 | <label for="signupEnabled"></label> | ||
24 | <label for="signupEnabled">Signup enabled</label> | ||
25 | </div> | ||
26 | |||
27 | <div *ngIf="isSignupEnabled()" class="form-group"> | ||
28 | <label for="signupLimit">Signup limit</label> | ||
29 | <input | ||
30 | type="text" id="signupLimit" | ||
31 | formControlName="signupLimit" [ngClass]="{ 'input-error': formErrors['signupLimit'] }" | ||
32 | > | ||
33 | <div *ngIf="formErrors.signupLimit" class="form-error"> | ||
34 | {{ formErrors.signupLimit }} | ||
35 | </div> | ||
36 | </div> | ||
37 | |||
38 | <div class="inner-form-title">Administrator</div> | ||
39 | |||
40 | <div class="form-group"> | ||
41 | <label for="adminEmail">Admin email</label> | ||
42 | <input | ||
43 | type="text" id="adminEmail" | ||
44 | formControlName="adminEmail" [ngClass]="{ 'input-error': formErrors['adminEmail'] }" | ||
45 | > | ||
46 | <div *ngIf="formErrors.adminEmail" class="form-error"> | ||
47 | {{ formErrors.adminEmail }} | ||
48 | </div> | ||
49 | </div> | ||
50 | |||
51 | <div class="inner-form-title">Users</div> | ||
52 | |||
53 | <div class="form-group"> | ||
54 | <label for="userVideoQuota">User default video quota</label> | ||
55 | <div class="peertube-select-container"> | ||
56 | <select id="userVideoQuota" formControlName="userVideoQuota"> | ||
57 | <option *ngFor="let videoQuotaOption of videoQuotaOptions" [value]="videoQuotaOption.value"> | ||
58 | {{ videoQuotaOption.label }} | ||
59 | </option> | ||
60 | </select> | ||
61 | </div> | ||
62 | </div> | ||
63 | |||
64 | <div class="inner-form-title">Transcoding</div> | ||
65 | |||
66 | <div class="form-group"> | ||
67 | <input type="checkbox" id="transcodingEnabled" formControlName="transcodingEnabled"> | ||
68 | |||
69 | <label for="transcodingEnabled"></label> | ||
70 | <label for="transcodingEnabled">Transcoding enabled</label> | ||
71 | </div> | ||
72 | |||
73 | <ng-template [ngIf]="isTranscodingEnabled()"> | ||
74 | |||
75 | <div class="form-group"> | ||
76 | <label for="transcodingThreads">Transcoding threads</label> | ||
77 | <div class="peertube-select-container"> | ||
78 | <select id="transcodingThreads" formControlName="transcodingThreads"> | ||
79 | <option *ngFor="let transcodingThreadOption of transcodingThreadOptions" [value]="transcodingThreadOption.value"> | ||
80 | {{ transcodingThreadOption.label }} | ||
81 | </option> | ||
82 | </select> | ||
83 | </div> | ||
84 | </div> | ||
85 | |||
86 | <div class="form-group" *ngFor="let resolution of resolutions"> | ||
87 | <input | ||
88 | type="checkbox" [id]="getResolutionKey(resolution)" | ||
89 | [formControlName]="getResolutionKey(resolution)" | ||
90 | > | ||
91 | <label [for]="getResolutionKey(resolution)"></label> | ||
92 | <label [for]="getResolutionKey(resolution)">Resolution {{ resolution }} enabled</label> | ||
93 | </div> | ||
94 | </ng-template> | ||
95 | |||
96 | <input type="submit" value="Update configuration" [disabled]="!form.valid"> | ||
97 | </form> | ||
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss new file mode 100644 index 000000000..0195f44eb --- /dev/null +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss | |||
@@ -0,0 +1,31 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | input[type=text] { | ||
5 | @include peertube-input-text(340px); | ||
6 | display: block; | ||
7 | } | ||
8 | |||
9 | input[type=checkbox] { | ||
10 | @include peertube-checkbox(1px); | ||
11 | } | ||
12 | |||
13 | .peertube-select-container { | ||
14 | @include peertube-select-container(340px); | ||
15 | } | ||
16 | |||
17 | input[type=submit] { | ||
18 | @include peertube-button; | ||
19 | @include orange-button; | ||
20 | |||
21 | margin-top: 20px; | ||
22 | } | ||
23 | |||
24 | .inner-form-title { | ||
25 | text-transform: uppercase; | ||
26 | color: $orange-color; | ||
27 | font-weight: $font-bold; | ||
28 | font-size: 13px; | ||
29 | margin-top: 30px; | ||
30 | margin-bottom: 10px; | ||
31 | } | ||
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts new file mode 100644 index 000000000..1b3522786 --- /dev/null +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts | |||
@@ -0,0 +1,174 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | import { FormBuilder, FormGroup } from '@angular/forms' | ||
3 | import { Router } from '@angular/router' | ||
4 | import { ConfigService } from '@app/+admin/config/shared/config.service' | ||
5 | import { ServerService } from '@app/core/server/server.service' | ||
6 | import { FormReactive, USER_VIDEO_QUOTA } from '@app/shared' | ||
7 | import { ADMIN_EMAIL, CACHE_PREVIEWS_SIZE, SIGNUP_LIMIT, TRANSCODING_THREADS } from '@app/shared/forms/form-validators/custom-config' | ||
8 | import { NotificationsService } from 'angular2-notifications' | ||
9 | import { CustomConfig } from '../../../../../../shared/models/config/custom-config.model' | ||
10 | |||
11 | @Component({ | ||
12 | selector: 'my-edit-custom-config', | ||
13 | templateUrl: './edit-custom-config.component.html', | ||
14 | styleUrls: [ './edit-custom-config.component.scss' ] | ||
15 | }) | ||
16 | export class EditCustomConfigComponent extends FormReactive implements OnInit { | ||
17 | customConfig: CustomConfig | ||
18 | resolutions = [ '240p', '360p', '480p', '720p', '1080p' ] | ||
19 | |||
20 | videoQuotaOptions = [ | ||
21 | { value: -1, label: 'Unlimited' }, | ||
22 | { value: 0, label: '0' }, | ||
23 | { value: 100 * 1024 * 1024, label: '100MB' }, | ||
24 | { value: 500 * 1024 * 1024, label: '500MB' }, | ||
25 | { value: 1024 * 1024 * 1024, label: '1GB' }, | ||
26 | { value: 5 * 1024 * 1024 * 1024, label: '5GB' }, | ||
27 | { value: 20 * 1024 * 1024 * 1024, label: '20GB' }, | ||
28 | { value: 50 * 1024 * 1024 * 1024, label: '50GB' } | ||
29 | ] | ||
30 | transcodingThreadOptions = [ | ||
31 | { value: 1, label: '1' }, | ||
32 | { value: 2, label: '2' }, | ||
33 | { value: 4, label: '4' }, | ||
34 | { value: 8, label: '8' } | ||
35 | ] | ||
36 | |||
37 | form: FormGroup | ||
38 | formErrors = { | ||
39 | cachePreviewsSize: '', | ||
40 | signupLimit: '', | ||
41 | adminEmail: '', | ||
42 | userVideoQuota: '', | ||
43 | transcodingThreads: '' | ||
44 | } | ||
45 | validationMessages = { | ||
46 | cachePreviewsSize: CACHE_PREVIEWS_SIZE.MESSAGES, | ||
47 | signupLimit: SIGNUP_LIMIT.MESSAGES, | ||
48 | adminEmail: ADMIN_EMAIL.MESSAGES, | ||
49 | userVideoQuota: USER_VIDEO_QUOTA.MESSAGES | ||
50 | } | ||
51 | |||
52 | constructor ( | ||
53 | private formBuilder: FormBuilder, | ||
54 | private router: Router, | ||
55 | private notificationsService: NotificationsService, | ||
56 | private configService: ConfigService, | ||
57 | private serverService: ServerService | ||
58 | ) { | ||
59 | super() | ||
60 | } | ||
61 | |||
62 | getResolutionKey (resolution: string) { | ||
63 | return 'transcodingResolution' + resolution | ||
64 | } | ||
65 | |||
66 | buildForm () { | ||
67 | const formGroupData = { | ||
68 | cachePreviewsSize: [ '', CACHE_PREVIEWS_SIZE.VALIDATORS ], | ||
69 | signupEnabled: [ ], | ||
70 | signupLimit: [ '', SIGNUP_LIMIT.VALIDATORS ], | ||
71 | adminEmail: [ '', ADMIN_EMAIL.VALIDATORS ], | ||
72 | userVideoQuota: [ '', USER_VIDEO_QUOTA.VALIDATORS ], | ||
73 | transcodingThreads: [ '', TRANSCODING_THREADS.VALIDATORS ], | ||
74 | transcodingEnabled: [ ] | ||
75 | } | ||
76 | |||
77 | for (const resolution of this.resolutions) { | ||
78 | const key = this.getResolutionKey(resolution) | ||
79 | formGroupData[key] = [ false ] | ||
80 | } | ||
81 | |||
82 | this.form = this.formBuilder.group(formGroupData) | ||
83 | |||
84 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)) | ||
85 | } | ||
86 | |||
87 | ngOnInit () { | ||
88 | this.buildForm() | ||
89 | |||
90 | this.configService.getCustomConfig() | ||
91 | .subscribe( | ||
92 | res => { | ||
93 | this.customConfig = res | ||
94 | |||
95 | this.updateForm() | ||
96 | }, | ||
97 | |||
98 | err => this.notificationsService.error('Error', err.message) | ||
99 | ) | ||
100 | } | ||
101 | |||
102 | isTranscodingEnabled () { | ||
103 | return this.form.value['transcodingEnabled'] === true | ||
104 | } | ||
105 | |||
106 | isSignupEnabled () { | ||
107 | return this.form.value['signupEnabled'] === true | ||
108 | } | ||
109 | |||
110 | formValidated () { | ||
111 | const data = { | ||
112 | cache: { | ||
113 | previews: { | ||
114 | size: this.form.value['cachePreviewsSize'] | ||
115 | } | ||
116 | }, | ||
117 | signup: { | ||
118 | enabled: this.form.value['signupEnabled'], | ||
119 | limit: this.form.value['signupLimit'] | ||
120 | }, | ||
121 | admin: { | ||
122 | email: this.form.value['adminEmail'] | ||
123 | }, | ||
124 | user: { | ||
125 | videoQuota: this.form.value['userVideoQuota'] | ||
126 | }, | ||
127 | transcoding: { | ||
128 | enabled: this.form.value['transcodingEnabled'], | ||
129 | threads: this.form.value['transcodingThreads'], | ||
130 | resolutions: { | ||
131 | '240p': this.form.value[this.getResolutionKey('240p')], | ||
132 | '360p': this.form.value[this.getResolutionKey('360p')], | ||
133 | '480p': this.form.value[this.getResolutionKey('480p')], | ||
134 | '720p': this.form.value[this.getResolutionKey('720p')], | ||
135 | '1080p': this.form.value[this.getResolutionKey('1080p')] | ||
136 | } | ||
137 | } | ||
138 | } | ||
139 | |||
140 | this.configService.updateCustomConfig(data) | ||
141 | .subscribe( | ||
142 | res => { | ||
143 | this.customConfig = res | ||
144 | |||
145 | // Reload general configuration | ||
146 | this.serverService.loadConfig() | ||
147 | |||
148 | this.updateForm() | ||
149 | }, | ||
150 | |||
151 | err => this.notificationsService.error('Error', err.message) | ||
152 | ) | ||
153 | } | ||
154 | |||
155 | private updateForm () { | ||
156 | const data = { | ||
157 | cachePreviewsSize: this.customConfig.cache.previews.size, | ||
158 | signupEnabled: this.customConfig.signup.enabled, | ||
159 | signupLimit: this.customConfig.signup.limit, | ||
160 | adminEmail: this.customConfig.admin.email, | ||
161 | userVideoQuota: this.customConfig.user.videoQuota, | ||
162 | transcodingThreads: this.customConfig.transcoding.threads, | ||
163 | transcodingEnabled: this.customConfig.transcoding.enabled | ||
164 | } | ||
165 | |||
166 | for (const resolution of this.resolutions) { | ||
167 | const key = this.getResolutionKey(resolution) | ||
168 | data[key] = this.customConfig.transcoding.resolutions[resolution] | ||
169 | } | ||
170 | |||
171 | this.form.patchValue(data) | ||
172 | } | ||
173 | |||
174 | } | ||
diff --git a/client/src/app/+admin/config/edit-custom-config/index.ts b/client/src/app/+admin/config/edit-custom-config/index.ts new file mode 100644 index 000000000..1ec12631f --- /dev/null +++ b/client/src/app/+admin/config/edit-custom-config/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './edit-custom-config.component' | |||
diff --git a/client/src/app/+admin/config/index.ts b/client/src/app/+admin/config/index.ts new file mode 100644 index 000000000..b47ebf8db --- /dev/null +++ b/client/src/app/+admin/config/index.ts | |||
@@ -0,0 +1,3 @@ | |||
1 | export * from './edit-custom-config' | ||
2 | export * from './config.component' | ||
3 | export * from './config.routes' | ||
diff --git a/client/src/app/+admin/config/shared/config.service.ts b/client/src/app/+admin/config/shared/config.service.ts new file mode 100644 index 000000000..13f1f6cd2 --- /dev/null +++ b/client/src/app/+admin/config/shared/config.service.ts | |||
@@ -0,0 +1,26 @@ | |||
1 | import { HttpClient } from '@angular/common/http' | ||
2 | import { Injectable } from '@angular/core' | ||
3 | import { CustomConfig } from '../../../../../../shared/models/config/custom-config.model' | ||
4 | import { environment } from '../../../../environments/environment' | ||
5 | import { RestExtractor, RestService } from '../../../shared' | ||
6 | |||
7 | @Injectable() | ||
8 | export class ConfigService { | ||
9 | private static BASE_APPLICATION_URL = environment.apiUrl + '/api/v1/config' | ||
10 | |||
11 | constructor ( | ||
12 | private authHttp: HttpClient, | ||
13 | private restService: RestService, | ||
14 | private restExtractor: RestExtractor | ||
15 | ) {} | ||
16 | |||
17 | getCustomConfig () { | ||
18 | return this.authHttp.get<CustomConfig>(ConfigService.BASE_APPLICATION_URL + '/custom') | ||
19 | .catch(res => this.restExtractor.handleError(res)) | ||
20 | } | ||
21 | |||
22 | updateCustomConfig (data: CustomConfig) { | ||
23 | return this.authHttp.put<CustomConfig>(ConfigService.BASE_APPLICATION_URL + '/custom', data) | ||
24 | .catch(res => this.restExtractor.handleError(res)) | ||
25 | } | ||
26 | } | ||
diff --git a/client/src/app/account/account-settings/account-details/account-details.component.html b/client/src/app/account/account-settings/account-details/account-details.component.html index c8e1e73b0..8f1475a4d 100644 --- a/client/src/app/account/account-settings/account-details/account-details.component.html +++ b/client/src/app/account/account-settings/account-details/account-details.component.html | |||
@@ -1,5 +1,3 @@ | |||
1 | <div *ngIf="error" class="alert alert-danger">{{ error }}</div> | ||
2 | |||
3 | <form role="form" (ngSubmit)="updateDetails()" [formGroup]="form"> | 1 | <form role="form" (ngSubmit)="updateDetails()" [formGroup]="form"> |
4 | <div class="form-group"> | 2 | <div class="form-group"> |
5 | <input | 3 | <input |
diff --git a/client/src/app/account/account-settings/account-details/account-details.component.ts b/client/src/app/account/account-settings/account-details/account-details.component.ts index b8c19d8d6..917f31651 100644 --- a/client/src/app/account/account-settings/account-details/account-details.component.ts +++ b/client/src/app/account/account-settings/account-details/account-details.component.ts | |||
@@ -14,8 +14,6 @@ import { FormReactive, User, UserService } from '../../../shared' | |||
14 | export class AccountDetailsComponent extends FormReactive implements OnInit { | 14 | export class AccountDetailsComponent extends FormReactive implements OnInit { |
15 | @Input() user: User = null | 15 | @Input() user: User = null |
16 | 16 | ||
17 | error: string = null | ||
18 | |||
19 | form: FormGroup | 17 | form: FormGroup |
20 | formErrors = {} | 18 | formErrors = {} |
21 | validationMessages = {} | 19 | validationMessages = {} |
@@ -50,7 +48,6 @@ export class AccountDetailsComponent extends FormReactive implements OnInit { | |||
50 | autoPlayVideo | 48 | autoPlayVideo |
51 | } | 49 | } |
52 | 50 | ||
53 | this.error = null | ||
54 | this.userService.updateMyDetails(details).subscribe( | 51 | this.userService.updateMyDetails(details).subscribe( |
55 | () => { | 52 | () => { |
56 | this.notificationsService.success('Success', 'Information updated.') | 53 | this.notificationsService.success('Success', 'Information updated.') |
@@ -58,7 +55,7 @@ export class AccountDetailsComponent extends FormReactive implements OnInit { | |||
58 | this.authService.refreshUserInformation() | 55 | this.authService.refreshUserInformation() |
59 | }, | 56 | }, |
60 | 57 | ||
61 | err => this.error = err.message | 58 | err => this.notificationsService.error('Error', err.message) |
62 | ) | 59 | ) |
63 | } | 60 | } |
64 | } | 61 | } |
diff --git a/client/src/app/menu/menu.component.html b/client/src/app/menu/menu.component.html index d138d2ba7..94f82e352 100644 --- a/client/src/app/menu/menu.component.html +++ b/client/src/app/menu/menu.component.html | |||
@@ -14,7 +14,7 @@ | |||
14 | 14 | ||
15 | <ul *dropdownMenu class="dropdown-menu"> | 15 | <ul *dropdownMenu class="dropdown-menu"> |
16 | <li> | 16 | <li> |
17 | <a routerLink="/account/settings" class="dropdown-item" title="My account"> | 17 | <a i18n routerLink="/account/settings" class="dropdown-item" title="My account"> |
18 | My account | 18 | My account |
19 | </a> | 19 | </a> |
20 | 20 | ||
diff --git a/client/src/app/shared/forms/form-validators/custom-config.ts b/client/src/app/shared/forms/form-validators/custom-config.ts new file mode 100644 index 000000000..17ae0e75c --- /dev/null +++ b/client/src/app/shared/forms/form-validators/custom-config.ts | |||
@@ -0,0 +1,35 @@ | |||
1 | import { Validators } from '@angular/forms' | ||
2 | |||
3 | export const CACHE_PREVIEWS_SIZE = { | ||
4 | VALIDATORS: [ Validators.required, Validators.min(1), Validators.pattern('[0-9]+') ], | ||
5 | MESSAGES: { | ||
6 | 'required': 'Preview cache size is required.', | ||
7 | 'min': 'Preview cache size must be greater than 1.', | ||
8 | 'pattern': 'Preview cache size must be a number.' | ||
9 | } | ||
10 | } | ||
11 | |||
12 | export const SIGNUP_LIMIT = { | ||
13 | VALIDATORS: [ Validators.required, Validators.min(1), Validators.pattern('[0-9]+') ], | ||
14 | MESSAGES: { | ||
15 | 'required': 'Signup limit is required.', | ||
16 | 'min': 'Signup limit must be greater than 1.', | ||
17 | 'pattern': 'Preview cache size must be a number.' | ||
18 | } | ||
19 | } | ||
20 | |||
21 | export const ADMIN_EMAIL = { | ||
22 | VALIDATORS: [ Validators.required, Validators.email ], | ||
23 | MESSAGES: { | ||
24 | 'required': 'Admin email is required.', | ||
25 | 'email': 'Admin email must be valid.' | ||
26 | } | ||
27 | } | ||
28 | |||
29 | export const TRANSCODING_THREADS = { | ||
30 | VALIDATORS: [ Validators.required, Validators.min(1) ], | ||
31 | MESSAGES: { | ||
32 | 'required': 'Transcoding threads is required.', | ||
33 | 'min': 'Transcoding threads must be greater than 1.' | ||
34 | } | ||
35 | } | ||