First implem global search
[oweals/peertube.git] / client / src / app / +admin / config / edit-custom-config / edit-custom-config.component.html
1 <form role="form" [formGroup]="form">
2
3   <div ngbNav #nav="ngbNav" class="nav-tabs">
4
5     <ng-container ngbNavItem="instance-information">
6       <a ngbNavLink i18n>Instance information</a>
7
8       <ng-template ngbNavContent>
9
10         <ng-container formGroupName="instance">
11
12           <div class="form-row mt-5"> <!-- instance grid -->
13             <div class="form-group col-12 col-lg-4 col-xl-3">
14               <div i18n class="inner-form-title">INSTANCE</div>
15             </div>
16
17             <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
18
19               <div class="form-group">
20                 <label i18n for="instanceName">Name</label>
21                 <input
22                   type="text" id="instanceName" class="form-control"
23                   formControlName="name" [ngClass]="{ 'input-error': formErrors.instance.name }"
24                 >
25                 <div *ngIf="formErrors.instance.name" class="form-error">{{ formErrors.instance.name }}</div>
26               </div>
27
28               <div class="form-group">
29                 <label i18n for="instanceShortDescription">Short description</label>
30                 <textarea
31                   id="instanceShortDescription" formControlName="shortDescription" class="form-control small"
32                   [ngClass]="{ 'input-error': formErrors['instance.shortDescription'] }"
33                 ></textarea>
34                 <div *ngIf="formErrors.instance.shortDescription" class="form-error">{{ formErrors.instance.shortDescription }}</div>
35               </div>
36
37               <div class="form-group">
38                 <label i18n for="instanceDescription">Description</label><my-help helpType="markdownText"></my-help>
39                 <my-markdown-textarea
40                   name="instanceDescription" formControlName="description" textareaMaxWidth="500px"
41                   [classes]="{ 'input-error': formErrors['instance.description'] }"
42                 ></my-markdown-textarea>
43                 <div *ngIf="formErrors.instance.description" class="form-error">{{ formErrors.instance.description }}</div>
44               </div>
45
46               <div class="form-group">
47                 <label i18n for="instanceCategories">Main instance categories</label>
48
49                 <div>
50                   <p-multiSelect
51                     inputId="instanceCategories" [options]="categoryItems" formControlName="categories" [showToggleAll]="false"
52                     [defaultLabel]="getDefaultCategoryLabel()" [selectedItemsLabel]="getSelectedCategoryLabel()"
53                     emptyFilterMessage="No results found" i18n-emptyFilterMessage
54                   ></p-multiSelect>
55                 </div>
56               </div>
57
58               <div class="form-group">
59                 <label i18n for="instanceLanguages">Main languages you/your moderators speak</label>
60
61                 <div>
62                   <p-multiSelect
63                     inputId="instanceLanguages" [options]="languageItems" formControlName="languages" [showToggleAll]="false"
64                     [defaultLabel]="getDefaultLanguageLabel()" [selectedItemsLabel]="getSelectedLanguageLabel()"
65                     emptyFilterMessage="No results found" i18n-emptyFilterMessage
66                   ></p-multiSelect>
67                 </div>
68               </div>
69
70             </div>
71           </div>
72
73           <div class="form-row mt-4"> <!-- moderation & nsfw grid -->
74             <div class="form-group col-12 col-lg-4 col-xl-3">
75               <div i18n class="inner-form-title">MODERATION & NSFW</div>
76               <div i18n class="inner-for-description">
77                 Manage <a routerLink="/admin/users">users</a> to build a moderation team.
78               </div>
79             </div>
80
81             <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
82
83               <div class="form-group">
84                 <my-peertube-checkbox inputName="instanceIsNSFW" formControlName="isNSFW">
85                   <ng-template ptTemplate="label">
86                     <ng-container i18n>This instance is dedicated to sensitive or NSFW content</ng-container>
87                   </ng-template>
88
89                   <ng-template ptTemplate="help">
90                     <ng-container i18n>
91                       Enabling it will allow other administrators to know that you are mainly federating sensitive content.<br /><br />
92                       Moreover, the NSFW checkbox on video upload will be automatically checked by default.
93                     </ng-container>
94                   </ng-template>
95                 </my-peertube-checkbox>
96               </div>
97
98               <div class="form-group">
99                 <label i18n for="instanceDefaultNSFWPolicy">Policy on videos containing sensitive content</label>
100
101                 <my-help>
102                   <ng-template ptTemplate="customHtml">
103                     <ng-container i18n>
104                       With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video.
105                     </ng-container>
106                   </ng-template>
107                 </my-help>
108
109                 <div class="peertube-select-container">
110                   <select id="instanceDefaultNSFWPolicy" formControlName="defaultNSFWPolicy" class="form-control">
111                     <option i18n value="undefined" disabled>Policy for sensitive videos</option>
112                     <option i18n value="do_not_list">Do not list</option>
113                     <option i18n value="blur">Blur thumbnails</option>
114                     <option i18n value="display">Display</option>
115                   </select>
116                 </div>
117                 <div *ngIf="formErrors.instance.defaultNSFWPolicy" class="form-error">{{ formErrors.instance.defaultNSFWPolicy }}</div>
118               </div>
119
120               <div class="form-group">
121                 <label i18n for="instanceTerms">Terms</label><my-help helpType="markdownText"></my-help>
122                 <my-markdown-textarea
123                   name="instanceTerms" formControlName="terms" textareaMaxWidth="500px"
124                   [ngClass]="{ 'input-error': formErrors['instance.terms'] }"
125                 ></my-markdown-textarea>
126                 <div *ngIf="formErrors.instance.terms" class="form-error">{{ formErrors.instance.terms }}</div>
127               </div>
128
129               <div class="form-group">
130                 <label i18n for="instanceCodeOfConduct">Code of conduct</label><my-help helpType="markdownText"></my-help>
131                 <my-markdown-textarea
132                   name="instanceCodeOfConduct" formControlName="codeOfConduct" textareaMaxWidth="500px"
133                   [ngClass]="{ 'input-error': formErrors['instance.codeOfConduct'] }"
134                 ></my-markdown-textarea>
135                 <div *ngIf="formErrors.instance.codeOfConduct" class="form-error">{{ formErrors.instance.codeOfConduct }}</div>
136               </div>
137
138               <div class="form-group">
139                 <label i18n for="instanceModerationInformation">Moderation information</label><my-help helpType="markdownText"></my-help>
140                 <div i18n class="label-small-info">Who moderates the instance? What is the policy regarding NSFW videos? Political videos? etc</div>
141
142                 <my-markdown-textarea
143                   name="instanceModerationInformation" formControlName="moderationInformation" textareaMaxWidth="500px"
144                   [ngClass]="{ 'input-error': formErrors['instance.moderationInformation'] }"
145                 ></my-markdown-textarea>
146                 <div *ngIf="formErrors.instance.moderationInformation" class="form-error">{{ formErrors.instance.moderationInformation }}</div>
147               </div>
148
149             </div>
150           </div>
151
152           <div class="form-row mt-4"> <!-- you and your instance grid -->
153             <div class="form-group col-12 col-lg-4 col-xl-3">
154               <div i18n class="inner-form-title">YOU AND YOUR INSTANCE</div>
155             </div>
156
157             <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
158
159               <div class="form-group">
160                 <label i18n for="instanceAdministrator">Who is behind the instance?</label>
161                 <div i18n class="label-small-info">A single person? A non-profit? A company?</div>
162
163                 <my-markdown-textarea
164                   name="instanceAdministrator" formControlName="administrator" textareaMaxWidth="500px" textareaHeight="75px"
165                   [classes]="{ 'input-error': formErrors['instance.administrator'] }"
166                 ></my-markdown-textarea>
167
168                 <div *ngIf="formErrors.instance.administrator" class="form-error">{{ formErrors.instance.administrator }}</div>
169               </div>
170
171               <div class="form-group">
172                 <label i18n for="instanceCreationReason">Why did you create this instance?</label>
173                 <div i18n class="label-small-info">To share your personal videos? To open registrations and allow people to upload what they want?</div>
174
175                 <textarea
176                   id="instanceCreationReason" formControlName="creationReason" class="small" class="form-control"
177                   [ngClass]="{ 'input-error': formErrors['instance.creationReason'] }"
178                 ></textarea>
179                 <div *ngIf="formErrors.instance.creationReason" class="form-error">{{ formErrors.instance.creationReason }}</div>
180               </div>
181
182               <div class="form-group">
183                 <label i18n for="instanceMaintenanceLifetime">How long do you plan to maintain this instance?</label>
184                 <div i18n class="label-small-info">It's important to know for users who want to register on your instance</div>
185
186                 <textarea
187                   id="instanceMaintenanceLifetime" formControlName="maintenanceLifetime" class="form-control small"
188                   [ngClass]="{ 'input-error': formErrors['instance.maintenanceLifetime'] }"
189                 ></textarea>
190                 <div *ngIf="formErrors.instance.maintenanceLifetime" class="form-error">{{ formErrors.instance.maintenanceLifetime }}</div>
191               </div>
192
193               <div class="form-group">
194                 <label i18n for="instanceBusinessModel">How will you finance the PeerTube server?</label>
195                 <div i18n class="label-small-info">With your own funds? With user donations? Advertising?</div>
196
197                 <textarea
198                   id="instanceBusinessModel" formControlName="businessModel" class="form-control small"
199                   [ngClass]="{ 'input-error': formErrors['instance.businessModel'] }"
200                 ></textarea>
201                 <div *ngIf="formErrors.instance.businessModel" class="form-error">{{ formErrors.instance.businessModel }}</div>
202               </div>
203
204             </div>
205           </div>
206
207           <div class="form-row mt-4"> <!-- other information grid -->
208             <div class="form-group col-12 col-lg-4 col-xl-3">
209               <div i18n class="inner-form-title">OTHER INFORMATION</div>
210             </div>
211
212             <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
213
214               <div class="form-group">
215                 <label i18n for="instanceHardwareInformation">What server/hardware does the instance run on?</label>
216                 <div i18n class="label-small-info">i.e. 2vCore 2GB RAM, a direct the link to the server you rent, etc.</div>
217
218                 <my-markdown-textarea
219                   name="instanceHardwareInformation" formControlName="hardwareInformation" textareaMaxWidth="500px" textareaHeight="75px"
220                   [classes]="{ 'input-error': formErrors['instance.hardwareInformation'] }"
221                 ></my-markdown-textarea>
222
223                 <div *ngIf="formErrors.instance.hardwareInformation" class="form-error">{{ formErrors.instance.hardwareInformation }}</div>
224               </div>
225
226             </div>
227           </div>
228
229         </ng-container>
230       </ng-template>
231     </ng-container>
232
233     <ng-container ngbNavItem="basic-configuration">
234       <a ngbNavLink i18n>Basic configuration</a>
235
236       <ng-template ngbNavContent>
237
238         <div class="form-row mt-5"> <!-- appearance grid -->
239           <div class="form-group col-12 col-lg-4 col-xl-3">
240             <div i18n class="inner-form-title">APPEARANCE</div>
241             <div i18n class="inner-for-description">
242               Use <a routerLink="/admin/plugins">plugins & themes</a> for more involved changes, or <a routerLink="/admin/config/edit-custom" fragment="customizations" (click)="gotoAnchor()">add slight customizations</a>.
243             </div>
244           </div>
245
246           <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
247
248             <ng-container formGroupName="theme">
249               <div class="form-group">
250                 <label i18n for="themeDefault">Theme</label>
251
252                 <div class="peertube-select-container">
253                   <select formControlName="default" id="themeDefault" class="form-control">
254                     <option i18n value="default">default</option>
255
256                     <option *ngFor="let theme of availableThemes" [value]="theme">{{ theme }}</option>
257                   </select>
258                 </div>
259               </div>
260             </ng-container>
261
262             <div class="form-group" formGroupName="instance">
263               <label i18n for="instanceDefaultClientRoute">Landing page</label>
264               <div class="peertube-select-container">
265                 <select id="instanceDefaultClientRoute" formControlName="defaultClientRoute" class="form-control">
266                   <option i18n value="/videos/overview">Discover videos</option>
267                   <option i18n value="/videos/trending">Trending videos</option>
268                   <option i18n value="/videos/most-liked">Most liked videos</option>
269                   <option i18n value="/videos/recently-added">Recently added videos</option>
270                   <option i18n value="/videos/local">Local videos</option>
271                 </select>
272               </div>
273               <div *ngIf="formErrors.instance.defaultClientRoute" class="form-error">{{ formErrors.instance.defaultClientRoute }}</div>
274             </div>
275
276           </div>
277         </div>
278
279         <div class="form-row mt-4"> <!-- broadcast grid -->
280           <div class="form-group col-12 col-lg-4 col-xl-3">
281             <div i18n class="inner-form-title">BROADCAST MESSAGE</div>
282             <div i18n class="inner-for-description">
283               Display a message on your instance
284             </div>
285           </div>
286
287           <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
288
289             <ng-container formGroupName="broadcastMessage">
290
291               <div class="form-group">
292                 <my-peertube-checkbox
293                   inputName="broadcastMessageEnabled" formControlName="enabled"
294                   i18n-labelText labelText="Enable broadcast message"
295                 ></my-peertube-checkbox>
296               </div>
297
298               <div class="form-group">
299                 <my-peertube-checkbox
300                   inputName="broadcastMessageDismissable" formControlName="dismissable"
301                   i18n-labelText labelText="Allow users to dismiss the broadcast message "
302                 ></my-peertube-checkbox>
303               </div>
304
305               <div class="form-group">
306                 <label i18n for="broadcastMessageLevel">Broadcast message level</label>
307                 <div class="peertube-select-container">
308                   <select id="broadcastMessageLevel" formControlName="level" class="form-control">
309                     <option value="info">info</option>
310                     <option value="warning">warning</option>
311                     <option value="error">error</option>
312                   </select>
313                 </div>
314                 <div *ngIf="formErrors.broadcastMessage.level" class="form-error">{{ formErrors.broadcastMessage.level }}</div>
315               </div>
316
317               <div class="form-group">
318                 <label i18n for="broadcastMessageMessage">Message</label><my-help helpType="markdownText"></my-help>
319                 <my-markdown-textarea
320                   name="broadcastMessageMessage" formControlName="message" textareaMaxWidth="500px"
321                   [classes]="{ 'input-error': formErrors['broadcastMessage.message'] }"
322                 ></my-markdown-textarea>
323                 <div *ngIf="formErrors.broadcastMessage.message" class="form-error">{{ formErrors.broadcastMessage.message }}</div>
324               </div>
325
326             </ng-container>
327
328           </div>
329         </div>
330
331         <div class="form-row mt-4"> <!-- new users grid -->
332           <div class="form-group col-12 col-lg-4 col-xl-3">
333             <div i18n class="inner-form-title">NEW USERS</div>
334             <div i18n class="inner-for-description">
335               Manage <a routerLink="/admin/users">users</a> to set their quota individually.
336             </div>
337           </div>
338
339           <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
340
341             <ng-container formGroupName="signup">
342               <div class="form-group">
343                 <my-peertube-checkbox
344                   inputName="signupEnabled" formControlName="enabled"
345                   i18n-labelText labelText="Signup enabled"
346                 >
347                   <ng-container ngProjectAs="description">
348                     <span i18n>⚠️ This functionality requires a lot of attention and extra moderation.</span>
349                   </ng-container>
350                   <ng-container ngProjectAs="extra">
351                     <my-peertube-checkbox [ngClass]="{ 'disabled-checkbox-extra': !isSignupEnabled() }"
352                       inputName="signupRequiresEmailVerification" formControlName="requiresEmailVerification"
353                       i18n-labelText labelText="Signup requires email verification"
354                     ></my-peertube-checkbox>
355
356                     <div [ngClass]="{ 'disabled-checkbox-extra': !isSignupEnabled() }" class="mt-3">
357                       <label i18n for="signupLimit">Signup limit</label>
358                       <input
359                         type="number" min="-1" id="signupLimit" class="form-control"
360                         formControlName="limit" [ngClass]="{ 'input-error': formErrors['signup.limit'] }"
361                       >
362                       <div *ngIf="formErrors.signup.limit" class="form-error">{{ formErrors.signup.limit }}</div>
363                       <small *ngIf="form.value['signup']['limit'] === -1" class="text-muted">Signup won't be limited to a fixed number of users.</small>
364                     </div>
365                   </ng-container>
366                 </my-peertube-checkbox>
367               </div>
368             </ng-container>
369
370             <ng-container formGroupName="user">
371               <div class="form-group">
372                 <label i18n for="userVideoQuota">Default video quota per user</label>
373                 <div class="peertube-select-container">
374                   <select id="userVideoQuota" formControlName="videoQuota" class="form-control">
375                     <option *ngFor="let videoQuotaOption of videoQuotaOptions" [value]="videoQuotaOption.value" [disabled]="videoQuotaOption.disabled">
376                       {{ videoQuotaOption.label }}
377                     </option>
378                   </select>
379                 </div>
380                 <div *ngIf="formErrors.user.videoQuota" class="form-error">{{ formErrors.user.videoQuota }}</div>
381               </div>
382
383               <div class="form-group">
384                 <label i18n for="userVideoQuotaDaily">Default daily upload limit per user</label>
385                 <div class="peertube-select-container">
386                   <select id="userVideoQuotaDaily" formControlName="videoQuotaDaily" class="form-control">
387                     <option *ngFor="let videoQuotaDailyOption of videoQuotaDailyOptions" [value]="videoQuotaDailyOption.value" [disabled]="videoQuotaDailyOption.disabled">
388                       {{ videoQuotaDailyOption.label }}
389                     </option>
390                   </select>
391                 </div>
392                 <div *ngIf="formErrors.user.videoQuotaDaily" class="form-error">{{ formErrors.user.videoQuotaDaily }}</div>
393               </div>
394             </ng-container>
395
396           </div>
397         </div>
398
399         <div class="form-row mt-4"> <!-- videos grid -->
400           <div class="form-group col-12 col-lg-4 col-xl-3">
401             <div i18n class="inner-form-title">VIDEOS</div>
402           </div>
403
404           <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
405
406             <ng-container formGroupName="import">
407               <ng-container formGroupName="videos">
408
409                 <div class="form-group" formGroupName="http">
410                   <my-peertube-checkbox
411                     inputName="importVideosHttpEnabled" formControlName="enabled"
412                     i18n-labelText labelText="Allow import with HTTP URL (i.e. YouTube)"
413                   ></my-peertube-checkbox>
414                 </div>
415
416                 <div class="form-group" formGroupName="torrent">
417                   <my-peertube-checkbox
418                     inputName="importVideosTorrentEnabled" formControlName="enabled"
419                     i18n-labelText labelText="Allow import with a torrent file or a magnet URI"
420                   ></my-peertube-checkbox>
421                 </div>
422
423               </ng-container>
424             </ng-container>
425
426             <ng-container formGroupName="autoBlacklist">
427               <ng-container formGroupName="videos">
428                 <ng-container formGroupName="ofUsers">
429
430                   <div class="form-group">
431                     <my-peertube-checkbox
432                       inputName="autoBlacklistVideosOfUsersEnabled" formControlName="enabled"
433                       i18n-labelText labelText="Blacklist new videos automatically"
434                     >
435                     <ng-container ngProjectAs="description">
436                       <span i18n>Unless a user is marked as trusted, their videos will stay private until a moderator reviews them.</span>
437                     </ng-container>
438                   </my-peertube-checkbox>
439                   </div>
440
441                 </ng-container>
442               </ng-container>
443             </ng-container>
444
445           </div>
446         </div>
447
448         <div class="form-row mt-4"> <!-- search grid -->
449           <div class="form-group col-12 col-lg-4 col-xl-3">
450             <div i18n class="inner-form-title">SEARCH</div>
451           </div>
452
453           <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
454
455             <ng-container formGroupName="search">
456               <ng-container formGroupName="remoteUri">
457
458                 <div class="form-group">
459                   <my-peertube-checkbox
460                     inputName="searchRemoteUriUsers" formControlName="users"
461                     i18n-labelText labelText="Allow users to do remote URI/handle search"
462                   >
463                     <ng-container ngProjectAs="description">
464                       <span i18n>Add ability for <strong>your users</strong> to fetch remote videos/actors by their URI, that may not be federated with your instance</span>
465                     </ng-container>
466                   </my-peertube-checkbox>
467                 </div>
468
469                 <div class="form-group">
470                   <my-peertube-checkbox
471                     inputName="searchRemoteUriAnonymous" formControlName="anonymous"
472                     i18n-labelText labelText="Allow anonymous to do remote URI/handle search"
473                   >
474                     <ng-container ngProjectAs="description">
475                       <span i18n>Add ability for <strong>anonymous</strong> to fetch remote videos/actors by their URI, that may not be federated with your instance</span>
476                     </ng-container>
477                   </my-peertube-checkbox>
478                 </div>
479
480               </ng-container>
481
482               <ng-container formGroupName="searchIndex">
483                 <div class="form-group">
484                   <my-peertube-checkbox
485                     inputName="searchIndexEnabled" formControlName="enabled"
486                     i18n-labelText labelText="Enable search index"
487                   >
488
489                   <ng-container ngProjectAs="extra">
490                     <div [ngClass]="{ 'disabled-checkbox-extra': !isSearchIndexEnabled() }">
491                       <label i18n for="searchIndexUrl">Search index URL</label>
492                       <input
493                         type="text"  id="searchIndexUrl" class="form-control"
494                         formControlName="url" [ngClass]="{ 'input-error': formErrors['search.searchIndex.url'] }"
495                       >
496                       <div *ngIf="formErrors.search.searchIndex.url" class="form-error">{{ formErrors.search.searchIndex.url }}</div>
497                     </div>
498
499                     <div class="mt-3">
500                       <my-peertube-checkbox [ngClass]="{ 'disabled-checkbox-extra': !isSearchIndexEnabled() }"
501                         inputName="searchIndexDisableLocalSearch" formControlName="disableLocalSearch"
502                         i18n-labelText labelText="Disable local search"
503                       ></my-peertube-checkbox>
504                     </div>
505
506                     <div class="mt-3">
507                       <my-peertube-checkbox [ngClass]="{ 'disabled-checkbox-extra': !isSearchIndexEnabled() }"
508                         inputName="searchIndexIsDefaultSearch" formControlName="isDefaultSearch"
509                         i18n-labelText labelText="Set search index as default"
510                       >
511                         <ng-container ngProjectAs="description">
512                           <span i18n>The local search is used by default</span>
513                         </ng-container>
514                       </my-peertube-checkbox>
515                     </div>
516
517                   </ng-container>
518                 </my-peertube-checkbox>
519                 </div>
520
521               </ng-container>
522
523             </ng-container>
524
525           </div>
526         </div>
527
528         <div class="form-row mt-4"> <!-- federation grid -->
529           <div class="form-group col-12 col-lg-4 col-xl-3">
530             <div i18n class="inner-form-title">FEDERATION</div>
531             <div i18n class="inner-form-description">
532               Manage <a routerLink="/admin/follows">relations</a> with other instances.
533             </div>
534           </div>
535
536           <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
537
538             <ng-container formGroupName="followers">
539               <ng-container formGroupName="instance">
540
541                 <div class="form-group">
542                   <my-peertube-checkbox
543                     inputName="followersInstanceEnabled" formControlName="enabled"
544                     i18n-labelText labelText="Other instances can follow yours"
545                   ></my-peertube-checkbox>
546                 </div>
547
548                 <div class="form-group">
549                   <my-peertube-checkbox
550                     inputName="followersInstanceManualApproval" formControlName="manualApproval"
551                     i18n-labelText labelText="Manually approve new instance followers"
552                   ></my-peertube-checkbox>
553                 </div>
554               </ng-container>
555             </ng-container>
556
557             <ng-container formGroupName="followings">
558               <ng-container formGroupName="instance">
559
560                 <ng-container formGroupName="autoFollowBack">
561                   <div class="form-group">
562                     <my-peertube-checkbox
563                       inputName="followingsInstanceAutoFollowBackEnabled" formControlName="enabled"
564                       i18n-labelText labelText="Automatically follow back instances"
565                     >
566                       <ng-container ngProjectAs="description">
567                         <span i18n>⚠️ This functionality requires a lot of attention and extra moderation.</span>
568                       </ng-container>
569                     </my-peertube-checkbox>
570                   </div>
571                 </ng-container>
572
573                 <ng-container formGroupName="autoFollowIndex">
574                   <div class="form-group">
575                     <my-peertube-checkbox
576                       inputName="followingsInstanceAutoFollowIndexEnabled" formControlName="enabled"
577                       i18n-labelText labelText="Automatically follow instances of a public index"
578                     >
579                       <ng-container ngProjectAs="description">
580                         <p i18n>⚠️ This functionality requires a lot of attention and extra moderation.</p>
581
582                         <span i18n>
583                           You should only follow indexes you trust, or <a href="https://framagit.org/framasoft/peertube/instances-peertube#peertube-auto-follow">host your own</a>.
584                         </span>
585                       </ng-container>
586
587                       <ng-container ngProjectAs="extra">
588                         <div [ngClass]="{ 'disabled-checkbox-extra': !isAutoFollowIndexEnabled() }">
589                           <label i18n for="followingsInstanceAutoFollowIndexUrl">Index URL</label>
590                           <input
591                             type="text" id="followingsInstanceAutoFollowIndexUrl" class="form-control"
592                             formControlName="indexUrl" [ngClass]="{ 'input-error': formErrors['followings.instance.autoFollowIndex.indexUrl'] }"
593                           >
594                           <div *ngIf="formErrors.followings.instance.autoFollowIndex.indexUrl" class="form-error">{{ formErrors.followings.instance.autoFollowIndex.indexUrl }}</div>
595                         </div>
596                       </ng-container>
597                     </my-peertube-checkbox>
598                   </div>
599
600                 </ng-container>
601               </ng-container>
602             </ng-container>
603
604           </div>
605         </div>
606
607         <div class="form-row mt-4"> <!-- administrators grid -->
608           <div class="form-group col-12 col-lg-4 col-xl-3">
609             <div i18n class="inner-form-title">ADMINISTRATORS</div>
610           </div>
611
612           <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
613
614             <div class="form-group" formGroupName="admin">
615               <label i18n for="adminEmail">Admin email</label>
616               <input
617                 type="text" id="adminEmail" class="form-control"
618                 formControlName="email" [ngClass]="{ 'input-error': formErrors['admin.email'] }"
619               >
620               <div *ngIf="formErrors.admin.email" class="form-error">{{ formErrors.admin.email }}</div>
621             </div>
622
623             <div class="form-group" formGroupName="contactForm">
624               <my-peertube-checkbox
625                 inputName="enableContactForm" formControlName="enabled"
626                 i18n-labelText labelText="Enable contact form"
627               ></my-peertube-checkbox>
628             </div>
629
630           </div>
631         </div>
632
633       </ng-template>
634     </ng-container>
635
636     <ng-container ngbNavItem="services">
637       <a ngbNavLink i18n>Services</a>
638
639       <ng-template ngbNavContent>
640
641         <div class="form-row mt-5"> <!-- twitter grid -->
642           <div class="form-group col-12 col-lg-4 col-xl-3">
643             <div i18n class="inner-form-title">TWITTER</div>
644             <div i18n class="inner-form-description">
645               Optional. If any, provide the Twitter account representing your instance to improve link previews.
646             </div>
647           </div>
648
649           <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
650
651             <ng-container formGroupName="services">
652               <ng-container formGroupName="twitter">
653
654                 <div class="form-group">
655                   <label i18n for="signupLimit">Your Twitter username</label>
656
657                   <input
658                     type="text" id="servicesTwitterUsername" class="form-control"
659                     formControlName="username" [ngClass]="{ 'input-error': formErrors['services.twitter.username'] }"
660                   >
661                   <div *ngIf="formErrors.services.twitter.username" class="form-error">{{ formErrors.services.twitter.username }}</div>
662                 </div>
663
664                 <div class="form-group">
665                   <my-peertube-checkbox inputName="servicesTwitterWhitelisted" formControlName="whitelisted">
666                     <ng-template ptTemplate="label">
667                       <ng-container i18n>Instance whitelisted by Twitter</ng-container>
668                     </ng-template>
669
670                     <ng-template ptTemplate="help">
671                       <ng-container i18n>
672                         If your instance is whitelisted by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br />
673                         If the instance is not whitelisted, we use an image link card that will redirect on your PeerTube instance.<br /><br />
674                         Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/videos/watch/blabla) on
675                         <a target='_blank' rel='noopener noreferrer' href='https://cards-dev.twitter.com/validator'>https://cards-dev.twitter.com/validator</a>
676                         to see if you instance is whitelisted.
677                       </ng-container>
678                     </ng-template>
679                   </my-peertube-checkbox>
680                 </div>
681
682               </ng-container>
683             </ng-container>
684
685           </div>
686         </div>
687       </ng-template>
688     </ng-container>
689
690     <ng-container ngbNavItem="advanced-configuration">
691       <a ngbNavLink i18n>Advanced configuration</a>
692
693       <ng-template ngbNavContent>
694
695         <div class="form-row mt-5"> <!-- transcoding grid -->
696           <div class="form-group col-12 col-lg-4 col-xl-3">
697             <div i18n class="inner-form-title">TRANSCODING</div>
698             <div i18n class="inner-form-description">
699               Process uploaded videos so that they are in a streamable form that any device can play. Though costly in
700               resources, this is a critical part of PeerTube, so tread carefully.
701             </div>
702           </div>
703
704           <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
705
706             <ng-container formGroupName="transcoding">
707
708               <div class="form-group">
709                 <my-peertube-checkbox inputName="transcodingEnabled" formControlName="enabled">
710                   <ng-template ptTemplate="label">
711                     <ng-container i18n>Transcoding enabled</ng-container>
712                   </ng-template>
713
714                   <ng-template ptTemplate="help">
715                     <ng-container i18n>If you disable transcoding, many videos from your users will not work!</ng-container>
716                   </ng-template>
717
718                   <ng-container ngProjectAs="extra">
719
720                     <div class="form-group" [ngClass]="{ 'disabled-checkbox-extra': !isTranscodingEnabled() }">
721                       <my-peertube-checkbox
722                         inputName="transcodingAllowAdditionalExtensions" formControlName="allowAdditionalExtensions"
723                         i18n-labelText labelText="Allow additional extensions"
724                       >
725                         <ng-container ngProjectAs="description">
726                           <span i18n>Allows users to upload .mkv, .mov, .avi and .flv videos.</span>
727                         </ng-container>
728                       </my-peertube-checkbox>
729                     </div>
730
731                     <div class="form-group" [ngClass]="{ 'disabled-checkbox-extra': !isTranscodingEnabled() }">
732                       <my-peertube-checkbox
733                         inputName="transcodingAllowAudioFiles" formControlName="allowAudioFiles"
734                         i18n-labelText labelText="Allow audio files upload"
735                       >
736                         <ng-container ngProjectAs="description">
737                           <span i18n>Allows users to upload audio files that will be merged with the preview file on upload.</span>
738                         </ng-container>
739                       </my-peertube-checkbox>
740                     </div>
741
742                     <ng-container formGroupName="webtorrent">
743                       <div class="form-group" [ngClass]="{ 'disabled-checkbox-extra': !isTranscodingEnabled() }">
744                         <my-peertube-checkbox
745                           inputName="transcodingWebTorrentEnabled" formControlName="enabled"
746                           i18n-labelText labelText="WebTorrent support enabled"
747                         >
748                           <ng-template ptTemplate="help">
749                             <ng-container i18n>
750                               <strong>Experimental, we suggest you to not disable webtorrent support for now</strong>
751
752                               <p>If you also enabled HLS support, it will multiply videos storage by 2</p>
753
754                               <br />
755
756                               <strong>If disabled, breaks federation with PeerTube instances < 2.1</strong>
757                             </ng-container>
758                           </ng-template>
759                         </my-peertube-checkbox>
760                       </div>
761                     </ng-container>
762
763                     <ng-container formGroupName="hls">
764                       <div class="form-group" [ngClass]="{ 'disabled-checkbox-extra': !isTranscodingEnabled() }">
765                         <my-peertube-checkbox
766                           inputName="transcodingHlsEnabled" formControlName="enabled"
767                           i18n-labelText labelText="HLS support enabled"
768                         >
769                           <ng-template ptTemplate="help">
770                             <ng-container i18n>
771                               <strong>Requires ffmpeg >= 4.1</strong>
772
773                               <p>Generate HLS playlists and fragmented MP4 files resulting in a better playback than with the current default player:</p>
774                               <ul>
775                                 <li>Resolution change is smoother</li>
776                                 <li>Faster playback in particular with long videos</li>
777                                 <li>More stable playback (less bugs/infinite loading)</li>
778                               </ul>
779
780                               <p>If you also enabled WebTorrent support, it will multiply videos storage by 2</p>
781                             </ng-container>
782                           </ng-template>
783                         </my-peertube-checkbox>
784                       </div>
785                     </ng-container>
786
787                   </ng-container>
788                 </my-peertube-checkbox>
789               </div>
790
791               <div class="form-group" [ngClass]="{ 'disabled-checkbox-extra': !isTranscodingEnabled() }">
792                 <label i18n for="transcodingThreads">Transcoding threads</label>
793                 <div class="peertube-select-container">
794                   <select id="transcodingThreads" formControlName="threads" class="form-control">
795                     <option *ngFor="let transcodingThreadOption of transcodingThreadOptions" [value]="transcodingThreadOption.value">
796                       {{ transcodingThreadOption.label }}
797                     </option>
798                   </select>
799                 </div>
800                 <div *ngIf="formErrors.transcoding.threads" class="form-error">{{ formErrors.transcoding.threads }}</div>
801               </div>
802
803               <div class="form-group" [ngClass]="{ 'disabled-checkbox-extra': !isTranscodingEnabled() }">
804
805                 <label i18n for="transcodingThreads">Resolutions to generate</label>
806
807                 <div class="ml-2 mt-2 d-flex flex-column">
808                   <ng-container formGroupName="resolutions">
809                     <div class="form-group" *ngFor="let resolution of resolutions">
810                       <my-peertube-checkbox
811                         [inputName]="getResolutionKey(resolution.id)" [formControlName]="resolution.id"
812                         labelText="{{resolution.label}}"
813                       >
814                         <ng-template *ngIf="resolution.description" ptTemplate="help">
815                           <div [innerHTML]="resolution.description"></div>
816                         </ng-template>
817                       </my-peertube-checkbox>
818                     </div>
819                   </ng-container>
820                 </div>
821
822               </div>
823
824             </ng-container>
825
826           </div>
827         </div>
828
829         <div class="form-row mt-4"> <!-- cache grid -->
830           <div class="form-group col-12 col-lg-4 col-xl-3">
831             <div i18n class="inner-form-title">CACHE</div>
832             <div i18n class="inner-form-description">
833               Some files are not federated, and fetched when necessary. Define their caching policies.
834             </div>
835           </div>
836
837           <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
838
839             <ng-container formGroupName="cache">
840               <div class="form-group" formGroupName="previews">
841                 <label i18n for="cachePreviewsSize">Number of previews to keep in cache</label>
842                 <input
843                   type="number" min="0" id="cachePreviewsSize" class="form-control"
844                   formControlName="size" [ngClass]="{ 'input-error': formErrors['cache.previews.size'] }"
845                 >
846                 <div *ngIf="formErrors.cache.previews.size" class="form-error">{{ formErrors.cache.previews.size }}</div>
847               </div>
848
849               <div class="form-group" formGroupName="captions">
850                 <label i18n for="cacheCaptionsSize">Number of video captions to keep in cache</label>
851                 <input
852                   type="number" min="0" id="cacheCaptionsSize" class="form-control"
853                   formControlName="size" [ngClass]="{ 'input-error': formErrors['cache.captions.size'] }"
854                 >
855                 <div *ngIf="formErrors.cache.captions.size" class="form-error">{{ formErrors.cache.captions.size }}</div>
856               </div>
857             </ng-container>
858
859           </div>
860         </div>
861
862         <div class="form-row mt-4"> <!-- cache grid -->
863           <div class="form-group col-12 col-lg-4 col-xl-3">
864             <div class="anchor" id="customizations"></div> <!-- customizations anchor -->
865             <div i18n class="inner-form-title">CUSTOMIZATIONS</div>
866             <div i18n class="inner-form-description">
867               Slight modifications to your PeerTube instance for when creating a plugin or theme is overkill.
868             </div>
869           </div>
870
871           <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
872
873             <ng-container formGroupName="instance">
874               <ng-container formGroupName="customizations">
875                 <div class="form-group">
876                   <label i18n for="customizationJavascript">JavaScript</label>
877                   <my-help>
878                     <ng-template ptTemplate="customHtml">
879                       <ng-container i18n>
880                         Write JavaScript code directly.<br />Example: <pre>console.log('my instance is amazing');</pre>
881                       </ng-container>
882                     </ng-template>
883                   </my-help>
884
885                   <textarea
886                     id="customizationJavascript" formControlName="javascript" class="form-control"
887                     [ngClass]="{ 'input-error': formErrors['instance.customizations.javascript'] }"
888                   ></textarea>
889
890                   <div *ngIf="formErrors.instance.customizations.javascript" class="form-error">{{ formErrors.instance.customizations.javascript }}</div>
891                 </div>
892
893                 <div class="form-group">
894                   <label for="customizationCSS">CSS</label>
895
896                   <my-help>
897                     <ng-template ptTemplate="customHtml">
898                       <ng-container i18n>
899                         Write CSS code directly. Example:<br /><br />
900     <pre>
901     #custom-css {{ '{' }}
902       color: red;
903     {{ '}' }}
904     </pre>
905                         Prepend with <em>#custom-css</em> to override styles. Example:<br /><br />
906     <pre>
907     #custom-css .logged-in-email {{ '{' }}
908       color: red;
909     {{ '}' }}
910     </pre>
911                       </ng-container>
912                     </ng-template>
913                   </my-help>
914
915                   <textarea
916                     id="customizationCSS" formControlName="css" class="form-control"
917                     [ngClass]="{ 'input-error': formErrors['instance.customizations.css'] }"
918                   ></textarea>
919                   <div *ngIf="formErrors.instance.customizations.css" class="form-error">{{ formErrors.instance.customizations.css }}</div>
920                 </div>
921               </ng-container>
922             </ng-container>
923
924           </div>
925         </div>
926
927       </ng-template>
928     </ng-container>
929   </div>
930
931   <div [ngbNavOutlet]="nav"></div>
932
933   <div class="form-row mt-4"> <!-- submit placement block -->
934     <div class="col-md-7 col-xl-5"></div>
935     <div class="col-md-5 col-xl-5">
936       <span class="form-error submit-error" i18n *ngIf="!form.valid">It seems like the configuration is invalid. Please search for potential errors in the different tabs.</span>
937
938       <input (click)="formValidated()" type="submit" i18n-value value="Update configuration" [disabled]="!form.valid">
939     </div>
940   </div>
941 </form>