rephrase warning for self-hostable services
[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="Enable Signup"
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="Block 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>Allow <strong>your users</strong> to look up 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>Allow <strong>anonymous users</strong> to look up 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 global search"
487                   >
488                     <ng-container ngProjectAs="description">
489                       <p i18n>⚠️ This functionality depends heavily on the moderation of instances followed by the search index you select.</p>
490
491                       <span i18n>
492                         You should only use moderated search indexes in production, or <a href="https://framagit.org/framasoft/peertube/search-index">host your own</a>.
493                       </span>
494                     </ng-container>
495
496                     <ng-container ngProjectAs="extra">
497                       <div [ngClass]="{ 'disabled-checkbox-extra': !isSearchIndexEnabled() }">
498                         <label i18n for="searchIndexUrl">Search index URL</label>
499                         <input
500                           type="text"  id="searchIndexUrl" class="form-control"
501                           formControlName="url" [ngClass]="{ 'input-error': formErrors['search.searchIndex.url'] }"
502                         >
503                         <div *ngIf="formErrors.search.searchIndex.url" class="form-error">{{ formErrors.search.searchIndex.url }}</div>
504                       </div>
505
506                       <div class="mt-3">
507                         <my-peertube-checkbox [ngClass]="{ 'disabled-checkbox-extra': !isSearchIndexEnabled() }"
508                           inputName="searchIndexDisableLocalSearch" formControlName="disableLocalSearch"
509                           i18n-labelText labelText="Disable local search in search bar"
510                         ></my-peertube-checkbox>
511                       </div>
512
513                       <div class="mt-3">
514                         <my-peertube-checkbox [ngClass]="{ 'disabled-checkbox-extra': !isSearchIndexEnabled() }"
515                           inputName="searchIndexIsDefaultSearch" formControlName="isDefaultSearch"
516                           i18n-labelText labelText="Search bar uses the global search index by default"
517                         >
518                           <ng-container ngProjectAs="description">
519                             <span i18n>Otherwise the local search stays used by default</span>
520                           </ng-container>
521                         </my-peertube-checkbox>
522                       </div>
523
524                     </ng-container>
525                   </my-peertube-checkbox>
526                 </div>
527
528               </ng-container>
529
530             </ng-container>
531
532           </div>
533         </div>
534
535         <div class="form-row mt-4"> <!-- federation grid -->
536           <div class="form-group col-12 col-lg-4 col-xl-3">
537             <div i18n class="inner-form-title">FEDERATION</div>
538             <div i18n class="inner-form-description">
539               Manage <a routerLink="/admin/follows">relations</a> with other instances.
540             </div>
541           </div>
542
543           <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
544
545             <ng-container formGroupName="followers">
546               <ng-container formGroupName="instance">
547
548                 <div class="form-group">
549                   <my-peertube-checkbox
550                     inputName="followersInstanceEnabled" formControlName="enabled"
551                     i18n-labelText labelText="Other instances can follow yours"
552                   ></my-peertube-checkbox>
553                 </div>
554
555                 <div class="form-group">
556                   <my-peertube-checkbox
557                     inputName="followersInstanceManualApproval" formControlName="manualApproval"
558                     i18n-labelText labelText="Manually approve new instance followers"
559                   ></my-peertube-checkbox>
560                 </div>
561               </ng-container>
562             </ng-container>
563
564             <ng-container formGroupName="followings">
565               <ng-container formGroupName="instance">
566
567                 <ng-container formGroupName="autoFollowBack">
568                   <div class="form-group">
569                     <my-peertube-checkbox
570                       inputName="followingsInstanceAutoFollowBackEnabled" formControlName="enabled"
571                       i18n-labelText labelText="Automatically follow back instances"
572                     >
573                       <ng-container ngProjectAs="description">
574                         <span i18n>⚠️ This functionality requires a lot of attention and extra moderation.</span>
575                       </ng-container>
576                     </my-peertube-checkbox>
577                   </div>
578                 </ng-container>
579
580                 <ng-container formGroupName="autoFollowIndex">
581                   <div class="form-group">
582                     <my-peertube-checkbox
583                       inputName="followingsInstanceAutoFollowIndexEnabled" formControlName="enabled"
584                       i18n-labelText labelText="Automatically follow instances of a public index"
585                     >
586                       <ng-container ngProjectAs="description">
587                         <p i18n>⚠️ This functionality requires a lot of attention and extra moderation.</p>
588
589                         <span i18n>
590                           You should only follow moderated indexes in production, or <a href="https://framagit.org/framasoft/peertube/instances-peertube#peertube-auto-follow">host your own</a>.
591                         </span>
592                       </ng-container>
593
594                       <ng-container ngProjectAs="extra">
595                         <div [ngClass]="{ 'disabled-checkbox-extra': !isAutoFollowIndexEnabled() }">
596                           <label i18n for="followingsInstanceAutoFollowIndexUrl">Index URL</label>
597                           <input
598                             type="text" id="followingsInstanceAutoFollowIndexUrl" class="form-control"
599                             formControlName="indexUrl" [ngClass]="{ 'input-error': formErrors['followings.instance.autoFollowIndex.indexUrl'] }"
600                           >
601                           <div *ngIf="formErrors.followings.instance.autoFollowIndex.indexUrl" class="form-error">{{ formErrors.followings.instance.autoFollowIndex.indexUrl }}</div>
602                         </div>
603                       </ng-container>
604                     </my-peertube-checkbox>
605                   </div>
606
607                 </ng-container>
608               </ng-container>
609             </ng-container>
610
611           </div>
612         </div>
613
614         <div class="form-row mt-4"> <!-- administrators grid -->
615           <div class="form-group col-12 col-lg-4 col-xl-3">
616             <div i18n class="inner-form-title">ADMINISTRATORS</div>
617           </div>
618
619           <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
620
621             <div class="form-group" formGroupName="admin">
622               <label i18n for="adminEmail">Admin email</label>
623               <input
624                 type="text" id="adminEmail" class="form-control"
625                 formControlName="email" [ngClass]="{ 'input-error': formErrors['admin.email'] }"
626               >
627               <div *ngIf="formErrors.admin.email" class="form-error">{{ formErrors.admin.email }}</div>
628             </div>
629
630             <div class="form-group" formGroupName="contactForm">
631               <my-peertube-checkbox
632                 inputName="enableContactForm" formControlName="enabled"
633                 i18n-labelText labelText="Enable contact form"
634               ></my-peertube-checkbox>
635             </div>
636
637           </div>
638         </div>
639
640       </ng-template>
641     </ng-container>
642
643     <ng-container ngbNavItem="services">
644       <a ngbNavLink i18n>Services</a>
645
646       <ng-template ngbNavContent>
647
648         <div class="form-row mt-5"> <!-- twitter grid -->
649           <div class="form-group col-12 col-lg-4 col-xl-3">
650             <div i18n class="inner-form-title">TWITTER</div>
651             <div i18n class="inner-form-description">
652               Optional. If any, provide the Twitter account representing your instance to improve link previews.
653             </div>
654           </div>
655
656           <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
657
658             <ng-container formGroupName="services">
659               <ng-container formGroupName="twitter">
660
661                 <div class="form-group">
662                   <label i18n for="signupLimit">Your Twitter username</label>
663
664                   <input
665                     type="text" id="servicesTwitterUsername" class="form-control"
666                     formControlName="username" [ngClass]="{ 'input-error': formErrors['services.twitter.username'] }"
667                   >
668                   <div *ngIf="formErrors.services.twitter.username" class="form-error">{{ formErrors.services.twitter.username }}</div>
669                 </div>
670
671                 <div class="form-group">
672                   <my-peertube-checkbox inputName="servicesTwitterWhitelisted" formControlName="whitelisted">
673                     <ng-template ptTemplate="label">
674                       <ng-container i18n>Instance allowed by Twitter</ng-container>
675                     </ng-template>
676
677                     <ng-template ptTemplate="help">
678                       <ng-container i18n>
679                         If your instance is explicitly allowed by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br />
680                         If the instance is not, we use an image link card that will redirect on your PeerTube instance.<br /><br />
681                         Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/videos/watch/blabla) on
682                         <a target='_blank' rel='noopener noreferrer' href='https://cards-dev.twitter.com/validator'>https://cards-dev.twitter.com/validator</a>
683                         to see if you instance is allowed.
684                       </ng-container>
685                     </ng-template>
686                   </my-peertube-checkbox>
687                 </div>
688
689               </ng-container>
690             </ng-container>
691
692           </div>
693         </div>
694       </ng-template>
695     </ng-container>
696
697     <ng-container ngbNavItem="advanced-configuration">
698       <a ngbNavLink i18n>Advanced configuration</a>
699
700       <ng-template ngbNavContent>
701
702         <div class="form-row mt-5"> <!-- transcoding grid -->
703           <div class="form-group col-12 col-lg-4 col-xl-3">
704             <div i18n class="inner-form-title">TRANSCODING</div>
705             <div i18n class="inner-form-description">
706               Process uploaded videos so that they are in a streamable form that any device can play. Though costly in
707               resources, this is a critical part of PeerTube, so tread carefully.
708             </div>
709           </div>
710
711           <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
712
713             <ng-container formGroupName="transcoding">
714
715               <div class="form-group">
716                 <my-peertube-checkbox inputName="transcodingEnabled" formControlName="enabled">
717                   <ng-template ptTemplate="label">
718                     <ng-container i18n>Transcoding enabled</ng-container>
719                   </ng-template>
720
721                   <ng-template ptTemplate="help">
722                     <ng-container i18n>If you disable transcoding, many videos from your users will not work!</ng-container>
723                   </ng-template>
724
725                   <ng-container ngProjectAs="extra">
726
727                     <div class="form-group" [ngClass]="{ 'disabled-checkbox-extra': !isTranscodingEnabled() }">
728                       <my-peertube-checkbox
729                         inputName="transcodingAllowAdditionalExtensions" formControlName="allowAdditionalExtensions"
730                         i18n-labelText labelText="Allow additional extensions"
731                       >
732                         <ng-container ngProjectAs="description">
733                           <span i18n>Allows users to upload .mkv, .mov, .avi and .flv videos.</span>
734                         </ng-container>
735                       </my-peertube-checkbox>
736                     </div>
737
738                     <div class="form-group" [ngClass]="{ 'disabled-checkbox-extra': !isTranscodingEnabled() }">
739                       <my-peertube-checkbox
740                         inputName="transcodingAllowAudioFiles" formControlName="allowAudioFiles"
741                         i18n-labelText labelText="Allow audio files upload"
742                       >
743                         <ng-container ngProjectAs="description">
744                           <span i18n>Allows users to upload audio files that will be merged with the preview file on upload.</span>
745                         </ng-container>
746                       </my-peertube-checkbox>
747                     </div>
748
749                     <ng-container formGroupName="webtorrent">
750                       <div class="form-group" [ngClass]="{ 'disabled-checkbox-extra': !isTranscodingEnabled() }">
751                         <my-peertube-checkbox
752                           inputName="transcodingWebTorrentEnabled" formControlName="enabled"
753                           i18n-labelText labelText="WebTorrent support enabled"
754                         >
755                           <ng-template ptTemplate="help">
756                             <ng-container i18n>
757                               <strong>Experimental, we suggest you to not disable webtorrent support for now</strong>
758
759                               <p>If you also enabled HLS support, it will multiply videos storage by 2</p>
760
761                               <br />
762
763                               <strong>If disabled, breaks federation with PeerTube instances < 2.1</strong>
764                             </ng-container>
765                           </ng-template>
766                         </my-peertube-checkbox>
767                       </div>
768                     </ng-container>
769
770                     <ng-container formGroupName="hls">
771                       <div class="form-group" [ngClass]="{ 'disabled-checkbox-extra': !isTranscodingEnabled() }">
772                         <my-peertube-checkbox
773                           inputName="transcodingHlsEnabled" formControlName="enabled"
774                           i18n-labelText labelText="HLS support enabled"
775                         >
776                           <ng-template ptTemplate="help">
777                             <ng-container i18n>
778                               <strong>Requires ffmpeg >= 4.1</strong>
779
780                               <p>Generate HLS playlists and fragmented MP4 files resulting in a better playback than with the current default player:</p>
781                               <ul>
782                                 <li>Resolution change is smoother</li>
783                                 <li>Faster playback in particular with long videos</li>
784                                 <li>More stable playback (less bugs/infinite loading)</li>
785                               </ul>
786
787                               <p>If you also enabled WebTorrent support, it will multiply videos storage by 2</p>
788                             </ng-container>
789                           </ng-template>
790                         </my-peertube-checkbox>
791                       </div>
792                     </ng-container>
793
794                   </ng-container>
795                 </my-peertube-checkbox>
796               </div>
797
798               <div class="form-group" [ngClass]="{ 'disabled-checkbox-extra': !isTranscodingEnabled() }">
799                 <label i18n for="transcodingThreads">Transcoding threads</label>
800                 <div class="peertube-select-container">
801                   <select id="transcodingThreads" formControlName="threads" class="form-control">
802                     <option *ngFor="let transcodingThreadOption of transcodingThreadOptions" [value]="transcodingThreadOption.value">
803                       {{ transcodingThreadOption.label }}
804                     </option>
805                   </select>
806                 </div>
807                 <div *ngIf="formErrors.transcoding.threads" class="form-error">{{ formErrors.transcoding.threads }}</div>
808               </div>
809
810               <div class="form-group" [ngClass]="{ 'disabled-checkbox-extra': !isTranscodingEnabled() }">
811
812                 <label i18n for="transcodingThreads">Resolutions to generate</label>
813
814                 <div class="ml-2 mt-2 d-flex flex-column">
815                   <ng-container formGroupName="resolutions">
816                     <div class="form-group" *ngFor="let resolution of resolutions">
817                       <my-peertube-checkbox
818                         [inputName]="getResolutionKey(resolution.id)" [formControlName]="resolution.id"
819                         labelText="{{resolution.label}}"
820                       >
821                         <ng-template *ngIf="resolution.description" ptTemplate="help">
822                           <div [innerHTML]="resolution.description"></div>
823                         </ng-template>
824                       </my-peertube-checkbox>
825                     </div>
826                   </ng-container>
827                 </div>
828
829               </div>
830
831             </ng-container>
832
833           </div>
834         </div>
835
836         <div class="form-row mt-4"> <!-- cache grid -->
837           <div class="form-group col-12 col-lg-4 col-xl-3">
838             <div i18n class="inner-form-title">CACHE</div>
839             <div i18n class="inner-form-description">
840               Some files are not federated, and fetched when necessary. Define their caching policies.
841             </div>
842           </div>
843
844           <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
845
846             <ng-container formGroupName="cache">
847               <div class="form-group" formGroupName="previews">
848                 <label i18n for="cachePreviewsSize">Number of previews to keep in cache</label>
849                 <input
850                   type="number" min="0" id="cachePreviewsSize" class="form-control"
851                   formControlName="size" [ngClass]="{ 'input-error': formErrors['cache.previews.size'] }"
852                 >
853                 <div *ngIf="formErrors.cache.previews.size" class="form-error">{{ formErrors.cache.previews.size }}</div>
854               </div>
855
856               <div class="form-group" formGroupName="captions">
857                 <label i18n for="cacheCaptionsSize">Number of video captions to keep in cache</label>
858                 <input
859                   type="number" min="0" id="cacheCaptionsSize" class="form-control"
860                   formControlName="size" [ngClass]="{ 'input-error': formErrors['cache.captions.size'] }"
861                 >
862                 <div *ngIf="formErrors.cache.captions.size" class="form-error">{{ formErrors.cache.captions.size }}</div>
863               </div>
864             </ng-container>
865
866           </div>
867         </div>
868
869         <div class="form-row mt-4"> <!-- cache grid -->
870           <div class="form-group col-12 col-lg-4 col-xl-3">
871             <div class="anchor" id="customizations"></div> <!-- customizations anchor -->
872             <div i18n class="inner-form-title">CUSTOMIZATIONS</div>
873             <div i18n class="inner-form-description">
874               Slight modifications to your PeerTube instance for when creating a plugin or theme is overkill.
875             </div>
876           </div>
877
878           <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
879
880             <ng-container formGroupName="instance">
881               <ng-container formGroupName="customizations">
882                 <div class="form-group">
883                   <label i18n for="customizationJavascript">JavaScript</label>
884                   <my-help>
885                     <ng-template ptTemplate="customHtml">
886                       <ng-container i18n>
887                         Write JavaScript code directly.<br />Example: <pre>console.log('my instance is amazing');</pre>
888                       </ng-container>
889                     </ng-template>
890                   </my-help>
891
892                   <textarea
893                     id="customizationJavascript" formControlName="javascript" class="form-control"
894                     [ngClass]="{ 'input-error': formErrors['instance.customizations.javascript'] }"
895                   ></textarea>
896
897                   <div *ngIf="formErrors.instance.customizations.javascript" class="form-error">{{ formErrors.instance.customizations.javascript }}</div>
898                 </div>
899
900                 <div class="form-group">
901                   <label for="customizationCSS">CSS</label>
902
903                   <my-help>
904                     <ng-template ptTemplate="customHtml">
905                       <ng-container i18n>
906                         Write CSS code directly. Example:<br /><br />
907     <pre>
908     #custom-css {{ '{' }}
909       color: red;
910     {{ '}' }}
911     </pre>
912                         Prepend with <em>#custom-css</em> to override styles. Example:<br /><br />
913     <pre>
914     #custom-css .logged-in-email {{ '{' }}
915       color: red;
916     {{ '}' }}
917     </pre>
918                       </ng-container>
919                     </ng-template>
920                   </my-help>
921
922                   <textarea
923                     id="customizationCSS" formControlName="css" class="form-control"
924                     [ngClass]="{ 'input-error': formErrors['instance.customizations.css'] }"
925                   ></textarea>
926                   <div *ngIf="formErrors.instance.customizations.css" class="form-error">{{ formErrors.instance.customizations.css }}</div>
927                 </div>
928               </ng-container>
929             </ng-container>
930
931           </div>
932         </div>
933
934       </ng-template>
935     </ng-container>
936   </div>
937
938   <div [ngbNavOutlet]="nav"></div>
939
940   <div class="form-row mt-4"> <!-- submit placement block -->
941     <div class="col-md-7 col-xl-5"></div>
942     <div class="col-md-5 col-xl-5">
943       <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>
944
945       <input (click)="formValidated()" type="submit" i18n-value value="Update configuration" [disabled]="!form.valid">
946     </div>
947   </div>
948 </form>