Add contact form checkbox in admin form
This commit is contained in:
parent
a4101923e6
commit
3866f1a02f
|
@ -7,169 +7,169 @@
|
|||
|
||||
<div i18n class="inner-form-title">Instance</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceName">Name</label>
|
||||
<input
|
||||
type="text" id="instanceName"
|
||||
formControlName="instanceName" [ngClass]="{ 'input-error': formErrors['instanceName'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.instanceName" class="form-error">
|
||||
{{ formErrors.instanceName }}
|
||||
<ng-container formGroupName="instance">
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceName">Name</label>
|
||||
<input
|
||||
type="text" id="instanceName"
|
||||
formControlName="name" [ngClass]="{ 'input-error': formErrors.instance.name }"
|
||||
>
|
||||
<div *ngIf="formErrors.instance.name" class="form-error">{{ formErrors.instance.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceShortDescription">Short description</label>
|
||||
<textarea
|
||||
id="instanceShortDescription" formControlName="instanceShortDescription"
|
||||
[ngClass]="{ 'input-error': formErrors['instanceShortDescription'] }"
|
||||
></textarea>
|
||||
<div *ngIf="formErrors.instanceShortDescription" class="form-error">
|
||||
{{ formErrors.instanceShortDescription }}
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceShortDescription">Short description</label>
|
||||
<textarea
|
||||
id="instanceShortDescription" formControlName="shortDescription"
|
||||
[ngClass]="{ 'input-error': formErrors['instance.shortDescription'] }"
|
||||
></textarea>
|
||||
<div *ngIf="formErrors.instance.shortDescription" class="form-error">{{ formErrors.instance.shortDescription }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceDescription">Description</label><my-help helpType="markdownText"></my-help>
|
||||
<my-markdown-textarea
|
||||
id="instanceDescription" formControlName="instanceDescription" textareaWidth="500px" [previewColumn]="true"
|
||||
[classes]="{ 'input-error': formErrors['instanceDescription'] }"
|
||||
></my-markdown-textarea>
|
||||
<div *ngIf="formErrors.instanceDescription" class="form-error">
|
||||
{{ formErrors.instanceDescription }}
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceDescription">Description</label><my-help helpType="markdownText"></my-help>
|
||||
<my-markdown-textarea
|
||||
id="instanceDescription" formControlName="description" textareaWidth="500px" [previewColumn]="true"
|
||||
[classes]="{ 'input-error': formErrors['instance.description'] }"
|
||||
></my-markdown-textarea>
|
||||
<div *ngIf="formErrors.instance.description" class="form-error">{{ formErrors.instance.description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceTerms">Terms</label><my-help helpType="markdownText"></my-help>
|
||||
<my-markdown-textarea
|
||||
id="instanceTerms" formControlName="instanceTerms" textareaWidth="500px" [previewColumn]="true"
|
||||
[ngClass]="{ 'input-error': formErrors['instanceTerms'] }"
|
||||
></my-markdown-textarea>
|
||||
<div *ngIf="formErrors.instanceTerms" class="form-error">
|
||||
{{ formErrors.instanceTerms }}
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceTerms">Terms</label><my-help helpType="markdownText"></my-help>
|
||||
<my-markdown-textarea
|
||||
id="instanceTerms" formControlName="terms" textareaWidth="500px" [previewColumn]="true"
|
||||
[ngClass]="{ 'input-error': formErrors['instance.terms'] }"
|
||||
></my-markdown-textarea>
|
||||
<div *ngIf="formErrors.instance.terms" class="form-error">{{ formErrors.instance.terms }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceDefaultClientRoute">Default client route</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="instanceDefaultClientRoute" formControlName="instanceDefaultClientRoute">
|
||||
<option i18n value="/videos/overview">Videos Overview</option>
|
||||
<option i18n value="/videos/trending">Videos Trending</option>
|
||||
<option i18n value="/videos/recently-added">Videos Recently Added</option>
|
||||
<option i18n value="/videos/local">Local videos</option>
|
||||
</select>
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceDefaultClientRoute">Default client route</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="instanceDefaultClientRoute" formControlName="defaultClientRoute">
|
||||
<option i18n value="/videos/overview">Videos Overview</option>
|
||||
<option i18n value="/videos/trending">Videos Trending</option>
|
||||
<option i18n value="/videos/recently-added">Videos Recently Added</option>
|
||||
<option i18n value="/videos/local">Local videos</option>
|
||||
</select>
|
||||
</div>
|
||||
<div *ngIf="formErrors.instance.defaultClientRoute" class="form-error">{{ formErrors.instance.defaultClientRoute }}</div>
|
||||
</div>
|
||||
<div *ngIf="formErrors.instanceDefaultClientRoute" class="form-error">
|
||||
{{ formErrors.instanceDefaultClientRoute }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceDefaultNSFWPolicy">Policy on videos containing sensitive content</label>
|
||||
<my-help
|
||||
helpType="custom" i18n-customHtml
|
||||
customHtml="With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video."
|
||||
></my-help>
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceDefaultNSFWPolicy">Policy on videos containing sensitive content</label>
|
||||
<my-help
|
||||
helpType="custom" i18n-customHtml
|
||||
customHtml="With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video."
|
||||
></my-help>
|
||||
|
||||
<div class="peertube-select-container">
|
||||
<select id="instanceDefaultNSFWPolicy" formControlName="instanceDefaultNSFWPolicy">
|
||||
<option i18n value="do_not_list">Do not list</option>
|
||||
<option i18n value="blur">Blur thumbnails</option>
|
||||
<option i18n value="display">Display</option>
|
||||
</select>
|
||||
<div class="peertube-select-container">
|
||||
<select id="instanceDefaultNSFWPolicy" formControlName="defaultNSFWPolicy">
|
||||
<option i18n value="do_not_list">Do not list</option>
|
||||
<option i18n value="blur">Blur thumbnails</option>
|
||||
<option i18n value="display">Display</option>
|
||||
</select>
|
||||
</div>
|
||||
<div *ngIf="formErrors.instance.defaultNSFWPolicy" class="form-error">{{ formErrors.instance.defaultNSFWPolicy }}</div>
|
||||
</div>
|
||||
<div *ngIf="formErrors.instanceDefaultNSFWPolicy" class="form-error">
|
||||
{{ formErrors.instanceDefaultNSFWPolicy }}
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div i18n class="inner-form-title">Signup</div>
|
||||
|
||||
<div class="form-group">
|
||||
<my-peertube-checkbox
|
||||
inputName="signupEnabled" formControlName="signupEnabled"
|
||||
i18n-labelText labelText="Signup enabled"
|
||||
></my-peertube-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<my-peertube-checkbox *ngIf="isSignupEnabled()"
|
||||
inputName="signupRequiresEmailVerification" formControlName="signupRequiresEmailVerification"
|
||||
i18n-labelText labelText="Signup requires email verification"
|
||||
></my-peertube-checkbox>
|
||||
</div>
|
||||
|
||||
<div *ngIf="isSignupEnabled()" class="form-group">
|
||||
<label i18n for="signupLimit">Signup limit</label>
|
||||
<input
|
||||
type="text" id="signupLimit"
|
||||
formControlName="signupLimit" [ngClass]="{ 'input-error': formErrors['signupLimit'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.signupLimit" class="form-error">
|
||||
{{ formErrors.signupLimit }}
|
||||
<ng-container formGroupName="signup">
|
||||
<div class="form-group">
|
||||
<my-peertube-checkbox
|
||||
inputName="signupEnabled" formControlName="enabled"
|
||||
i18n-labelText labelText="Signup enabled"
|
||||
></my-peertube-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div i18n class="inner-form-title">Import</div>
|
||||
|
||||
<div class="form-group">
|
||||
<my-peertube-checkbox
|
||||
inputName="importVideosHttpEnabled" formControlName="importVideosHttpEnabled"
|
||||
i18n-labelText labelText="Video import with HTTP URL (i.e. YouTube) enabled"
|
||||
></my-peertube-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<my-peertube-checkbox
|
||||
inputName="importVideosTorrentEnabled" formControlName="importVideosTorrentEnabled"
|
||||
i18n-labelText labelText="Video import with a torrent file or a magnet URI enabled"
|
||||
></my-peertube-checkbox>
|
||||
</div>
|
||||
|
||||
<div i18n class="inner-form-title">Administrator</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n for="adminEmail">Admin email</label>
|
||||
<input
|
||||
type="text" id="adminEmail"
|
||||
formControlName="adminEmail" [ngClass]="{ 'input-error': formErrors['adminEmail'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.adminEmail" class="form-error">
|
||||
{{ formErrors.adminEmail }}
|
||||
<div class="form-group">
|
||||
<my-peertube-checkbox *ngIf="isSignupEnabled()"
|
||||
inputName="signupRequiresEmailVerification" formControlName="requiresEmailVerification"
|
||||
i18n-labelText labelText="Signup requires email verification"
|
||||
></my-peertube-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="isSignupEnabled()" class="form-group">
|
||||
<label i18n for="signupLimit">Signup limit</label>
|
||||
<input
|
||||
type="text" id="signupLimit"
|
||||
formControlName="limit" [ngClass]="{ 'input-error': formErrors['signup.limit'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.signup.limit" class="form-error">{{ formErrors.signup.limit }}</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div i18n class="inner-form-title">Users</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n for="userVideoQuota">User default video quota</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="userVideoQuota" formControlName="userVideoQuota">
|
||||
<option *ngFor="let videoQuotaOption of videoQuotaOptions" [value]="videoQuotaOption.value">
|
||||
{{ videoQuotaOption.label }}
|
||||
</option>
|
||||
</select>
|
||||
<ng-container formGroupName="user">
|
||||
<div class="form-group">
|
||||
<label i18n for="userVideoQuota">User default video quota</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="userVideoQuota" formControlName="videoQuota">
|
||||
<option *ngFor="let videoQuotaOption of videoQuotaOptions" [value]="videoQuotaOption.value">
|
||||
{{ videoQuotaOption.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div *ngIf="formErrors.user.videoQuota" class="form-error">{{ formErrors.user.videoQuota }}</div>
|
||||
</div>
|
||||
<div *ngIf="formErrors.userVideoQuota" class="form-error">
|
||||
{{ formErrors.userVideoQuota }}
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n for="userVideoQuotaDaily">User default daily upload limit</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="userVideoQuotaDaily" formControlName="videoQuotaDaily">
|
||||
<option *ngFor="let videoQuotaDailyOption of videoQuotaDailyOptions" [value]="videoQuotaDailyOption.value">
|
||||
{{ videoQuotaDailyOption.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div *ngIf="formErrors.user.videoQuotaDaily" class="form-error">{{ formErrors.user.videoQuotaDaily }}</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div i18n class="inner-form-title">Import</div>
|
||||
|
||||
<ng-container formGroupName="import">
|
||||
<ng-container formGroupName="videos">
|
||||
|
||||
<div class="form-group" formGroupName="http">
|
||||
<my-peertube-checkbox
|
||||
inputName="importVideosHttpEnabled" formControlName="enabled"
|
||||
i18n-labelText labelText="Video import with HTTP URL (i.e. YouTube) enabled"
|
||||
></my-peertube-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="form-group" formGroupName="torrent">
|
||||
<my-peertube-checkbox
|
||||
inputName="importVideosTorrentEnabled" formControlName="enabled"
|
||||
i18n-labelText labelText="Video import with a torrent file or a magnet URI enabled"
|
||||
></my-peertube-checkbox>
|
||||
</div>
|
||||
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<div i18n class="inner-form-title">Administrator</div>
|
||||
|
||||
<div class="form-group" formGroupName="admin">
|
||||
<label i18n for="adminEmail">Admin email</label>
|
||||
<input
|
||||
type="text" id="adminEmail"
|
||||
formControlName="email" [ngClass]="{ 'input-error': formErrors['admin.email'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.admin.email" class="form-error">{{ formErrors.admin.email }}</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n for="userVideoQuotaDaily">User default daily upload limit</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="userVideoQuotaDaily" formControlName="userVideoQuotaDaily">
|
||||
<option *ngFor="let videoQuotaDailyOption of videoQuotaDailyOptions" [value]="videoQuotaDailyOption.value">
|
||||
{{ videoQuotaDailyOption.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div *ngIf="formErrors.userVideoQuotaDaily" class="form-error">
|
||||
{{ formErrors.userVideoQuotaDaily }}
|
||||
</div>
|
||||
<div class="form-group" formGroupName="contactForm">
|
||||
<my-peertube-checkbox
|
||||
inputName="enableContactForm" formControlName="enabled"
|
||||
i18n-labelText labelText="Enable contact form"
|
||||
></my-peertube-checkbox>
|
||||
</div>
|
||||
|
||||
</ng-template>
|
||||
</ngb-tab>
|
||||
|
||||
|
@ -177,30 +177,35 @@
|
|||
<ng-template ngbTabContent>
|
||||
<div i18n class="inner-form-title">Twitter</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n for="signupLimit">Your Twitter username</label>
|
||||
<my-help
|
||||
helpType="custom" i18n-customHtml
|
||||
customHtml="Indicates the Twitter account for the website or platform on which the content was published."
|
||||
></my-help>
|
||||
<input
|
||||
type="text" id="servicesTwitterUsername"
|
||||
formControlName="servicesTwitterUsername" [ngClass]="{ 'input-error': formErrors['servicesTwitterUsername'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.servicesTwitterUsername" class="form-error">
|
||||
{{ formErrors.servicesTwitterUsername }}
|
||||
</div>
|
||||
</div>
|
||||
<ng-container formGroupName="services">
|
||||
<ng-container formGroupName="twitter">
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n for="signupLimit">Your Twitter username</label>
|
||||
<my-help
|
||||
helpType="custom" i18n-customHtml
|
||||
customHtml="Indicates the Twitter account for the website or platform on which the content was published."
|
||||
></my-help>
|
||||
<input
|
||||
type="text" id="servicesTwitterUsername"
|
||||
formControlName="username" [ngClass]="{ 'input-error': formErrors['services.twitter.username'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.services.twitter.username" class="form-error">{{ formErrors.services.twitter.username }}</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<my-peertube-checkbox
|
||||
inputName="servicesTwitterWhitelisted" formControlName="whitelisted"
|
||||
i18n-labelText labelText="Instance whitelisted by Twitter"
|
||||
i18n-helpHtml helpHtml="If your instance is whitelisted by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br />
|
||||
If the instance is not whitelisted, we use an image link card that will redirect on your PeerTube instance.<br /><br />
|
||||
Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/videos/watch/blabla) on <a target='_blank' rel='noopener noreferrer' href='https://cards-dev.twitter.com/validator'>https://cards-dev.twitter.com/validator</a> to see if you instance is whitelisted."
|
||||
></my-peertube-checkbox>
|
||||
</div>
|
||||
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<div class="form-group">
|
||||
<my-peertube-checkbox
|
||||
inputName="servicesTwitterWhitelisted" formControlName="servicesTwitterWhitelisted"
|
||||
i18n-labelText labelText="Instance whitelisted by Twitter"
|
||||
i18n-helpHtml helpHtml="If your instance is whitelisted by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br />
|
||||
If the instance is not whitelisted, we use an image link card that will redirect on your PeerTube instance.<br /><br />
|
||||
Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/videos/watch/blabla) on <a target='_blank' rel='noopener noreferrer' href='https://cards-dev.twitter.com/validator'>https://cards-dev.twitter.com/validator</a> to see if you instance is whitelisted."
|
||||
></my-peertube-checkbox>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ngb-tab>
|
||||
|
||||
|
@ -209,45 +214,48 @@
|
|||
|
||||
<div i18n class="inner-form-title">Transcoding</div>
|
||||
|
||||
<div class="form-group">
|
||||
<my-peertube-checkbox
|
||||
inputName="transcodingEnabled" formControlName="transcodingEnabled"
|
||||
i18n-labelText labelText="Transcoding enabled"
|
||||
i18n-helpHtml helpHtml="If you disable transcoding, many videos from your users will not work!"
|
||||
></my-peertube-checkbox>
|
||||
</div>
|
||||
|
||||
<ng-template [ngIf]="isTranscodingEnabled()">
|
||||
|
||||
<ng-container formGroupName="transcoding">
|
||||
<div class="form-group">
|
||||
<my-peertube-checkbox
|
||||
inputName="transcodingAllowAdditionalExtensions" formControlName="transcodingAllowAdditionalExtensions"
|
||||
i18n-labelText labelText="Allow additional extensions"
|
||||
i18n-helpHtml helpHtml="Allow your users to upload .mkv, .mov, .avi, .flv videos"
|
||||
inputName="transcodingEnabled" formControlName="enabled"
|
||||
i18n-labelText labelText="Transcoding enabled"
|
||||
i18n-helpHtml helpHtml="If you disable transcoding, many videos from your users will not work!"
|
||||
></my-peertube-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n for="transcodingThreads">Transcoding threads</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="transcodingThreads" formControlName="transcodingThreads">
|
||||
<option *ngFor="let transcodingThreadOption of transcodingThreadOptions" [value]="transcodingThreadOption.value">
|
||||
{{ transcodingThreadOption.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div *ngIf="formErrors.transcodingThreads" class="form-error">
|
||||
{{ formErrors.transcodingThreads }}
|
||||
</div>
|
||||
</div>
|
||||
<ng-container *ngIf="isTranscodingEnabled()">
|
||||
|
||||
<div class="form-group" *ngFor="let resolution of resolutions">
|
||||
<my-peertube-checkbox
|
||||
[inputName]="getResolutionKey(resolution)" [formControlName]="getResolutionKey(resolution)"
|
||||
i18n-labelText labelText="Resolution {{resolution}} enabled"
|
||||
></my-peertube-checkbox>
|
||||
</div>
|
||||
</ng-template>
|
||||
<div class="form-group">
|
||||
<my-peertube-checkbox
|
||||
inputName="transcodingAllowAdditionalExtensions" formControlName="allowAdditionalExtensions"
|
||||
i18n-labelText labelText="Allow additional extensions"
|
||||
i18n-helpHtml helpHtml="Allow your users to upload .mkv, .mov, .avi, .flv videos"
|
||||
></my-peertube-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n for="transcodingThreads">Transcoding threads</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="transcodingThreads" formControlName="threads">
|
||||
<option *ngFor="let transcodingThreadOption of transcodingThreadOptions" [value]="transcodingThreadOption.value">
|
||||
{{ transcodingThreadOption.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div *ngIf="formErrors.transcoding.threads" class="form-error">{{ formErrors.transcoding.threads }}</div>
|
||||
</div>
|
||||
|
||||
<ng-container formGroupName="resolutions">
|
||||
<div class="form-group" *ngFor="let resolution of resolutions">
|
||||
<my-peertube-checkbox
|
||||
[inputName]="getResolutionKey(resolution)" [formControlName]="resolution"
|
||||
i18n-labelText labelText="Resolution {{resolution}} enabled"
|
||||
></my-peertube-checkbox>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<div i18n class="inner-form-title">
|
||||
Cache
|
||||
|
@ -258,74 +266,73 @@
|
|||
></my-help>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n for="cachePreviewsSize">Previews cache size</label>
|
||||
<input
|
||||
type="text" id="cachePreviewsSize"
|
||||
formControlName="cachePreviewsSize" [ngClass]="{ 'input-error': formErrors['cachePreviewsSize'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.cachePreviewsSize" class="form-error">
|
||||
{{ formErrors.cachePreviewsSize }}
|
||||
<ng-container formGroupName="cache">
|
||||
<div class="form-group" formGroupName="previews">
|
||||
<label i18n for="cachePreviewsSize">Previews cache size</label>
|
||||
<input
|
||||
type="text" id="cachePreviewsSize"
|
||||
formControlName="size" [ngClass]="{ 'input-error': formErrors['cache.previews.size'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.cache.previews.size" class="form-error">{{ formErrors.cache.previews.size }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n for="cachePreviewsSize">Video captions cache size</label>
|
||||
<input
|
||||
type="text" id="cacheCaptionsSize"
|
||||
formControlName="cacheCaptionsSize" [ngClass]="{ 'input-error': formErrors['cacheCaptionsSize'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.cacheCaptionsSize" class="form-error">
|
||||
{{ formErrors.cacheCaptionsSize }}
|
||||
<div class="form-group" formGroupName="captions">
|
||||
<label i18n for="cacheCaptionsSize">Video captions cache size</label>
|
||||
<input
|
||||
type="text" id="cacheCaptionsSize"
|
||||
formControlName="size" [ngClass]="{ 'input-error': formErrors['cache.captions.size'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.cache.captions.size" class="form-error">{{ formErrors.cache.captions.size }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<div i18n class="inner-form-title">Customizations</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label i18n for="customizationJavascript">JavaScript</label>
|
||||
<my-help
|
||||
helpType="custom" i18n-customHtml
|
||||
customHtml="Write directly JavaScript code.<br />Example: <pre>console.log('my instance is amazing');</pre>"
|
||||
></my-help>
|
||||
<textarea
|
||||
id="customizationJavascript" formControlName="customizationJavascript"
|
||||
[ngClass]="{ 'input-error': formErrors['customizationJavascript'] }"
|
||||
></textarea>
|
||||
<div *ngIf="formErrors.customizationJavascript" class="form-error">
|
||||
{{ formErrors.customizationJavascript }}
|
||||
</div>
|
||||
</div>
|
||||
<ng-container formGroupName="instance">
|
||||
<ng-container formGroupName="customizations">
|
||||
<div class="form-group">
|
||||
<label i18n for="customizationJavascript">JavaScript</label>
|
||||
<my-help
|
||||
helpType="custom" i18n-customHtml
|
||||
customHtml="Write directly JavaScript code.<br />Example: <pre>console.log('my instance is amazing');</pre>"
|
||||
></my-help>
|
||||
<textarea
|
||||
id="customizationJavascript" formControlName="javascript"
|
||||
[ngClass]="{ 'input-error': formErrors['instance.customizations.javascript'] }"
|
||||
></textarea>
|
||||
<div *ngIf="formErrors.instance.customizations.javascript" class="form-error">{{ formErrors.instance.customizations.javascript }}</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="customizationCSS">CSS</label>
|
||||
<my-help
|
||||
helpType="custom"
|
||||
i18n-customHtml
|
||||
customHtml="
|
||||
Write directly CSS code. Example:<br />
|
||||
<pre>
|
||||
body {{ '{' }}
|
||||
background-color: red;
|
||||
{{ '}' }}
|
||||
</pre>
|
||||
<div class="form-group">
|
||||
<label for="customizationCSS">CSS</label>
|
||||
<my-help
|
||||
helpType="custom"
|
||||
i18n-customHtml
|
||||
customHtml="
|
||||
Write directly CSS code. Example:<br />
|
||||
<pre>
|
||||
body {{ '{' }}
|
||||
background-color: red;
|
||||
{{ '}' }}
|
||||
</pre>
|
||||
|
||||
Prepend with <em>#custom-css</em> to override styles. Example:
|
||||
<pre>
|
||||
#custom-css .logged-in-email {{ '{' }}
|
||||
color: red;
|
||||
{{ '}' }}
|
||||
</pre>
|
||||
"
|
||||
></my-help>
|
||||
<textarea
|
||||
id="customizationCSS" formControlName="css"
|
||||
[ngClass]="{ 'input-error': formErrors['instance.customizations.css'] }"
|
||||
></textarea>
|
||||
<div *ngIf="formErrors.instance.customizations.css" class="form-error">{{ formErrors.instance.customizations.css }}</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
Prepend with <em>#custom-css</em> to override styles. Example:
|
||||
<pre>
|
||||
#custom-css .logged-in-email {{ '{' }}
|
||||
color: red;
|
||||
{{ '}' }}
|
||||
</pre>
|
||||
"
|
||||
></my-help>
|
||||
<textarea
|
||||
id="customizationCSS" formControlName="customizationCSS"
|
||||
[ngClass]="{ 'input-error': formErrors['customizationCSS'] }"
|
||||
></textarea>
|
||||
<div *ngIf="formErrors.customizationCSS" class="form-error">
|
||||
{{ formErrors.customizationCSS }}
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ngb-tab>
|
||||
</ngb-tabset>
|
||||
|
|
|
@ -18,9 +18,6 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
|
|||
resolutions: string[] = []
|
||||
transcodingThreadOptions: { label: string, value: number }[] = []
|
||||
|
||||
private oldCustomJavascript: string
|
||||
private oldCustomCSS: string
|
||||
|
||||
constructor (
|
||||
protected formValidatorService: FormValidatorService,
|
||||
private customConfigValidatorsService: CustomConfigValidatorsService,
|
||||
|
@ -58,41 +55,78 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
|
|||
}
|
||||
|
||||
getResolutionKey (resolution: string) {
|
||||
return 'transcodingResolution' + resolution
|
||||
return 'transcoding.resolutions.' + resolution
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
const formGroupData: { [key: string]: any } = {
|
||||
instanceName: this.customConfigValidatorsService.INSTANCE_NAME,
|
||||
instanceShortDescription: this.customConfigValidatorsService.INSTANCE_SHORT_DESCRIPTION,
|
||||
instanceDescription: null,
|
||||
instanceTerms: null,
|
||||
instanceDefaultClientRoute: null,
|
||||
instanceDefaultNSFWPolicy: null,
|
||||
servicesTwitterUsername: this.customConfigValidatorsService.SERVICES_TWITTER_USERNAME,
|
||||
servicesTwitterWhitelisted: null,
|
||||
cachePreviewsSize: this.customConfigValidatorsService.CACHE_PREVIEWS_SIZE,
|
||||
cacheCaptionsSize: this.customConfigValidatorsService.CACHE_CAPTIONS_SIZE,
|
||||
signupEnabled: null,
|
||||
signupLimit: this.customConfigValidatorsService.SIGNUP_LIMIT,
|
||||
signupRequiresEmailVerification: null,
|
||||
importVideosHttpEnabled: null,
|
||||
importVideosTorrentEnabled: null,
|
||||
adminEmail: this.customConfigValidatorsService.ADMIN_EMAIL,
|
||||
userVideoQuota: this.userValidatorsService.USER_VIDEO_QUOTA,
|
||||
userVideoQuotaDaily: this.userValidatorsService.USER_VIDEO_QUOTA_DAILY,
|
||||
transcodingThreads: this.customConfigValidatorsService.TRANSCODING_THREADS,
|
||||
transcodingAllowAdditionalExtensions: null,
|
||||
transcodingEnabled: null,
|
||||
customizationJavascript: null,
|
||||
customizationCSS: null
|
||||
const formGroupData: { [key in keyof CustomConfig ]: any } = {
|
||||
instance: {
|
||||
name: this.customConfigValidatorsService.INSTANCE_NAME,
|
||||
shortDescription: this.customConfigValidatorsService.INSTANCE_SHORT_DESCRIPTION,
|
||||
description: null,
|
||||
terms: null,
|
||||
defaultClientRoute: null,
|
||||
defaultNSFWPolicy: null,
|
||||
customizations: {
|
||||
javascript: null,
|
||||
css: null
|
||||
}
|
||||
},
|
||||
services: {
|
||||
twitter: {
|
||||
username: this.customConfigValidatorsService.SERVICES_TWITTER_USERNAME,
|
||||
whitelisted: null
|
||||
}
|
||||
},
|
||||
cache: {
|
||||
previews: {
|
||||
size: this.customConfigValidatorsService.CACHE_PREVIEWS_SIZE
|
||||
},
|
||||
captions: {
|
||||
size: this.customConfigValidatorsService.CACHE_CAPTIONS_SIZE
|
||||
}
|
||||
},
|
||||
signup: {
|
||||
enabled: null,
|
||||
limit: this.customConfigValidatorsService.SIGNUP_LIMIT,
|
||||
requiresEmailVerification: null
|
||||
},
|
||||
import: {
|
||||
videos: {
|
||||
http: {
|
||||
enabled: null
|
||||
},
|
||||
torrent: {
|
||||
enabled: null
|
||||
}
|
||||
}
|
||||
},
|
||||
admin: {
|
||||
email: this.customConfigValidatorsService.ADMIN_EMAIL
|
||||
},
|
||||
contactForm: {
|
||||
enabled: null
|
||||
},
|
||||
user: {
|
||||
videoQuota: this.userValidatorsService.USER_VIDEO_QUOTA,
|
||||
videoQuotaDaily: this.userValidatorsService.USER_VIDEO_QUOTA_DAILY
|
||||
},
|
||||
transcoding: {
|
||||
enabled: null,
|
||||
threads: this.customConfigValidatorsService.TRANSCODING_THREADS,
|
||||
allowAdditionalExtensions: null,
|
||||
resolutions: {}
|
||||
}
|
||||
}
|
||||
|
||||
const defaultValues: BuildFormDefaultValues = {}
|
||||
const defaultValues = {
|
||||
transcoding: {
|
||||
resolutions: {}
|
||||
}
|
||||
}
|
||||
for (const resolution of this.resolutions) {
|
||||
const key = this.getResolutionKey(resolution)
|
||||
defaultValues[key] = 'false'
|
||||
formGroupData[key] = null
|
||||
defaultValues.transcoding.resolutions[resolution] = 'false'
|
||||
formGroupData.transcoding.resolutions[resolution] = null
|
||||
}
|
||||
|
||||
this.buildForm(formGroupData)
|
||||
|
@ -102,9 +136,6 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
|
|||
res => {
|
||||
this.customConfig = res
|
||||
|
||||
this.oldCustomCSS = this.customConfig.instance.customizations.css
|
||||
this.oldCustomJavascript = this.customConfig.instance.customizations.javascript
|
||||
|
||||
this.updateForm()
|
||||
// Force form validation
|
||||
this.forceCheck()
|
||||
|
@ -115,78 +146,15 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
|
|||
}
|
||||
|
||||
isTranscodingEnabled () {
|
||||
return this.form.value['transcodingEnabled'] === true
|
||||
return this.form.value['transcoding']['enabled'] === true
|
||||
}
|
||||
|
||||
isSignupEnabled () {
|
||||
return this.form.value['signupEnabled'] === true
|
||||
return this.form.value['signup']['enabled'] === true
|
||||
}
|
||||
|
||||
async formValidated () {
|
||||
const data: CustomConfig = {
|
||||
instance: {
|
||||
name: this.form.value['instanceName'],
|
||||
shortDescription: this.form.value['instanceShortDescription'],
|
||||
description: this.form.value['instanceDescription'],
|
||||
terms: this.form.value['instanceTerms'],
|
||||
defaultClientRoute: this.form.value['instanceDefaultClientRoute'],
|
||||
defaultNSFWPolicy: this.form.value['instanceDefaultNSFWPolicy'],
|
||||
customizations: {
|
||||
javascript: this.form.value['customizationJavascript'],
|
||||
css: this.form.value['customizationCSS']
|
||||
}
|
||||
},
|
||||
services: {
|
||||
twitter: {
|
||||
username: this.form.value['servicesTwitterUsername'],
|
||||
whitelisted: this.form.value['servicesTwitterWhitelisted']
|
||||
}
|
||||
},
|
||||
cache: {
|
||||
previews: {
|
||||
size: this.form.value['cachePreviewsSize']
|
||||
},
|
||||
captions: {
|
||||
size: this.form.value['cacheCaptionsSize']
|
||||
}
|
||||
},
|
||||
signup: {
|
||||
enabled: this.form.value['signupEnabled'],
|
||||
limit: this.form.value['signupLimit'],
|
||||
requiresEmailVerification: this.form.value['signupRequiresEmailVerification']
|
||||
},
|
||||
admin: {
|
||||
email: this.form.value['adminEmail']
|
||||
},
|
||||
user: {
|
||||
videoQuota: this.form.value['userVideoQuota'],
|
||||
videoQuotaDaily: this.form.value['userVideoQuotaDaily']
|
||||
},
|
||||
transcoding: {
|
||||
enabled: this.form.value['transcodingEnabled'],
|
||||
allowAdditionalExtensions: this.form.value['transcodingAllowAdditionalExtensions'],
|
||||
threads: this.form.value['transcodingThreads'],
|
||||
resolutions: {
|
||||
'240p': this.form.value[this.getResolutionKey('240p')],
|
||||
'360p': this.form.value[this.getResolutionKey('360p')],
|
||||
'480p': this.form.value[this.getResolutionKey('480p')],
|
||||
'720p': this.form.value[this.getResolutionKey('720p')],
|
||||
'1080p': this.form.value[this.getResolutionKey('1080p')]
|
||||
}
|
||||
},
|
||||
import: {
|
||||
videos: {
|
||||
http: {
|
||||
enabled: this.form.value['importVideosHttpEnabled']
|
||||
},
|
||||
torrent: {
|
||||
enabled: this.form.value['importVideosTorrentEnabled']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.configService.updateCustomConfig(data)
|
||||
this.configService.updateCustomConfig(this.form.value)
|
||||
.subscribe(
|
||||
res => {
|
||||
this.customConfig = res
|
||||
|
@ -204,38 +172,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
|
|||
}
|
||||
|
||||
private updateForm () {
|
||||
const data: { [key: string]: any } = {
|
||||
instanceName: this.customConfig.instance.name,
|
||||
instanceShortDescription: this.customConfig.instance.shortDescription,
|
||||
instanceDescription: this.customConfig.instance.description,
|
||||
instanceTerms: this.customConfig.instance.terms,
|
||||
instanceDefaultClientRoute: this.customConfig.instance.defaultClientRoute,
|
||||
instanceDefaultNSFWPolicy: this.customConfig.instance.defaultNSFWPolicy,
|
||||
servicesTwitterUsername: this.customConfig.services.twitter.username,
|
||||
servicesTwitterWhitelisted: this.customConfig.services.twitter.whitelisted,
|
||||
cachePreviewsSize: this.customConfig.cache.previews.size,
|
||||
cacheCaptionsSize: this.customConfig.cache.captions.size,
|
||||
signupEnabled: this.customConfig.signup.enabled,
|
||||
signupLimit: this.customConfig.signup.limit,
|
||||
signupRequiresEmailVerification: this.customConfig.signup.requiresEmailVerification,
|
||||
adminEmail: this.customConfig.admin.email,
|
||||
userVideoQuota: this.customConfig.user.videoQuota,
|
||||
userVideoQuotaDaily: this.customConfig.user.videoQuotaDaily,
|
||||
transcodingThreads: this.customConfig.transcoding.threads,
|
||||
transcodingEnabled: this.customConfig.transcoding.enabled,
|
||||
transcodingAllowAdditionalExtensions: this.customConfig.transcoding.allowAdditionalExtensions,
|
||||
customizationJavascript: this.customConfig.instance.customizations.javascript,
|
||||
customizationCSS: this.customConfig.instance.customizations.css,
|
||||
importVideosHttpEnabled: this.customConfig.import.videos.http.enabled,
|
||||
importVideosTorrentEnabled: this.customConfig.import.videos.torrent.enabled
|
||||
}
|
||||
|
||||
for (const resolution of this.resolutions) {
|
||||
const key = this.getResolutionKey(resolution)
|
||||
data[key] = this.customConfig.transcoding.resolutions[resolution]
|
||||
}
|
||||
|
||||
this.form.patchValue(data)
|
||||
this.form.patchValue(this.customConfig)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,6 +40,9 @@ export class ServerService {
|
|||
email: {
|
||||
enabled: false
|
||||
},
|
||||
contactForm: {
|
||||
enabled: false
|
||||
},
|
||||
serverVersion: 'Unknown',
|
||||
signup: {
|
||||
allowed: false,
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
import { FormGroup } from '@angular/forms'
|
||||
import { BuildFormArgument, BuildFormDefaultValues, FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
||||
|
||||
export type FormReactiveErrors = { [ id: string ]: string }
|
||||
export type FormReactiveErrors = { [ id: string ]: string | FormReactiveErrors }
|
||||
export type FormReactiveValidationMessages = {
|
||||
[ id: string ]: {
|
||||
[ name: string ]: string
|
||||
}
|
||||
[ id: string ]: { [ name: string ]: string } | FormReactiveValidationMessages
|
||||
}
|
||||
|
||||
export abstract class FormReactive {
|
||||
|
@ -23,29 +21,49 @@ export abstract class FormReactive {
|
|||
this.formErrors = formErrors
|
||||
this.validationMessages = validationMessages
|
||||
|
||||
this.form.valueChanges.subscribe(() => this.onValueChanged(false))
|
||||
this.form.valueChanges.subscribe(() => this.onValueChanged(this.form, this.formErrors, this.validationMessages, false))
|
||||
}
|
||||
|
||||
protected onValueChanged (forceCheck = false) {
|
||||
for (const field in this.formErrors) {
|
||||
protected forceCheck () {
|
||||
return this.onValueChanged(this.form, this.formErrors, this.validationMessages, true)
|
||||
}
|
||||
|
||||
protected check () {
|
||||
return this.onValueChanged(this.form, this.formErrors, this.validationMessages, false)
|
||||
}
|
||||
|
||||
private onValueChanged (
|
||||
form: FormGroup,
|
||||
formErrors: FormReactiveErrors,
|
||||
validationMessages: FormReactiveValidationMessages,
|
||||
forceCheck = false
|
||||
) {
|
||||
for (const field of Object.keys(formErrors)) {
|
||||
if (formErrors[field] && typeof formErrors[field] === 'object') {
|
||||
this.onValueChanged(
|
||||
form.controls[field] as FormGroup,
|
||||
formErrors[field] as FormReactiveErrors,
|
||||
validationMessages[field] as FormReactiveValidationMessages,
|
||||
forceCheck
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
// clear previous error message (if any)
|
||||
this.formErrors[ field ] = ''
|
||||
const control = this.form.get(field)
|
||||
formErrors[ field ] = ''
|
||||
const control = form.get(field)
|
||||
|
||||
if (control.dirty) this.formChanged = true
|
||||
|
||||
// Don't care if dirty on force check
|
||||
const isDirty = control.dirty || forceCheck === true
|
||||
if (control && isDirty && !control.valid) {
|
||||
const messages = this.validationMessages[ field ]
|
||||
const messages = validationMessages[ field ]
|
||||
for (const key in control.errors) {
|
||||
this.formErrors[ field ] += messages[ key ] + ' '
|
||||
formErrors[ field ] += messages[ key ] + ' '
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected forceCheck () {
|
||||
return this.onValueChanged(true)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,10 +7,10 @@ export type BuildFormValidator = {
|
|||
MESSAGES: { [ name: string ]: string }
|
||||
}
|
||||
export type BuildFormArgument = {
|
||||
[ id: string ]: BuildFormValidator
|
||||
[ id: string ]: BuildFormValidator | BuildFormArgument
|
||||
}
|
||||
export type BuildFormDefaultValues = {
|
||||
[ name: string ]: string | string[]
|
||||
[ name: string ]: string | string[] | BuildFormDefaultValues
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
|
@ -29,7 +29,16 @@ export class FormValidatorService {
|
|||
formErrors[name] = ''
|
||||
|
||||
const field = obj[name]
|
||||
if (field && field.MESSAGES) validationMessages[name] = field.MESSAGES
|
||||
if (this.isRecursiveField(field)) {
|
||||
const result = this.buildForm(field as BuildFormArgument, defaultValues[name] as BuildFormDefaultValues)
|
||||
group[name] = result.form
|
||||
formErrors[name] = result.formErrors
|
||||
validationMessages[name] = result.validationMessages
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if (field && field.MESSAGES) validationMessages[name] = field.MESSAGES as { [ name: string ]: string }
|
||||
|
||||
const defaultValue = defaultValues[name] || ''
|
||||
|
||||
|
@ -52,13 +61,27 @@ export class FormValidatorService {
|
|||
formErrors[name] = ''
|
||||
|
||||
const field = obj[name]
|
||||
if (field && field.MESSAGES) validationMessages[name] = field.MESSAGES
|
||||
if (this.isRecursiveField(field)) {
|
||||
this.updateForm(
|
||||
form[name],
|
||||
formErrors[name] as FormReactiveErrors,
|
||||
validationMessages[name] as FormReactiveValidationMessages,
|
||||
obj[name] as BuildFormArgument,
|
||||
defaultValues[name] as BuildFormDefaultValues
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
if (field && field.MESSAGES) validationMessages[name] = field.MESSAGES as { [ name: string ]: string }
|
||||
|
||||
const defaultValue = defaultValues[name] || ''
|
||||
|
||||
if (field && field.VALIDATORS) form.addControl(name, new FormControl(defaultValue, field.VALIDATORS))
|
||||
if (field && field.VALIDATORS) form.addControl(name, new FormControl(defaultValue, field.VALIDATORS as ValidatorFn[]))
|
||||
else form.addControl(name, new FormControl(defaultValue))
|
||||
}
|
||||
}
|
||||
|
||||
private isRecursiveField (field: any) {
|
||||
return field && typeof field === 'object' && !field.MESSAGES && !field.VALIDATORS
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
}
|
||||
|
||||
/deep/ {
|
||||
.popover-help.popover {
|
||||
.help-popover {
|
||||
max-width: 300px;
|
||||
|
||||
.popover-body {
|
||||
|
|
|
@ -29,7 +29,7 @@ export class RemoteSubscribeComponent extends FormReactive implements OnInit {
|
|||
}
|
||||
|
||||
onValidKey () {
|
||||
this.onValueChanged()
|
||||
this.check()
|
||||
if (!this.form.valid) return
|
||||
|
||||
this.formValidated()
|
||||
|
|
|
@ -70,7 +70,7 @@ export class VideoCommentAddComponent extends FormReactive implements OnInit {
|
|||
}
|
||||
|
||||
onValidKey () {
|
||||
this.onValueChanged()
|
||||
this.check()
|
||||
if (!this.form.valid) return
|
||||
|
||||
this.formValidated()
|
||||
|
|
Loading…
Reference in New Issue