Fix alert accessibility

This commit is contained in:
Chocobozzz 2024-09-23 11:22:14 +02:00
parent 2dbb83c11b
commit 2011bc29dd
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
91 changed files with 510 additions and 414 deletions

View File

@ -46,7 +46,7 @@
<div *ngIf="formErrors.body" class="form-error" role="alert">{{ formErrors.body }}</div> <div *ngIf="formErrors.body" class="form-error" role="alert">{{ formErrors.body }}</div>
</div> </div>
<div *ngIf="error" class="alert alert-danger">{{ error }}</div> <my-alert *ngIf="error" type="danger">{{ error }}</my-alert>
<div class="form-group inputs"> <div class="form-group inputs">
<input <input
@ -58,7 +58,6 @@
</div> </div>
</form> </form>
<div *ngIf="!isContactFormEnabled()" class="alert alert-danger" i18n>The contact form is not enabled on this instance.</div> <my-alert *ngIf="!isContactFormEnabled()" type="danger" i18n>The contact form is not enabled on this instance.</my-alert>
</div> </div>
</ng-template> </ng-template>

View File

@ -1,4 +1,6 @@
import { NgClass, NgIf } from '@angular/common'
import { Component, OnInit, ViewChild } from '@angular/core' import { Component, OnInit, ViewChild } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Router } from '@angular/router' import { Router } from '@angular/router'
import { Notifier, ServerService } from '@app/core' import { Notifier, ServerService } from '@app/core'
import { import {
@ -9,13 +11,12 @@ import {
} from '@app/shared/form-validators/instance-validators' } from '@app/shared/form-validators/instance-validators'
import { FormReactive } from '@app/shared/shared-forms/form-reactive' import { FormReactive } from '@app/shared/shared-forms/form-reactive'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { InstanceService } from '@app/shared/shared-main/instance/instance.service'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
import { HTMLServerConfig, HttpStatusCode } from '@peertube/peertube-models' import { HTMLServerConfig, HttpStatusCode } from '@peertube/peertube-models'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgIf, NgClass } from '@angular/common'
import { GlobalIconComponent } from '../../shared/shared-icons/global-icon.component' import { GlobalIconComponent } from '../../shared/shared-icons/global-icon.component'
import { InstanceService } from '@app/shared/shared-main/instance/instance.service'
type Prefill = { type Prefill = {
subject?: string subject?: string
@ -27,7 +28,7 @@ type Prefill = {
templateUrl: './contact-admin-modal.component.html', templateUrl: './contact-admin-modal.component.html',
styleUrls: [ './contact-admin-modal.component.scss' ], styleUrls: [ './contact-admin-modal.component.scss' ],
standalone: true, standalone: true,
imports: [ GlobalIconComponent, NgIf, FormsModule, ReactiveFormsModule, NgClass ] imports: [ GlobalIconComponent, NgIf, FormsModule, ReactiveFormsModule, NgClass, AlertComponent ]
}) })
export class ContactAdminModalComponent extends FormReactive implements OnInit { export class ContactAdminModalComponent extends FormReactive implements OnInit {
@ViewChild('modal', { static: true }) modal: NgbModal @ViewChild('modal', { static: true }) modal: NgbModal

View File

@ -165,7 +165,7 @@
<ng-container ngProjectAs="description"> <ng-container ngProjectAs="description">
<span i18n>⚠️ This functionality requires a lot of attention and extra moderation.</span> <span i18n>⚠️ This functionality requires a lot of attention and extra moderation.</span>
<div class="alert pt-alert-primary alert-signup" *ngIf="signupAlertMessage">{{ signupAlertMessage }}</div> <my-alert type="primary" class="alert-signup" *ngIf="signupAlertMessage">{{ signupAlertMessage }}</my-alert>
</ng-container> </ng-container>
<ng-container ngProjectAs="extra"> <ng-container ngProjectAs="extra">

View File

@ -1,19 +1,20 @@
import { pairwise } from 'rxjs/operators' import { NgClass, NgFor, NgIf } from '@angular/common'
import { SelectOptionsItem } from 'src/types/select-options-item.model'
import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core' import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'
import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'
import { RouterLink } from '@angular/router'
import { MenuService, ThemeService } from '@app/core' import { MenuService, ThemeService } from '@app/core'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { HTMLServerConfig } from '@peertube/peertube-models' import { HTMLServerConfig } from '@peertube/peertube-models'
import { ConfigService } from '../shared/config.service' import { pairwise } from 'rxjs/operators'
import { PeerTubeTemplateDirective } from '../../../shared/shared-main/common/peertube-template.directive' import { SelectOptionsItem } from 'src/types/select-options-item.model'
import { SelectOptionsComponent } from '../../../shared/shared-forms/select/select-options.component'
import { UserRealQuotaInfoComponent } from '../../shared/user-real-quota-info.component'
import { MarkdownTextareaComponent } from '../../../shared/shared-forms/markdown-textarea.component' import { MarkdownTextareaComponent } from '../../../shared/shared-forms/markdown-textarea.component'
import { HelpComponent } from '../../../shared/shared-main/buttons/help.component'
import { PeertubeCheckboxComponent } from '../../../shared/shared-forms/peertube-checkbox.component' import { PeertubeCheckboxComponent } from '../../../shared/shared-forms/peertube-checkbox.component'
import { SelectCustomValueComponent } from '../../../shared/shared-forms/select/select-custom-value.component' import { SelectCustomValueComponent } from '../../../shared/shared-forms/select/select-custom-value.component'
import { NgFor, NgIf, NgClass } from '@angular/common' import { SelectOptionsComponent } from '../../../shared/shared-forms/select/select-options.component'
import { RouterLink } from '@angular/router' import { HelpComponent } from '../../../shared/shared-main/buttons/help.component'
import { PeerTubeTemplateDirective } from '../../../shared/shared-main/common/peertube-template.directive'
import { UserRealQuotaInfoComponent } from '../../shared/user-real-quota-info.component'
import { ConfigService } from '../shared/config.service'
@Component({ @Component({
selector: 'my-edit-basic-configuration', selector: 'my-edit-basic-configuration',
@ -33,7 +34,8 @@ import { RouterLink } from '@angular/router'
NgClass, NgClass,
UserRealQuotaInfoComponent, UserRealQuotaInfoComponent,
SelectOptionsComponent, SelectOptionsComponent,
PeerTubeTemplateDirective PeerTubeTemplateDirective,
AlertComponent
] ]
}) })
export class EditBasicConfigurationComponent implements OnInit, OnChanges { export class EditBasicConfigurationComponent implements OnInit, OnChanges {

View File

@ -1,8 +1,8 @@
<h1 class="visually-hidden" i18n>Configuration</h1> <h1 class="visually-hidden" i18n>Configuration</h1>
<div class="alert alert-warning" *ngIf="!isUpdateAllowed()" i18n> <my-alert type="warning" *ngIf="!isUpdateAllowed()" i18n>
Updating instance configuration from the web interface is disabled by the system administrator. Updating instance configuration from the web interface is disabled by the system administrator.
</div> </my-alert>
<form role="form" [formGroup]="form"> <form role="form" [formGroup]="form">

View File

@ -27,9 +27,11 @@ import {
import { USER_VIDEO_QUOTA_DAILY_VALIDATOR, USER_VIDEO_QUOTA_VALIDATOR } from '@app/shared/form-validators/user-validators' import { USER_VIDEO_QUOTA_DAILY_VALIDATOR, USER_VIDEO_QUOTA_VALIDATOR } from '@app/shared/form-validators/user-validators'
import { FormReactive } from '@app/shared/shared-forms/form-reactive' import { FormReactive } from '@app/shared/shared-forms/form-reactive'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { CustomPageService } from '@app/shared/shared-main/custom-page/custom-page.service' import { CustomPageService } from '@app/shared/shared-main/custom-page/custom-page.service'
import { NgbNav, NgbNavContent, NgbNavItem, NgbNavLink, NgbNavLinkBase, NgbNavOutlet } from '@ng-bootstrap/ng-bootstrap' import { NgbNav, NgbNavContent, NgbNavItem, NgbNavLink, NgbNavLinkBase, NgbNavOutlet } from '@ng-bootstrap/ng-bootstrap'
import { CustomConfig, CustomPage, HTMLServerConfig } from '@peertube/peertube-models' import { CustomConfig, CustomPage, HTMLServerConfig } from '@peertube/peertube-models'
import merge from 'lodash-es/merge'
import omit from 'lodash-es/omit' import omit from 'lodash-es/omit'
import { forkJoin } from 'rxjs' import { forkJoin } from 'rxjs'
import { SelectOptionsItem } from 'src/types/select-options-item.model' import { SelectOptionsItem } from 'src/types/select-options-item.model'
@ -40,7 +42,6 @@ import { EditHomepageComponent } from './edit-homepage.component'
import { EditInstanceInformationComponent } from './edit-instance-information.component' import { EditInstanceInformationComponent } from './edit-instance-information.component'
import { EditLiveConfigurationComponent } from './edit-live-configuration.component' import { EditLiveConfigurationComponent } from './edit-live-configuration.component'
import { EditVODTranscodingComponent } from './edit-vod-transcoding.component' import { EditVODTranscodingComponent } from './edit-vod-transcoding.component'
import merge from 'lodash-es/merge'
type ComponentCustomConfig = CustomConfig & { type ComponentCustomConfig = CustomConfig & {
instanceCustomHomepage: CustomPage instanceCustomHomepage: CustomPage
@ -67,7 +68,8 @@ type ComponentCustomConfig = CustomConfig & {
EditLiveConfigurationComponent, EditLiveConfigurationComponent,
EditAdvancedConfigurationComponent, EditAdvancedConfigurationComponent,
NgbNavOutlet, NgbNavOutlet,
NgFor NgFor,
AlertComponent
] ]
}) })
export class EditCustomConfigComponent extends FormReactive implements OnInit { export class EditCustomConfigComponent extends FormReactive implements OnInit {

View File

@ -26,9 +26,9 @@
</div> </div>
</div> </div>
<div i18n *ngIf="httpEnabled() === false" class="alert alert-warning"> <my-alert i18n *ngIf="httpEnabled() === false" type="warning">
It seems that you are not on a HTTPS server. Your webserver needs to have TLS activated in order to follow servers. It seems that you are not on a HTTPS server. Your webserver needs to have TLS activated in order to follow servers.
</div> </my-alert>
<div class="form-group inputs"> <div class="form-group inputs">
<input <input

View File

@ -7,6 +7,7 @@ import { UNIQUE_HOSTS_OR_HANDLE_VALIDATOR } from '@app/shared/form-validators/ho
import { FormReactive } from '@app/shared/shared-forms/form-reactive' import { FormReactive } from '@app/shared/shared-forms/form-reactive'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { InstanceFollowService } from '@app/shared/shared-instance/instance-follow.service' import { InstanceFollowService } from '@app/shared/shared-instance/instance-follow.service'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
import { splitAndGetNotEmpty } from '@root-helpers/string' import { splitAndGetNotEmpty } from '@root-helpers/string'
@ -17,7 +18,7 @@ import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.co
templateUrl: './follow-modal.component.html', templateUrl: './follow-modal.component.html',
styleUrls: [ './follow-modal.component.scss' ], styleUrls: [ './follow-modal.component.scss' ],
standalone: true, standalone: true,
imports: [ GlobalIconComponent, FormsModule, ReactiveFormsModule, NgClass, NgIf ] imports: [ GlobalIconComponent, FormsModule, ReactiveFormsModule, NgClass, NgIf, AlertComponent ]
}) })
export class FollowModalComponent extends FormReactive implements OnInit { export class FollowModalComponent extends FormReactive implements OnInit {
@ViewChild('modal', { static: true }) modal: NgbModal @ViewChild('modal', { static: true }) modal: NgbModal

View File

@ -13,9 +13,9 @@
<form novalidate [formGroup]="form" (ngSubmit)="processRegistration()"> <form novalidate [formGroup]="form" (ngSubmit)="processRegistration()">
<div class="modal-body mb-3"> <div class="modal-body mb-3">
<div i18n *ngIf="!registration.emailVerified" class="alert alert-warning"> <my-alert i18n *ngIf="!registration.emailVerified" type="warning">
Registration email has not been verified. Email delivery has been disabled by default. Registration email has not been verified. Email delivery has been disabled by default.
</div> </my-alert>
<div class="description"> <div class="description">
<ng-container *ngIf="isAccept()"> <ng-container *ngIf="isAccept()">
@ -27,9 +27,9 @@
An email will be sent to <em>{{ registration.email }}</em> explaining its account has been created with the moderation response you'll write below. An email will be sent to <em>{{ registration.email }}</em> explaining its account has been created with the moderation response you'll write below.
</p> </p>
<div *ngIf="!isEmailEnabled()" class="alert alert-warning" i18n> <my-alert *ngIf="!isEmailEnabled()" type="warning" i18n>
Emails are not enabled on this instance so PeerTube won't be able to send an email to <em>{{ registration.email }}</em> explaining its account has been created. Emails are not enabled on this instance so PeerTube won't be able to send an email to <em>{{ registration.email }}</em> explaining its account has been created.
</div> </my-alert>
</ng-container> </ng-container>
<ng-container *ngIf="isReject()"> <ng-container *ngIf="isReject()">
@ -37,9 +37,9 @@
An email will be sent to <em>{{ registration.email }}</em> explaining its registration request has been <strong>rejected</strong> with the moderation response you'll write below. An email will be sent to <em>{{ registration.email }}</em> explaining its registration request has been <strong>rejected</strong> with the moderation response you'll write below.
</p> </p>
<div *ngIf="!isEmailEnabled()" class="alert alert-warning" i18n> <my-alert *ngIf="!isEmailEnabled()" type="warning" i18n>
Emails are not enabled on this instance so PeerTube won't be able to send an email to <em>{{ registration.email }}</em> explaining its registration request has been rejected. Emails are not enabled on this instance so PeerTube won't be able to send an email to <em>{{ registration.email }}</em> explaining its registration request has been rejected.
</div> </my-alert>
</ng-container> </ng-container>
</div> </div>

View File

@ -1,22 +1,23 @@
import { NgClass, NgIf } from '@angular/common'
import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Notifier, ServerService } from '@app/core' import { Notifier, ServerService } from '@app/core'
import { FormReactive } from '@app/shared/shared-forms/form-reactive' import { FormReactive } from '@app/shared/shared-forms/form-reactive'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
import { UserRegistration } from '@peertube/peertube-models' import { UserRegistration } from '@peertube/peertube-models'
import { PeertubeCheckboxComponent } from '../../../shared/shared-forms/peertube-checkbox.component'
import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.component'
import { AdminRegistrationService } from './admin-registration.service' import { AdminRegistrationService } from './admin-registration.service'
import { REGISTRATION_MODERATION_RESPONSE_VALIDATOR } from './process-registration-validators' import { REGISTRATION_MODERATION_RESPONSE_VALIDATOR } from './process-registration-validators'
import { PeertubeCheckboxComponent } from '../../../shared/shared-forms/peertube-checkbox.component'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.component'
import { NgIf, NgClass } from '@angular/common'
@Component({ @Component({
selector: 'my-process-registration-modal', selector: 'my-process-registration-modal',
templateUrl: './process-registration-modal.component.html', templateUrl: './process-registration-modal.component.html',
standalone: true, standalone: true,
imports: [ NgIf, GlobalIconComponent, FormsModule, ReactiveFormsModule, NgClass, PeertubeCheckboxComponent ] imports: [ NgIf, GlobalIconComponent, FormsModule, ReactiveFormsModule, NgClass, PeertubeCheckboxComponent, AlertComponent ]
}) })
export class ProcessRegistrationModalComponent extends FormReactive implements OnInit { export class ProcessRegistrationModalComponent extends FormReactive implements OnInit {
@ViewChild('modal', { static: true }) modal: NgbModal @ViewChild('modal', { static: true }) modal: NgbModal

View File

@ -1,4 +1,6 @@
import { NgClass, NgFor, NgIf, NgTemplateOutlet } from '@angular/common'
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Router, RouterLink } from '@angular/router' import { Router, RouterLink } from '@angular/router'
import { ConfigService } from '@app/+admin/config/shared/config.service' import { ConfigService } from '@app/+admin/config/shared/config.service'
import { AuthService, Notifier, ScreenService, ServerService } from '@app/core' import { AuthService, Notifier, ScreenService, ServerService } from '@app/core'
@ -13,20 +15,19 @@ import {
USER_VIDEO_QUOTA_VALIDATOR USER_VIDEO_QUOTA_VALIDATOR
} from '@app/shared/form-validators/user-validators' } from '@app/shared/form-validators/user-validators'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { UserCreate, UserRole } from '@peertube/peertube-models' import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { UserEdit } from './user-edit'
import { BytesPipe } from '../../../../shared/shared-main/common/bytes.pipe'
import { UserPasswordComponent } from './user-password.component'
import { PeertubeCheckboxComponent } from '../../../../shared/shared-forms/peertube-checkbox.component'
import { UserRealQuotaInfoComponent } from '../../../shared/user-real-quota-info.component'
import { SelectCustomValueComponent } from '../../../../shared/shared-forms/select/select-custom-value.component'
import { InputTextComponent } from '../../../../shared/shared-forms/input-text.component'
import { PeerTubeTemplateDirective } from '../../../../shared/shared-main/common/peertube-template.directive'
import { HelpComponent } from '../../../../shared/shared-main/buttons/help.component'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { ActorAvatarEditComponent } from '../../../../shared/shared-actor-image-edit/actor-avatar-edit.component'
import { NgIf, NgTemplateOutlet, NgClass, NgFor } from '@angular/common'
import { UserAdminService } from '@app/shared/shared-users/user-admin.service' import { UserAdminService } from '@app/shared/shared-users/user-admin.service'
import { UserCreate, UserRole } from '@peertube/peertube-models'
import { ActorAvatarEditComponent } from '../../../../shared/shared-actor-image-edit/actor-avatar-edit.component'
import { InputTextComponent } from '../../../../shared/shared-forms/input-text.component'
import { PeertubeCheckboxComponent } from '../../../../shared/shared-forms/peertube-checkbox.component'
import { SelectCustomValueComponent } from '../../../../shared/shared-forms/select/select-custom-value.component'
import { HelpComponent } from '../../../../shared/shared-main/buttons/help.component'
import { BytesPipe } from '../../../../shared/shared-main/common/bytes.pipe'
import { PeerTubeTemplateDirective } from '../../../../shared/shared-main/common/peertube-template.directive'
import { UserRealQuotaInfoComponent } from '../../../shared/user-real-quota-info.component'
import { UserEdit } from './user-edit'
import { UserPasswordComponent } from './user-password.component'
@Component({ @Component({
selector: 'my-user-create', selector: 'my-user-create',
@ -49,7 +50,8 @@ import { UserAdminService } from '@app/shared/shared-users/user-admin.service'
UserRealQuotaInfoComponent, UserRealQuotaInfoComponent,
PeertubeCheckboxComponent, PeertubeCheckboxComponent,
UserPasswordComponent, UserPasswordComponent,
BytesPipe BytesPipe,
AlertComponent
] ]
}) })
export class UserCreateComponent extends UserEdit implements OnInit { export class UserCreateComponent extends UserEdit implements OnInit {

View File

@ -57,7 +57,7 @@
</div> </div>
</ng-template> </ng-template>
<div *ngIf="error" class="alert alert-danger">{{ error }}</div> <my-alert *ngIf="error" type="danger">{{ error }}</my-alert>
<div class="pt-two-cols d-xxl-none"> <!-- hidden on large screens, as it is then displayed on the right side of the form --> <div class="pt-two-cols d-xxl-none"> <!-- hidden on large screens, as it is then displayed on the right side of the form -->
<div class="col-0 col-xl-3"></div> <div class="col-0 col-xl-3"></div>

View File

@ -1,5 +1,6 @@
import { Subscription } from 'rxjs' import { NgClass, NgFor, NgIf, NgTemplateOutlet } from '@angular/common'
import { Component, OnDestroy, OnInit } from '@angular/core' import { Component, OnDestroy, OnInit } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { ActivatedRoute, Router, RouterLink } from '@angular/router' import { ActivatedRoute, Router, RouterLink } from '@angular/router'
import { ConfigService } from '@app/+admin/config/shared/config.service' import { ConfigService } from '@app/+admin/config/shared/config.service'
import { AuthService, Notifier, ScreenService, ServerService, User, UserService } from '@app/core' import { AuthService, Notifier, ScreenService, ServerService, User, UserService } from '@app/core'
@ -10,21 +11,21 @@ import {
USER_VIDEO_QUOTA_VALIDATOR USER_VIDEO_QUOTA_VALIDATOR
} from '@app/shared/form-validators/user-validators' } from '@app/shared/form-validators/user-validators'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { User as UserType, UserAdminFlag, UserRole, UserUpdate } from '@peertube/peertube-models' import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { UserEdit } from './user-edit'
import { BytesPipe } from '../../../../shared/shared-main/common/bytes.pipe'
import { UserPasswordComponent } from './user-password.component'
import { PeertubeCheckboxComponent } from '../../../../shared/shared-forms/peertube-checkbox.component'
import { UserRealQuotaInfoComponent } from '../../../shared/user-real-quota-info.component'
import { SelectCustomValueComponent } from '../../../../shared/shared-forms/select/select-custom-value.component'
import { InputTextComponent } from '../../../../shared/shared-forms/input-text.component'
import { PeerTubeTemplateDirective } from '../../../../shared/shared-main/common/peertube-template.directive'
import { HelpComponent } from '../../../../shared/shared-main/buttons/help.component'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { ActorAvatarEditComponent } from '../../../../shared/shared-actor-image-edit/actor-avatar-edit.component'
import { NgIf, NgTemplateOutlet, NgClass, NgFor } from '@angular/common'
import { UserAdminService } from '@app/shared/shared-users/user-admin.service'
import { TwoFactorService } from '@app/shared/shared-users/two-factor.service' import { TwoFactorService } from '@app/shared/shared-users/two-factor.service'
import { UserAdminService } from '@app/shared/shared-users/user-admin.service'
import { UserAdminFlag, UserRole, User as UserType, UserUpdate } from '@peertube/peertube-models'
import { Subscription } from 'rxjs'
import { ActorAvatarEditComponent } from '../../../../shared/shared-actor-image-edit/actor-avatar-edit.component'
import { InputTextComponent } from '../../../../shared/shared-forms/input-text.component'
import { PeertubeCheckboxComponent } from '../../../../shared/shared-forms/peertube-checkbox.component'
import { SelectCustomValueComponent } from '../../../../shared/shared-forms/select/select-custom-value.component'
import { HelpComponent } from '../../../../shared/shared-main/buttons/help.component'
import { BytesPipe } from '../../../../shared/shared-main/common/bytes.pipe'
import { PeerTubeTemplateDirective } from '../../../../shared/shared-main/common/peertube-template.directive'
import { UserRealQuotaInfoComponent } from '../../../shared/user-real-quota-info.component'
import { UserEdit } from './user-edit'
import { UserPasswordComponent } from './user-password.component'
@Component({ @Component({
selector: 'my-user-update', selector: 'my-user-update',
@ -47,7 +48,8 @@ import { TwoFactorService } from '@app/shared/shared-users/two-factor.service'
UserRealQuotaInfoComponent, UserRealQuotaInfoComponent,
PeertubeCheckboxComponent, PeertubeCheckboxComponent,
UserPasswordComponent, UserPasswordComponent,
BytesPipe BytesPipe,
AlertComponent
] ]
}) })
export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy { export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy {

View File

@ -1,8 +1,8 @@
<my-plugin-navigation [pluginType]="pluginType"></my-plugin-navigation> <my-plugin-navigation [pluginType]="pluginType"></my-plugin-navigation>
<div class="alert pt-alert-primary" i18n *ngIf="pluginInstalled"> <my-alert class="mt-3" type="primary" i18n *ngIf="pluginInstalled">
To load your new installed plugins or themes, refresh the page. To load your new installed plugins or themes, refresh the page.
</div> </my-alert>
<div class="result-and-search"> <div class="result-and-search">
<ng-container *ngIf="!search"> <ng-container *ngIf="!search">

View File

@ -25,7 +25,3 @@
@include margin-left(15px); @include margin-left(15px);
} }
.alert {
margin-top: 15px;
}

