aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/+admin
diff options
context:
space:
mode:
authorChocobozzz <chocobozzz@cpy.re>2021-05-27 15:59:55 +0200
committerGitHub <noreply@github.com>2021-05-27 15:59:55 +0200
commit2539932e16129992a2c0889b4ff527c265a8e2c7 (patch)
treefb5048e63e02a2485eb96d27455f43e4b22e8ae0 /client/src/app/+admin
parenteb34ec30e0b57286fc6f85160490d2e973a3b0b1 (diff)
downloadPeerTube-2539932e16129992a2c0889b4ff527c265a8e2c7.tar.gz
PeerTube-2539932e16129992a2c0889b4ff527c265a8e2c7.tar.zst
PeerTube-2539932e16129992a2c0889b4ff527c265a8e2c7.zip
Instance homepage support (#4007)
* Prepare homepage parsers * Add ability to update instance hompage * Add ability to set homepage as landing page * Add homepage preview in admin * Dynamically update left menu for homepage * Inject home content in homepage * Add videos list and channel miniature custom markup * Remove unused elements in markup service
Diffstat (limited to 'client/src/app/+admin')
-rw-r--r--client/src/app/+admin/admin.module.ts8
-rw-r--r--client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html23
-rw-r--r--client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.ts26
-rw-r--r--client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html14
-rw-r--r--client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts48
-rw-r--r--client/src/app/+admin/config/edit-custom-config/edit-homepage.component.html28
-rw-r--r--client/src/app/+admin/config/edit-custom-config/edit-homepage.component.ts25
-rw-r--r--client/src/app/+admin/config/edit-custom-config/index.ts1
8 files changed, 136 insertions, 37 deletions
diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts
index 45366f9ec..a7fe20b07 100644
--- a/client/src/app/+admin/admin.module.ts
+++ b/client/src/app/+admin/admin.module.ts
@@ -4,12 +4,13 @@ import { TableModule } from 'primeng/table'
4import { NgModule } from '@angular/core' 4import { NgModule } from '@angular/core'
5import { SharedAbuseListModule } from '@app/shared/shared-abuse-list' 5import { SharedAbuseListModule } from '@app/shared/shared-abuse-list'
6import { SharedActorImageEditModule } from '@app/shared/shared-actor-image-edit' 6import { SharedActorImageEditModule } from '@app/shared/shared-actor-image-edit'
7import { SharedActorImageModule } from '@app/shared/shared-actor-image/shared-actor-image.module'
8import { SharedCustomMarkupModule } from '@app/shared/shared-custom-markup'
7import { SharedFormModule } from '@app/shared/shared-forms' 9import { SharedFormModule } from '@app/shared/shared-forms'
8import { SharedGlobalIconModule } from '@app/shared/shared-icons' 10import { SharedGlobalIconModule } from '@app/shared/shared-icons'
9import { SharedMainModule } from '@app/shared/shared-main' 11import { SharedMainModule } from '@app/shared/shared-main'
10import { SharedModerationModule } from '@app/shared/shared-moderation' 12import { SharedModerationModule } from '@app/shared/shared-moderation'
11import { SharedVideoCommentModule } from '@app/shared/shared-video-comment' 13import { SharedVideoCommentModule } from '@app/shared/shared-video-comment'
12import { SharedActorImageModule } from '../shared/shared-actor-image/shared-actor-image.module'
13import { AdminRoutingModule } from './admin-routing.module' 14import { AdminRoutingModule } from './admin-routing.module'
14import { AdminComponent } from './admin.component' 15import { AdminComponent } from './admin.component'
15import { 16import {
@@ -18,6 +19,7 @@ import {
18 EditBasicConfigurationComponent, 19 EditBasicConfigurationComponent,
19 EditConfigurationService, 20 EditConfigurationService,
20 EditCustomConfigComponent, 21 EditCustomConfigComponent,
22 EditHomepageComponent,
21 EditInstanceInformationComponent, 23 EditInstanceInformationComponent,
22 EditLiveConfigurationComponent, 24 EditLiveConfigurationComponent,
23 EditVODTranscodingComponent 25 EditVODTranscodingComponent
@@ -53,6 +55,7 @@ import { UserCreateComponent, UserListComponent, UserPasswordComponent, UsersCom
53 SharedVideoCommentModule, 55 SharedVideoCommentModule,
54 SharedActorImageModule, 56 SharedActorImageModule,
55 SharedActorImageEditModule, 57 SharedActorImageEditModule,
58 SharedCustomMarkupModule,
56 59
57 TableModule, 60 TableModule,
58 SelectButtonModule, 61 SelectButtonModule,
@@ -100,7 +103,8 @@ import { UserCreateComponent, UserListComponent, UserPasswordComponent, UsersCom
100 EditVODTranscodingComponent, 103 EditVODTranscodingComponent,
101 EditLiveConfigurationComponent, 104 EditLiveConfigurationComponent,
102 EditAdvancedConfigurationComponent, 105 EditAdvancedConfigurationComponent,
103 EditInstanceInformationComponent 106 EditInstanceInformationComponent,
107 EditHomepageComponent
104 ], 108 ],
105 109
106 exports: [ 110 exports: [
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html b/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html
index 84a793ae4..451e6a34a 100644
--- a/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html
+++ b/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html
@@ -26,22 +26,13 @@
26 <div class="form-group" formGroupName="instance"> 26 <div class="form-group" formGroupName="instance">
27 <label i18n for="instanceDefaultClientRoute">Landing page</label> 27 <label i18n for="instanceDefaultClientRoute">Landing page</label>
28 28
29 <div class="peertube-select-container"> 29 <my-select-custom-value
30 <select id="instanceDefaultClientRoute" formControlName="defaultClientRoute" class="form-control"> 30 id="instanceDefaultClientRoute"
31 <option i18n value="/videos/overview">Discover videos</option> 31 [items]="defaultLandingPageOptions"
32 32 formControlName="defaultClientRoute"
33 <optgroup i18n-label label="Trending pages"> 33 inputType="text"
34 <option i18n value="/videos/trending">Default trending page</option> 34 [clearable]="false"
35 <option i18n value="/videos/trending?alg=best" [disabled]="!doesTrendingVideosAlgorithmsEnabledInclude('best')">Best videos</option> 35 ></my-select-custom-value>
36 <option i18n value="/videos/trending?alg=hot" [disabled]="!doesTrendingVideosAlgorithmsEnabledInclude('hot')">Hot videos</option>
37 <option i18n value="/videos/trending?alg=most-viewed" [disabled]="!doesTrendingVideosAlgorithmsEnabledInclude('most-viewed')">Most viewed videos</option>
38 <option i18n value="/videos/trending?alg=most-liked" [disabled]="!doesTrendingVideosAlgorithmsEnabledInclude('most-liked')">Most liked videos</option>
39 </optgroup>
40
41 <option i18n value="/videos/recently-added">Recently added videos</option>
42 <option i18n value="/videos/local">Local videos</option>
43 </select>
44 </div>
45 36
46 <div *ngIf="formErrors.instance.defaultClientRoute" class="form-error">{{ formErrors.instance.defaultClientRoute }}</div> 37 <div *ngIf="formErrors.instance.defaultClientRoute" class="form-error">{{ formErrors.instance.defaultClientRoute }}</div>
47 </div> 38 </div>
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.ts
index 34d05f9f3..d50148e7a 100644
--- a/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.ts
+++ b/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.ts
@@ -1,7 +1,9 @@
1 1
2import { pairwise } from 'rxjs/operators' 2import { pairwise } from 'rxjs/operators'
3import { Component, Input, OnInit } from '@angular/core' 3import { SelectOptionsItem } from 'src/types/select-options-item.model'
4import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'
4import { FormGroup } from '@angular/forms' 5import { FormGroup } from '@angular/forms'
6import { MenuService } from '@app/core'
5import { ServerConfig } from '@shared/models' 7import { ServerConfig } from '@shared/models'
6import { ConfigService } from '../shared/config.service' 8import { ConfigService } from '../shared/config.service'
7 9
@@ -10,22 +12,31 @@ import { ConfigService } from '../shared/config.service'
10 templateUrl: './edit-basic-configuration.component.html', 12 templateUrl: './edit-basic-configuration.component.html',
11 styleUrls: [ './edit-custom-config.component.scss' ] 13 styleUrls: [ './edit-custom-config.component.scss' ]
12}) 14})
13export class EditBasicConfigurationComponent implements OnInit { 15export class EditBasicConfigurationComponent implements OnInit, OnChanges {
14 @Input() form: FormGroup 16 @Input() form: FormGroup
15 @Input() formErrors: any 17 @Input() formErrors: any
16 18
17 @Input() serverConfig: ServerConfig 19 @Input() serverConfig: ServerConfig
18 20
19 signupAlertMessage: string 21 signupAlertMessage: string
22 defaultLandingPageOptions: SelectOptionsItem[] = []
20 23
21 constructor ( 24 constructor (
22 private configService: ConfigService 25 private configService: ConfigService,
26 private menuService: MenuService
23 ) { } 27 ) { }
24 28
25 ngOnInit () { 29 ngOnInit () {
30 this.buildLandingPageOptions()
26 this.checkSignupField() 31 this.checkSignupField()
27 } 32 }
28 33
34 ngOnChanges (changes: SimpleChanges) {
35 if (changes['serverConfig']) {
36 this.buildLandingPageOptions()
37 }
38 }
39
29 getVideoQuotaOptions () { 40 getVideoQuotaOptions () {
30 return this.configService.videoQuotaOptions 41 return this.configService.videoQuotaOptions
31 } 42 }
@@ -70,6 +81,15 @@ export class EditBasicConfigurationComponent implements OnInit {
70 return this.form.value['followings']['instance']['autoFollowIndex']['enabled'] === true 81 return this.form.value['followings']['instance']['autoFollowIndex']['enabled'] === true
71 } 82 }
72 83
84 buildLandingPageOptions () {
85 this.defaultLandingPageOptions = this.menuService.buildCommonLinks(this.serverConfig)
86 .map(o => ({
87 id: o.path,
88 label: o.label,
89 description: o.path
90 }))
91 }
92
73 private checkSignupField () { 93 private checkSignupField () {
74 const signupControl = this.form.get('signup.enabled') 94 const signupControl = this.form.get('signup.enabled')
75 95
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
index b6365614d..3ceea02ca 100644
--- 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
@@ -3,8 +3,16 @@
3 3
4 <div ngbNav #nav="ngbNav" [activeId]="activeNav" (activeIdChange)="onNavChange($event)" class="nav-tabs"> 4 <div ngbNav #nav="ngbNav" [activeId]="activeNav" (activeIdChange)="onNavChange($event)" class="nav-tabs">
5 5
6 <ng-container ngbNavItem="instance-homepage">
7 <a ngbNavLink i18n>Homepage</a>
8
9 <ng-template ngbNavContent>
10 <my-edit-homepage [form]="form" [formErrors]="formErrors"></my-edit-homepage>
11 </ng-template>
12 </ng-container>
13
6 <ng-container ngbNavItem="instance-information"> 14 <ng-container ngbNavItem="instance-information">
7 <a ngbNavLink i18n>Instance information</a> 15 <a ngbNavLink i18n>Information</a>
8 16
9 <ng-template ngbNavContent> 17 <ng-template ngbNavContent>
10 <my-edit-instance-information [form]="form" [formErrors]="formErrors" [languageItems]="languageItems" [categoryItems]="categoryItems"> 18 <my-edit-instance-information [form]="form" [formErrors]="formErrors" [languageItems]="languageItems" [categoryItems]="categoryItems">
@@ -13,7 +21,7 @@
13 </ng-container> 21 </ng-container>
14 22
15 <ng-container ngbNavItem="basic-configuration"> 23 <ng-container ngbNavItem="basic-configuration">
16 <a ngbNavLink i18n>Basic configuration</a> 24 <a ngbNavLink i18n>Basic</a>
17 25
18 <ng-template ngbNavContent> 26 <ng-template ngbNavContent>
19 <my-edit-basic-configuration [form]="form" [formErrors]="formErrors" [serverConfig]="serverConfig"> 27 <my-edit-basic-configuration [form]="form" [formErrors]="formErrors" [serverConfig]="serverConfig">
@@ -40,7 +48,7 @@
40 </ng-container> 48 </ng-container>
41 49
42 <ng-container ngbNavItem="advanced-configuration"> 50 <ng-container ngbNavItem="advanced-configuration">
43 <a ngbNavLink i18n>Advanced configuration</a> 51 <a ngbNavLink i18n>Advanced</a>
44 52
45 <ng-template ngbNavContent> 53 <ng-template ngbNavContent>
46 <my-edit-advanced-configuration [form]="form" [formErrors]="formErrors"> 54 <my-edit-advanced-configuration [form]="form" [formErrors]="formErrors">
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
index 4b35d65fc..dc8334dd0 100644
--- 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
@@ -1,4 +1,5 @@
1 1
2import omit from 'lodash-es/omit'
2import { forkJoin } from 'rxjs' 3import { forkJoin } from 'rxjs'
3import { SelectOptionsItem } from 'src/types/select-options-item.model' 4import { SelectOptionsItem } from 'src/types/select-options-item.model'
4import { Component, OnInit } from '@angular/core' 5import { Component, OnInit } from '@angular/core'
@@ -24,9 +25,14 @@ import {
24} from '@app/shared/form-validators/custom-config-validators' 25} from '@app/shared/form-validators/custom-config-validators'
25import { USER_VIDEO_QUOTA_DAILY_VALIDATOR, USER_VIDEO_QUOTA_VALIDATOR } from '@app/shared/form-validators/user-validators' 26import { USER_VIDEO_QUOTA_DAILY_VALIDATOR, USER_VIDEO_QUOTA_VALIDATOR } from '@app/shared/form-validators/user-validators'
26import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' 27import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
27import { CustomConfig, ServerConfig } from '@shared/models' 28import { CustomPageService } from '@app/shared/shared-main/custom-page'
29import { CustomConfig, CustomPage, ServerConfig } from '@shared/models'
28import { EditConfigurationService } from './edit-configuration.service' 30import { EditConfigurationService } from './edit-configuration.service'
29 31
32type ComponentCustomConfig = CustomConfig & {
33 instanceCustomHomepage: CustomPage
34}
35
30@Component({ 36@Component({
31 selector: 'my-edit-custom-config', 37 selector: 'my-edit-custom-config',
32 templateUrl: './edit-custom-config.component.html', 38 templateUrl: './edit-custom-config.component.html',
@@ -35,9 +41,11 @@ import { EditConfigurationService } from './edit-configuration.service'
35export class EditCustomConfigComponent extends FormReactive implements OnInit { 41export class EditCustomConfigComponent extends FormReactive implements OnInit {
36 activeNav: string 42 activeNav: string
37 43
38 customConfig: CustomConfig 44 customConfig: ComponentCustomConfig
39 serverConfig: ServerConfig 45 serverConfig: ServerConfig
40 46
47 homepage: CustomPage
48
41 languageItems: SelectOptionsItem[] = [] 49 languageItems: SelectOptionsItem[] = []
42 categoryItems: SelectOptionsItem[] = [] 50 categoryItems: SelectOptionsItem[] = []
43 51
@@ -47,6 +55,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
47 protected formValidatorService: FormValidatorService, 55 protected formValidatorService: FormValidatorService,
48 private notifier: Notifier, 56 private notifier: Notifier,
49 private configService: ConfigService, 57 private configService: ConfigService,
58 private customPage: CustomPageService,
50 private serverService: ServerService, 59 private serverService: ServerService,
51 private editConfigurationService: EditConfigurationService 60 private editConfigurationService: EditConfigurationService
52 ) { 61 ) {
@@ -56,11 +65,9 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
56 ngOnInit () { 65 ngOnInit () {
57 this.serverConfig = this.serverService.getTmpConfig() 66 this.serverConfig = this.serverService.getTmpConfig()
58 this.serverService.getConfig() 67 this.serverService.getConfig()
59 .subscribe(config => { 68 .subscribe(config => this.serverConfig = config)
60 this.serverConfig = config
61 })
62 69
63 const formGroupData: { [key in keyof CustomConfig ]: any } = { 70 const formGroupData: { [key in keyof ComponentCustomConfig ]: any } = {
64 instance: { 71 instance: {
65 name: INSTANCE_NAME_VALIDATOR, 72 name: INSTANCE_NAME_VALIDATOR,
66 shortDescription: INSTANCE_SHORT_DESCRIPTION_VALIDATOR, 73 shortDescription: INSTANCE_SHORT_DESCRIPTION_VALIDATOR,
@@ -215,6 +222,10 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
215 disableLocalSearch: null, 222 disableLocalSearch: null,
216 isDefaultSearch: null 223 isDefaultSearch: null
217 } 224 }
225 },
226
227 instanceCustomHomepage: {
228 content: null
218 } 229 }
219 } 230 }
220 231
@@ -250,15 +261,23 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
250 } 261 }
251 262
252 async formValidated () { 263 async formValidated () {
253 const value: CustomConfig = this.form.getRawValue() 264 const value: ComponentCustomConfig = this.form.getRawValue()
254 265
255 this.configService.updateCustomConfig(value) 266 forkJoin([
267 this.configService.updateCustomConfig(omit(value, 'instanceCustomHomepage')),
268 this.customPage.updateInstanceHomepage(value.instanceCustomHomepage.content)
269 ])
256 .subscribe( 270 .subscribe(
257 res => { 271 ([ resConfig ]) => {
258 this.customConfig = res 272 const instanceCustomHomepage = {
273 content: value.instanceCustomHomepage.content
274 }
275
276 this.customConfig = { ...resConfig, instanceCustomHomepage }
259 277
260 // Reload general configuration 278 // Reload general configuration
261 this.serverService.resetConfig() 279 this.serverService.resetConfig()
280 .subscribe(config => this.serverConfig = config)
262 281
263 this.updateForm() 282 this.updateForm()
264 283
@@ -317,9 +336,12 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
317 } 336 }
318 337
319 private loadConfigAndUpdateForm () { 338 private loadConfigAndUpdateForm () {
320 this.configService.getCustomConfig() 339 forkJoin([
321 .subscribe(config => { 340 this.configService.getCustomConfig(),
322 this.customConfig = config 341 this.customPage.getInstanceHomepage()
342 ])
343 .subscribe(([ config, homepage ]) => {
344 this.customConfig = { ...config, instanceCustomHomepage: homepage }
323 345
324 this.updateForm() 346 this.updateForm()
325 // Force form validation 347 // Force form validation
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-homepage.component.html b/client/src/app/+admin/config/edit-custom-config/edit-homepage.component.html
new file mode 100644
index 000000000..c48fa5bf8
--- /dev/null
+++ b/client/src/app/+admin/config/edit-custom-config/edit-homepage.component.html
@@ -0,0 +1,28 @@
1<ng-container [formGroup]="form">
2
3 <ng-container formGroupName="instanceCustomHomepage">
4
5 <div class="form-row mt-5"> <!-- homepage grid -->
6 <div class="form-group col-12 col-lg-4 col-xl-3">
7 <div i18n class="inner-form-title">INSTANCE HOMEPAGE</div>
8 </div>
9
10 <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
11
12 <div class="form-group">
13 <label i18n for="instanceCustomHomepageContent">Homepage</label>
14
15 <my-markdown-textarea
16 name="instanceCustomHomepageContent" formControlName="content" textareaMaxWidth="90%" textareaHeight="300px"
17 [customMarkdownRenderer]="customMarkdownRenderer"
18 [classes]="{ 'input-error': formErrors['instanceCustomHomepage.content'] }"
19 ></my-markdown-textarea>
20
21 <div *ngIf="formErrors.instanceCustomHomepage.content" class="form-error">{{ formErrors.instanceCustomHomepage.content }}</div>
22 </div>
23 </div>
24 </div>
25
26 </ng-container>
27
28</ng-container>
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-homepage.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-homepage.component.ts
new file mode 100644
index 000000000..7decf8f75
--- /dev/null
+++ b/client/src/app/+admin/config/edit-custom-config/edit-homepage.component.ts
@@ -0,0 +1,25 @@
1import { Component, Input, OnInit } from '@angular/core'
2import { FormGroup } from '@angular/forms'
3import { CustomMarkupService } from '@app/shared/shared-custom-markup'
4
5@Component({
6 selector: 'my-edit-homepage',
7 templateUrl: './edit-homepage.component.html',
8 styleUrls: [ './edit-custom-config.component.scss' ]
9})
10export class EditHomepageComponent implements OnInit {
11 @Input() form: FormGroup
12 @Input() formErrors: any
13
14 customMarkdownRenderer: (text: string) => Promise<HTMLElement>
15
16 constructor (private customMarkup: CustomMarkupService) {
17
18 }
19
20 ngOnInit () {
21 this.customMarkdownRenderer = async (text: string) => {
22 return this.customMarkup.buildElement(text)
23 }
24 }
25}
diff --git a/client/src/app/+admin/config/edit-custom-config/index.ts b/client/src/app/+admin/config/edit-custom-config/index.ts
index 95fcc8f52..4281ad09b 100644
--- a/client/src/app/+admin/config/edit-custom-config/index.ts
+++ b/client/src/app/+admin/config/edit-custom-config/index.ts
@@ -2,6 +2,7 @@ export * from './edit-advanced-configuration.component'
2export * from './edit-basic-configuration.component' 2export * from './edit-basic-configuration.component'
3export * from './edit-configuration.service' 3export * from './edit-configuration.service'
4export * from './edit-custom-config.component' 4export * from './edit-custom-config.component'
5export * from './edit-homepage.component'
5export * from './edit-instance-information.component' 6export * from './edit-instance-information.component'
6export * from './edit-live-configuration.component' 7export * from './edit-live-configuration.component'
7export * from './edit-vod-transcoding.component' 8export * from './edit-vod-transcoding.component'