View File

@ -1,18 +1,19 @@
import { Subject } from 'rxjs' import { NgFor, NgIf } from '@angular/common'
import { debounceTime, distinctUntilChanged } from 'rxjs/operators'
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service' import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service'
import { ComponentPagination, ConfirmService, hasMoreItems, Notifier, PluginService } from '@app/core' import { ComponentPagination, ConfirmService, hasMoreItems, Notifier, PluginService } from '@app/core'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { PeerTubePluginIndex, PluginType, PluginType_Type } from '@peertube/peertube-models' import { PeerTubePluginIndex, PluginType, PluginType_Type } from '@peertube/peertube-models'
import { logger } from '@root-helpers/logger' import { logger } from '@root-helpers/logger'
import { Subject } from 'rxjs'
import { debounceTime, distinctUntilChanged } from 'rxjs/operators'
import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.component'
import { ButtonComponent } from '../../../shared/shared-main/buttons/button.component' import { ButtonComponent } from '../../../shared/shared-main/buttons/button.component'
import { EditButtonComponent } from '../../../shared/shared-main/buttons/edit-button.component' import { EditButtonComponent } from '../../../shared/shared-main/buttons/edit-button.component'
import { PluginCardComponent } from '../shared/plugin-card.component'
import { InfiniteScrollerDirective } from '../../../shared/shared-main/common/infinite-scroller.directive'
import { AutofocusDirective } from '../../../shared/shared-main/common/autofocus.directive' import { AutofocusDirective } from '../../../shared/shared-main/common/autofocus.directive'
import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.component' import { InfiniteScrollerDirective } from '../../../shared/shared-main/common/infinite-scroller.directive'
import { NgIf, NgFor } from '@angular/common' import { PluginCardComponent } from '../shared/plugin-card.component'
import { PluginNavigationComponent } from '../shared/plugin-navigation.component' import { PluginNavigationComponent } from '../shared/plugin-navigation.component'
@Component({ @Component({
@ -29,7 +30,8 @@ import { PluginNavigationComponent } from '../shared/plugin-navigation.component
NgFor, NgFor,
PluginCardComponent, PluginCardComponent,
EditButtonComponent, EditButtonComponent,
ButtonComponent ButtonComponent,
AlertComponent
] ]
}) })
export class PluginSearchComponent implements OnInit { export class PluginSearchComponent implements OnInit {

View File

@ -15,7 +15,7 @@
<div class="margin-content"> <div class="margin-content">
<ng-container *ngIf="!externalAuthError && !isAuthenticatedWithExternalAuth"> <ng-container *ngIf="!externalAuthError && !isAuthenticatedWithExternalAuth">
<div class="alert pt-alert-primary" role="alert"> <my-alert type="primary">
<h5 class="alert-heading" i18n> <h5 class="alert-heading" i18n>
Logging into an account lets you publish content Logging into an account lets you publish content
</h5> </h5>
@ -31,19 +31,19 @@
Find yours among multiple instances at: <a class="link-orange" href="https://joinpeertube.org/instances" target="_blank" rel="noopener noreferrer">https://joinpeertube.org/instances</a>. Find yours among multiple instances at: <a class="link-orange" href="https://joinpeertube.org/instances" target="_blank" rel="noopener noreferrer">https://joinpeertube.org/instances</a>.
</p> </p>
} }
</div> </my-alert>
<div class="alert alert-danger" i18n *ngIf="externalAuthError"> <my-alert type="danger" i18n *ngIf="externalAuthError">
Sorry but there was an issue with the external login process. Please <a class="link-orange" routerLink="/about">contact an administrator</a>. Sorry but there was an issue with the external login process. Please <a class="link-orange" routerLink="/about">contact an administrator</a>.
</div> </my-alert>
<div *ngIf="error" class="alert alert-danger" role="alert"> <my-alert *ngIf="error" type="danger">
{{ error }} {{ error }}
<a *ngIf="error === 'User email is not verified.'" class="ms-1 link-orange" i18n routerLink="/verify-account/ask-send-email"> <a *ngIf="error === 'User email is not verified.'" class="ms-1 link-orange" i18n routerLink="/verify-account/ask-send-email">
Request new verification email Request new verification email
</a> </a>
</div> </my-alert>
<div class="wrapper"> <div class="wrapper">
<div class="login-form-and-externals"> <div class="login-form-and-externals">
@ -137,9 +137,9 @@
<div class="modal-body text-start"> <div class="modal-body text-start">
<div *ngIf="isEmailDisabled()" class="alert alert-danger" i18n> <my-alert *ngIf="isEmailDisabled()" type="danger" i18n>
We are sorry, you cannot recover your password because your instance administrator did not configure the PeerTube email system. We are sorry, you cannot recover your password because your instance administrator did not configure the PeerTube email system.
</div> </my-alert>
<div *ngIf="!isEmailDisabled()" class="mb-4" i18n> <div *ngIf="!isEmailDisabled()" class="mb-4" i18n>
Enter your email address and we will send you a link to reset your password. Enter your email address and we will send you a link to reset your password.

View File

@ -25,11 +25,12 @@ input[type=email] {
} }
.wrapper, .wrapper,
.alert { my-alert {
display: block;
max-width: 1200px; max-width: 1200px;
} }
.alert { my-alert {
@include margin(0, auto, 2rem); @include margin(0, auto, 2rem);
} }

View File

@ -1,23 +1,24 @@
import { environment } from 'src/environments/environment' import { NgClass, NgFor, NgIf, NgTemplateOutlet } from '@angular/common'
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core' import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { ActivatedRoute, Router, RouterLink } from '@angular/router' import { ActivatedRoute, Router, RouterLink } from '@angular/router'
import { AuthService, Notifier, RedirectService, SessionStorageService, UserService } from '@app/core' import { AuthService, Notifier, RedirectService, SessionStorageService, UserService } from '@app/core'
import { HooksService } from '@app/core/plugins/hooks.service' import { HooksService } from '@app/core/plugins/hooks.service'
import { LOGIN_PASSWORD_VALIDATOR, LOGIN_USERNAME_VALIDATOR } from '@app/shared/form-validators/login-validators' import { LOGIN_PASSWORD_VALIDATOR, LOGIN_USERNAME_VALIDATOR } from '@app/shared/form-validators/login-validators'
import { USER_OTP_TOKEN_VALIDATOR } from '@app/shared/form-validators/user-validators' import { USER_OTP_TOKEN_VALIDATOR } from '@app/shared/form-validators/user-validators'
import { FormReactive } from '@app/shared/shared-forms/form-reactive'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { InputTextComponent } from '@app/shared/shared-forms/input-text.component'
import { InstanceAboutAccordionComponent } from '@app/shared/shared-instance/instance-about-accordion.component'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { NgbAccordionDirective, NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap' import { NgbAccordionDirective, NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
import { getExternalAuthHref } from '@peertube/peertube-core-utils' import { getExternalAuthHref } from '@peertube/peertube-core-utils'
import { RegisteredExternalAuthConfig, ServerConfig, ServerErrorCode } from '@peertube/peertube-models' import { RegisteredExternalAuthConfig, ServerConfig, ServerErrorCode } from '@peertube/peertube-models'
import { environment } from 'src/environments/environment'
import { GlobalIconComponent } from '../shared/shared-icons/global-icon.component' import { GlobalIconComponent } from '../shared/shared-icons/global-icon.component'
import { InstanceBannerComponent } from '../shared/shared-instance/instance-banner.component' import { InstanceBannerComponent } from '../shared/shared-instance/instance-banner.component'
import { AutofocusDirective } from '../shared/shared-main/common/autofocus.directive' import { AutofocusDirective } from '../shared/shared-main/common/autofocus.directive'
import { PluginSelectorDirective } from '../shared/shared-main/plugins/plugin-selector.directive' import { PluginSelectorDirective } from '../shared/shared-main/plugins/plugin-selector.directive'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgIf, NgClass, NgTemplateOutlet, NgFor } from '@angular/common'
import { InstanceAboutAccordionComponent } from '@app/shared/shared-instance/instance-about-accordion.component'
import { InputTextComponent } from '@app/shared/shared-forms/input-text.component'
import { FormReactive } from '@app/shared/shared-forms/form-reactive'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
@Component({ @Component({
selector: 'my-login', selector: 'my-login',
@ -37,7 +38,8 @@ import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.serv
NgFor, NgFor,
InstanceBannerComponent, InstanceBannerComponent,
InstanceAboutAccordionComponent, InstanceAboutAccordionComponent,
GlobalIconComponent GlobalIconComponent,
AlertComponent
] ]
}) })

View File

@ -1,6 +1,6 @@
import { of } from 'rxjs' import { NgClass, NgIf } from '@angular/common'
import { switchMap } from 'rxjs/operators'
import { AfterViewInit, Component, OnInit } from '@angular/core' import { AfterViewInit, Component, OnInit } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Router } from '@angular/router' import { Router } from '@angular/router'
import { AuthService, HooksService, Notifier } from '@app/core' import { AuthService, HooksService, Notifier } from '@app/core'
import { import {
@ -10,17 +10,18 @@ import {
VIDEO_CHANNEL_SUPPORT_VALIDATOR VIDEO_CHANNEL_SUPPORT_VALIDATOR
} from '@app/shared/form-validators/video-channel-validators' } from '@app/shared/form-validators/video-channel-validators'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { HttpStatusCode, VideoChannelCreate } from '@peertube/peertube-models'
import { VideoChannelEdit } from './video-channel-edit'
import { PeertubeCheckboxComponent } from '../../shared/shared-forms/peertube-checkbox.component'
import { MarkdownTextareaComponent } from '../../shared/shared-forms/markdown-textarea.component'
import { HelpComponent } from '../../shared/shared-main/buttons/help.component'
import { ActorAvatarEditComponent } from '../../shared/shared-actor-image-edit/actor-avatar-edit.component'
import { ActorBannerEditComponent } from '../../shared/shared-actor-image-edit/actor-banner-edit.component'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgIf, NgClass } from '@angular/common'
import { VideoChannel } from '@app/shared/shared-main/channel/video-channel.model' import { VideoChannel } from '@app/shared/shared-main/channel/video-channel.model'
import { VideoChannelService } from '@app/shared/shared-main/channel/video-channel.service' import { VideoChannelService } from '@app/shared/shared-main/channel/video-channel.service'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { HttpStatusCode, VideoChannelCreate } from '@peertube/peertube-models'
import { of } from 'rxjs'
import { switchMap } from 'rxjs/operators'
import { ActorAvatarEditComponent } from '../../shared/shared-actor-image-edit/actor-avatar-edit.component'
import { ActorBannerEditComponent } from '../../shared/shared-actor-image-edit/actor-banner-edit.component'
import { MarkdownTextareaComponent } from '../../shared/shared-forms/markdown-textarea.component'
import { PeertubeCheckboxComponent } from '../../shared/shared-forms/peertube-checkbox.component'
import { HelpComponent } from '../../shared/shared-main/buttons/help.component'
import { VideoChannelEdit } from './video-channel-edit'
@Component({ @Component({
templateUrl: './video-channel-edit.component.html', templateUrl: './video-channel-edit.component.html',
@ -35,7 +36,8 @@ import { VideoChannelService } from '@app/shared/shared-main/channel/video-chann
NgClass, NgClass,
HelpComponent, HelpComponent,
MarkdownTextareaComponent, MarkdownTextareaComponent,
PeertubeCheckboxComponent PeertubeCheckboxComponent,
AlertComponent
] ]
}) })
export class VideoChannelCreateComponent extends VideoChannelEdit implements OnInit, AfterViewInit { export class VideoChannelCreateComponent extends VideoChannelEdit implements OnInit, AfterViewInit {

View File

@ -1,4 +1,4 @@
<div *ngIf="error" class="alert alert-danger">{{ error }}</div> <my-alert *ngIf="error" type="danger">{{ error }}</my-alert>
<div class="margin-content pt-4"> <div class="margin-content pt-4">
<form role="form" (ngSubmit)="formValidated()" [formGroup]="form"> <form role="form" (ngSubmit)="formValidated()" [formGroup]="form">

View File

@ -12,6 +12,7 @@ import {
} from '@app/shared/form-validators/video-channel-validators' } from '@app/shared/form-validators/video-channel-validators'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { VideoChannelService } from '@app/shared/shared-main/channel/video-channel.service' import { VideoChannelService } from '@app/shared/shared-main/channel/video-channel.service'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { shallowCopy } from '@peertube/peertube-core-utils' import { shallowCopy } from '@peertube/peertube-core-utils'
import { VideoChannelUpdate } from '@peertube/peertube-models' import { VideoChannelUpdate } from '@peertube/peertube-models'
import { Subscription } from 'rxjs' import { Subscription } from 'rxjs'
@ -36,7 +37,8 @@ import { VideoChannelEdit } from './video-channel-edit'
NgClass, NgClass,
HelpComponent, HelpComponent,
MarkdownTextareaComponent, MarkdownTextareaComponent,
PeertubeCheckboxComponent PeertubeCheckboxComponent,
AlertComponent
] ]
}) })
export class VideoChannelUpdateComponent extends VideoChannelEdit implements OnInit, AfterViewInit, OnDestroy { export class VideoChannelUpdateComponent extends VideoChannelEdit implements OnInit, AfterViewInit, OnDestroy {

View File

@ -89,11 +89,11 @@
<div class="modal-body"> <div class="modal-body">
<div i18n class="alert alert-warning" *ngIf="hasAlreadyACompletedArchive()"> <my-alert i18n type="warning" *ngIf="hasAlreadyACompletedArchive()">
You already have an active archive. Requesting a new export archive will remove the current one. You already have an active archive. Requesting a new export archive will remove the current one.
</div> </my-alert>
<div *ngIf="errorInModal" class="alert alert-danger">{{ errorInModal }}</div> <my-alert *ngIf="errorInModal" type="danger">{{ errorInModal }}</my-alert>
<my-peertube-checkbox <my-peertube-checkbox
inputName="exportWithVideos" [(ngModel)]="exportWithVideosFiles" inputName="exportWithVideos" [(ngModel)]="exportWithVideosFiles"

View File

@ -2,6 +2,7 @@ import { DatePipe, NgFor, NgIf } from '@angular/common'
import { Component, Input, OnInit, ViewChild } from '@angular/core' import { Component, Input, OnInit, ViewChild } from '@angular/core'
import { FormsModule } from '@angular/forms' import { FormsModule } from '@angular/forms'
import { AuthService, ServerService } from '@app/core' import { AuthService, ServerService } from '@app/core'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap' import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
import { PeerTubeProblemDocument, ServerErrorCode, UserExport, UserExportState } from '@peertube/peertube-models' import { PeerTubeProblemDocument, ServerErrorCode, UserExport, UserExportState } from '@peertube/peertube-models'
import { concatMap, from, of, switchMap, toArray } from 'rxjs' import { concatMap, from, of, switchMap, toArray } from 'rxjs'
@ -15,7 +16,7 @@ import { UserImportExportService } from './user-import-export.service'
templateUrl: './my-account-export.component.html', templateUrl: './my-account-export.component.html',
styleUrls: [ './my-account-export.component.scss' ], styleUrls: [ './my-account-export.component.scss' ],
standalone: true, standalone: true,
imports: [ NgIf, NgFor, GlobalIconComponent, PeertubeCheckboxComponent, FormsModule, DatePipe, BytesPipe ] imports: [ NgIf, NgFor, GlobalIconComponent, PeertubeCheckboxComponent, FormsModule, DatePipe, BytesPipe, AlertComponent ]
}) })
export class MyAccountExportComponent implements OnInit { export class MyAccountExportComponent implements OnInit {
@ViewChild('exportModal', { static: true }) exportModal: NgbModal @ViewChild('exportModal', { static: true }) exportModal: NgbModal

View File

@ -48,9 +48,9 @@
</div> </div>
@if (hasPendingImport()) { @if (hasPendingImport()) {
<div i18n class="alert pt-alert-primary"> <my-alert i18n type="primary">
You can't re-import an archive because you already have an import that is currently being processed by PeerTube. You can't re-import an archive because you already have an import that is currently being processed by PeerTube.
</div> </my-alert>
} @else { } @else {
<my-upload-progress <my-upload-progress
[isUploading]="uploadingArchive" [uploadPercents]="uploadPercents" [error]="error" [uploaded]="archiveUploadFinished" [isUploading]="uploadingArchive" [uploadPercents]="uploadPercents" [error]="error" [uploaded]="archiveUploadFinished"
@ -58,9 +58,9 @@
> >
</my-upload-progress> </my-upload-progress>
<div *ngIf="archiveUploadFinished && !error" class="alert pt-alert-primary" i18n> <my-alert *ngIf="archiveUploadFinished && !error" type="primary" i18n>
Upload completed. Your archive import will be processed as soon as possible. Upload completed. Your archive import will be processed as soon as possible.
</div> </my-alert>
<div [hidden]="uploadingArchive || archiveUploadFinished" class="button-file form-control" i18n-ngbTooltip ngbTooltip="(extension: .zip)"> <div [hidden]="uploadingArchive || archiveUploadFinished" class="button-file form-control" i18n-ngbTooltip ngbTooltip="(extension: .zip)">
<span i18n>Select the archive file to import</span> <span i18n>Select the archive file to import</span>

View File

@ -6,6 +6,7 @@
@include orange-button; @include orange-button;
} }
.pt-alert-primary { my-alert {
display: block;
width: fit-content; width: fit-content;
} }

View File

@ -3,6 +3,7 @@ import { HttpErrorResponse } from '@angular/common/http'
import { Component, Input, OnDestroy, OnInit } from '@angular/core' import { Component, Input, OnDestroy, OnInit } from '@angular/core'
import { AuthService, CanComponentDeactivate, Notifier, ServerService } from '@app/core' import { AuthService, CanComponentDeactivate, Notifier, ServerService } from '@app/core'
import { buildHTTPErrorResponse, genericUploadErrorHandler, getUploadXRetryConfig } from '@app/helpers' import { buildHTTPErrorResponse, genericUploadErrorHandler, getUploadXRetryConfig } from '@app/helpers'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { BytesPipe } from '@app/shared/shared-main/common/bytes.pipe' import { BytesPipe } from '@app/shared/shared-main/common/bytes.pipe'
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap' import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'
import { HttpStatusCode, UserImport, UserImportState } from '@peertube/peertube-models' import { HttpStatusCode, UserImport, UserImportState } from '@peertube/peertube-models'
@ -16,7 +17,7 @@ import { UserImportExportService } from './user-import-export.service'
templateUrl: './my-account-import.component.html', templateUrl: './my-account-import.component.html',
styleUrls: [ './my-account-import.component.scss' ], styleUrls: [ './my-account-import.component.scss' ],
standalone: true, standalone: true,
imports: [ NgIf, UploadProgressComponent, NgbTooltip, DatePipe ] imports: [ NgIf, UploadProgressComponent, NgbTooltip, DatePipe, AlertComponent ]
}) })
export class MyAccountImportComponent implements OnInit, OnDestroy, CanComponentDeactivate { export class MyAccountImportComponent implements OnInit, OnDestroy, CanComponentDeactivate {
@Input() videoQuotaUsed: number @Input() videoQuotaUsed: number

View File

@ -1,5 +1,5 @@
<div *ngIf="error" class="alert alert-danger">{{ error }}</div> <my-alert *ngIf="error" type="danger">{{ error }}</my-alert>
<div *ngIf="success" class="alert alert-success">{{ success }}</div> <my-alert *ngIf="success" type="success">{{ success }}</my-alert>
<div i18n class="pending-email" *ngIf="user.pendingEmail"> <div i18n class="pending-email" *ngIf="user.pendingEmail">
<strong>{{ user.pendingEmail }}</strong> is awaiting email verification <strong>{{ user.pendingEmail }}</strong> is awaiting email verification

View File

@ -5,6 +5,7 @@ import { AuthService, ServerService, UserService } from '@app/core'
import { USER_EMAIL_VALIDATOR, USER_PASSWORD_VALIDATOR } from '@app/shared/form-validators/user-validators' import { USER_EMAIL_VALIDATOR, USER_PASSWORD_VALIDATOR } from '@app/shared/form-validators/user-validators'
import { FormReactive } from '@app/shared/shared-forms/form-reactive' import { FormReactive } from '@app/shared/shared-forms/form-reactive'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { HttpStatusCode, User } from '@peertube/peertube-models' import { HttpStatusCode, User } from '@peertube/peertube-models'
import { forkJoin } from 'rxjs' import { forkJoin } from 'rxjs'
import { tap } from 'rxjs/operators' import { tap } from 'rxjs/operators'
@ -15,7 +16,7 @@ import { InputTextComponent } from '../../../shared/shared-forms/input-text.comp
templateUrl: './my-account-change-email.component.html', templateUrl: './my-account-change-email.component.html',
styleUrls: [ './my-account-change-email.component.scss' ], styleUrls: [ './my-account-change-email.component.scss' ],
standalone: true, standalone: true,
imports: [ NgIf, FormsModule, ReactiveFormsModule, NgClass, InputTextComponent ] imports: [ NgIf, FormsModule, ReactiveFormsModule, NgClass, InputTextComponent, AlertComponent ]
}) })
export class MyAccountChangeEmailComponent extends FormReactive implements OnInit { export class MyAccountChangeEmailComponent extends FormReactive implements OnInit {
error: string error: string

View File

@ -1,4 +1,4 @@
<div *ngIf="error" class="alert alert-danger">{{ error }}</div> <my-alert *ngIf="error" type="danger">{{ error }}</my-alert>
<form role="form" (ngSubmit)="changePassword()" [formGroup]="form"> <form role="form" (ngSubmit)="changePassword()" [formGroup]="form">

View File

@ -1,5 +1,6 @@
import { filter } from 'rxjs/operators' import { NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { AuthService, Notifier, UserService } from '@app/core' import { AuthService, Notifier, UserService } from '@app/core'
import { import {
USER_CONFIRM_PASSWORD_VALIDATOR, USER_CONFIRM_PASSWORD_VALIDATOR,
@ -8,17 +9,17 @@ import {
} from '@app/shared/form-validators/user-validators' } from '@app/shared/form-validators/user-validators'
import { FormReactive } from '@app/shared/shared-forms/form-reactive' import { FormReactive } from '@app/shared/shared-forms/form-reactive'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { HttpStatusCode, User } from '@peertube/peertube-models' import { HttpStatusCode, User } from '@peertube/peertube-models'
import { filter } from 'rxjs/operators'
import { InputTextComponent } from '../../../shared/shared-forms/input-text.component' import { InputTextComponent } from '../../../shared/shared-forms/input-text.component'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgIf } from '@angular/common'
@Component({ @Component({
selector: 'my-account-change-password', selector: 'my-account-change-password',
templateUrl: './my-account-change-password.component.html', templateUrl: './my-account-change-password.component.html',
styleUrls: [ './my-account-change-password.component.scss' ], styleUrls: [ './my-account-change-password.component.scss' ],
standalone: true, standalone: true,
imports: [ NgIf, FormsModule, ReactiveFormsModule, InputTextComponent ] imports: [ NgIf, FormsModule, ReactiveFormsModule, InputTextComponent, AlertComponent ]
}) })
export class MyAccountChangePasswordComponent extends FormReactive implements OnInit { export class MyAccountChangePasswordComponent extends FormReactive implements OnInit {
error: string error: string

View File

@ -1,4 +1,4 @@
<div *ngIf="error" class="alert alert-danger">{{ error }}</div> <my-alert *ngIf="error" type="danger">{{ error }}</my-alert>
<form role="form" (ngSubmit)="updateMyProfile()" [formGroup]="form"> <form role="form" (ngSubmit)="updateMyProfile()" [formGroup]="form">

View File

@ -5,13 +5,14 @@ import { Notifier, User, UserService } from '@app/core'
import { USER_DESCRIPTION_VALIDATOR, USER_DISPLAY_NAME_REQUIRED_VALIDATOR } from '@app/shared/form-validators/user-validators' import { USER_DESCRIPTION_VALIDATOR, USER_DISPLAY_NAME_REQUIRED_VALIDATOR } from '@app/shared/form-validators/user-validators'
import { FormReactive } from '@app/shared/shared-forms/form-reactive' import { FormReactive } from '@app/shared/shared-forms/form-reactive'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
@Component({ @Component({
selector: 'my-account-profile', selector: 'my-account-profile',
templateUrl: './my-account-profile.component.html', templateUrl: './my-account-profile.component.html',
styleUrls: [ './my-account-profile.component.scss' ], styleUrls: [ './my-account-profile.component.scss' ],
standalone: true, standalone: true,
imports: [ NgIf, FormsModule, ReactiveFormsModule, NgClass ] imports: [ NgIf, FormsModule, ReactiveFormsModule, NgClass, AlertComponent ]
}) })
export class MyAccountProfileComponent extends FormReactive implements OnInit { export class MyAccountProfileComponent extends FormReactive implements OnInit {
@Input() user: User = null @Input() user: User = null

View File

@ -1,4 +1,4 @@
<div *ngIf="error" class="alert alert-danger">{{ error }}</div> <my-alert *ngIf="error" type="danger">{{ error }}</my-alert>
<h1> <h1>
<my-global-icon iconName="refresh" aria-hidden="true"></my-global-icon> <my-global-icon iconName="refresh" aria-hidden="true"></my-global-icon>

View File

@ -4,6 +4,7 @@ import { RouterLink } from '@angular/router'
import { AuthService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' import { AuthService, Notifier, RestPagination, RestTable, ServerService } from '@app/core'
import { VideoChannelSyncService } from '@app/shared/shared-main/channel/video-channel-sync.service' import { VideoChannelSyncService } from '@app/shared/shared-main/channel/video-channel-sync.service'
import { VideoChannelService } from '@app/shared/shared-main/channel/video-channel.service' import { VideoChannelService } from '@app/shared/shared-main/channel/video-channel.service'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap' import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'
import { HTMLServerConfig, VideoChannelSync, VideoChannelSyncState, VideoChannelSyncStateType } from '@peertube/peertube-models' import { HTMLServerConfig, VideoChannelSync, VideoChannelSyncState, VideoChannelSyncStateType } from '@peertube/peertube-models'
import { SharedModule, SortMeta } from 'primeng/api' import { SharedModule, SortMeta } from 'primeng/api'
@ -27,7 +28,8 @@ import { ActionDropdownComponent, DropdownAction } from '../../shared/shared-mai
ActionDropdownComponent, ActionDropdownComponent,
ActorAvatarComponent, ActorAvatarComponent,
NgClass, NgClass,
DatePipe DatePipe,
AlertComponent
] ]
}) })
export class MyVideoChannelSyncsComponent extends RestTable implements OnInit { export class MyVideoChannelSyncsComponent extends RestTable implements OnInit {

View File

@ -1,4 +1,4 @@
<div *ngIf="error" class="alert alert-danger">{{ error }}</div> <my-alert *ngIf="error" type="danger">{{ error }}</my-alert>
<div class="pt-two-cols"> <div class="pt-two-cols">

View File

@ -9,6 +9,7 @@ import { FormReactive } from '@app/shared/shared-forms/form-reactive'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { VideoChannelSyncService } from '@app/shared/shared-main/channel/video-channel-sync.service' import { VideoChannelSyncService } from '@app/shared/shared-main/channel/video-channel-sync.service'
import { VideoChannelService } from '@app/shared/shared-main/channel/video-channel.service' import { VideoChannelService } from '@app/shared/shared-main/channel/video-channel.service'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { VideoChannelSyncCreate } from '@peertube/peertube-models' import { VideoChannelSyncCreate } from '@peertube/peertube-models'
import { mergeMap } from 'rxjs' import { mergeMap } from 'rxjs'
import { SelectChannelItem } from 'src/types' import { SelectChannelItem } from 'src/types'
@ -19,7 +20,7 @@ import { SelectChannelComponent } from '../../../shared/shared-forms/select/sele
templateUrl: './video-channel-sync-edit.component.html', templateUrl: './video-channel-sync-edit.component.html',
styleUrls: [ './video-channel-sync-edit.component.scss' ], styleUrls: [ './video-channel-sync-edit.component.scss' ],
standalone: true, standalone: true,
imports: [ NgIf, FormsModule, ReactiveFormsModule, NgClass, SelectChannelComponent ] imports: [ NgIf, FormsModule, ReactiveFormsModule, NgClass, SelectChannelComponent, AlertComponent ]
}) })
export class VideoChannelSyncEditComponent extends FormReactive implements OnInit { export class VideoChannelSyncEditComponent extends FormReactive implements OnInit {
error: string error: string

View File

@ -1,4 +1,6 @@
import { NgClass, NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Router, RouterLink } from '@angular/router' import { Router, RouterLink } from '@angular/router'
import { AuthService, Notifier, ServerService } from '@app/core' import { AuthService, Notifier, ServerService } from '@app/core'
import { listUserChannelsForSelect } from '@app/helpers' import { listUserChannelsForSelect } from '@app/helpers'
@ -10,16 +12,15 @@ import {
VIDEO_PLAYLIST_PRIVACY_VALIDATOR VIDEO_PLAYLIST_PRIVACY_VALIDATOR
} from '@app/shared/form-validators/video-playlist-validators' } from '@app/shared/form-validators/video-playlist-validators'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { VideoPlaylistService } from '@app/shared/shared-video-playlist/video-playlist.service'
import { VideoPlaylistCreate, VideoPlaylistPrivacy } from '@peertube/peertube-models' import { VideoPlaylistCreate, VideoPlaylistPrivacy } from '@peertube/peertube-models'
import { MyVideoPlaylistEdit } from './my-video-playlist-edit' import { MarkdownTextareaComponent } from '../../shared/shared-forms/markdown-textarea.component'
import { PreviewUploadComponent } from '../../shared/shared-forms/preview-upload.component'
import { SelectChannelComponent } from '../../shared/shared-forms/select/select-channel.component' import { SelectChannelComponent } from '../../shared/shared-forms/select/select-channel.component'
import { SelectOptionsComponent } from '../../shared/shared-forms/select/select-options.component' import { SelectOptionsComponent } from '../../shared/shared-forms/select/select-options.component'
import { MarkdownTextareaComponent } from '../../shared/shared-forms/markdown-textarea.component'
import { HelpComponent } from '../../shared/shared-main/buttons/help.component' import { HelpComponent } from '../../shared/shared-main/buttons/help.component'
import { PreviewUploadComponent } from '../../shared/shared-forms/preview-upload.component' import { MyVideoPlaylistEdit } from './my-video-playlist-edit'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgIf, NgClass } from '@angular/common'
import { VideoPlaylistService } from '@app/shared/shared-video-playlist/video-playlist.service'
@Component({ @Component({
templateUrl: './my-video-playlist-edit.component.html', templateUrl: './my-video-playlist-edit.component.html',
@ -35,7 +36,8 @@ import { VideoPlaylistService } from '@app/shared/shared-video-playlist/video-pl
HelpComponent, HelpComponent,
MarkdownTextareaComponent, MarkdownTextareaComponent,
SelectOptionsComponent, SelectOptionsComponent,
SelectChannelComponent SelectChannelComponent,
AlertComponent
] ]
}) })
export class MyVideoPlaylistCreateComponent extends MyVideoPlaylistEdit implements OnInit { export class MyVideoPlaylistCreateComponent extends MyVideoPlaylistEdit implements OnInit {

View File

@ -1,4 +1,4 @@
<div *ngIf="error" class="alert alert-danger">{{ error }}</div> <my-alert *ngIf="error" type="danger">{{ error }}</my-alert>
<div class="pt-two-cols"> <!-- playlist grid --> <div class="pt-two-cols"> <!-- playlist grid -->
<div class="title-col"> <div class="title-col">

View File

@ -12,6 +12,7 @@ import {
VIDEO_PLAYLIST_PRIVACY_VALIDATOR VIDEO_PLAYLIST_PRIVACY_VALIDATOR
} from '@app/shared/form-validators/video-playlist-validators' } from '@app/shared/form-validators/video-playlist-validators'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { VideoPlaylistService } from '@app/shared/shared-video-playlist/video-playlist.service' import { VideoPlaylistService } from '@app/shared/shared-video-playlist/video-playlist.service'
import { VideoPlaylistUpdate } from '@peertube/peertube-models' import { VideoPlaylistUpdate } from '@peertube/peertube-models'
import { forkJoin, Subscription } from 'rxjs' import { forkJoin, Subscription } from 'rxjs'
@ -37,7 +38,8 @@ import { MyVideoPlaylistEdit } from './my-video-playlist-edit'
HelpComponent, HelpComponent,
MarkdownTextareaComponent, MarkdownTextareaComponent,
SelectOptionsComponent, SelectOptionsComponent,
SelectChannelComponent SelectChannelComponent,
AlertComponent
] ]
}) })
export class MyVideoPlaylistUpdateComponent extends MyVideoPlaylistEdit implements OnInit, OnDestroy { export class MyVideoPlaylistUpdateComponent extends MyVideoPlaylistEdit implements OnInit, OnDestroy {

View File

@ -1,5 +1,3 @@
<div class="root"> <div class="root">
<my-alert type="danger" *ngIf="error">{{ error }}</my-alert>
<div class="alert alert-danger" *ngIf="error">{{ error }}</div>
</div> </div>

View File

@ -1,16 +1,17 @@
import { forkJoin } from 'rxjs' import { NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { NgIf } from '@angular/common'
import { Video } from '@app/shared/shared-main/video/video.model'
import { VideoChannel } from '@app/shared/shared-main/channel/video-channel.model' import { VideoChannel } from '@app/shared/shared-main/channel/video-channel.model'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { Video } from '@app/shared/shared-main/video/video.model'
import { SearchService } from '@app/shared/shared-search/search.service' import { SearchService } from '@app/shared/shared-search/search.service'
import { forkJoin } from 'rxjs'
@Component({ @Component({
selector: 'my-remote-interaction', selector: 'my-remote-interaction',
templateUrl: './remote-interaction.component.html', templateUrl: './remote-interaction.component.html',
standalone: true, standalone: true,
imports: [ NgIf ] imports: [ NgIf, AlertComponent ]
}) })
export class RemoteInteractionComponent implements OnInit { export class RemoteInteractionComponent implements OnInit {
error = '' error = ''

View File

@ -27,7 +27,7 @@
<div id="search-results-filter" class="results-filter" [ngbCollapse]="isSearchFilterCollapsed" [animation]="true"> <div id="search-results-filter" class="results-filter" [ngbCollapse]="isSearchFilterCollapsed" [animation]="true">
<my-search-filters [advancedSearch]="advancedSearch" (filtered)="onFiltered()"></my-search-filters> <my-search-filters [advancedSearch]="advancedSearch" (filtered)="onFiltered()"></my-search-filters>
<div *ngIf="error" class="alert alert-danger">{{ error }}</div> <my-alert *ngIf="error" type="danger">{{ error }}</my-alert>
</div> </div>
</div> </div>

View File

@ -1,25 +1,26 @@
import { forkJoin, Subject, Subscription } from 'rxjs' import { NgFor, NgIf, NgTemplateOutlet } from '@angular/common'
import { LinkType } from 'src/types/link.type'
import { Component, OnDestroy, OnInit } from '@angular/core' import { Component, OnDestroy, OnInit } from '@angular/core'
import { ActivatedRoute, Router, RouterLink } from '@angular/router' import { ActivatedRoute, Router, RouterLink } from '@angular/router'
import { AuthService, HooksService, MetaService, Notifier, ServerService, User, UserService } from '@app/core' import { AuthService, HooksService, MetaService, Notifier, ServerService, User, UserService } from '@app/core'
import { immutableAssign, SimpleMemoize } from '@app/helpers' import { immutableAssign, SimpleMemoize } from '@app/helpers'
import { validateHost } from '@app/shared/form-validators/host-validators' import { validateHost } from '@app/shared/form-validators/host-validators'
import { HTMLServerConfig, SearchTargetType } from '@peertube/peertube-models'
import { NumberFormatterPipe } from '../shared/shared-main/common/number-formatter.pipe'
import { VideoPlaylistMiniatureComponent } from '../shared/shared-video-playlist/video-playlist-miniature.component'
import { MiniatureDisplayOptions, VideoMiniatureComponent } from '../shared/shared-video-miniature/video-miniature.component'
import { SubscribeButtonComponent } from '../shared/shared-user-subscription/subscribe-button.component'
import { ActorAvatarComponent } from '../shared/shared-actor-image/actor-avatar.component'
import { SearchFiltersComponent } from './search-filters.component'
import { NgbCollapse } from '@ng-bootstrap/ng-bootstrap'
import { NgIf, NgFor, NgTemplateOutlet } from '@angular/common'
import { InfiniteScrollerDirective } from '../shared/shared-main/common/infinite-scroller.directive'
import { VideoChannel } from '@app/shared/shared-main/channel/video-channel.model' import { VideoChannel } from '@app/shared/shared-main/channel/video-channel.model'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { Video } from '@app/shared/shared-main/video/video.model' import { Video } from '@app/shared/shared-main/video/video.model'
import { VideoPlaylist } from '@app/shared/shared-video-playlist/video-playlist.model'
import { AdvancedSearch } from '@app/shared/shared-search/advanced-search.model' import { AdvancedSearch } from '@app/shared/shared-search/advanced-search.model'
import { SearchService } from '@app/shared/shared-search/search.service' import { SearchService } from '@app/shared/shared-search/search.service'
import { VideoPlaylist } from '@app/shared/shared-video-playlist/video-playlist.model'
import { NgbCollapse } from '@ng-bootstrap/ng-bootstrap'
import { HTMLServerConfig, SearchTargetType } from '@peertube/peertube-models'
import { forkJoin, Subject, Subscription } from 'rxjs'
import { LinkType } from 'src/types/link.type'
import { ActorAvatarComponent } from '../shared/shared-actor-image/actor-avatar.component'
import { InfiniteScrollerDirective } from '../shared/shared-main/common/infinite-scroller.directive'
import { NumberFormatterPipe } from '../shared/shared-main/common/number-formatter.pipe'
import { SubscribeButtonComponent } from '../shared/shared-user-subscription/subscribe-button.component'
import { MiniatureDisplayOptions, VideoMiniatureComponent } from '../shared/shared-video-miniature/video-miniature.component'
import { VideoPlaylistMiniatureComponent } from '../shared/shared-video-playlist/video-playlist-miniature.component'
import { SearchFiltersComponent } from './search-filters.component'
@Component({ @Component({
selector: 'my-search', selector: 'my-search',
@ -38,7 +39,8 @@ import { SearchService } from '@app/shared/shared-search/search.service'
SubscribeButtonComponent, SubscribeButtonComponent,
VideoMiniatureComponent, VideoMiniatureComponent,
VideoPlaylistMiniatureComponent, VideoPlaylistMiniatureComponent,
NumberFormatterPipe NumberFormatterPipe,
AlertComponent
] ]
}) })
export class SearchComponent implements OnInit, OnDestroy { export class SearchComponent implements OnInit, OnDestroy {

View File

@ -1,7 +1,7 @@
<div> <div>
<div class="margin-content signup-disabled" *ngIf="signupDisabled"> <div class="margin-content signup-disabled" *ngIf="signupDisabled">
<div class="alert alert-warning" i18n>Signup is not enabled on this instance.</div> <my-alert type="warning" i18n>Signup is not enabled on this instance.</my-alert>
</div> </div>
<ng-container *ngIf="!signupDisabled"> <ng-container *ngIf="!signupDisabled">
@ -114,7 +114,7 @@
<div i18n>PeerTube is creating your account...</div> <div i18n>PeerTube is creating your account...</div>
</div> </div>
<div *ngIf="signupError" class="alert alert-danger">{{ signupError }}</div> <my-alert *ngIf="signupError" type="danger">{{ signupError }}</my-alert>
<my-signup-success-before-email <my-signup-success-before-email
*ngIf="signupSuccess" *ngIf="signupSuccess"

View File

@ -1,22 +1,23 @@
import { CdkStep, CdkStepperNext, CdkStepperPrevious } from '@angular/cdk/stepper' import { CdkStep, CdkStepperNext, CdkStepperPrevious } from '@angular/cdk/stepper'
import { NgIf } from '@angular/common'
import { Component, OnInit, ViewChild } from '@angular/core' import { Component, OnInit, ViewChild } from '@angular/core'
import { FormGroup } from '@angular/forms' import { FormGroup } from '@angular/forms'
import { ActivatedRoute, RouterLink } from '@angular/router' import { ActivatedRoute, RouterLink } from '@angular/router'
import { AuthService, ServerService } from '@app/core' import { AuthService, ServerService } from '@app/core'
import { HooksService } from '@app/core/plugins/hooks.service' import { HooksService } from '@app/core/plugins/hooks.service'
import { ServerConfig, ServerStats, UserRegister } from '@peertube/peertube-models'
import { SignupService } from '../shared/signup.service'
import { SignupSuccessBeforeEmailComponent } from '../shared/signup-success-before-email.component'
import { LoaderComponent } from '../../shared/shared-main/common/loader.component'
import { RegisterStepChannelComponent } from './steps/register-step-channel.component'
import { RegisterStepUserComponent } from './steps/register-step-user.component'
import { RegisterStepTermsComponent } from './steps/register-step-terms.component'
import { RegisterStepAboutComponent } from './steps/register-step-about.component'
import { SignupStepTitleComponent } from '../shared/signup-step-title.component'
import { CustomStepperComponent } from './custom-stepper.component'
import { SignupLabelComponent } from '../../shared/shared-main/users/signup-label.component'
import { NgIf } from '@angular/common'
import { InstanceAboutAccordionComponent } from '@app/shared/shared-instance/instance-about-accordion.component' import { InstanceAboutAccordionComponent } from '@app/shared/shared-instance/instance-about-accordion.component'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { ServerConfig, ServerStats, UserRegister } from '@peertube/peertube-models'
import { LoaderComponent } from '../../shared/shared-main/common/loader.component'
import { SignupLabelComponent } from '../../shared/shared-main/users/signup-label.component'
import { SignupStepTitleComponent } from '../shared/signup-step-title.component'
import { SignupSuccessBeforeEmailComponent } from '../shared/signup-success-before-email.component'
import { SignupService } from '../shared/signup.service'
import { CustomStepperComponent } from './custom-stepper.component'
import { RegisterStepAboutComponent } from './steps/register-step-about.component'
import { RegisterStepChannelComponent } from './steps/register-step-channel.component'
import { RegisterStepTermsComponent } from './steps/register-step-terms.component'
import { RegisterStepUserComponent } from './steps/register-step-user.component'
@Component({ @Component({
selector: 'my-register', selector: 'my-register',
@ -38,7 +39,8 @@ import { InstanceAboutAccordionComponent } from '@app/shared/shared-instance/ins
RegisterStepUserComponent, RegisterStepUserComponent,
RegisterStepChannelComponent, RegisterStepChannelComponent,
LoaderComponent, LoaderComponent,
SignupSuccessBeforeEmailComponent SignupSuccessBeforeEmailComponent,
AlertComponent
] ]
}) })
export class RegisterComponent implements OnInit { export class RegisterComponent implements OnInit {

View File

@ -1,10 +1,12 @@
<my-instance-banner class="d-block mb-4" rounded="true"></my-instance-banner> <my-instance-banner class="d-block mb-4" rounded="true"></my-instance-banner>
<p class="alert pt-alert-primary text-center" *ngIf="requiresApproval"> <my-alert *ngIf="requiresApproval" type="primary" class="text-center">
<ng-container i18n>Moderators of {{ instanceName }} will have to approve your registration request once you have finished to fill the form.</ng-container> <p>
<ng-container i18n>Moderators of {{ instanceName }} will have to approve your registration request once you have finished to fill the form.</ng-container>
<ng-container *ngIf="averageResponseTime" i18n>They usually respond within {{ averageResponseTime | myDaysDurationFormatter }}.</ng-container> <ng-container *ngIf="averageResponseTime" i18n>They usually respond within {{ averageResponseTime | myDaysDurationFormatter }}.</ng-container>
</p> </p>
</my-alert>
<div class="why"> <div class="why">
<h3 i18n>Why creating an account?</h3> <h3 i18n>Why creating an account?</h3>

View File

@ -1,16 +1,17 @@
import { NgIf } from '@angular/common'
import { Component, Input } from '@angular/core' import { Component, Input } from '@angular/core'
import { ServerService } from '@app/core' import { ServerService } from '@app/core'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { ServerStats } from '@peertube/peertube-models' import { ServerStats } from '@peertube/peertube-models'
import { DaysDurationFormatterPipe } from '../../../shared/shared-main/date/days-duration-formatter.pipe'
import { NgIf } from '@angular/common'
import { InstanceBannerComponent } from '../../../shared/shared-instance/instance-banner.component' import { InstanceBannerComponent } from '../../../shared/shared-instance/instance-banner.component'
import { DaysDurationFormatterPipe } from '../../../shared/shared-main/date/days-duration-formatter.pipe'
@Component({ @Component({
selector: 'my-register-step-about', selector: 'my-register-step-about',
templateUrl: './register-step-about.component.html', templateUrl: './register-step-about.component.html',
styleUrls: [ './register-step-about.component.scss' ], styleUrls: [ './register-step-about.component.scss' ],
standalone: true, standalone: true,
imports: [ InstanceBannerComponent, NgIf, DaysDurationFormatterPipe ] imports: [ InstanceBannerComponent, NgIf, DaysDurationFormatterPipe, AlertComponent ]
}) })
export class RegisterStepAboutComponent { export class RegisterStepAboutComponent {
@Input() requiresApproval: boolean @Input() requiresApproval: boolean

View File

@ -1,6 +1,6 @@
<div class="alert pt-alert-primary" i18n *ngIf="videoUploadDisabled"> <my-alert type="primary" i18n *ngIf="videoUploadDisabled">
Video uploads are disabled on this instance, hence your account won't be able to upload videos. Video uploads are disabled on this instance, hence your account won't be able to upload videos.
</div> </my-alert>
<form role="form" [formGroup]="form"> <form role="form" [formGroup]="form">
<div class="row"> <div class="row">

View File

@ -1,5 +1,4 @@
import { concat, of } from 'rxjs' import { NgClass, NgIf } from '@angular/common'
import { pairwise } from 'rxjs/operators'
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core' import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'
import { SignupService } from '@app/+signup/shared/signup.service' import { SignupService } from '@app/+signup/shared/signup.service'
@ -11,15 +10,17 @@ import {
} from '@app/shared/form-validators/user-validators' } from '@app/shared/form-validators/user-validators'
import { FormReactive } from '@app/shared/shared-forms/form-reactive' import { FormReactive } from '@app/shared/shared-forms/form-reactive'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { concat, of } from 'rxjs'
import { pairwise } from 'rxjs/operators'
import { InputTextComponent } from '../../../shared/shared-forms/input-text.component' import { InputTextComponent } from '../../../shared/shared-forms/input-text.component'
import { NgIf, NgClass } from '@angular/common'
@Component({ @Component({
selector: 'my-register-step-user', selector: 'my-register-step-user',
templateUrl: './register-step-user.component.html', templateUrl: './register-step-user.component.html',
styleUrls: [ './step.component.scss' ], styleUrls: [ './step.component.scss' ],
standalone: true, standalone: true,
imports: [ NgIf, FormsModule, ReactiveFormsModule, NgClass, InputTextComponent ] imports: [ NgIf, FormsModule, ReactiveFormsModule, NgClass, InputTextComponent, AlertComponent ]
}) })
export class RegisterStepUserComponent extends FormReactive implements OnInit { export class RegisterStepUserComponent extends FormReactive implements OnInit {
@Input() videoUploadDisabled = false @Input() videoUploadDisabled = false

View File

@ -7,13 +7,13 @@
> >
</my-signup-success-after-email> </my-signup-success-after-email>
<div i18n class="alert alert-success" *ngIf="!isRegistrationRequest() && isPendingEmail && success">Email updated.</div> <my-alert type="success" i18n *ngIf="!isRegistrationRequest() && isPendingEmail && success">Email updated.</my-alert>
<div class="alert alert-danger" *ngIf="failed"> <my-alert type="danger" *ngIf="failed">
<span i18n>An error occurred.</span> <span i18n>An error occurred.</span>
<a i18n class="ms-1 link-orange" routerLink="/verify-account/ask-send-email"> <a i18n class="ms-1 link-orange" routerLink="/verify-account/ask-send-email">
Request a new verification email Request a new verification email
</a> </a>
</div> </my-alert>
</div> </div>

View File

@ -1,15 +1,16 @@
import { NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { ActivatedRoute, RouterLink } from '@angular/router' import { ActivatedRoute, RouterLink } from '@angular/router'
import { SignupService } from '@app/+signup/shared/signup.service' import { SignupService } from '@app/+signup/shared/signup.service'
import { AuthService, Notifier, ServerService } from '@app/core' import { AuthService, Notifier, ServerService } from '@app/core'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { SignupSuccessAfterEmailComponent } from '../../shared/signup-success-after-email.component' import { SignupSuccessAfterEmailComponent } from '../../shared/signup-success-after-email.component'
import { NgIf } from '@angular/common'
@Component({ @Component({
selector: 'my-verify-account-email', selector: 'my-verify-account-email',
templateUrl: './verify-account-email.component.html', templateUrl: './verify-account-email.component.html',
standalone: true, standalone: true,
imports: [ NgIf, SignupSuccessAfterEmailComponent, RouterLink ] imports: [ NgIf, SignupSuccessAfterEmailComponent, RouterLink, AlertComponent ]
}) })
export class VerifyAccountEmailComponent implements OnInit { export class VerifyAccountEmailComponent implements OnInit {

View File

@ -2,7 +2,7 @@
<strong i18n>Email verified!</strong> <strong i18n>Email verified!</strong>
</my-signup-step-title> </my-signup-step-title>
<div class="alert pt-alert-primary"> <my-alert type="primary">
<ng-container *ngIf="requiresApproval"> <ng-container *ngIf="requiresApproval">
<p i18n>Your email has been verified and your account request has been sent!</p> <p i18n>Your email has been verified and your account request has been sent!</p>
@ -18,4 +18,4 @@
If you need help using PeerTube, you can have a look at the <a class="link-orange" href="https://docs.joinpeertube.org/use/setup-account" target="_blank" rel="noopener noreferrer">documentation</a>. If you need help using PeerTube, you can have a look at the <a class="link-orange" href="https://docs.joinpeertube.org/use/setup-account" target="_blank" rel="noopener noreferrer">documentation</a>.
</p> </p>
</ng-container> </ng-container>
</div> </my-alert>

View File

@ -1,5 +1,6 @@
import { Component, Input } from '@angular/core'
import { NgIf } from '@angular/common' import { NgIf } from '@angular/common'
import { Component, Input } from '@angular/core'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { SignupStepTitleComponent } from './signup-step-title.component' import { SignupStepTitleComponent } from './signup-step-title.component'
@Component({ @Component({
@ -7,7 +8,7 @@ import { SignupStepTitleComponent } from './signup-step-title.component'
templateUrl: './signup-success-after-email.component.html', templateUrl: './signup-success-after-email.component.html',
styleUrls: [ './signup-success.component.scss' ], styleUrls: [ './signup-success.component.scss' ],
standalone: true, standalone: true,
imports: [ SignupStepTitleComponent, NgIf ] imports: [ SignupStepTitleComponent, NgIf, AlertComponent ]
}) })
export class SignupSuccessAfterEmailComponent { export class SignupSuccessAfterEmailComponent {
@Input() requiresApproval: boolean @Input() requiresApproval: boolean

View File

@ -9,7 +9,7 @@
</ng-container> </ng-container>
</my-signup-step-title> </my-signup-step-title>
<div class="alert pt-alert-primary"> <my-alert type="primary">
<p *ngIf="requiresApproval" i18n>Your account request has been sent!</p> <p *ngIf="requiresApproval" i18n>Your account request has been sent!</p>
<p *ngIf="!requiresApproval" i18n>Your account has been created!</p> <p *ngIf="!requiresApproval" i18n>Your account has been created!</p>
@ -32,4 +32,4 @@
If you need help using PeerTube, you can have a look at the <a class="link-orange" href="https://docs.joinpeertube.org/use/setup-account" target="_blank" rel="noopener noreferrer">documentation</a>. If you need help using PeerTube, you can have a look at the <a class="link-orange" href="https://docs.joinpeertube.org/use/setup-account" target="_blank" rel="noopener noreferrer">documentation</a>.
</p> </p>
</ng-container> </ng-container>
</div> </my-alert>

View File

@ -1,5 +1,6 @@
import { Component, Input } from '@angular/core'
import { NgIf } from '@angular/common' import { NgIf } from '@angular/common'
import { Component, Input } from '@angular/core'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { SignupStepTitleComponent } from './signup-step-title.component' import { SignupStepTitleComponent } from './signup-step-title.component'
@Component({ @Component({
@ -7,7 +8,7 @@ import { SignupStepTitleComponent } from './signup-step-title.component'
templateUrl: './signup-success-before-email.component.html', templateUrl: './signup-success-before-email.component.html',
styleUrls: [ './signup-success.component.scss' ], styleUrls: [ './signup-success.component.scss' ],
standalone: true, standalone: true,
imports: [ SignupStepTitleComponent, NgIf ] imports: [ SignupStepTitleComponent, NgIf, AlertComponent ]
}) })
export class SignupSuccessBeforeEmailComponent { export class SignupSuccessBeforeEmailComponent {
@Input() requiresApproval: boolean @Input() requiresApproval: boolean

View File

@ -1,4 +1,5 @@
.alert { my-alert {
display: block;
font-size: 18px; font-size: 18px;
max-width: 900px; max-width: 900px;
text-align: center; text-align: center;

View File

@ -174,9 +174,9 @@
<ng-template ngbNavContent> <ng-template ngbNavContent>
<div class="captions"> <div class="captions">
<div class="alert pt-alert-primary" *ngIf="displayTranscriptionInfo && isTranscriptionEnabled() && !hasCaptions()" i18n> <my-alert type="primary" *ngIf="displayTranscriptionInfo && isTranscriptionEnabled() && !hasCaptions()" i18n>
A subtitle will be automatically generated from your video. A subtitle will be automatically generated from your video.
</div> </my-alert>
<div class="form-group" *ngFor="let videoCaption of videoCaptions"> <div class="form-group" *ngFor="let videoCaption of videoCaptions">
@ -246,11 +246,11 @@
<ng-template ngbNavContent> <ng-template ngbNavContent>
<div class="row mb-5"> <div class="row mb-5">
<div class="chapters col-md-12 col-xl-6" formArrayName="chapters"> <div class="chapters col-md-12 col-xl-6" formArrayName="chapters">
<div i18n class="alert pt-alert-primary"> <my-alert type="primary" i18n>
Chapters can also be set in the video description. Chapters can also be set in the video description.
Check the format <a href="https://docs.joinpeertube.org/use/create-upload-video#chapters" target="_blank">in the PeerTube documentation</a> Check the format <a href="https://docs.joinpeertube.org/use/create-upload-video#chapters" target="_blank">in the PeerTube documentation</a>
</div> </my-alert>
<ng-container *ngFor="let chapterControl of getChaptersFormArray().controls; let i = index"> <ng-container *ngFor="let chapterControl of getChaptersFormArray().controls; let i = index">
<div class="chapter" [formGroupName]="i"> <div class="chapter" [formGroupName]="i">
@ -303,9 +303,9 @@
<ng-template ngbNavContent> <ng-template ngbNavContent>
<div class="row live-settings"> <div class="row live-settings">
<div class="col-md-12"> <div class="col-md-12">
<div class="alert pt-alert-primary"> <my-alert type="primary">
<my-live-documentation-link></my-live-documentation-link> <my-live-documentation-link></my-live-documentation-link>
</div> </my-alert>
<div *ngIf="liveVideo.rtmpUrl" class="form-group"> <div *ngIf="liveVideo.rtmpUrl" class="form-group">
<label for="liveVideoRTMPUrl" i18n>Live RTMP Url</label> <label for="liveVideoRTMPUrl" i18n>Live RTMP Url</label>

View File

@ -32,6 +32,7 @@ import {
} from '@app/shared/form-validators/video-validators' } from '@app/shared/form-validators/video-validators'
import { FormReactiveErrors, FormReactiveValidationMessages } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveErrors, FormReactiveValidationMessages } from '@app/shared/shared-forms/form-reactive.service'
import { FormValidatorService } from '@app/shared/shared-forms/form-validator.service' import { FormValidatorService } from '@app/shared/shared-forms/form-validator.service'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { InstanceService } from '@app/shared/shared-main/instance/instance.service' import { InstanceService } from '@app/shared/shared-main/instance/instance.service'
import { VideoCaptionEdit, VideoCaptionWithPathEdit } from '@app/shared/shared-main/video-caption/video-caption-edit.model' import { VideoCaptionEdit, VideoCaptionWithPathEdit } from '@app/shared/shared-main/video-caption/video-caption-edit.model'
import { VideoChaptersEdit } from '@app/shared/shared-main/video/video-chapters-edit.model' import { VideoChaptersEdit } from '@app/shared/shared-main/video/video-chapters-edit.model'
@ -68,10 +69,11 @@ import { SelectOptionsComponent } from '../../../shared/shared-forms/select/sele
import { SelectTagsComponent } from '../../../shared/shared-forms/select/select-tags.component' import { SelectTagsComponent } from '../../../shared/shared-forms/select/select-tags.component'
import { TimestampInputComponent } from '../../../shared/shared-forms/timestamp-input.component' import { TimestampInputComponent } from '../../../shared/shared-forms/timestamp-input.component'
import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.component' import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.component'
import { PeerTubeTemplateDirective } from '../../../shared/shared-main/common/peertube-template.directive' import { ButtonComponent } from '../../../shared/shared-main/buttons/button.component'
import { DeleteButtonComponent } from '../../../shared/shared-main/buttons/delete-button.component' import { DeleteButtonComponent } from '../../../shared/shared-main/buttons/delete-button.component'
import { EditButtonComponent } from '../../../shared/shared-main/buttons/edit-button.component' import { EditButtonComponent } from '../../../shared/shared-main/buttons/edit-button.component'
import { HelpComponent } from '../../../shared/shared-main/buttons/help.component' import { HelpComponent } from '../../../shared/shared-main/buttons/help.component'
import { PeerTubeTemplateDirective } from '../../../shared/shared-main/common/peertube-template.directive'
import { EmbedComponent } from '../../../shared/shared-main/video/embed.component' import { EmbedComponent } from '../../../shared/shared-main/video/embed.component'
import { LiveDocumentationLinkComponent } from '../../../shared/shared-video-live/live-documentation-link.component' import { LiveDocumentationLinkComponent } from '../../../shared/shared-video-live/live-documentation-link.component'
import { VideoCaptionAddModalComponent } from './caption/video-caption-add-modal.component' import { VideoCaptionAddModalComponent } from './caption/video-caption-add-modal.component'
@ -79,7 +81,6 @@ import { VideoCaptionEditModalContentComponent } from './caption/video-caption-e
import { I18nPrimengCalendarService } from './i18n-primeng-calendar.service' import { I18nPrimengCalendarService } from './i18n-primeng-calendar.service'
import { ThumbnailManagerComponent } from './thumbnail-manager/thumbnail-manager.component' import { ThumbnailManagerComponent } from './thumbnail-manager/thumbnail-manager.component'
import { VideoEditType } from './video-edit.type' import { VideoEditType } from './video-edit.type'
import { ButtonComponent } from '../../../shared/shared-main/buttons/button.component'
type VideoLanguages = VideoConstant<string> & { group?: string } type VideoLanguages = VideoConstant<string> & { group?: string }
type PluginField = { type PluginField = {
@ -126,7 +127,8 @@ type PluginField = {
DatePipe, DatePipe,
ThumbnailManagerComponent, ThumbnailManagerComponent,
EditButtonComponent, EditButtonComponent,
ButtonComponent ButtonComponent,
AlertComponent
] ]
}) })
export class VideoEditComponent implements OnInit, OnDestroy { export class VideoEditComponent implements OnInit, OnDestroy {

View File

@ -39,15 +39,16 @@
</div> </div>
</div> </div>
<div *ngIf="error" class="alert alert-danger"> <my-alert *ngIf="error" type="danger">
<div i18n>Sorry, but something went wrong</div> <div i18n>Sorry, but something went wrong</div>
{{ error }}
</div>
<div class="alert pt-alert-primary" i18n *ngIf="isInUpdateForm && getMaxLiveDuration() >= 0"> {{ error }}
</my-alert>
<my-alert type="primary" i18n *ngIf="isInUpdateForm && getMaxLiveDuration() >= 0">
Max live duration is {{ getMaxLiveDuration() | myTimeDurationFormatter }}. Max live duration is {{ getMaxLiveDuration() | myTimeDurationFormatter }}.
If your live reaches this limit, it will be automatically terminated. If your live reaches this limit, it will be automatically terminated.
</div> </my-alert>
<!-- Hidden because we want to load the component --> <!-- Hidden because we want to load the component -->
<form [hidden]="!isInUpdateForm" novalidate [formGroup]="form"> <form [hidden]="!isInUpdateForm" novalidate [formGroup]="form">

View File

@ -1,11 +1,18 @@
import { forkJoin } from 'rxjs' import { NgIf } from '@angular/common'
import { AfterViewInit, Component, EventEmitter, OnInit, Output } from '@angular/core' import { AfterViewInit, Component, EventEmitter, OnInit, Output } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Router } from '@angular/router' import { Router } from '@angular/router'
import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService } from '@app/core' import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService } from '@app/core'
import { scrollToTop } from '@app/helpers' import { scrollToTop } from '@app/helpers'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { VideoCaptionService } from '@app/shared/shared-main/video-caption/video-caption.service'
import { VideoChapterService } from '@app/shared/shared-main/video/video-chapter.service'
import { VideoEdit } from '@app/shared/shared-main/video/video-edit.model'
import { Video } from '@app/shared/shared-main/video/video.model'
import { VideoService } from '@app/shared/shared-main/video/video.service'
import { LiveVideoService } from '@app/shared/shared-video-live/live-video.service'
import { LoadingBarService } from '@ngx-loading-bar/core' import { LoadingBarService } from '@ngx-loading-bar/core'
import { logger } from '@root-helpers/logger'
import { import {
LiveVideo, LiveVideo,
LiveVideoCreate, LiveVideoCreate,
@ -15,21 +22,15 @@ import {
ServerErrorCode, ServerErrorCode,
VideoPrivacy VideoPrivacy
} from '@peertube/peertube-models' } from '@peertube/peertube-models'
import { VideoSend } from './video-send' import { logger } from '@root-helpers/logger'
import { TimeDurationFormatterPipe } from '../../../shared/shared-main/date/time-duration-formatter.pipe' import { forkJoin } from 'rxjs'
import { ButtonComponent } from '../../../shared/shared-main/buttons/button.component'
import { VideoEditComponent } from '../shared/video-edit.component'
import { SelectOptionsComponent } from '../../../shared/shared-forms/select/select-options.component'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { SelectChannelComponent } from '../../../shared/shared-forms/select/select-channel.component' import { SelectChannelComponent } from '../../../shared/shared-forms/select/select-channel.component'
import { SelectOptionsComponent } from '../../../shared/shared-forms/select/select-options.component'
import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.component' import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.component'
import { NgIf } from '@angular/common' import { ButtonComponent } from '../../../shared/shared-main/buttons/button.component'
import { VideoCaptionService } from '@app/shared/shared-main/video-caption/video-caption.service' import { TimeDurationFormatterPipe } from '../../../shared/shared-main/date/time-duration-formatter.pipe'
import { VideoChapterService } from '@app/shared/shared-main/video/video-chapter.service' import { VideoEditComponent } from '../shared/video-edit.component'
import { VideoEdit } from '@app/shared/shared-main/video/video-edit.model' import { VideoSend } from './video-send'
import { Video } from '@app/shared/shared-main/video/video.model'
import { VideoService } from '@app/shared/shared-main/video/video.service'
import { LiveVideoService } from '@app/shared/shared-video-live/live-video.service'
@Component({ @Component({
selector: 'my-video-go-live', selector: 'my-video-go-live',
@ -49,7 +50,8 @@ import { LiveVideoService } from '@app/shared/shared-video-live/live-video.servi
ReactiveFormsModule, ReactiveFormsModule,
VideoEditComponent, VideoEditComponent,
ButtonComponent, ButtonComponent,
TimeDurationFormatterPipe TimeDurationFormatterPipe,
AlertComponent
] ]
}) })
export class VideoGoLiveComponent extends VideoSend implements OnInit, AfterViewInit, CanComponentDeactivate { export class VideoGoLiveComponent extends VideoSend implements OnInit, AfterViewInit, CanComponentDeactivate {

View File

@ -47,14 +47,15 @@
</div> </div>
</div> </div>
<div *ngIf="error" class="alert alert-danger"> <my-alert *ngIf="error" type="danger">
<div i18n>Sorry, but something went wrong</div> <div i18n>Sorry, but something went wrong</div>
{{ error }}
</div>
<div *ngIf="hasImportedVideo && !error" class="alert pt-alert-primary" i18n> {{ error }}
</my-alert>
<my-alert type="primary" *ngIf="hasImportedVideo && !error" i18n>
Congratulations, the video will be imported with BitTorrent! You can already add information about this video. Congratulations, the video will be imported with BitTorrent! You can already add information about this video.
</div> </my-alert>
<!-- Hidden because we want to load the component --> <!-- Hidden because we want to load the component -->
<form [hidden]="!hasImportedVideo" novalidate [formGroup]="form"> <form [hidden]="!hasImportedVideo" novalidate [formGroup]="form">

View File

@ -1,30 +1,31 @@
import { switchMap } from 'rxjs' import { NgIf } from '@angular/common'
import { AfterViewInit, Component, ElementRef, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' import { AfterViewInit, Component, ElementRef, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Router } from '@angular/router' import { Router } from '@angular/router'
import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService } from '@app/core' import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService } from '@app/core'
import { scrollToTop } from '@app/helpers' import { scrollToTop } from '@app/helpers'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { LoadingBarService } from '@ngx-loading-bar/core' import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { logger } from '@root-helpers/logger'
import { PeerTubeProblemDocument, ServerErrorCode, VideoUpdate } from '@peertube/peertube-models'
import { hydrateFormFromVideo } from '../shared/video-edit-utils'
import { VideoSend } from './video-send'
import { ButtonComponent } from '../../../shared/shared-main/buttons/button.component'
import { VideoEditComponent } from '../shared/video-edit.component'
import { SelectOptionsComponent } from '../../../shared/shared-forms/select/select-options.component'
import { SelectChannelComponent } from '../../../shared/shared-forms/select/select-channel.component'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { PeerTubeTemplateDirective } from '../../../shared/shared-main/common/peertube-template.directive'
import { HelpComponent } from '../../../shared/shared-main/buttons/help.component'
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'
import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.component'
import { DragDropDirective } from './drag-drop.directive'
import { NgIf } from '@angular/common'
import { VideoCaptionService } from '@app/shared/shared-main/video-caption/video-caption.service' import { VideoCaptionService } from '@app/shared/shared-main/video-caption/video-caption.service'
import { VideoChapterService } from '@app/shared/shared-main/video/video-chapter.service' import { VideoChapterService } from '@app/shared/shared-main/video/video-chapter.service'
import { VideoEdit } from '@app/shared/shared-main/video/video-edit.model' import { VideoEdit } from '@app/shared/shared-main/video/video-edit.model'
import { VideoImportService } from '@app/shared/shared-main/video/video-import.service' import { VideoImportService } from '@app/shared/shared-main/video/video-import.service'
import { VideoService } from '@app/shared/shared-main/video/video.service' import { VideoService } from '@app/shared/shared-main/video/video.service'
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'
import { LoadingBarService } from '@ngx-loading-bar/core'
import { PeerTubeProblemDocument, ServerErrorCode, VideoUpdate } from '@peertube/peertube-models'
import { logger } from '@root-helpers/logger'
import { switchMap } from 'rxjs'
import { SelectChannelComponent } from '../../../shared/shared-forms/select/select-channel.component'
import { SelectOptionsComponent } from '../../../shared/shared-forms/select/select-options.component'
import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.component'
import { ButtonComponent } from '../../../shared/shared-main/buttons/button.component'
import { HelpComponent } from '../../../shared/shared-main/buttons/help.component'
import { PeerTubeTemplateDirective } from '../../../shared/shared-main/common/peertube-template.directive'
import { hydrateFormFromVideo } from '../shared/video-edit-utils'
import { VideoEditComponent } from '../shared/video-edit.component'
import { DragDropDirective } from './drag-drop.directive'
import { VideoSend } from './video-send'
@Component({ @Component({
selector: 'my-video-import-torrent', selector: 'my-video-import-torrent',
@ -47,7 +48,8 @@ import { VideoService } from '@app/shared/shared-main/video/video.service'
SelectOptionsComponent, SelectOptionsComponent,
ReactiveFormsModule, ReactiveFormsModule,
VideoEditComponent, VideoEditComponent,
ButtonComponent ButtonComponent,
AlertComponent
] ]
}) })
export class VideoImportTorrentComponent extends VideoSend implements OnInit, AfterViewInit, CanComponentDeactivate { export class VideoImportTorrentComponent extends VideoSend implements OnInit, AfterViewInit, CanComponentDeactivate {

View File

@ -44,14 +44,15 @@
</div> </div>
<div *ngIf="error" class="alert alert-danger"> <my-alert *ngIf="error" type="danger">
<div i18n>Sorry, but something went wrong</div> <div i18n>Sorry, but something went wrong</div>
{{ error }}
</div>
<div *ngIf="!error && hasImportedVideo" class="alert pt-alert-primary" i18n> {{ error }}
</my-alert>
<my-alert type="primary" *ngIf="!error && hasImportedVideo" i18n>
Congratulations, the video behind {{ targetUrl }} will be imported! You can already add information about this video. Congratulations, the video behind {{ targetUrl }} will be imported! You can already add information about this video.
</div> </my-alert>
<!-- Hidden because we want to load the component --> <!-- Hidden because we want to load the component -->
<form [hidden]="!hasImportedVideo" novalidate [formGroup]="form"> <form [hidden]="!hasImportedVideo" novalidate [formGroup]="form">

View File

@ -1,29 +1,30 @@
import { forkJoin } from 'rxjs' import { NgIf } from '@angular/common'
import { map, switchMap } from 'rxjs/operators'
import { AfterViewInit, Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' import { AfterViewInit, Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Router, RouterLink } from '@angular/router' import { Router, RouterLink } from '@angular/router'
import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService } from '@app/core' import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService } from '@app/core'
import { scrollToTop } from '@app/helpers' import { scrollToTop } from '@app/helpers'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { LoadingBarService } from '@ngx-loading-bar/core' import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { logger } from '@root-helpers/logger'
import { VideoUpdate } from '@peertube/peertube-models'
import { hydrateFormFromVideo } from '../shared/video-edit-utils'
import { VideoSend } from './video-send'
import { VideoEditComponent } from '../shared/video-edit.component'
import { ButtonComponent } from '../../../shared/shared-main/buttons/button.component'
import { SelectOptionsComponent } from '../../../shared/shared-forms/select/select-options.component'
import { SelectChannelComponent } from '../../../shared/shared-forms/select/select-channel.component'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { PeerTubeTemplateDirective } from '../../../shared/shared-main/common/peertube-template.directive'
import { HelpComponent } from '../../../shared/shared-main/buttons/help.component'
import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.component'
import { NgIf } from '@angular/common'
import { VideoCaptionService } from '@app/shared/shared-main/video-caption/video-caption.service' import { VideoCaptionService } from '@app/shared/shared-main/video-caption/video-caption.service'
import { VideoChapterService } from '@app/shared/shared-main/video/video-chapter.service' import { VideoChapterService } from '@app/shared/shared-main/video/video-chapter.service'
import { VideoEdit } from '@app/shared/shared-main/video/video-edit.model' import { VideoEdit } from '@app/shared/shared-main/video/video-edit.model'
import { VideoImportService } from '@app/shared/shared-main/video/video-import.service' import { VideoImportService } from '@app/shared/shared-main/video/video-import.service'
import { VideoService } from '@app/shared/shared-main/video/video.service' import { VideoService } from '@app/shared/shared-main/video/video.service'
import { LoadingBarService } from '@ngx-loading-bar/core'
import { VideoUpdate } from '@peertube/peertube-models'
import { logger } from '@root-helpers/logger'
import { forkJoin } from 'rxjs'
import { map, switchMap } from 'rxjs/operators'
import { SelectChannelComponent } from '../../../shared/shared-forms/select/select-channel.component'
import { SelectOptionsComponent } from '../../../shared/shared-forms/select/select-options.component'
import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.component'
import { ButtonComponent } from '../../../shared/shared-main/buttons/button.component'
import { HelpComponent } from '../../../shared/shared-main/buttons/help.component'
import { PeerTubeTemplateDirective } from '../../../shared/shared-main/common/peertube-template.directive'
import { hydrateFormFromVideo } from '../shared/video-edit-utils'
import { VideoEditComponent } from '../shared/video-edit.component'
import { VideoSend } from './video-send'
@Component({ @Component({
selector: 'my-video-import-url', selector: 'my-video-import-url',
@ -44,7 +45,8 @@ import { VideoService } from '@app/shared/shared-main/video/video.service'
SelectOptionsComponent, SelectOptionsComponent,
ReactiveFormsModule, ReactiveFormsModule,
VideoEditComponent, VideoEditComponent,
ButtonComponent ButtonComponent,
AlertComponent
] ]
}) })
export class VideoImportUrlComponent extends VideoSend implements OnInit, AfterViewInit, CanComponentDeactivate { export class VideoImportUrlComponent extends VideoSend implements OnInit, AfterViewInit, CanComponentDeactivate {

View File

@ -58,9 +58,9 @@
> >
</my-upload-progress> </my-upload-progress>
<div *ngIf="videoUploaded && !error" class="alert pt-alert-primary" i18n> <my-alert *ngIf="videoUploaded && !error" type="primary" i18n>
Congratulations! Your video is now available in your private library. Congratulations! Your video is now available in your private library.
</div> </my-alert>
<!-- Hidden because we want to load the component --> <!-- Hidden because we want to load the component -->
<form [hidden]="!isUploadingVideo" novalidate [formGroup]="form" class="mb-3"> <form [hidden]="!isUploadingVideo" novalidate [formGroup]="form" class="mb-3">

View File

@ -1,33 +1,34 @@
import { truncate } from 'lodash-es' import { NgIf } from '@angular/common'
import { UploadState, UploadxService } from 'ngx-uploadx'
import { Subscription } from 'rxjs'
import { HttpErrorResponse } from '@angular/common/http' import { HttpErrorResponse } from '@angular/common/http'
import { AfterViewInit, Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core' import { AfterViewInit, Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { AuthService, CanComponentDeactivate, HooksService, MetaService, Notifier, ServerService, UserService } from '@app/core' import { AuthService, CanComponentDeactivate, HooksService, MetaService, Notifier, ServerService, UserService } from '@app/core'
import { buildHTTPErrorResponse, genericUploadErrorHandler, scrollToTop } from '@app/helpers' import { buildHTTPErrorResponse, genericUploadErrorHandler, scrollToTop } from '@app/helpers'
import { LoadingBarService } from '@ngx-loading-bar/core' import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { logger } from '@root-helpers/logger' import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { HttpStatusCode, VideoCreateResult } from '@peertube/peertube-models'
import { VideoUploadService } from '../shared/video-upload.service'
import { VideoSend } from './video-send'
import { VideoEditComponent } from '../shared/video-edit.component'
import { UploadProgressComponent } from '../../../shared/standalone-upload/upload-progress.component'
import { ButtonComponent } from '../../../shared/shared-main/buttons/button.component'
import { PreviewUploadComponent } from '../../../shared/shared-forms/preview-upload.component'
import { SelectOptionsComponent } from '../../../shared/shared-forms/select/select-options.component'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { SelectChannelComponent } from '../../../shared/shared-forms/select/select-channel.component'
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'
import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.component'
import { DragDropDirective } from './drag-drop.directive'
import { NgIf } from '@angular/common'
import { VideoCaptionService } from '@app/shared/shared-main/video-caption/video-caption.service' import { VideoCaptionService } from '@app/shared/shared-main/video-caption/video-caption.service'
import { VideoChapterService } from '@app/shared/shared-main/video/video-chapter.service' import { VideoChapterService } from '@app/shared/shared-main/video/video-chapter.service'
import { VideoEdit } from '@app/shared/shared-main/video/video-edit.model' import { VideoEdit } from '@app/shared/shared-main/video/video-edit.model'
import { Video } from '@app/shared/shared-main/video/video.model' import { Video } from '@app/shared/shared-main/video/video.model'
import { VideoService } from '@app/shared/shared-main/video/video.service' import { VideoService } from '@app/shared/shared-main/video/video.service'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service' import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'
import { LoadingBarService } from '@ngx-loading-bar/core'
import { HttpStatusCode, VideoCreateResult } from '@peertube/peertube-models'
import { logger } from '@root-helpers/logger'
import { truncate } from 'lodash-es'
import { UploadState, UploadxService } from 'ngx-uploadx'
import { Subscription } from 'rxjs'
import { PreviewUploadComponent } from '../../../shared/shared-forms/preview-upload.component'
import { SelectChannelComponent } from '../../../shared/shared-forms/select/select-channel.component'
import { SelectOptionsComponent } from '../../../shared/shared-forms/select/select-options.component'
import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.component'
import { ButtonComponent } from '../../../shared/shared-main/buttons/button.component'
import { UploadProgressComponent } from '../../../shared/standalone-upload/upload-progress.component'
import { VideoEditComponent } from '../shared/video-edit.component'
import { VideoUploadService } from '../shared/video-upload.service'
import { DragDropDirective } from './drag-drop.directive'
import { VideoSend } from './video-send'
@Component({ @Component({
selector: 'my-video-upload', selector: 'my-video-upload',
@ -50,7 +51,8 @@ import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.serv
ButtonComponent, ButtonComponent,
UploadProgressComponent, UploadProgressComponent,
ReactiveFormsModule, ReactiveFormsModule,
VideoEditComponent VideoEditComponent,
AlertComponent
] ]
}) })
export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy, AfterViewInit, CanComponentDeactivate { export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy, AfterViewInit, CanComponentDeactivate {

View File

@ -1,13 +1,16 @@
<ng-template #AlertButtons> <ng-template #AlertButtons>
<a i18n routerLink="/about/instance" *ngIf="!isContactFormEnabled" class="about-link">Read instance rules for help</a> @if (isContactFormEnabled) {
<a i18n routerLink="/about/contact" *ngIf="isContactFormEnabled" class="contact-link">Contact us</a> <a i18n routerLink="/about/contact" class="peertube-button-link orange-button mt-2">Contact us</a>
} @else {
<a i18n routerLink="/about/instance" class="peertube-button-link orange-button mt-2">Read instance rules for help</a>
}
</ng-template> </ng-template>
<ng-container *ngIf="user.isUploadDisabled()"> <ng-container *ngIf="user.isUploadDisabled()">
<div class="upload-message upload-disabled alert alert-warning"> <my-alert class="upload-message upload-disabled" type="warning">
<div>{{ uploadMessages?.noQuota }}</div> <div>{{ uploadMessages?.noQuota }}</div>
<ng-template [ngTemplateOutlet]="AlertButtons"></ng-template> <ng-template [ngTemplateOutlet]="AlertButtons"></ng-template>
</div> </my-alert>
<div class="upload-image"> <div class="upload-image">
<img src="/client/assets/images/mascot/defeated.svg" alt="defeated mascot"> <img src="/client/assets/images/mascot/defeated.svg" alt="defeated mascot">
@ -15,26 +18,28 @@
</ng-container> </ng-container>
<ng-container *ngIf="!user.isUploadDisabled()"> <ng-container *ngIf="!user.isUploadDisabled()">
<div *ngIf="user.isAutoBlocked(serverConfig)" class="upload-message auto-blocked alert alert-warning"> <my-alert rounded="false" *ngIf="user.isAutoBlocked(serverConfig)" class="upload-message auto-blocked" type="warning">
<div>{{ uploadMessages?.autoBlock }}</div> <div>{{ uploadMessages?.autoBlock }}</div>
<ng-template [ngTemplateOutlet]="AlertButtons" *ngIf="!hasNoQuotaLeft && !hasNoQuotaLeftDaily"></ng-template> <ng-template [ngTemplateOutlet]="AlertButtons" *ngIf="!hasNoQuotaLeft && !hasNoQuotaLeftDaily"></ng-template>
</div> </my-alert>
<div *ngIf="hasNoQuotaLeftDaily" class="upload-message quota-daily-left alert alert-warning"> <my-alert rounded="false" *ngIf="hasNoQuotaLeftDaily" class="upload-message quota-daily-left" type="warning">
<div>{{ uploadMessages?.quotaLeftDaily }}</div> <div>{{ uploadMessages?.quotaLeftDaily }}</div>
<ng-template [ngTemplateOutlet]="AlertButtons" *ngIf="!hasNoQuotaLeft"></ng-template> <ng-template [ngTemplateOutlet]="AlertButtons" *ngIf="!hasNoQuotaLeft"></ng-template>
</div> </my-alert>
<div *ngIf="hasNoQuotaLeft" class="upload-message quota-left alert alert-warning"> <my-alert rounded="false" *ngIf="hasNoQuotaLeft" class="upload-message quota-left" type="warning">
<div>{{ uploadMessages?.quotaLeft }}</div> <div>{{ uploadMessages?.quotaLeft }}</div>
<ng-template [ngTemplateOutlet]="AlertButtons"></ng-template> <ng-template [ngTemplateOutlet]="AlertButtons"></ng-template>
</div> </my-alert>
<my-alert rounded="false" *ngIf="isRootUser()" class="upload-message root-user root-user root-user" type="warning">
<ng-container i18n>We recommend you to not use the <strong>root</strong> user to publish your videos, since it's the super-admin account of your instance.</ng-container>
<div *ngIf="isRootUser()" class="upload-message root-user alert alert-warning" i18n>
We recommend you to not use the <strong>root</strong> user to publish your videos, since it's the super-admin account of your instance.
<br /> <br />
Instead, <a class="text-decoration-underline alert-link" routerLink="/admin/users">create a dedicated account</a> to upload your videos.
</div> <ng-container i18n>Instead, <a class="text-decoration-underline alert-link" routerLink="/admin/users">create a dedicated account</a> to upload your videos.</ng-container>
</my-alert>
</ng-container> </ng-container>
<div *ngIf="!user.isUploadDisabled()" class="margin-content"> <div *ngIf="!user.isUploadDisabled()" class="margin-content">

View File

@ -8,23 +8,14 @@ $border-color: #EAEAEA;
$nav-link-height: 40px; $nav-link-height: 40px;
.upload-message { .upload-message {
display: block;
width: 100%; width: 100%;
text-align: center; text-align: center;
margin-bottom: 0; margin-bottom: 0;
border-radius: 0;
&:last-child { &:last-child {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
.about-link,
.contact-link {
height: fit-content;
margin-top: 10px;
@include peertube-button-link;
@include orange-button;
}
} }
.upload-image { .upload-image {

View File

@ -1,3 +1,4 @@
import { NgClass, NgIf, NgTemplateOutlet } from '@angular/common'
import { Component, HostListener, OnInit, ViewChild } from '@angular/core' import { Component, HostListener, OnInit, ViewChild } from '@angular/core'
import { ActivatedRoute, Router, RouterLink } from '@angular/router' import { ActivatedRoute, Router, RouterLink } from '@angular/router'
import { import {
@ -8,16 +9,16 @@ import {
ServerService, ServerService,
UserService UserService
} from '@app/core' } from '@app/core'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { NgbNav, NgbNavContent, NgbNavItem, NgbNavLink, NgbNavLinkBase, NgbNavOutlet } from '@ng-bootstrap/ng-bootstrap'
import { HTMLServerConfig } from '@peertube/peertube-models' import { HTMLServerConfig } from '@peertube/peertube-models'
import { ChannelsSetupMessageComponent } from '../../shared/shared-main/channel/channels-setup-message.component'
import { UserQuotaComponent } from '../../shared/shared-main/users/user-quota.component'
import { VideoEditType } from './shared/video-edit.type' import { VideoEditType } from './shared/video-edit.type'
import { VideoGoLiveComponent } from './video-add-components/video-go-live.component' import { VideoGoLiveComponent } from './video-add-components/video-go-live.component'
import { VideoImportTorrentComponent } from './video-add-components/video-import-torrent.component' import { VideoImportTorrentComponent } from './video-add-components/video-import-torrent.component'
import { VideoImportUrlComponent } from './video-add-components/video-import-url.component' import { VideoImportUrlComponent } from './video-add-components/video-import-url.component'
import { VideoUploadComponent } from './video-add-components/video-upload.component' import { VideoUploadComponent } from './video-add-components/video-upload.component'
import { NgbNav, NgbNavItem, NgbNavLink, NgbNavLinkBase, NgbNavContent, NgbNavOutlet } from '@ng-bootstrap/ng-bootstrap'
import { ChannelsSetupMessageComponent } from '../../shared/shared-main/channel/channels-setup-message.component'
import { UserQuotaComponent } from '../../shared/shared-main/users/user-quota.component'
import { NgIf, NgTemplateOutlet, NgClass } from '@angular/common'
@Component({ @Component({
selector: 'my-videos-add', selector: 'my-videos-add',
@ -40,7 +41,8 @@ import { NgIf, NgTemplateOutlet, NgClass } from '@angular/common'
VideoImportUrlComponent, VideoImportUrlComponent,
VideoImportTorrentComponent, VideoImportTorrentComponent,
VideoGoLiveComponent, VideoGoLiveComponent,
NgbNavOutlet NgbNavOutlet,
AlertComponent
] ]
}) })
export class VideoAddComponent implements OnInit, CanComponentDeactivate { export class VideoAddComponent implements OnInit, CanComponentDeactivate {

View File

@ -1,28 +1,28 @@
<div i18n class="alert pt-alert-primary" *ngIf="hasVideoScheduledPublication()"> <my-alert rounded="false" type="primary" i18n *ngIf="hasVideoScheduledPublication()">
This video will be published on {{ video.scheduledUpdate.updateAt | date: 'full' }}. This video will be published on {{ video.scheduledUpdate.updateAt | date: 'full' }}.
</div> </my-alert>
<div i18n class="alert pt-alert-primary" *ngIf="isWaitingForLive()"> <my-alert rounded="false" type="primary" i18n *ngIf="isWaitingForLive()">
This live is not currently streaming. This live is not currently streaming.
</div> </my-alert>
<div i18n class="alert pt-alert-primary" *ngIf="isLiveEnded()"> <my-alert rounded="false" type="primary" i18n *ngIf="isLiveEnded()">
This live has ended. This live has ended.
</div> </my-alert>
<div class="alert alert-warning" *ngIf="getAlertWarning()"> <my-alert rounded="false" type="warning" *ngIf="getAlertWarning()">
{{ getAlertWarning() }} {{ getAlertWarning() }}
</div> </my-alert>
<div i18n class="alert alert-warning" *ngIf="noPlaylistVideoFound"> <my-alert rounded="false" i18n type="warning" *ngIf="noPlaylistVideoFound">
There are no videos available in this playlist. There are no videos available in this playlist.
</div> </my-alert>
<div class="alert alert-danger" *ngIf="video?.blacklisted"> <my-alert rounded="false" type="danger" *ngIf="video?.blacklisted">
<div class="blocked-label" i18n>This video is blocked.</div> <div class="blocked-label" i18n>This video is blocked.</div>
{{ video.blacklistedReason }} {{ video.blacklistedReason }}
</div> </my-alert>
<div i18n class="alert alert-warning" *ngIf="video?.canAccessPasswordProtectedVideoWithoutPassword(user)"> <my-alert rounded="false" i18n type="warning" *ngIf="video?.canAccessPasswordProtectedVideoWithoutPassword(user)">
This video is password protected. This video is password protected.
</div> </my-alert>

View File

@ -1,7 +0,0 @@
@use '_variables' as *;
@use '_mixins' as *;
.alert {
text-align: center;
border-radius: 0;
}

View File

@ -1,15 +1,16 @@
import { DatePipe, NgIf } from '@angular/common'
import { Component, Input } from '@angular/core' import { Component, Input } from '@angular/core'
import { AuthUser } from '@app/core' import { AuthUser } from '@app/core'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { VideoDetails } from '@app/shared/shared-main/video/video-details.model' import { VideoDetails } from '@app/shared/shared-main/video/video-details.model'
import { VideoPrivacy, VideoState } from '@peertube/peertube-models' import { VideoPrivacy, VideoState } from '@peertube/peertube-models'
import { NgIf, DatePipe } from '@angular/common'
@Component({ @Component({
selector: 'my-video-alert', selector: 'my-video-alert',
templateUrl: './video-alert.component.html', templateUrl: './video-alert.component.html',
styleUrls: [ './video-alert.component.scss' ],
standalone: true, standalone: true,
imports: [ NgIf, DatePipe ] styles: `my-alert { text-align: center }`,
imports: [ NgIf, DatePipe, AlertComponent ]
}) })
export class VideoAlertComponent { export class VideoAlertComponent {
@Input() user: AuthUser @Input() user: AuthUser

View File

@ -7,7 +7,7 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div i18n class="alert pt-alert-primary">These settings apply only to your session on this instance.</div> <my-alert i18n type="primary">These settings apply only to your session on this instance.</my-alert>
<h5 i18n class="mt-4 mb-2">Videos</h5> <h5 i18n class="mt-4 mb-2">Videos</h5>

View File

@ -1,20 +1,21 @@
import { ReplaySubject, Subscription } from 'rxjs' import { CommonModule } from '@angular/common'
import { filter } from 'rxjs/operators'
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core' import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { AuthService, AuthStatus, LocalStorageService, User, UserService } from '@app/core' import { AuthService, AuthStatus, LocalStorageService, User, UserService } from '@app/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
import { CommonModule } from '@angular/common'
import { GlobalIconComponent } from '@app/shared/shared-icons/global-icon.component' import { GlobalIconComponent } from '@app/shared/shared-icons/global-icon.component'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { UserInterfaceSettingsComponent } from '@app/shared/shared-user-settings/user-interface-settings.component' import { UserInterfaceSettingsComponent } from '@app/shared/shared-user-settings/user-interface-settings.component'
import { UserVideoSettingsComponent } from '@app/shared/shared-user-settings/user-video-settings.component' import { UserVideoSettingsComponent } from '@app/shared/shared-user-settings/user-video-settings.component'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
import { ReplaySubject, Subscription } from 'rxjs'
import { filter } from 'rxjs/operators'
@Component({ @Component({
selector: 'my-quick-settings', selector: 'my-quick-settings',
templateUrl: './quick-settings-modal.component.html', templateUrl: './quick-settings-modal.component.html',
standalone: true, standalone: true,
imports: [ CommonModule, GlobalIconComponent, UserVideoSettingsComponent, UserInterfaceSettingsComponent ] imports: [ CommonModule, GlobalIconComponent, UserVideoSettingsComponent, UserInterfaceSettingsComponent, AlertComponent ]
}) })
export class QuickSettingsModalComponent implements OnInit, OnDestroy { export class QuickSettingsModalComponent implements OnInit, OnDestroy {
private static readonly QUERY_MODAL_NAME = 'quick-settings' private static readonly QUERY_MODAL_NAME = 'quick-settings'

View File

@ -1,7 +1,7 @@
<div *ngIf="hasChannelNotConfigured()" class="alert pt-alert-primary"> <my-alert *ngIf="hasChannelNotConfigured()" type="primary" class="text-center">
<my-global-icon iconName="tip"></my-global-icon> <my-global-icon iconName="tip"></my-global-icon>
<div i18n>Some of your channels are not fully set up. Make them welcoming and explicit about what you publish by adding a <strong>banner</strong>, an <strong>avatar</strong> and a <strong>description</strong>.</div> <div i18n>Some of your channels are not fully set up. Make them welcoming and explicit about what you publish by adding a <strong>banner</strong>, an <strong>avatar</strong> and a <strong>description</strong>.</div>
<a *ngIf="!hideLink" class="peertube-button-link grey-button mt-2" routerLink="/my-library/video-channels" i18n>Set up my channels</a> <a *ngIf="!hideLink" class="peertube-button-link grey-button mt-2" routerLink="/my-library/video-channels" i18n>Set up my channels</a>
</div> </my-alert>

View File

@ -1,10 +1,6 @@
@use '_variables' as *; @use '_variables' as *;
@use '_mixins' as *; @use '_mixins' as *;
.pt-alert-primary {
text-align: center;
}
my-global-icon { my-global-icon {
width: 32px; width: 32px;
display: inline-block; display: inline-block;

View File

@ -1,8 +1,9 @@
import { Component, Input, OnInit } from '@angular/core'
import { AuthService, User } from '@app/core'
import { RouterLink } from '@angular/router'
import { GlobalIconComponent } from '../../shared-icons/global-icon.component'
import { NgIf } from '@angular/common' import { NgIf } from '@angular/common'
import { Component, Input, OnInit } from '@angular/core'
import { RouterLink } from '@angular/router'
import { AuthService, User } from '@app/core'
import { GlobalIconComponent } from '../../shared-icons/global-icon.component'
import { AlertComponent } from '../common/alert.component'
import { VideoChannel } from './video-channel.model' import { VideoChannel } from './video-channel.model'
@Component({ @Component({
@ -10,7 +11,7 @@ import { VideoChannel } from './video-channel.model'
templateUrl: './channels-setup-message.component.html', templateUrl: './channels-setup-message.component.html',
styleUrls: [ './channels-setup-message.component.scss' ], styleUrls: [ './channels-setup-message.component.scss' ],
standalone: true, standalone: true,
imports: [ NgIf, GlobalIconComponent, RouterLink ] imports: [ NgIf, GlobalIconComponent, RouterLink, AlertComponent ]
}) })
export class ChannelsSetupMessageComponent implements OnInit { export class ChannelsSetupMessageComponent implements OnInit {
@Input() hideLink = false @Input() hideLink = false

View File

@ -0,0 +1,3 @@
<div [ngClass]="builtClasses" role="alert">
<ng-content></ng-content>
</div>

View File

@ -0,0 +1,41 @@
import { NgClass, NgIf, NgTemplateOutlet } from '@angular/common'
import { booleanAttribute, Component, Input, OnChanges, OnInit } from '@angular/core'
import { RouterLink } from '@angular/router'
export type AlertType = 'success' | 'info' | 'warning' | 'danger' | 'primary'
@Component({
selector: 'my-alert',
styleUrls: [ './alert.component.scss' ],
templateUrl: './alert.component.html',
standalone: true,
imports: [ NgIf, RouterLink, NgClass, NgTemplateOutlet ]
})
export class AlertComponent implements OnInit, OnChanges {
@Input({ required: true }) type: AlertType
@Input({ transform: booleanAttribute }) rounded = true
builtClasses = ''
ngOnInit () {
this.buildClasses()
}
ngOnChanges () {
this.buildClasses()
}
private buildClasses () {
this.builtClasses = 'alert'
if (this.type === 'primary') {
this.builtClasses += ' pt-alert-primary'
} else {
this.builtClasses += ' alert-' + this.type
}
if (this.rounded !== true) {
this.builtClasses += ' rounded-0'
}
}
}

View File

@ -13,13 +13,13 @@
<div class="playlist" *ngIf="playlist"> <div class="playlist" *ngIf="playlist">
<h5 *ngIf="video" i18n class="text-center mb-4">Share the playlist</h5> <h5 *ngIf="video" i18n class="text-center mb-4">Share the playlist</h5>
<div *ngIf="isPrivatePlaylist()" class="alert-private alert alert-warning"> <my-alert *ngIf="isPrivatePlaylist()" class="alert-private" type="warning">
<div i18n>This playlist is private so you won't be able to share it with external users</div> <div i18n>This playlist is private so you won't be able to share it with external users</div>
<a i18n class="peertube-button-link orange-button" [routerLink]="[ '/my-library/video-playlists/update', playlist.shortUUID ]" target="_blank" rel="noopener noreferrer"> <a i18n class="peertube-button-link orange-button" [routerLink]="[ '/my-library/video-playlists/update', playlist.shortUUID ]" target="_blank" rel="noopener noreferrer">
Update playlist privacy Update playlist privacy
</a> </a>
</div> </my-alert>
<div ngbNav #nav="ngbNav" class="nav-tabs" [(activeId)]="activePlaylistId"> <div ngbNav #nav="ngbNav" class="nav-tabs" [(activeId)]="activePlaylistId">
@ -57,9 +57,9 @@
[withToggle]="false" [withCopy]="true" [show]="true" [readonly]="true" [withToggle]="false" [withCopy]="true" [show]="true" [readonly]="true"
></my-input-text> ></my-input-text>
<div i18n *ngIf="notSecure()" class="alert alert-warning"> <my-alert i18n *ngIf="notSecure()" type="warning">
The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites). The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites).
</div> </my-alert>
<div class="embed" [innerHTML]="playlistEmbedSafeHTML"></div> <div class="embed" [innerHTML]="playlistEmbedSafeHTML"></div>
</div> </div>
@ -103,17 +103,17 @@
<div class="video" *ngIf="video"> <div class="video" *ngIf="video">
<h5 *ngIf="playlist" i18n class="text-center mb-4">Share the video</h5> <h5 *ngIf="playlist" i18n class="text-center mb-4">Share the video</h5>
<div *ngIf="isPrivateVideo()" class="alert-private alert alert-warning"> <my-alert *ngIf="isPrivateVideo()" class="alert-private" type="warning">
<div i18n>This video is private so you won't be able to share it with external users</div> <div i18n>This video is private so you won't be able to share it with external users</div>
<a i18n class="peertube-button-link orange-button" [routerLink]="[ '/videos/', 'update', video.shortUUID ]" target="_blank" rel="noopener noreferrer"> <a i18n class="peertube-button-link orange-button" [routerLink]="[ '/videos/', 'update', video.shortUUID ]" target="_blank" rel="noopener noreferrer">
Update video privacy Update video privacy
</a> </a>
</div> </my-alert>
<div i18n *ngIf="isPasswordProtectedVideo()" class="alert-private alert alert-warning"> <my-alert i18n *ngIf="isPasswordProtectedVideo()" class="alert-private" type="warning">
This video is password protected, please note that recipients will require the corresponding password to access the content. This video is password protected, please note that recipients will require the corresponding password to access the content.
</div> </my-alert>
<div ngbNav #nav="ngbNav" class="nav-tabs" [(activeId)]="activeVideoId"> <div ngbNav #nav="ngbNav" class="nav-tabs" [(activeId)]="activeVideoId">
@ -151,9 +151,9 @@
[withToggle]="false" [withCopy]="true" [show]="true" [readonly]="true" [withToggle]="false" [withCopy]="true" [show]="true" [readonly]="true"
></my-input-text> ></my-input-text>
<div i18n *ngIf="notSecure()" class="alert alert-warning"> <my-alert i18n *ngIf="notSecure()" type="warning">
The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites). The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites).
</div> </my-alert>
<div class="embed" [innerHTML]="videoEmbedSafeHTML"></div> <div class="embed" [innerHTML]="videoEmbedSafeHTML"></div>
</div> </div>

View File

@ -1,29 +1,30 @@
import { NgClass, NgFor, NgIf } from '@angular/common'
import { Component, ElementRef, Input, ViewChild } from '@angular/core' import { Component, ElementRef, Input, ViewChild } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { DomSanitizer, SafeHtml } from '@angular/platform-browser' import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
import { RouterLink } from '@angular/router'
import { HooksService, ServerService } from '@app/core' import { HooksService, ServerService } from '@app/core'
import { VideoDetails } from '@app/shared/shared-main/video/video-details.model' import { VideoDetails } from '@app/shared/shared-main/video/video-details.model'
import { import {
NgbCollapse,
NgbModal, NgbModal,
NgbNav, NgbNav,
NgbNavContent,
NgbNavItem, NgbNavItem,
NgbNavLink, NgbNavLink,
NgbNavLinkBase, NgbNavLinkBase,
NgbNavContent, NgbNavOutlet
NgbNavOutlet,
NgbCollapse
} from '@ng-bootstrap/ng-bootstrap' } from '@ng-bootstrap/ng-bootstrap'
import { buildVideoOrPlaylistEmbed } from '@root-helpers/video'
import { buildPlaylistLink, buildVideoLink, decoratePlaylistLink, decorateVideoLink } from '@peertube/peertube-core-utils' import { buildPlaylistLink, buildVideoLink, decoratePlaylistLink, decorateVideoLink } from '@peertube/peertube-core-utils'
import { VideoCaption, VideoPlaylistPrivacy, VideoPrivacy } from '@peertube/peertube-models' import { VideoCaption, VideoPlaylistPrivacy, VideoPrivacy } from '@peertube/peertube-models'
import { TimestampInputComponent } from '../shared-forms/timestamp-input.component' import { buildVideoOrPlaylistEmbed } from '@root-helpers/video'
import { PluginPlaceholderComponent } from '../shared-main/plugins/plugin-placeholder.component'
import { FormsModule } from '@angular/forms'
import { PeertubeCheckboxComponent } from '../shared-forms/peertube-checkbox.component'
import { QRCodeModule } from 'angularx-qrcode' import { QRCodeModule } from 'angularx-qrcode'
import { InputTextComponent } from '../shared-forms/input-text.component' import { InputTextComponent } from '../shared-forms/input-text.component'
import { RouterLink } from '@angular/router' import { PeertubeCheckboxComponent } from '../shared-forms/peertube-checkbox.component'
import { NgIf, NgClass, NgFor } from '@angular/common' import { TimestampInputComponent } from '../shared-forms/timestamp-input.component'
import { GlobalIconComponent } from '../shared-icons/global-icon.component' import { GlobalIconComponent } from '../shared-icons/global-icon.component'
import { AlertComponent } from '../shared-main/common/alert.component'
import { PluginPlaceholderComponent } from '../shared-main/plugins/plugin-placeholder.component'
import { VideoPlaylist } from '../shared-video-playlist/video-playlist.model' import { VideoPlaylist } from '../shared-video-playlist/video-playlist.model'
type Customizations = { type Customizations = {
@ -77,7 +78,8 @@ type TabId = 'url' | 'qrcode' | 'embed'
TimestampInputComponent, TimestampInputComponent,
NgClass, NgClass,
NgFor, NgFor,
NgbCollapse NgbCollapse,
AlertComponent
] ]
}) })
export class VideoShareComponent { export class VideoShareComponent {

View File

@ -13,9 +13,9 @@
<div class="pt-badge badge-blue" *ngIf="live.saveReplay" i18n>Replay will be saved</div> <div class="pt-badge badge-blue" *ngIf="live.saveReplay" i18n>Replay will be saved</div>
</div> </div>
<div class="alert pt-alert-primary"> <my-alert type="primary">
<my-live-documentation-link></my-live-documentation-link> <my-live-documentation-link></my-live-documentation-link>
</div> </my-alert>
<div *ngIf="live.rtmpUrl" class="form-group"> <div *ngIf="live.rtmpUrl" class="form-group">
<label for="liveVideoRTMPUrl" i18n>Live RTMP Url</label> <label for="liveVideoRTMPUrl" i18n>Live RTMP Url</label>

View File

@ -9,7 +9,8 @@ p-autocomplete {
margin: 20px 0; margin: 20px 0;
} }
.pt-alert-primary { my-alert {
display: block;
margin: 1rem 0; margin: 1rem 0;
} }

View File

@ -1,14 +1,15 @@
import { DatePipe, NgFor, NgIf } from '@angular/common'
import { Component, ElementRef, ViewChild } from '@angular/core' import { Component, ElementRef, ViewChild } from '@angular/core'
import { RouterLink } from '@angular/router'
import { Video } from '@app/shared/shared-main/video/video.model' import { Video } from '@app/shared/shared-main/video/video.model'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { LiveVideo, LiveVideoError, LiveVideoErrorType, LiveVideoSession } from '@peertube/peertube-models' import { LiveVideo, LiveVideoError, LiveVideoErrorType, LiveVideoSession } from '@peertube/peertube-models'
import { LiveVideoService } from './live-video.service'
import { EditButtonComponent } from '../shared-main/buttons/edit-button.component'
import { RouterLink } from '@angular/router'
import { InputTextComponent } from '../shared-forms/input-text.component' import { InputTextComponent } from '../shared-forms/input-text.component'
import { LiveDocumentationLinkComponent } from './live-documentation-link.component'
import { NgIf, NgFor, DatePipe } from '@angular/common'
import { GlobalIconComponent } from '../shared-icons/global-icon.component' import { GlobalIconComponent } from '../shared-icons/global-icon.component'
import { EditButtonComponent } from '../shared-main/buttons/edit-button.component'
import { AlertComponent } from '../shared-main/common/alert.component'
import { LiveDocumentationLinkComponent } from './live-documentation-link.component'
import { LiveVideoService } from './live-video.service'
@Component({ @Component({
selector: 'my-live-stream-information', selector: 'my-live-stream-information',
@ -23,7 +24,8 @@ import { GlobalIconComponent } from '../shared-icons/global-icon.component'
NgFor, NgFor,
RouterLink, RouterLink,
EditButtonComponent, EditButtonComponent,
DatePipe DatePipe,
AlertComponent
], ],
providers: [ LiveVideoService ] providers: [ LiveVideoService ]
}) })

View File

@ -1,6 +1,6 @@
<div class="alert alert-warning" *ngIf="isConfidentialVideo()" i18n> <my-alert type="warning" *ngIf="isConfidentialVideo()" i18n>
The following link contains a private token and should not be shared with anyone. The following link contains a private token and should not be shared with anyone.
</div> </my-alert>
<div ngbNav #resolutionNav="ngbNav" class="nav-tabs" [activeId]="activeResolutionId" (activeIdChange)="onResolutionIdChange($event)"> <div ngbNav #resolutionNav="ngbNav" class="nav-tabs" [activeId]="activeResolutionId" (activeIdChange)="onResolutionIdChange($event)">

View File

@ -1,6 +1,7 @@
import { KeyValuePipe, NgClass, NgFor, NgIf, NgTemplateOutlet } from '@angular/common' import { KeyValuePipe, NgClass, NgFor, NgIf, NgTemplateOutlet } from '@angular/common'
import { Component, EventEmitter, Inject, Input, LOCALE_ID, OnInit, Output } from '@angular/core' import { Component, EventEmitter, Inject, Input, LOCALE_ID, OnInit, Output } from '@angular/core'
import { FormsModule } from '@angular/forms' import { FormsModule } from '@angular/forms'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { import {
NgbCollapse, NgbCollapse,
NgbNav, NgbNav,
@ -48,7 +49,8 @@ type FileMetadata = { [key: string]: { label: string, value: string | number } }
KeyValuePipe, KeyValuePipe,
NgbTooltip, NgbTooltip,
NgTemplateOutlet, NgTemplateOutlet,
NgClass NgClass,
AlertComponent
] ]
}) })
export class VideoFilesDownloadComponent implements OnInit { export class VideoFilesDownloadComponent implements OnInit {

View File

@ -23,7 +23,7 @@
<input type="button" class="peertube-button grey-button ms-1" i18n-value="Cancel ongoing upload" value="Cancel" (click)="cancel.emit()" /> <input type="button" class="peertube-button grey-button ms-1" i18n-value="Cancel ongoing upload" value="Cancel" (click)="cancel.emit()" />
</div> </div>
<div *ngIf="error && !enableRetryAfterError" class="alert alert-danger"> <my-alert *ngIf="error && !enableRetryAfterError" type="danger">
<div i18n>Sorry, but something went wrong</div> <div i18n>Sorry, but something went wrong</div>
{{ error }} {{ error }}
</div> </my-alert>

View File

@ -1,12 +1,13 @@
import { CommonModule } from '@angular/common' import { CommonModule } from '@angular/common'
import { Component, EventEmitter, Input, Output } from '@angular/core' import { Component, EventEmitter, Input, Output } from '@angular/core'
import { AlertComponent } from '../shared-main/common/alert.component'
import { ProgressBarComponent } from '../shared-main/common/progress-bar.component' import { ProgressBarComponent } from '../shared-main/common/progress-bar.component'
@Component({ @Component({
selector: 'my-upload-progress', selector: 'my-upload-progress',
templateUrl: './upload-progress.component.html', templateUrl: './upload-progress.component.html',
styleUrls: [ './upload-progress.component.scss' ], styleUrls: [ './upload-progress.component.scss' ],
imports: [ CommonModule, ProgressBarComponent ], imports: [ CommonModule, ProgressBarComponent, AlertComponent ],
standalone: true standalone: true
}) })
export class UploadProgressComponent { export class UploadProgressComponent {

View File

@ -130,6 +130,8 @@ async function getUser (usernameOrEmail?: string, password?: string, bypassLogin
checkUserValidityOrThrow(user) checkUserValidityOrThrow(user)
if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION && user.emailVerified === false) { if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION && user.emailVerified === false) {
// Keep this message sync with the client
// TODO: use custom server code
throw new AccessDeniedError('User email is not verified.') throw new AccessDeniedError('User email is not verified.')
} }