Execute Angular migrations

* inject() Function
 * signal inputs
 * outputs
 * signal queries
 * cleanup unused imports

https://angular.dev/reference/migrations
This commit is contained in:
Chocobozzz 2025-02-19 09:58:38 +01:00
parent 8ae98c5ad5
commit 017795cf45
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
456 changed files with 6033 additions and 6590 deletions

View File

@ -38,8 +38,8 @@
"forStatement.spaceAfterForKeyword": true,
"forStatement.spaceAfterSemiColons": true,
"functionDeclaration.spaceBeforeParentheses": true,
"functionExpression.spaceBeforeParentheses": false,
"functionExpression.spaceAfterFunctionKeyword": false,
"functionExpression.spaceBeforeParentheses": true,
"functionExpression.spaceAfterFunctionKeyword": true,
"getAccessor.spaceBeforeParentheses": true,
"ifStatement.spaceAfterIfKeyword": true,
"importDeclaration.spaceSurroundingNamedImports": true,

View File

@ -50,7 +50,7 @@
"SwitchCase": 1,
"MemberExpression": "off",
// https://github.com/eslint/eslint/issues/15299
"ignoredNodes": ["PropertyDefinition"]
"ignoredNodes": ["PropertyDefinition", "TSTypeParameterInstantiation"]
}
],
"@typescript-eslint/consistent-type-assertions": [

View File

@ -1,5 +1,5 @@
import { NgClass, NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { ActivatedRoute } from '@angular/router'
import { ServerService } from '@app/core'
@ -26,20 +26,16 @@ type Prefill = {
imports: [ NgIf, FormsModule, ReactiveFormsModule, NgClass, AlertComponent ]
})
export class AboutContactComponent extends FormReactive implements OnInit {
protected formReactiveService = inject(FormReactiveService)
private route = inject(ActivatedRoute)
private instanceService = inject(InstanceService)
private serverService = inject(ServerService)
error: string
success: string
private serverConfig: HTMLServerConfig
constructor (
protected formReactiveService: FormReactiveService,
private route: ActivatedRoute,
private instanceService: InstanceService,
private serverService: ServerService
) {
super()
}
get instanceName () {
return this.serverConfig.instance.name
}
@ -68,17 +64,17 @@ export class AboutContactComponent extends FormReactive implements OnInit {
const body = this.form.value['body']
this.instanceService.contactAdministrator(fromEmail, fromName, subject, body)
.subscribe({
next: () => {
this.success = $localize`Your message has been sent.`
},
.subscribe({
next: () => {
this.success = $localize`Your message has been sent.`
},
error: err => {
this.error = err.status === HttpStatusCode.FORBIDDEN_403
? $localize`You already sent this form recently`
: err.message
}
})
error: err => {
this.error = err.status === HttpStatusCode.FORBIDDEN_403
? $localize`You already sent this form recently`
: err.message
}
})
}
private prefillForm (prefill: Prefill) {

View File

@ -1,5 +1,5 @@
import { DecimalPipe, NgFor, NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { RouterLink } from '@angular/router'
import { ComponentPagination, hasMoreItems, Notifier, RestService, ServerService } from '@app/core'
import { ActorAvatarComponent } from '@app/shared/shared-actor-image/actor-avatar.component'
@ -29,8 +29,12 @@ import { SubscriptionImageComponent } from './subscription-image.component'
FollowerImageComponent
]
})
export class AboutFollowsComponent implements OnInit {
private server = inject(ServerService)
private restService = inject(RestService)
private notifier = inject(Notifier)
private followService = inject(InstanceFollowService)
instanceName: string
followers: Actor[] = []
@ -58,13 +62,6 @@ export class AboutFollowsComponent implements OnInit {
order: -1
}
constructor (
private server: ServerService,
private restService: RestService,
private notifier: Notifier,
private followService: InstanceFollowService
) { }
ngOnInit () {
this.loadMoreFollowers(true)
this.loadMoreSubscriptions(true)
@ -96,20 +93,20 @@ export class AboutFollowsComponent implements OnInit {
const pagination = this.restService.componentToRestPagination(this.followersPagination)
this.followService.getFollowers({ pagination, sort: this.sort, state: 'accepted' })
.subscribe({
next: resultList => {
if (reset) this.followers = []
.subscribe({
next: resultList => {
if (reset) this.followers = []
const newFollowers = resultList.data.map(r => this.formatFollow(r.follower))
this.followers = this.followers.concat(newFollowers)
const newFollowers = resultList.data.map(r => this.formatFollow(r.follower))
this.followers = this.followers.concat(newFollowers)
this.followersPagination.totalItems = resultList.total
},
this.followersPagination.totalItems = resultList.total
},
error: err => this.notifier.error(err.message),
error: err => this.notifier.error(err.message),
complete: () => this.loadingFollowers = false
})
complete: () => this.loadingFollowers = false
})
}
loadMoreSubscriptions (reset = false) {
@ -122,20 +119,20 @@ export class AboutFollowsComponent implements OnInit {
const pagination = this.restService.componentToRestPagination(this.subscriptionsPagination)
this.followService.getFollowing({ pagination, sort: this.sort, state: 'accepted' })
.subscribe({
next: resultList => {
if (reset) this.subscriptions = []
.subscribe({
next: resultList => {
if (reset) this.subscriptions = []
const newFollowings = resultList.data.map(r => this.formatFollow(r.following))
this.subscriptions = this.subscriptions.concat(newFollowings)
const newFollowings = resultList.data.map(r => this.formatFollow(r.following))
this.subscriptions = this.subscriptions.concat(newFollowings)
this.subscriptionsPagination.totalItems = resultList.total
},
this.subscriptionsPagination.totalItems = resultList.total
},
error: err => this.notifier.error(err.message),
error: err => this.notifier.error(err.message),
complete: () => this.loadingSubscriptions = false
})
complete: () => this.loadingSubscriptions = false
})
}
private formatFollow (actor: Actor) {

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { ServerService } from '@app/core'
import { Actor } from '@app/shared/shared-main/account/actor.model'
@ -9,9 +9,9 @@ import { Actor } from '@app/shared/shared-main/account/actor.model'
standalone: true
})
export class FollowerImageComponent implements OnInit {
avatarUrl: string
private server = inject(ServerService)
constructor (private server: ServerService) {}
avatarUrl: string
ngOnInit () {
this.avatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.server.getHTMLConfig().instance, 30)

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { ServerService } from '@app/core'
import { Actor } from '@app/shared/shared-main/account/actor.model'
@ -9,9 +9,9 @@ import { Actor } from '@app/shared/shared-main/account/actor.model'
standalone: true
})
export class SubscriptionImageComponent implements OnInit {
avatarUrl: string
private server = inject(ServerService)
constructor (private server: ServerService) {}
avatarUrl: string
ngOnInit () {
this.avatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.server.getHTMLConfig().instance, 30)

View File

@ -1,4 +1,4 @@
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'
import { Component, ElementRef, OnInit, inject, viewChild } from '@angular/core'
import { ActivatedRoute, RouterOutlet } from '@angular/router'
import { AboutHTML } from '@app/shared/shared-main/instance/instance.service'
import { ServerConfig, ServerStats } from '@peertube/peertube-models'
@ -17,17 +17,15 @@ import { HorizontalMenuComponent, HorizontalMenuEntry } from '@app/shared/shared
]
})
export class AboutInstanceComponent implements OnInit {
@ViewChild('descriptionWrapper') descriptionWrapper: ElementRef<HTMLInputElement>
private route = inject(ActivatedRoute)
readonly descriptionWrapper = viewChild<ElementRef<HTMLInputElement>>('descriptionWrapper')
aboutHTML: AboutHTML
serverStats: ServerStats
serverConfig: ServerConfig
menuEntries: HorizontalMenuEntry[] = []
constructor (
private route: ActivatedRoute
) {}
ngOnInit () {
const {
aboutHTML,

View File

@ -1,6 +1,6 @@
import { forkJoin, Observable } from 'rxjs'
import { map, switchMap } from 'rxjs/operators'
import { Injectable } from '@angular/core'
import { Injectable, inject } from '@angular/core'
import { ServerService } from '@app/core'
import { About, ServerConfig, ServerStats } from '@peertube/peertube-models'
import { AboutHTML, InstanceService } from '@app/shared/shared-main/instance/instance.service'
@ -18,12 +18,9 @@ export type ResolverData = {
@Injectable()
export class AboutInstanceResolver {
constructor (
private instanceService: InstanceService,
private customMarkupService: CustomMarkupService,
private serverService: ServerService
) {}
private instanceService = inject(InstanceService)
private customMarkupService = inject(CustomMarkupService)
private serverService = inject(ServerService)
resolve (): Observable<ResolverData> {
return forkJoin([

View File

@ -1,5 +1,5 @@
import { NgFor, NgIf } from '@angular/common'
import { Component, OnInit, ViewChild } from '@angular/core'
import { Component, OnInit, inject, viewChild } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { ServerService } from '@app/core'
import { AboutHTML } from '@app/shared/shared-main/instance/instance.service'
@ -19,7 +19,11 @@ import { ResolverData } from '../about-instance.resolver'
]
})
export class AboutInstanceHomeComponent implements OnInit {
@ViewChild('supportModal') supportModal: SupportModalComponent
private router = inject(Router)
private route = inject(ActivatedRoute)
private serverService = inject(ServerService)
readonly supportModal = viewChild<SupportModalComponent>('supportModal')
aboutHTML: AboutHTML
descriptionElement: HTMLDivElement
@ -29,12 +33,6 @@ export class AboutInstanceHomeComponent implements OnInit {
config: HTMLServerConfig
constructor (
private router: Router,
private route: ActivatedRoute,
private serverService: ServerService
) {}
ngOnInit () {
this.config = this.serverService.getHTMLConfig()
@ -55,7 +53,7 @@ export class AboutInstanceHomeComponent implements OnInit {
if (!data?.isSupport) return
setTimeout(() => {
const modal = this.supportModal.show()
const modal = this.supportModal().show()
modal.hidden.subscribe(() => this.router.navigateByUrl('/about/instance/home'))
}, 0)

View File

@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { ServerService } from '@app/core'
import { AboutHTML } from '@app/shared/shared-main/instance/instance.service'
@ -12,12 +12,10 @@ import { PluginSelectorDirective } from '@app/shared/shared-main/plugins/plugin-
imports: [ CommonModule, PluginSelectorDirective ]
})
export class AboutInstanceModerationComponent implements OnInit {
aboutHTML: AboutHTML
private route = inject(ActivatedRoute)
private serverService = inject(ServerService)
constructor (
private route: ActivatedRoute,
private serverService: ServerService
) {}
aboutHTML: AboutHTML
get instanceName () {
return this.serverService.getHTMLConfig().instance.name

View File

@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { ServerService } from '@app/core'
import { AboutHTML } from '@app/shared/shared-main/instance/instance.service'
@ -11,12 +11,10 @@ import { ResolverData } from '../about-instance.resolver'
imports: [ CommonModule ]
})
export class AboutInstanceTeamComponent implements OnInit {
aboutHTML: AboutHTML
private route = inject(ActivatedRoute)
private serverService = inject(ServerService)
constructor (
private route: ActivatedRoute,
private serverService: ServerService
) {}
aboutHTML: AboutHTML
get instanceName () {
return this.serverService.getHTMLConfig().instance.name

View File

@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { ServerService } from '@app/core'
import { AboutHTML } from '@app/shared/shared-main/instance/instance.service'
@ -13,12 +13,10 @@ import { InstanceFeaturesTableComponent } from '@app/shared/shared-instance/inst
imports: [ CommonModule, PluginSelectorDirective, InstanceFeaturesTableComponent ]
})
export class AboutInstanceTechComponent implements OnInit {
aboutHTML: AboutHTML
private route = inject(ActivatedRoute)
private serverService = inject(ServerService)
constructor (
private route: ActivatedRoute,
private serverService: ServerService
) {}
aboutHTML: AboutHTML
get instanceName () {
return this.serverService.getHTMLConfig().instance.name

View File

@ -5,37 +5,37 @@
<div class="blocks" myPluginSelector pluginSelectorId="about-instance-statistics">
<div class="stat">
<strong>{{ stats.totalModerators + stats.totalAdmins | number }}</strong>
<strong>{{ stats().totalModerators + stats().totalAdmins | number }}</strong>
<div i18n>moderators</div>
<my-global-icon iconName="moderation"></my-global-icon>
</div>
<div class="stat">
<strong>{{ stats.totalUsers | number }}</strong>
<strong>{{ stats().totalUsers | number }}</strong>
<div i18n>users</div>
<my-global-icon iconName="user"></my-global-icon>
</div>
<div class="stat">
<strong>{{ stats.totalLocalVideos | number }}</strong>
<strong>{{ stats().totalLocalVideos | number }}</strong>
<a routerLink="/videos/browse" [queryParams]="{ scope: 'local' }" i18n>videos</a>
<my-global-icon iconName="videos"></my-global-icon>
</div>
<div class="stat">
<strong>{{ stats.totalLocalVideoViews | number }}</strong>
<strong>{{ stats().totalLocalVideoViews | number }}</strong>
<div i18n>views</div>
<my-global-icon iconName="eye-open"></my-global-icon>
</div>
<div class="stat">
<strong>{{ stats.totalLocalVideoComments | number }}</strong>
<strong>{{ stats().totalLocalVideoComments | number }}</strong>
<div i18n>comments</div>
<my-global-icon iconName="message-circle"></my-global-icon>
</div>
<div class="stat">
<strong>{{ stats.totalLocalVideoFilesSize | bytes:1 }}</strong>
<strong>{{ stats().totalLocalVideoFilesSize | bytes:1 }}</strong>
<div i18n>hosted videos</div>
<my-global-icon iconName="film"></my-global-icon>
</div>
@ -47,7 +47,7 @@
<div class="blocks">
<div class="usage-rule" *ngIf="config.instance.serverCountry">
<div class="usage-rule" *ngIf="config().instance.serverCountry">
<div class="icon-container">
<my-global-icon iconName="message-circle"></my-global-icon>
@ -57,10 +57,10 @@
</div>
<div>
<strong i18n>This platform has been created in {{ config.instance.serverCountry }}</strong>
<strong i18n>This platform has been created in {{ config().instance.serverCountry }}</strong>
<div class="rule-content">
<ng-container i18n>Your content (comments, videos...) must comply with the legislation in force in this country.</ng-container>
<ng-container *ngIf="aboutHTML.codeOfConduct" i18n> You must also follow our <a routerLink="/about/instance/moderation">code of conduct</a>.</ng-container>
<ng-container *ngIf="aboutHTML().codeOfConduct" i18n> You must also follow our <a routerLink="/about/instance/moderation">code of conduct</a>.</ng-container>
</div>
</div>
</div>
@ -69,7 +69,7 @@
<div class="icon-container">
<my-global-icon iconName="user"></my-global-icon>
@if (config.signup.allowed && config.signup.allowedForCurrentIP) {
@if (config().signup.allowed && config().signup.allowedForCurrentIP) {
<div class="icon-status">
<my-global-icon iconName="tick"></my-global-icon>
</div>
@ -81,12 +81,12 @@
</div>
<div>
@if (config.signup.allowed && config.signup.allowedForCurrentIP) {
@if (config.signup.requiresApproval) {
@if (config().signup.allowed && config().signup.allowedForCurrentIP) {
@if (config().signup.requiresApproval) {
<strong i18n>You can <a routerLink="/signup">request an account</a> on our platform</strong>
@if (stats.averageRegistrationRequestResponseTimeMs) {
<div class="rule-content" i18n>Our moderator will validate it within a {{ stats.averageRegistrationRequestResponseTimeMs | myDaysDurationFormatter }}.</div>
@if (stats().averageRegistrationRequestResponseTimeMs) {
<div class="rule-content" i18n>Our moderator will validate it within a {{ stats().averageRegistrationRequestResponseTimeMs | myDaysDurationFormatter }}.</div>
} @else {
<div class="rule-content" i18n>Our moderator will validate it within a few days.</div>
}
@ -99,7 +99,7 @@
</div>
</div>
<div class="usage-rule" *ngIf="config.federation.enabled">
<div class="usage-rule" *ngIf="config().federation.enabled">
<div class="icon-container">
<my-global-icon iconName="fediverse"></my-global-icon>

View File

@ -1,5 +1,5 @@
import { CommonModule, DecimalPipe, NgIf } from '@angular/common'
import { Component, Input } from '@angular/core'
import { Component, inject, input } from '@angular/core'
import { RouterLink } from '@angular/router'
import { BytesPipe } from '@app/shared/shared-main/common/bytes.pipe'
import { DaysDurationFormatterPipe } from '@app/shared/shared-main/date/days-duration-formatter.pipe'
@ -25,13 +25,11 @@ import { AuthService } from '@app/core'
]
})
export class InstanceStatRulesComponent {
@Input({ required: true }) stats: ServerStats
@Input({ required: true }) config: ServerConfig
@Input({ required: true }) aboutHTML: AboutHTML
private auth = inject(AuthService)
constructor (private auth: AuthService) {
}
readonly stats = input.required<ServerStats>()
readonly config = input.required<ServerConfig>()
readonly aboutHTML = input.required<AboutHTML>()
canUpload () {
const user = this.auth.getUser()
@ -42,14 +40,16 @@ export class InstanceStatRulesComponent {
return true
}
return this.config.user.videoQuota !== 0 && this.config.user.videoQuotaDaily !== 0
const config = this.config()
return config.user.videoQuota !== 0 && config.user.videoQuotaDaily !== 0
}
canPublishLive () {
return this.config.live.enabled
return this.config().live.enabled
}
isContactFormEnabled () {
return this.config.email.enabled && this.config.contactForm.enabled
const config = this.config()
return config.email.enabled && config.contactForm.enabled
}
}

View File

@ -1,4 +1,4 @@
import { Component, AfterViewChecked } from '@angular/core'
import { Component, AfterViewChecked, inject } from '@angular/core'
import { ViewportScroller } from '@angular/common'
@Component({
@ -7,13 +7,10 @@ import { ViewportScroller } from '@angular/common'
styleUrls: [ './about-peertube.component.scss' ],
standalone: true
})
export class AboutPeertubeComponent implements AfterViewChecked {
private lastScrollHash: string
private viewportScroller = inject(ViewportScroller)
constructor (
private viewportScroller: ViewportScroller
) {}
private lastScrollHash: string
ngAfterViewChecked () {
if (window.location.hash && window.location.hash !== this.lastScrollHash) {

View File

@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common'
import { Component, OnInit, ViewChild } from '@angular/core'
import { Component, OnInit, inject, viewChild } from '@angular/core'
import { RouterOutlet } from '@angular/router'
import { ServerService } from '@app/core'
import { GlobalIconComponent } from '@app/shared/shared-icons/global-icon.component'
@ -14,11 +14,12 @@ import { HTMLServerConfig } from '@peertube/peertube-models'
selector: 'my-about',
templateUrl: './about.component.html',
styleUrls: [ './about.component.scss' ],
imports: [ CommonModule, RouterOutlet, HorizontalMenuComponent, GlobalIconComponent, ButtonComponent, SupportModalComponent ]
imports: [ CommonModule, RouterOutlet, HorizontalMenuComponent, GlobalIconComponent, ButtonComponent ]
})
export class AboutComponent implements OnInit {
@ViewChild('supportModal') supportModal: SupportModalComponent
private server = inject(ServerService)
readonly supportModal = viewChild<SupportModalComponent>('supportModal')
bannerUrl: string
avatarUrl: string
@ -27,12 +28,6 @@ export class AboutComponent implements OnInit {
config: HTMLServerConfig
constructor (
private server: ServerService
) {
}
ngOnInit () {
this.config = this.server.getHTMLConfig()

View File

@ -1,6 +1,6 @@
import { from, Subject, Subscription } from 'rxjs'
import { concatMap, map, switchMap, tap } from 'rxjs/operators'
import { Component, OnDestroy, OnInit } from '@angular/core'
import { Component, OnDestroy, OnInit, inject } from '@angular/core'
import { ComponentPagination, hasMoreItems, MarkdownService, User, UserService } from '@app/core'
import { SimpleMemoize } from '@app/helpers'
import { NSFWPolicyType, VideoSortField } from '@peertube/peertube-models'
@ -24,12 +24,18 @@ import { Video } from '@app/shared/shared-main/video/video.model'
imports: [ NgIf, InfiniteScrollerDirective, NgFor, ActorAvatarComponent, RouterLink, SubscribeButtonComponent, VideoMiniatureComponent ]
})
export class AccountVideoChannelsComponent implements OnInit, OnDestroy {
private accountService = inject(AccountService)
private videoChannelService = inject(VideoChannelService)
private videoService = inject(VideoService)
private markdown = inject(MarkdownService)
private userService = inject(UserService)
account: Account
videoChannels: VideoChannel[] = []
videos: { [id: number]: { total: number, videos: Video[] } } = {}
channelsDescriptionHTML: { [ id: number ]: string } = {}
channelsDescriptionHTML: { [id: number]: string } = {}
channelPagination: ComponentPagination = {
currentPage: 1,
@ -61,23 +67,15 @@ export class AccountVideoChannelsComponent implements OnInit, OnDestroy {
private accountSub: Subscription
constructor (
private accountService: AccountService,
private videoChannelService: VideoChannelService,
private videoService: VideoService,
private markdown: MarkdownService,
private userService: UserService
) { }
ngOnInit () {
// Parent get the account for us
this.accountSub = this.accountService.accountLoaded
.subscribe(account => {
this.account = account
this.videoChannels = []
.subscribe(account => {
this.account = account
this.videoChannels = []
this.loadMoreChannels()
})
this.loadMoreChannels()
})
this.userService.getAnonymousOrLoggedUser()
.subscribe(user => {

View File

@ -1,5 +1,5 @@
import { NgIf } from '@angular/common'
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'
import { Component, OnDestroy, OnInit, inject, viewChild } from '@angular/core'
import { ComponentPaginationLight, DisableForReuseHook, ScreenService } from '@app/core'
import { Account } from '@app/shared/shared-main/account/account.model'
import { AccountService } from '@app/shared/shared-main/account/account.service'
@ -15,7 +15,11 @@ import { VideosListComponent } from '../../shared/shared-video-miniature/videos-
imports: [ NgIf, VideosListComponent ]
})
export class AccountVideosComponent implements OnInit, OnDestroy, DisableForReuseHook {
@ViewChild('videosList') videosList: VideosListComponent
private screenService = inject(ScreenService)
private accountService = inject(AccountService)
private videoService = inject(VideoService)
readonly videosList = viewChild<VideosListComponent>('videosList')
getVideosObservableFunction = this.getVideosObservable.bind(this)
getSyndicationItemsFunction = this.getSyndicationItems.bind(this)
@ -29,19 +33,12 @@ export class AccountVideosComponent implements OnInit, OnDestroy, DisableForReus
private accountSub: Subscription
constructor (
private screenService: ScreenService,
private accountService: AccountService,
private videoService: VideoService
) {
}
ngOnInit () {
// Parent get the account for us
this.accountSub = this.accountService.accountLoaded
.subscribe(account => {
this.account = account
if (this.alreadyLoaded) this.videosList.reloadVideos()
if (this.alreadyLoaded) this.videosList().reloadVideos()
this.alreadyLoaded = true
})

View File

@ -1,5 +1,5 @@
import { NgClass, NgIf } from '@angular/common'
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'
import { Component, OnDestroy, OnInit, inject, viewChild } from '@angular/core'
import { ActivatedRoute, Router, RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router'
import { AuthService, MarkdownService, MetaService, Notifier, RedirectService, RestExtractor, ScreenService, UserService } from '@app/core'
import { Account } from '@app/shared/shared-main/account/account.model'
@ -44,7 +44,22 @@ import { SubscribeButtonComponent } from '../shared/shared-user-subscription/sub
]
})
export class AccountsComponent implements OnInit, OnDestroy {
@ViewChild('accountReportModal') accountReportModal: AccountReportComponent
private route = inject(ActivatedRoute)
private router = inject(Router)
private userService = inject(UserService)
private accountService = inject(AccountService)
private videoChannelService = inject(VideoChannelService)
private notifier = inject(Notifier)
private restExtractor = inject(RestExtractor)
private redirectService = inject(RedirectService)
private authService = inject(AuthService)
private videoService = inject(VideoService)
private markdown = inject(MarkdownService)
private blocklist = inject(BlocklistService)
private screenService = inject(ScreenService)
private metaService = inject(MetaService)
readonly accountReportModal = viewChild<AccountReportComponent>('accountReportModal')
account: Account
accountUser: User
@ -62,24 +77,6 @@ export class AccountsComponent implements OnInit, OnDestroy {
private routeSub: Subscription
constructor (
private route: ActivatedRoute,
private router: Router,
private userService: UserService,
private accountService: AccountService,
private videoChannelService: VideoChannelService,
private notifier: Notifier,
private restExtractor: RestExtractor,
private redirectService: RedirectService,
private authService: AuthService,
private videoService: VideoService,
private markdown: MarkdownService,
private blocklist: BlocklistService,
private screenService: ScreenService,
private metaService: MetaService
) {
}
ngOnInit () {
this.routeSub = this.route.params
.pipe(
@ -88,10 +85,12 @@ export class AccountsComponent implements OnInit, OnDestroy {
switchMap(accountId => this.accountService.getAccount(accountId)),
tap(account => this.onAccount(account)),
switchMap(account => this.videoChannelService.listAccountVideoChannels({ account })),
catchError(err => this.restExtractor.redirectTo404IfNotFound(err, 'other', [
HttpStatusCode.BAD_REQUEST_400,
HttpStatusCode.NOT_FOUND_404
]))
catchError(err =>
this.restExtractor.redirectTo404IfNotFound(err, 'other', [
HttpStatusCode.BAD_REQUEST_400,
HttpStatusCode.NOT_FOUND_404
])
)
)
.subscribe({
next: videoChannels => {
@ -187,7 +186,7 @@ export class AccountsComponent implements OnInit, OnDestroy {
}
private showReportModal () {
this.accountReportModal.show(this.account)
this.accountReportModal().show(this.account)
}
private loadUserIfNeeded (account: Account) {

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { RouterOutlet } from '@angular/router'
import { AuthService, ServerService } from '@app/core'
import { HorizontalMenuComponent, HorizontalMenuEntry } from '@app/shared/shared-main/menu/horizontal-menu.component'
@ -9,12 +9,10 @@ import { UserRight, UserRightType } from '@peertube/peertube-models'
imports: [ HorizontalMenuComponent, RouterOutlet ]
})
export class AdminModerationComponent implements OnInit {
menuEntries: HorizontalMenuEntry[] = []
private auth = inject(AuthService)
private server = inject(ServerService)
constructor (
private auth: AuthService,
private server: ServerService
) { }
menuEntries: HorizontalMenuEntry[] = []
ngOnInit () {
this.server.configReloaded.subscribe(() => this.buildMenu())

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { RouterOutlet } from '@angular/router'
import { AuthService } from '@app/core'
import { HorizontalMenuComponent, HorizontalMenuEntry } from '@app/shared/shared-main/menu/horizontal-menu.component'
@ -9,11 +9,9 @@ import { UserRight, UserRightType } from '@peertube/peertube-models'
imports: [ HorizontalMenuComponent, RouterOutlet ]
})
export class AdminOverviewComponent implements OnInit {
menuEntries: HorizontalMenuEntry[] = []
private auth = inject(AuthService)
constructor (
private auth: AuthService
) { }
menuEntries: HorizontalMenuEntry[] = []
ngOnInit () {
this.buildMenu()

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { RouterOutlet } from '@angular/router'
import { AuthService, ServerService } from '@app/core'
import { HorizontalMenuComponent, HorizontalMenuEntry } from '@app/shared/shared-main/menu/horizontal-menu.component'
@ -9,12 +9,10 @@ import { PluginType, UserRight, UserRightType } from '@peertube/peertube-models'
imports: [ HorizontalMenuComponent, RouterOutlet ]
})
export class AdminSettingsComponent implements OnInit {
menuEntries: HorizontalMenuEntry[] = []
private auth = inject(AuthService)
private server = inject(ServerService)
constructor (
private auth: AuthService,
private server: ServerService
) { }
menuEntries: HorizontalMenuEntry[] = []
ngOnInit () {
this.server.configReloaded.subscribe(() => this.buildMenu())

View File

@ -1,4 +1,4 @@
<ng-container [formGroup]="form">
<ng-container [formGroup]="form()">
<div class="pt-two-cols mt-5"> <!-- cache grid -->
@ -17,12 +17,12 @@
<div class="number-with-unit">
<input
type="number" min="0" id="cachePreviewsSize" class="form-control"
formControlName="size" [ngClass]="{ 'input-error': formErrors['cache.previews.size'] }"
formControlName="size" [ngClass]="{ 'input-error': formErrors()['cache.previews.size'] }"
>
<span i18n>{getCacheSize('previews'), plural, =1 {cached image} other {cached images}}</span>
</div>
<div *ngIf="formErrors.cache.previews.size" class="form-error" role="alert">{{ formErrors.cache.previews.size }}</div>
<div *ngIf="formErrors().cache.previews.size" class="form-error" role="alert">{{ formErrors().cache.previews.size }}</div>
</div>
<div class="form-group" formGroupName="captions">
@ -31,12 +31,12 @@
<div class="number-with-unit">
<input
type="number" min="0" id="cacheCaptionsSize" class="form-control"
formControlName="size" [ngClass]="{ 'input-error': formErrors['cache.captions.size'] }"
formControlName="size" [ngClass]="{ 'input-error': formErrors()['cache.captions.size'] }"
>
<span i18n>{getCacheSize('captions'), plural, =1 {cached caption} other {cached captions}}</span>
</div>
<div *ngIf="formErrors.cache.captions.size" class="form-error" role="alert">{{ formErrors.cache.captions.size }}</div>
<div *ngIf="formErrors().cache.captions.size" class="form-error" role="alert">{{ formErrors().cache.captions.size }}</div>
</div>
<div class="form-group" formGroupName="torrents">
@ -45,12 +45,12 @@
<div class="number-with-unit">
<input
type="number" min="0" id="cacheTorrentsSize" class="form-control"
formControlName="size" [ngClass]="{ 'input-error': formErrors['cache.torrents.size'] }"
formControlName="size" [ngClass]="{ 'input-error': formErrors()['cache.torrents.size'] }"
>
<span i18n>{getCacheSize('torrents'), plural, =1 {cached torrent} other {cached torrents}}</span>
</div>
<div *ngIf="formErrors.cache.torrents.size" class="form-error" role="alert">{{ formErrors.cache.torrents.size }}</div>
<div *ngIf="formErrors().cache.torrents.size" class="form-error" role="alert">{{ formErrors().cache.torrents.size }}</div>
</div>
<div class="form-group" formGroupName="torrents">
@ -59,12 +59,12 @@
<div class="number-with-unit">
<input
type="number" min="0" id="cacheStoryboardsSize" class="form-control"
formControlName="size" [ngClass]="{ 'input-error': formErrors['cache.storyboards.size'] }"
formControlName="size" [ngClass]="{ 'input-error': formErrors()['cache.storyboards.size'] }"
>
<span i18n>{getCacheSize('storyboards'), plural, =1 {cached storyboard} other {cached storyboards}}</span>
</div>
<div *ngIf="formErrors.cache.storyboards.size" class="form-error" role="alert">{{ formErrors.cache.storyboards.size }}</div>
<div *ngIf="formErrors().cache.storyboards.size" class="form-error" role="alert">{{ formErrors().cache.storyboards.size }}</div>
</div>
</ng-container>
@ -96,10 +96,10 @@
<textarea
id="customizationJavascript" formControlName="javascript" class="form-control" dir="ltr"
[ngClass]="{ 'input-error': formErrors['instance.customizations.javascript'] }"
[ngClass]="{ 'input-error': formErrors()['instance.customizations.javascript'] }"
></textarea>
<div *ngIf="formErrors.instance.customizations.javascript" class="form-error" role="alert">{{ formErrors.instance.customizations.javascript }}</div>
<div *ngIf="formErrors().instance.customizations.javascript" class="form-error" role="alert">{{ formErrors().instance.customizations.javascript }}</div>
</div>
<div class="form-group">
@ -126,9 +126,9 @@
<textarea
id="customizationCSS" formControlName="css" class="form-control" dir="ltr"
[ngClass]="{ 'input-error': formErrors['instance.customizations.css'] }"
[ngClass]="{ 'input-error': formErrors()['instance.customizations.css'] }"
></textarea>
<div *ngIf="formErrors.instance.customizations.css" class="form-error" role="alert">{{ formErrors.instance.customizations.css }}</div>
<div *ngIf="formErrors().instance.customizations.css" class="form-error" role="alert">{{ formErrors().instance.customizations.css }}</div>
</div>
</ng-container>
</ng-container>

View File

@ -1,4 +1,4 @@
import { Component, Input } from '@angular/core'
import { Component, input } from '@angular/core'
import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'
import { PeerTubeTemplateDirective } from '../../../shared/shared-main/common/peertube-template.directive'
import { HelpComponent } from '../../../shared/shared-main/buttons/help.component'
@ -11,10 +11,10 @@ import { NgClass, NgIf } from '@angular/common'
imports: [ FormsModule, ReactiveFormsModule, NgClass, NgIf, HelpComponent, PeerTubeTemplateDirective ]
})
export class EditAdvancedConfigurationComponent {
@Input() form: FormGroup
@Input() formErrors: any
readonly form = input<FormGroup>(undefined)
readonly formErrors = input<any>(undefined)
getCacheSize (type: 'captions' | 'previews' | 'torrents' | 'storyboards') {
return this.form.value['cache'][type]['size']
return this.form().value['cache'][type]['size']
}
}

View File

@ -1,4 +1,4 @@
<ng-container [formGroup]="form">
<ng-container [formGroup]="form()">
<div class="pt-two-cols mt-5"> <!-- appearance grid -->
<div class="title-col">
<h2 i18n>APPEARANCE</h2>
@ -30,7 +30,7 @@
[clearable]="false"
></my-select-custom-value>
<div *ngIf="formErrors.instance.defaultClientRoute" class="form-error" role="alert">{{ formErrors.instance.defaultClientRoute }}</div>
<div *ngIf="formErrors().instance.defaultClientRoute" class="form-error" role="alert">{{ formErrors().instance.defaultClientRoute }}</div>
</div>
<div class="form-group" formGroupName="trending">
@ -47,7 +47,7 @@
</select>
</div>
<div *ngIf="formErrors.trending.videos.algorithms.default" class="form-error" role="alert">{{ formErrors.trending.videos.algorithms.default }}</div>
<div *ngIf="formErrors().trending.videos.algorithms.default" class="form-error" role="alert">{{ formErrors().trending.videos.algorithms.default }}</div>
</ng-container>
</ng-container>
</div>
@ -122,7 +122,7 @@
</select>
</div>
<div *ngIf="formErrors.broadcastMessage.level" class="form-error" role="alert">{{ formErrors.broadcastMessage.level }}</div>
<div *ngIf="formErrors().broadcastMessage.level" class="form-error" role="alert">{{ formErrors().broadcastMessage.level }}</div>
</div>
<div class="form-group">
@ -130,10 +130,10 @@
<my-markdown-textarea
inputId="broadcastMessageMessage" formControlName="message"
[formError]="formErrors['broadcastMessage.message']" markdownType="to-unsafe-html"
[formError]="formErrors()['broadcastMessage.message']" markdownType="to-unsafe-html"
></my-markdown-textarea>
<div *ngIf="formErrors.broadcastMessage.message" class="form-error" role="alert">{{ formErrors.broadcastMessage.message }}</div>
<div *ngIf="formErrors().broadcastMessage.message" class="form-error" role="alert">{{ formErrors().broadcastMessage.message }}</div>
</div>
</ng-container>
@ -185,12 +185,12 @@
<div class="number-with-unit">
<input
type="number" min="-1" id="signupLimit" class="form-control"
formControlName="limit" [ngClass]="{ 'input-error': formErrors['signup.limit'] }"
formControlName="limit" [ngClass]="{ 'input-error': formErrors()['signup.limit'] }"
>
<span i18n>{form.value['signup']['limit'], plural, =1 {user} other {users}}</span>
<span i18n>{form().value['signup']['limit'], plural, =1 {user} other {users}}</span>
</div>
<div *ngIf="formErrors.signup.limit" class="form-error" role="alert">{{ formErrors.signup.limit }}</div>
<div *ngIf="formErrors().signup.limit" class="form-error" role="alert">{{ formErrors().signup.limit }}</div>
<small i18n *ngIf="hasUnlimitedSignup()" class="muted small">Signup won't be limited to a fixed number of users.</small>
</div>
@ -201,12 +201,12 @@
<div class="number-with-unit">
<input
type="number" min="1" id="signupMinimumAge" class="form-control"
formControlName="minimumAge" [ngClass]="{ 'input-error': formErrors['signup.minimumAge'] }"
formControlName="minimumAge" [ngClass]="{ 'input-error': formErrors()['signup.minimumAge'] }"
>
<span i18n>{form.value['signup']['minimumAge'], plural, =1 {year old} other {years old}}</span>
<span i18n>{form().value['signup']['minimumAge'], plural, =1 {year old} other {years old}}</span>
</div>
<div *ngIf="formErrors.signup.minimumAge" class="form-error" role="alert">{{ formErrors.signup.minimumAge }}</div>
<div *ngIf="formErrors().signup.minimumAge" class="form-error" role="alert">{{ formErrors().signup.minimumAge }}</div>
</div>
</ng-container>
</my-peertube-checkbox>
@ -228,7 +228,7 @@
<my-user-real-quota-info class="mt-2 d-block small muted" [videoQuota]="getUserVideoQuota()"></my-user-real-quota-info>
<div *ngIf="formErrors.user.videoQuota" class="form-error" role="alert">{{ formErrors.user.videoQuota }}</div>
<div *ngIf="formErrors().user.videoQuota" class="form-error" role="alert">{{ formErrors().user.videoQuota }}</div>
</div>
<div class="form-group">
@ -243,7 +243,7 @@
[clearable]="false"
></my-select-custom-value>
<div *ngIf="formErrors.user.videoQuotaDaily" class="form-error" role="alert">{{ formErrors.user.videoQuotaDaily }}</div>
<div *ngIf="formErrors().user.videoQuotaDaily" class="form-error" role="alert">{{ formErrors().user.videoQuotaDaily }}</div>
</div>
<div class="form-group">
<ng-container formGroupName="history">
@ -281,7 +281,7 @@
<span i18n>jobs in parallel</span>
</div>
<div *ngIf="formErrors.import.concurrency" class="form-error" role="alert">{{ formErrors.import.concurrency }}</div>
<div *ngIf="formErrors().import.concurrency" class="form-error" role="alert">{{ formErrors().import.concurrency }}</div>
</div>
<div class="form-group" formGroupName="http">
@ -328,12 +328,12 @@
<div class="number-with-unit">
<input
type="number" min="1" id="videoChannelSynchronizationMaxPerUser" class="form-control"
formControlName="maxPerUser" [ngClass]="{ 'input-error': formErrors['import']['videoChannelSynchronization']['maxPerUser'] }"
formControlName="maxPerUser" [ngClass]="{ 'input-error': formErrors()['import']['videoChannelSynchronization']['maxPerUser'] }"
>
<span i18n>{form.value['import']['videoChannelSynchronization']['maxPerUser'], plural, =1 {sync} other {syncs}}</span>
<span i18n>{form().value['import']['videoChannelSynchronization']['maxPerUser'], plural, =1 {sync} other {syncs}}</span>
</div>
<div *ngIf="formErrors.import.videoChannelSynchronization.maxPerUser" class="form-error" role="alert">{{ formErrors.import.videoChannelSynchronization.maxPerUser }}</div>
<div *ngIf="formErrors().import.videoChannelSynchronization.maxPerUser" class="form-error" role="alert">{{ formErrors().import.videoChannelSynchronization.maxPerUser }}</div>
</div>
</ng-container>
@ -426,12 +426,12 @@
<div class="number-with-unit">
<input
type="number" min="1" id="videoChannelsMaxPerUser" class="form-control"
formControlName="maxPerUser" [ngClass]="{ 'input-error': formErrors['videoChannels.maxPerUser'] }"
formControlName="maxPerUser" [ngClass]="{ 'input-error': formErrors()['videoChannels.maxPerUser'] }"
>
<span i18n>{form.value['videoChannels']['maxPerUser'], plural, =1 {channel} other {channels}}</span>
<span i18n>{form().value['videoChannels']['maxPerUser'], plural, =1 {channel} other {channels}}</span>
</div>
<div *ngIf="formErrors.videoChannels.maxPerUser" class="form-error" role="alert">{{ formErrors.videoChannels.maxPerUser }}</div>
<div *ngIf="formErrors().videoChannels.maxPerUser" class="form-error" role="alert">{{ formErrors().videoChannels.maxPerUser }}</div>
</div>
</div>
</div>
@ -490,10 +490,10 @@
<input
type="text" id="searchIndexUrl" class="form-control"
formControlName="url" [ngClass]="{ 'input-error': formErrors['search.searchIndex.url'] }"
formControlName="url" [ngClass]="{ 'input-error': formErrors()['search.searchIndex.url'] }"
>
<div *ngIf="formErrors.search.searchIndex.url" class="form-error" role="alert">{{ formErrors.search.searchIndex.url }}</div>
<div *ngIf="formErrors().search.searchIndex.url" class="form-error" role="alert">{{ formErrors().search.searchIndex.url }}</div>
</div>
<div class="mt-3">
@ -577,7 +577,7 @@
[clearable]="false"
></my-select-custom-value>
<div *ngIf="formErrors.export.users.maxUserVideoQuota" class="form-error" role="alert">{{ formErrors.export.users.maxUserVideoQuota }}</div>
<div *ngIf="formErrors().export.users.maxUserVideoQuota" class="form-error" role="alert">{{ formErrors().export.users.maxUserVideoQuota }}</div>
</div>
<div class="form-group" [ngClass]="getDisabledExportUsersClass()">
@ -587,7 +587,7 @@
<div i18n class="mt-1 small muted">The archive file is deleted after this period.</div>
<div *ngIf="formErrors.export.users.exportExpiration" class="form-error" role="alert">{{ formErrors.export.users.exportExpiration }}</div>
<div *ngIf="formErrors().export.users.exportExpiration" class="form-error" role="alert">{{ formErrors().export.users.exportExpiration }}</div>
</div>
</ng-container>
@ -663,9 +663,9 @@
<label i18n for="followingsInstanceAutoFollowIndexUrl">Index URL</label>
<input
type="text" id="followingsInstanceAutoFollowIndexUrl" class="form-control"
formControlName="indexUrl" [ngClass]="{ 'input-error': formErrors['followings.instance.autoFollowIndex.indexUrl'] }"
formControlName="indexUrl" [ngClass]="{ 'input-error': formErrors()['followings.instance.autoFollowIndex.indexUrl'] }"
>
<div *ngIf="formErrors.followings.instance.autoFollowIndex.indexUrl" class="form-error" role="alert">{{ formErrors.followings.instance.autoFollowIndex.indexUrl }}</div>
<div *ngIf="formErrors().followings.instance.autoFollowIndex.indexUrl" class="form-error" role="alert">{{ formErrors().followings.instance.autoFollowIndex.indexUrl }}</div>
</div>
</ng-container>
</my-peertube-checkbox>
@ -690,10 +690,10 @@
<input
type="text" id="adminEmail" class="form-control"
formControlName="email" [ngClass]="{ 'input-error': formErrors['admin.email'] }"
formControlName="email" [ngClass]="{ 'input-error': formErrors()['admin.email'] }"
>
<div *ngIf="formErrors.admin.email" class="form-error" role="alert">{{ formErrors.admin.email }}</div>
<div *ngIf="formErrors().admin.email" class="form-error" role="alert">{{ formErrors().admin.email }}</div>
</div>
<div class="form-group" formGroupName="contactForm">
@ -731,10 +731,10 @@
<input
type="text" id="servicesTwitterUsername" class="form-control"
formControlName="username" [ngClass]="{ 'input-error': formErrors['services.twitter.username'] }"
formControlName="username" [ngClass]="{ 'input-error': formErrors()['services.twitter.username'] }"
>
<div *ngIf="formErrors.services.twitter.username" class="form-error" role="alert">{{ formErrors.services.twitter.username }}</div>
<div *ngIf="formErrors().services.twitter.username" class="form-error" role="alert">{{ formErrors().services.twitter.username }}</div>
</div>
</ng-container>

View File

@ -1,5 +1,5 @@
import { NgClass, NgFor, NgIf } from '@angular/common'
import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'
import { NgClass, NgIf } from '@angular/common'
import { Component, OnChanges, OnInit, SimpleChanges, inject, input } from '@angular/core'
import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'
import { RouterLink } from '@angular/router'
import { ThemeService } from '@app/core'
@ -23,7 +23,6 @@ import { ConfigService } from '../shared/config.service'
FormsModule,
ReactiveFormsModule,
RouterLink,
NgFor,
SelectCustomValueComponent,
NgIf,
PeertubeCheckboxComponent,
@ -36,10 +35,13 @@ import { ConfigService } from '../shared/config.service'
]
})
export class EditBasicConfigurationComponent implements OnInit, OnChanges {
@Input() form: FormGroup
@Input() formErrors: any
private configService = inject(ConfigService)
private themeService = inject(ThemeService)
@Input() serverConfig: HTMLServerConfig
readonly form = input<FormGroup>(undefined)
readonly formErrors = input<any>(undefined)
readonly serverConfig = input<HTMLServerConfig>(undefined)
signupAlertMessage: string
defaultLandingPageOptions: SelectOptionsItem[] = []
@ -48,11 +50,6 @@ export class EditBasicConfigurationComponent implements OnInit, OnChanges {
exportExpirationOptions: SelectOptionsItem[] = []
exportMaxUserVideoQuotaOptions: SelectOptionsItem[] = []
constructor (
private configService: ConfigService,
private themeService: ThemeService
) {}
ngOnInit () {
this.buildLandingPageOptions()
this.checkSignupField()
@ -81,7 +78,7 @@ export class EditBasicConfigurationComponent implements OnInit, OnChanges {
}
countExternalAuth () {
return this.serverConfig.plugin.registeredExternalAuths.length
return this.serverConfig().plugin.registeredExternalAuths.length
}
getVideoQuotaOptions () {
@ -93,18 +90,18 @@ export class EditBasicConfigurationComponent implements OnInit, OnChanges {
}
doesTrendingVideosAlgorithmsEnabledInclude (algorithm: string) {
const enabled = this.form.value['trending']['videos']['algorithms']['enabled']
const enabled = this.form().value['trending']['videos']['algorithms']['enabled']
if (!Array.isArray(enabled)) return false
return !!enabled.find((e: string) => e === algorithm)
}
getUserVideoQuota () {
return this.form.value['user']['videoQuota']
return this.form().value['user']['videoQuota']
}
isExportUsersEnabled () {
return this.form.value['export']['users']['enabled'] === true
return this.form().value['export']['users']['enabled'] === true
}
getDisabledExportUsersClass () {
@ -112,7 +109,7 @@ export class EditBasicConfigurationComponent implements OnInit, OnChanges {
}
isSignupEnabled () {
return this.form.value['signup']['enabled'] === true
return this.form().value['signup']['enabled'] === true
}
getDisabledSignupClass () {
@ -120,19 +117,19 @@ export class EditBasicConfigurationComponent implements OnInit, OnChanges {
}
isImportVideosHttpEnabled (): boolean {
return this.form.value['import']['videos']['http']['enabled'] === true
return this.form().value['import']['videos']['http']['enabled'] === true
}
importSynchronizationChecked () {
return this.isImportVideosHttpEnabled() && this.form.value['import']['videoChannelSynchronization']['enabled']
return this.isImportVideosHttpEnabled() && this.form().value['import']['videoChannelSynchronization']['enabled']
}
hasUnlimitedSignup () {
return this.form.value['signup']['limit'] === -1
return this.form().value['signup']['limit'] === -1
}
isSearchIndexEnabled () {
return this.form.value['search']['searchIndex']['enabled'] === true
return this.form().value['search']['searchIndex']['enabled'] === true
}
getDisabledSearchIndexClass () {
@ -142,7 +139,7 @@ export class EditBasicConfigurationComponent implements OnInit, OnChanges {
// ---------------------------------------------------------------------------
isTranscriptionEnabled () {
return this.form.value['videoTranscription']['enabled'] === true
return this.form().value['videoTranscription']['enabled'] === true
}
getTranscriptionRunnerDisabledClass () {
@ -152,13 +149,13 @@ export class EditBasicConfigurationComponent implements OnInit, OnChanges {
// ---------------------------------------------------------------------------
isAutoFollowIndexEnabled () {
return this.form.value['followings']['instance']['autoFollowIndex']['enabled'] === true
return this.form().value['followings']['instance']['autoFollowIndex']['enabled'] === true
}
buildLandingPageOptions () {
let links: { label: string, path: string }[] = []
if (this.serverConfig.homepage.enabled) {
if (this.serverConfig().homepage.enabled) {
links.push({ label: $localize`Home`, path: '/home' })
}
@ -176,11 +173,11 @@ export class EditBasicConfigurationComponent implements OnInit, OnChanges {
}
private checkImportSyncField () {
const importSyncControl = this.form.get('import.videoChannelSynchronization.enabled')
const importVideosHttpControl = this.form.get('import.videos.http.enabled')
const importSyncControl = this.form().get('import.videoChannelSynchronization.enabled')
const importVideosHttpControl = this.form().get('import.videos.http.enabled')
importVideosHttpControl.valueChanges
.subscribe((httpImportEnabled) => {
.subscribe(httpImportEnabled => {
importSyncControl.setValue(httpImportEnabled && importSyncControl.value)
if (httpImportEnabled) {
importSyncControl.enable()
@ -191,16 +188,17 @@ export class EditBasicConfigurationComponent implements OnInit, OnChanges {
}
private checkSignupField () {
const signupControl = this.form.get('signup.enabled')
const signupControl = this.form().get('signup.enabled')
signupControl.valueChanges
.pipe(pairwise())
.subscribe(([ oldValue, newValue ]) => {
if (oldValue === false && newValue === true) {
/* eslint-disable max-len */
this.signupAlertMessage = $localize`You enabled signup: we automatically enabled the "Block new videos automatically" checkbox of the "Videos" section just below.`
this.signupAlertMessage =
$localize`You enabled signup: we automatically enabled the "Block new videos automatically" checkbox of the "Videos" section just below.`
this.form.patchValue({
this.form().patchValue({
autoBlacklist: {
videos: {
ofUsers: {

View File

@ -1,5 +1,5 @@
import { NgFor, NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { ActivatedRoute, Router } from '@angular/router'
import { ConfigService } from '@app/+admin/config/shared/config.service'
@ -73,6 +73,15 @@ type ComponentCustomConfig = CustomConfig & {
]
})
export class EditCustomConfigComponent extends FormReactive implements OnInit {
protected formReactiveService = inject(FormReactiveService)
private router = inject(Router)
private route = inject(ActivatedRoute)
private notifier = inject(Notifier)
private configService = inject(ConfigService)
private customPage = inject(CustomPageService)
private serverService = inject(ServerService)
private editConfigurationService = inject(EditConfigurationService)
activeNav: string
customConfig: ComponentCustomConfig
@ -83,23 +92,10 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
languageItems: SelectOptionsItem[] = []
categoryItems: SelectOptionsItem[] = []
constructor (
protected formReactiveService: FormReactiveService,
private router: Router,
private route: ActivatedRoute,
private notifier: Notifier,
private configService: ConfigService,
private customPage: CustomPageService,
private serverService: ServerService,
private editConfigurationService: EditConfigurationService
) {
super()
}
ngOnInit () {
this.serverConfig = this.serverService.getHTMLConfig()
const formGroupData: { [key in keyof ComponentCustomConfig ]: any } = {
const formGroupData: { [key in keyof ComponentCustomConfig]: any } = {
instance: {
name: INSTANCE_NAME_VALIDATOR,
shortDescription: INSTANCE_SHORT_DESCRIPTION_VALIDATOR,
@ -193,7 +189,6 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
videoChannelSynchronization: {
enabled: null,
maxPerUser: MAX_SYNC_PER_USER
},
users: {
enabled: null

View File

@ -1,4 +1,4 @@
<ng-container [formGroup]="form">
<ng-container [formGroup]="form()">
<ng-container formGroupName="instanceCustomHomepage">
@ -18,11 +18,11 @@
<my-markdown-textarea
inputId="instanceCustomHomepageContent" formControlName="content"
[customMarkdownRenderer]="getCustomMarkdownRenderer()" [debounceTime]="500"
[formError]="formErrors['instanceCustomHomepage.content']"
[formError]="formErrors()['instanceCustomHomepage.content']"
dir="ltr"
></my-markdown-textarea>
<div *ngIf="formErrors.instanceCustomHomepage.content" class="form-error" role="alert">{{ formErrors.instanceCustomHomepage.content }}</div>
<div *ngIf="formErrors().instanceCustomHomepage.content" class="form-error" role="alert">{{ formErrors().instanceCustomHomepage.content }}</div>
</div>
</div>
</div>

View File

@ -1,4 +1,4 @@
import { Component, Input } from '@angular/core'
import { Component, inject, input } from '@angular/core'
import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgIf } from '@angular/common'
import { MarkdownTextareaComponent } from '../../../shared/shared-forms/markdown-textarea.component'
@ -12,15 +12,13 @@ import { CustomMarkupService } from '@app/shared/shared-custom-markup/custom-mar
imports: [ FormsModule, ReactiveFormsModule, CustomMarkupHelpComponent, MarkdownTextareaComponent, NgIf ]
})
export class EditHomepageComponent {
@Input() form: FormGroup
@Input() formErrors: any
private customMarkup = inject(CustomMarkupService)
readonly form = input<FormGroup>(undefined)
readonly formErrors = input<any>(undefined)
customMarkdownRenderer: (text: string) => Promise<HTMLElement>
constructor (private customMarkup: CustomMarkupService) {
}
getCustomMarkdownRenderer () {
return this.customMarkup.getCustomMarkdownRenderer()
}

View File

@ -1,4 +1,4 @@
<ng-container [formGroup]="form">
<ng-container [formGroup]="form()">
<ng-container formGroupName="instance">
@ -41,10 +41,10 @@
<input
type="text" id="instanceName" class="form-control"
formControlName="name" [ngClass]="{ 'input-error': formErrors.instance.name }"
formControlName="name" [ngClass]="{ 'input-error': formErrors().instance.name }"
>
<div *ngIf="formErrors.instance.name" class="form-error" role="alert">{{ formErrors.instance.name }}</div>
<div *ngIf="formErrors().instance.name" class="form-error" role="alert">{{ formErrors().instance.name }}</div>
</div>
<div class="form-group">
@ -52,10 +52,10 @@
<textarea
id="instanceShortDescription" formControlName="shortDescription" class="form-control small"
[ngClass]="{ 'input-error': formErrors['instance.shortDescription'] }"
[ngClass]="{ 'input-error': formErrors()['instance.shortDescription'] }"
></textarea>
<div *ngIf="formErrors.instance.shortDescription" class="form-error" role="alert">{{ formErrors.instance.shortDescription }}</div>
<div *ngIf="formErrors().instance.shortDescription" class="form-error" role="alert">{{ formErrors().instance.shortDescription }}</div>
</div>
<div class="form-group">
@ -67,7 +67,7 @@
<my-markdown-textarea
inputId="instanceDescription" formControlName="description"
[customMarkdownRenderer]="getCustomMarkdownRenderer()" [debounceTime]="500"
[formError]="formErrors['instance.description']"
[formError]="formErrors()['instance.description']"
></my-markdown-textarea>
</div>
@ -77,7 +77,7 @@
<div>
<my-select-checkbox
inputId="instanceCategories"
formControlName="categories" [availableItems]="categoryItems"
formControlName="categories" [availableItems]="categoryItems()"
[selectableGroup]="false"
i18n-placeholder placeholder="Add a new category"
>
@ -91,7 +91,7 @@
<div>
<my-select-checkbox
inputId="instanceLanguages"
formControlName="languages" [availableItems]="languageItems"
formControlName="languages" [availableItems]="languageItems()"
[selectableGroup]="false"
i18n-placeholder placeholder="Add a new language"
>
@ -105,10 +105,10 @@
<input
type="text" id="instanceServerCountry" class="form-control"
formControlName="serverCountry" [ngClass]="{ 'input-error': formErrors.instance.serverCountry }"
formControlName="serverCountry" [ngClass]="{ 'input-error': formErrors().instance.serverCountry }"
>
<div *ngIf="formErrors.instance.serverCountry" class="form-error" role="alert">{{ formErrors.instance.serverCountry }}</div>
<div *ngIf="formErrors().instance.serverCountry" class="form-error" role="alert">{{ formErrors().instance.serverCountry }}</div>
</div>
</div>
@ -130,7 +130,7 @@
<my-markdown-textarea
inputId="instanceSupportText" formControlName="text" markdownType="enhanced"
[formError]="formErrors['instance.support.text']"
[formError]="formErrors()['instance.support.text']"
></my-markdown-textarea>
</div>
@ -141,10 +141,10 @@
<input
type="text" id="instanceSocialExternalLink" class="form-control"
formControlName="externalLink" [ngClass]="{ 'input-error': formErrors.instance.social.externalLink }"
formControlName="externalLink" [ngClass]="{ 'input-error': formErrors().instance.social.externalLink }"
>
<div *ngIf="formErrors.instance.social.externalLink" class="form-error" role="alert">{{ formErrors.instance.social.externalLink }}</div>
<div *ngIf="formErrors().instance.social.externalLink" class="form-error" role="alert">{{ formErrors().instance.social.externalLink }}</div>
</div>
<div class="form-group">
@ -152,10 +152,10 @@
<input
type="text" id="instanceSocialMastodonLink" class="form-control"
formControlName="mastodonLink" [ngClass]="{ 'input-error': formErrors.instance.social.mastodonLink }"
formControlName="mastodonLink" [ngClass]="{ 'input-error': formErrors().instance.social.mastodonLink }"
>
<div *ngIf="formErrors.instance.social.mastodonLink" class="form-error" role="alert">{{ formErrors.instance.social.mastodonLink }}</div>
<div *ngIf="formErrors().instance.social.mastodonLink" class="form-error" role="alert">{{ formErrors().instance.social.mastodonLink }}</div>
</div>
<div class="form-group">
@ -163,10 +163,10 @@
<input
type="text" id="instanceSocialBlueskyLink" class="form-control"
formControlName="blueskyLink" [ngClass]="{ 'input-error': formErrors.instance.social.blueskyLink }"
formControlName="blueskyLink" [ngClass]="{ 'input-error': formErrors().instance.social.blueskyLink }"
>
<div *ngIf="formErrors.instance.social.blueskyLink" class="form-error" role="alert">{{ formErrors.instance.social.blueskyLink }}</div>
<div *ngIf="formErrors().instance.social.blueskyLink" class="form-error" role="alert">{{ formErrors().instance.social.blueskyLink }}</div>
</div>
</ng-container>
@ -217,7 +217,7 @@
</select>
</div>
<div *ngIf="formErrors.instance.defaultNSFWPolicy" class="form-error" role="alert">{{ formErrors.instance.defaultNSFWPolicy }}</div>
<div *ngIf="formErrors().instance.defaultNSFWPolicy" class="form-error" role="alert">{{ formErrors().instance.defaultNSFWPolicy }}</div>
</div>
<div class="form-group">
@ -225,7 +225,7 @@
<my-markdown-textarea
inputId="instanceTerms" formControlName="terms" markdownType="enhanced"
[formError]="formErrors['instance.terms']"
[formError]="formErrors()['instance.terms']"
></my-markdown-textarea>
</div>
@ -234,7 +234,7 @@
<my-markdown-textarea
inputId="instanceCodeOfConduct" formControlName="codeOfConduct" markdownType="enhanced"
[formError]="formErrors['instance.codeOfConduct']"
[formError]="formErrors()['instance.codeOfConduct']"
></my-markdown-textarea>
</div>
@ -244,7 +244,7 @@
<my-markdown-textarea
inputId="instanceModerationInformation" formControlName="moderationInformation" markdownType="enhanced"
[formError]="formErrors['instance.moderationInformation']"
[formError]="formErrors()['instance.moderationInformation']"
></my-markdown-textarea>
</div>
@ -264,7 +264,7 @@
<my-markdown-textarea
inputId="instanceAdministrator" formControlName="administrator" markdownType="enhanced"
[formError]="formErrors['instance.administrator']"
[formError]="formErrors()['instance.administrator']"
></my-markdown-textarea>
</div>
@ -274,7 +274,7 @@
<my-markdown-textarea
inputId="instanceCreationReason" formControlName="creationReason" markdownType="enhanced"
[formError]="formErrors['instance.creationReason']"
[formError]="formErrors()['instance.creationReason']"
></my-markdown-textarea>
</div>
@ -284,7 +284,7 @@
<my-markdown-textarea
inputId="instanceMaintenanceLifetime" formControlName="maintenanceLifetime" markdownType="enhanced"
[formError]="formErrors['instance.maintenanceLifetime']"
[formError]="formErrors()['instance.maintenanceLifetime']"
></my-markdown-textarea>
</div>
@ -294,7 +294,7 @@
<my-markdown-textarea
inputId="instanceBusinessModel" formControlName="businessModel" markdownType="enhanced"
[formError]="formErrors['instance.businessModel']"
[formError]="formErrors()['instance.businessModel']"
></my-markdown-textarea>
</div>
@ -314,7 +314,7 @@
<my-markdown-textarea
inputId="instanceHardwareInformation" formControlName="hardwareInformation" markdownType="enhanced"
[formError]="formErrors['instance.hardwareInformation']"
[formError]="formErrors()['instance.hardwareInformation']"
></my-markdown-textarea>
</div>

View File

@ -1,6 +1,6 @@
import { NgClass, NgIf } from '@angular/common'
import { HttpErrorResponse } from '@angular/common/http'
import { Component, Input, OnInit } from '@angular/core'
import { Component, OnInit, inject, input } from '@angular/core'
import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'
import { RouterLink } from '@angular/router'
import { Notifier, ServerService } from '@app/core'
@ -40,26 +40,22 @@ import { HelpComponent } from '../../../shared/shared-main/buttons/help.componen
]
})
export class EditInstanceInformationComponent implements OnInit {
@Input() form: FormGroup
@Input() formErrors: any
private customMarkup = inject(CustomMarkupService)
private notifier = inject(Notifier)
private instanceService = inject(InstanceService)
private server = inject(ServerService)
@Input() languageItems: SelectOptionsItem[] = []
@Input() categoryItems: SelectOptionsItem[] = []
readonly form = input<FormGroup>(undefined)
readonly formErrors = input<any>(undefined)
readonly languageItems = input<SelectOptionsItem[]>([])
readonly categoryItems = input<SelectOptionsItem[]>([])
instanceBannerUrl: string
instanceAvatars: ActorImage[] = []
private serverConfig: HTMLServerConfig
constructor (
private customMarkup: CustomMarkupService,
private notifier: Notifier,
private instanceService: InstanceService,
private server: ServerService
) {
}
get instanceName () {
return this.server.getHTMLConfig().instance.name
}
@ -139,5 +135,4 @@ export class EditInstanceInformationComponent implements OnInit {
this.updateActorImages()
})
}
}

View File

@ -1,4 +1,4 @@
<ng-container [formGroup]="form">
<ng-container [formGroup]="form()">
<div class="pt-two-cols mt-5">
<div class="title-col">
@ -52,10 +52,10 @@
<div class="number-with-unit">
<input type="number" id="liveMaxInstanceLives" formControlName="maxInstanceLives" />
<span i18n>{form.value['live']['maxInstanceLives'], plural, =1 {live} other {lives}}</span>
<span i18n>{form().value['live']['maxInstanceLives'], plural, =1 {live} other {lives}}</span>
</div>
<div *ngIf="formErrors.live.maxInstanceLives" class="form-error" role="alert">{{ formErrors.live.maxInstanceLives }}</div>
<div *ngIf="formErrors().live.maxInstanceLives" class="form-error" role="alert">{{ formErrors().live.maxInstanceLives }}</div>
</div>
<div class="form-group" [ngClass]="getDisabledLiveClass()">
@ -64,10 +64,10 @@
<div class="number-with-unit">
<input type="number" id="liveMaxUserLives" formControlName="maxUserLives" />
<span i18n>{form.value['live']['maxUserLives'], plural, =1 {live} other {lives}}</span>
<span i18n>{form().value['live']['maxUserLives'], plural, =1 {live} other {lives}}</span>
</div>
<div *ngIf="formErrors.live.maxUserLives" class="form-error" role="alert">{{ formErrors.live.maxUserLives }}</div>
<div *ngIf="formErrors().live.maxUserLives" class="form-error" role="alert">{{ formErrors().live.maxUserLives }}</div>
</div>
<div class="form-group" [ngClass]="getDisabledLiveClass()">
@ -75,7 +75,7 @@
<my-select-options inputId="liveMaxDuration" [items]="liveMaxDurationOptions" formControlName="maxDuration"></my-select-options>
<div *ngIf="formErrors.live.maxDuration" class="form-error" role="alert">{{ formErrors.live.maxDuration }}</div>
<div *ngIf="formErrors().live.maxDuration" class="form-error" role="alert">{{ formErrors().live.maxDuration }}</div>
</div>
</ng-container>
@ -123,7 +123,7 @@
<span>FPS</span>
</div>
<div *ngIf="formErrors.live.transcoding.fps.max" class="form-error" role="alert">{{ formErrors.live.transcoding.fps.max }}</div>
<div *ngIf="formErrors().live.transcoding.fps.max" class="form-error" role="alert">{{ formErrors().live.transcoding.fps.max }}</div>
</div>
<div class="ms-2 mt-3">
@ -193,7 +193,7 @@
formControlName="threads"
[clearable]="false"
></my-select-custom-value>
<div *ngIf="formErrors.live.transcoding.threads" class="form-error" role="alert">{{ formErrors.live.transcoding.threads }}</div>
<div *ngIf="formErrors().live.transcoding.threads" class="form-error" role="alert">{{ formErrors().live.transcoding.threads }}</div>
</div>
<div class="form-group mt-4" [ngClass]="getDisabledLiveLocalTranscodingClass()">
@ -202,7 +202,7 @@
<my-select-options inputId="liveTranscodingProfile" formControlName="profile" [items]="transcodingProfiles"></my-select-options>
<div *ngIf="formErrors.live.transcoding.profile" class="form-error" role="alert">{{ formErrors.live.transcoding.profile }}</div>
<div *ngIf="formErrors().live.transcoding.profile" class="form-error" role="alert">{{ formErrors().live.transcoding.profile }}</div>
</div>
</ng-container>

View File

@ -1,5 +1,5 @@
import { SelectOptionsItem } from 'src/types/select-options-item.model'
import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'
import { Component, OnChanges, OnInit, SimpleChanges, inject, input } from '@angular/core'
import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'
import { HTMLServerConfig } from '@peertube/peertube-models'
import { ConfigService } from '../shared/config.service'
@ -29,9 +29,12 @@ import { PeertubeCheckboxComponent } from '../../../shared/shared-forms/peertube
]
})
export class EditLiveConfigurationComponent implements OnInit, OnChanges {
@Input() form: FormGroup
@Input() formErrors: any
@Input() serverConfig: HTMLServerConfig
private configService = inject(ConfigService)
private editConfigurationService = inject(EditConfigurationService)
readonly form = input<FormGroup>(undefined)
readonly formErrors = input<any>(undefined)
readonly serverConfig = input<HTMLServerConfig>(undefined)
transcodingThreadOptions: SelectOptionsItem[] = []
transcodingProfiles: SelectOptionsItem[] = []
@ -39,11 +42,6 @@ export class EditLiveConfigurationComponent implements OnInit, OnChanges {
liveMaxDurationOptions: SelectOptionsItem[] = []
liveResolutions: ResolutionOption[] = []
constructor (
private configService: ConfigService,
private editConfigurationService: EditConfigurationService
) { }
ngOnInit () {
this.transcodingThreadOptions = this.configService.transcodingThreadOptions
@ -65,7 +63,7 @@ export class EditLiveConfigurationComponent implements OnInit, OnChanges {
}
buildAvailableTranscodingProfile () {
const profiles = this.serverConfig.live.transcoding.availableProfiles
const profiles = this.serverConfig().live.transcoding.availableProfiles
return profiles.map(p => {
if (p === 'default') {
@ -81,15 +79,15 @@ export class EditLiveConfigurationComponent implements OnInit, OnChanges {
}
getLiveRTMPPort () {
return this.serverConfig.live.rtmp.port
return this.serverConfig().live.rtmp.port
}
isLiveEnabled () {
return this.editConfigurationService.isLiveEnabled(this.form)
return this.editConfigurationService.isLiveEnabled(this.form())
}
isRemoteRunnerLiveEnabled () {
return this.editConfigurationService.isRemoteRunnerLiveEnabled(this.form)
return this.editConfigurationService.isRemoteRunnerLiveEnabled(this.form())
}
getDisabledLiveClass () {
@ -105,10 +103,10 @@ export class EditLiveConfigurationComponent implements OnInit, OnChanges {
}
isLiveTranscodingEnabled () {
return this.editConfigurationService.isLiveTranscodingEnabled(this.form)
return this.editConfigurationService.isLiveTranscodingEnabled(this.form())
}
getTotalTranscodingThreads () {
return this.editConfigurationService.getTotalTranscodingThreads(this.form)
return this.editConfigurationService.getTotalTranscodingThreads(this.form())
}
}

View File

@ -1,4 +1,4 @@
<ng-container [formGroup]="form">
<ng-container [formGroup]="form()">
<div class="pt-two-cols mt-4">
<div class="title-col"></div>
@ -151,7 +151,7 @@
<span>FPS</span>
</div>
<div *ngIf="formErrors.transcoding.fps.max" class="form-error" role="alert">{{ formErrors.transcoding.fps.max }}</div>
<div *ngIf="formErrors().transcoding.fps.max" class="form-error" role="alert">{{ formErrors().transcoding.fps.max }}</div>
</div>
<div class="form-group" [ngClass]="getTranscodingDisabledClass()">
@ -220,7 +220,7 @@
[clearable]="false"
></my-select-custom-value>
<div *ngIf="formErrors.transcoding.threads" class="form-error" role="alert">{{ formErrors.transcoding.threads }}</div>
<div *ngIf="formErrors().transcoding.threads" class="form-error" role="alert">{{ formErrors().transcoding.threads }}</div>
</div>
<div class="form-group" [ngClass]="getLocalTranscodingDisabledClass()">
@ -232,7 +232,7 @@
<span i18n>jobs in parallel</span>
</div>
<div *ngIf="formErrors.transcoding.concurrency" class="form-error" role="alert">{{ formErrors.transcoding.concurrency }}</div>
<div *ngIf="formErrors().transcoding.concurrency" class="form-error" role="alert">{{ formErrors().transcoding.concurrency }}</div>
</div>
<div class="form-group" [ngClass]="getLocalTranscodingDisabledClass()">
@ -241,7 +241,7 @@
<my-select-options inputId="transcodingProfile" formControlName="profile" [items]="transcodingProfiles"></my-select-options>
<div *ngIf="formErrors.transcoding.profile" class="form-error" role="alert">{{ formErrors.transcoding.profile }}</div>
<div *ngIf="formErrors().transcoding.profile" class="form-error" role="alert">{{ formErrors().transcoding.profile }}</div>
</div>
</ng-container>

View File

@ -1,5 +1,5 @@
import { NgClass, NgFor, NgIf } from '@angular/common'
import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'
import { Component, OnChanges, OnInit, SimpleChanges, inject, input } from '@angular/core'
import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'
import { RouterLink } from '@angular/router'
import { Notifier } from '@app/core'
@ -30,9 +30,13 @@ import { EditConfigurationService, ResolutionOption } from './edit-configuration
]
})
export class EditVODTranscodingComponent implements OnInit, OnChanges {
@Input() form: FormGroup
@Input() formErrors: any
@Input() serverConfig: HTMLServerConfig
private configService = inject(ConfigService)
private editConfigurationService = inject(EditConfigurationService)
private notifier = inject(Notifier)
readonly form = input<FormGroup>(undefined)
readonly formErrors = input<any>(undefined)
readonly serverConfig = input<HTMLServerConfig>(undefined)
transcodingThreadOptions: SelectOptionsItem[] = []
transcodingProfiles: SelectOptionsItem[] = []
@ -40,12 +44,6 @@ export class EditVODTranscodingComponent implements OnInit, OnChanges {
additionalVideoExtensions = ''
constructor (
private configService: ConfigService,
private editConfigurationService: EditConfigurationService,
private notifier: Notifier
) { }
ngOnInit () {
this.transcodingThreadOptions = this.configService.transcodingThreadOptions
this.resolutions = this.editConfigurationService.getTranscodingResolutions()
@ -57,12 +55,12 @@ export class EditVODTranscodingComponent implements OnInit, OnChanges {
if (changes['serverConfig']) {
this.transcodingProfiles = this.buildAvailableTranscodingProfile()
this.additionalVideoExtensions = this.serverConfig.video.file.extensions.join(' ')
this.additionalVideoExtensions = this.serverConfig().video.file.extensions.join(' ')
}
}
buildAvailableTranscodingProfile () {
const profiles = this.serverConfig.transcoding.availableProfiles
const profiles = this.serverConfig().transcoding.availableProfiles
return profiles.map(p => {
if (p === 'default') {
@ -78,19 +76,19 @@ export class EditVODTranscodingComponent implements OnInit, OnChanges {
}
isRemoteRunnerVODEnabled () {
return this.editConfigurationService.isRemoteRunnerVODEnabled(this.form)
return this.editConfigurationService.isRemoteRunnerVODEnabled(this.form())
}
isTranscodingEnabled () {
return this.editConfigurationService.isTranscodingEnabled(this.form)
return this.editConfigurationService.isTranscodingEnabled(this.form())
}
isHLSEnabled () {
return this.editConfigurationService.isHLSEnabled(this.form)
return this.editConfigurationService.isHLSEnabled(this.form())
}
isStudioEnabled () {
return this.editConfigurationService.isStudioEnabled(this.form)
return this.editConfigurationService.isStudioEnabled(this.form())
}
getTranscodingDisabledClass () {
@ -110,14 +108,14 @@ export class EditVODTranscodingComponent implements OnInit, OnChanges {
}
getTotalTranscodingThreads () {
return this.editConfigurationService.getTotalTranscodingThreads(this.form)
return this.editConfigurationService.getTotalTranscodingThreads(this.form())
}
private checkTranscodingFields () {
const transcodingControl = this.form.get('transcoding.enabled')
const videoStudioControl = this.form.get('videoStudio.enabled')
const hlsControl = this.form.get('transcoding.hls.enabled')
const webVideosControl = this.form.get('transcoding.webVideos.enabled')
const transcodingControl = this.form().get('transcoding.enabled')
const videoStudioControl = this.form().get('videoStudio.enabled')
const hlsControl = this.form().get('transcoding.hls.enabled')
const webVideosControl = this.form().get('transcoding.webVideos.enabled')
webVideosControl.valueChanges
.subscribe(newValue => {
@ -125,7 +123,11 @@ export class EditVODTranscodingComponent implements OnInit, OnChanges {
hlsControl.setValue(true)
// eslint-disable-next-line max-len
this.notifier.info($localize`Automatically enable HLS transcoding because at least 1 output format must be enabled when transcoding is enabled`, '', 10000)
this.notifier.info(
$localize`Automatically enable HLS transcoding because at least 1 output format must be enabled when transcoding is enabled`,
'',
10000
)
}
})
@ -134,8 +136,12 @@ export class EditVODTranscodingComponent implements OnInit, OnChanges {
if (newValue === false && webVideosControl.value === false) {
webVideosControl.setValue(true)
// eslint-disable-next-line max-len
this.notifier.info($localize`Automatically enable Web Videos transcoding because at least 1 output format must be enabled when transcoding is enabled`, '', 10000)
this.notifier.info(
// eslint-disable-next-line max-len
$localize`Automatically enable Web Videos transcoding because at least 1 output format must be enabled when transcoding is enabled`,
'',
10000
)
}
})

View File

@ -1,6 +1,6 @@
import { catchError } from 'rxjs/operators'
import { HttpClient } from '@angular/common/http'
import { Injectable } from '@angular/core'
import { Injectable, inject } from '@angular/core'
import { RestExtractor } from '@app/core'
import { CustomConfig } from '@peertube/peertube-models'
import { SelectOptionsItem } from '../../../../types/select-options-item.model'
@ -8,16 +8,16 @@ import { environment } from '../../../../environments/environment'
@Injectable()
export class ConfigService {
private authHttp = inject(HttpClient)
private restExtractor = inject(RestExtractor)
private static BASE_APPLICATION_URL = environment.apiUrl + '/api/v1/config'
videoQuotaOptions: SelectOptionsItem[] = []
videoQuotaDailyOptions: SelectOptionsItem[] = []
transcodingThreadOptions: SelectOptionsItem[] = []
constructor (
private authHttp: HttpClient,
private restExtractor: RestExtractor
) {
constructor () {
this.videoQuotaOptions = [
{ id: -1, label: $localize`Unlimited` },
{ id: 0, label: $localize`None - no upload possible` },
@ -60,11 +60,11 @@ export class ConfigService {
getCustomConfig () {
return this.authHttp.get<CustomConfig>(ConfigService.BASE_APPLICATION_URL + '/custom')
.pipe(catchError(res => this.restExtractor.handleError(res)))
.pipe(catchError(res => this.restExtractor.handleError(res)))
}
updateCustomConfig (data: CustomConfig) {
return this.authHttp.put<CustomConfig>(ConfigService.BASE_APPLICATION_URL + '/custom', data)
.pipe(catchError(res => this.restExtractor.handleError(res)))
.pipe(catchError(res => this.restExtractor.handleError(res)))
}
}

View File

@ -1,5 +1,5 @@
import { NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core'
import { formatICU } from '@app/helpers'
import { InstanceFollowService } from '@app/shared/shared-instance/instance-follow.service'
@ -33,7 +33,11 @@ import { AutoColspanDirective } from '../../../shared/shared-main/common/auto-co
PTDatePipe
]
})
export class FollowersListComponent extends RestTable <ActorFollow> implements OnInit {
export class FollowersListComponent extends RestTable<ActorFollow> implements OnInit {
private confirmService = inject(ConfirmService)
private notifier = inject(Notifier)
private followService = inject(InstanceFollowService)
followers: ActorFollow[] = []
totalRecords = 0
sort: SortMeta = { field: 'createdAt', order: -1 }
@ -43,14 +47,6 @@ export class FollowersListComponent extends RestTable <ActorFollow> implements O
bulkActions: DropdownAction<ActorFollow[]>[] = []
constructor (
private confirmService: ConfirmService,
private notifier: Notifier,
private followService: InstanceFollowService
) {
super()
}
ngOnInit () {
this.initialize()
@ -108,20 +104,20 @@ export class FollowersListComponent extends RestTable <ActorFollow> implements O
if (res === false) return
this.followService.rejectFollower(follows)
.subscribe({
next: () => {
// eslint-disable-next-line max-len
const message = formatICU(
$localize`Rejected {count, plural, =1 {{followerName} follow request} other {{count} follow requests}}`,
{ count: follows.length, followerName: this.buildFollowerName(follows[0]) }
)
this.notifier.success(message)
.subscribe({
next: () => {
// eslint-disable-next-line max-len
const message = formatICU(
$localize`Rejected {count, plural, =1 {{followerName} follow request} other {{count} follow requests}}`,
{ count: follows.length, followerName: this.buildFollowerName(follows[0]) }
)
this.notifier.success(message)
this.reloadData()
},
this.reloadData()
},
error: err => this.notifier.error(err.message)
})
error: err => this.notifier.error(err.message)
})
}
async deleteFollowers (follows: ActorFollow[]) {
@ -140,21 +136,21 @@ export class FollowersListComponent extends RestTable <ActorFollow> implements O
if (res === false) return
this.followService.removeFollower(follows)
.subscribe({
next: () => {
// eslint-disable-next-line max-len
const message = formatICU(
$localize`Removed {count, plural, =1 {{followerName} follow request} other {{count} follow requests}}`,
icuParams
)
.subscribe({
next: () => {
// eslint-disable-next-line max-len
const message = formatICU(
$localize`Removed {count, plural, =1 {{followerName} follow request} other {{count} follow requests}}`,
icuParams
)
this.notifier.success(message)
this.notifier.success(message)
this.reloadData()
},
this.reloadData()
},
error: err => this.notifier.error(err.message)
})
error: err => this.notifier.error(err.message)
})
}
buildFollowerName (follow: ActorFollow) {
@ -163,13 +159,13 @@ export class FollowersListComponent extends RestTable <ActorFollow> implements O
protected reloadDataInternal () {
this.followService.getFollowers({ pagination: this.pagination, sort: this.sort, search: this.search })
.subscribe({
next: resultList => {
this.followers = resultList.data
this.totalRecords = resultList.total
},
.subscribe({
next: resultList => {
this.followers = resultList.data
this.totalRecords = resultList.total
},
error: err => this.notifier.error(err.message)
})
error: err => this.notifier.error(err.message)
})
}
}

View File

@ -1,5 +1,5 @@
import { NgClass, NgIf } from '@angular/common'
import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'
import { Component, OnInit, inject, output, viewChild } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Notifier } from '@app/core'
import { formatICU } from '@app/helpers'
@ -20,23 +20,19 @@ import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.co
imports: [ GlobalIconComponent, FormsModule, ReactiveFormsModule, NgClass, NgIf, AlertComponent ]
})
export class FollowModalComponent extends FormReactive implements OnInit {
@ViewChild('modal', { static: true }) modal: NgbModal
protected formReactiveService = inject(FormReactiveService)
private modalService = inject(NgbModal)
private followService = inject(InstanceFollowService)
private notifier = inject(Notifier)
@Output() newFollow = new EventEmitter<void>()
readonly modal = viewChild<NgbModal>('modal')
readonly newFollow = output()
placeholder = 'example.com\nchocobozzz@example.com\nchocobozzz_channel@example.com'
private openedModal: NgbModalRef
constructor (
protected formReactiveService: FormReactiveService,
private modalService: NgbModal,
private followService: InstanceFollowService,
private notifier: Notifier
) {
super()
}
ngOnInit () {
this.buildForm({
hostsOrHandles: UNIQUE_HOSTS_OR_HANDLE_VALIDATOR
@ -44,7 +40,7 @@ export class FollowModalComponent extends FormReactive implements OnInit {
}
openModal () {
this.openedModal = this.modalService.open(this.modal, { centered: true })
this.openedModal = this.modalService.open(this.modal(), { centered: true })
}
hide () {

View File

@ -1,5 +1,5 @@
import { NgIf } from '@angular/common'
import { Component, OnInit, ViewChild } from '@angular/core'
import { Component, OnInit, inject, viewChild } from '@angular/core'
import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core'
import { formatICU } from '@app/helpers'
import { InstanceFollowService } from '@app/shared/shared-instance/instance-follow.service'
@ -34,8 +34,12 @@ import { FollowModalComponent } from './follow-modal.component'
ButtonComponent
]
})
export class FollowingListComponent extends RestTable <ActorFollow> implements OnInit {
@ViewChild('followModal') followModal: FollowModalComponent
export class FollowingListComponent extends RestTable<ActorFollow> implements OnInit {
private notifier = inject(Notifier)
private confirmService = inject(ConfirmService)
private followService = inject(InstanceFollowService)
readonly followModal = viewChild<FollowModalComponent>('followModal')
following: ActorFollow[] = []
totalRecords = 0
@ -46,14 +50,6 @@ export class FollowingListComponent extends RestTable <ActorFollow> implements O
bulkActions: DropdownAction<ActorFollow[]>[] = []
constructor (
private notifier: Notifier,
private confirmService: ConfirmService,
private followService: InstanceFollowService
) {
super()
}
ngOnInit () {
this.initialize()
@ -72,7 +68,7 @@ export class FollowingListComponent extends RestTable <ActorFollow> implements O
}
openFollowModal () {
this.followModal.openModal()
this.followModal().openModal()
}
isInstanceFollowing (follow: ActorFollow) {
@ -113,13 +109,13 @@ export class FollowingListComponent extends RestTable <ActorFollow> implements O
protected reloadDataInternal () {
this.followService.getFollowing({ pagination: this.pagination, sort: this.sort, search: this.search })
.subscribe({
next: resultList => {
this.following = resultList.data
this.totalRecords = resultList.total
},
.subscribe({
next: resultList => {
this.following = resultList.data
this.totalRecords = resultList.total
},
error: err => this.notifier.error(err.message)
})
error: err => this.notifier.error(err.message)
})
}
}

View File

@ -1,3 +1,3 @@
<my-peertube-checkbox
[inputName]="host + '-redundancy-allowed'" [(ngModel)]="redundancyAllowed" (ngModelChange)="updateRedundancyState()"
></my-peertube-checkbox>
[inputName]="host() + '-redundancy-allowed'" [(ngModel)]="redundancyAllowed" (ngModelChange)="updateRedundancyState()"
></my-peertube-checkbox>

View File

@ -1,4 +1,4 @@
import { Component, Input } from '@angular/core'
import { Component, inject, input } from '@angular/core'
import { Notifier } from '@app/core'
import { FormsModule } from '@angular/forms'
import { PeertubeCheckboxComponent } from '../../../shared/shared-forms/peertube-checkbox.component'
@ -10,24 +10,22 @@ import { RedundancyService } from '@app/shared/shared-main/video/redundancy.serv
imports: [ PeertubeCheckboxComponent, FormsModule ]
})
export class RedundancyCheckboxComponent {
@Input() redundancyAllowed: boolean
@Input() host: string
private notifier = inject(Notifier)
private redundancyService = inject(RedundancyService)
constructor (
private notifier: Notifier,
private redundancyService: RedundancyService
) { }
readonly redundancyAllowed = input<boolean>(undefined)
readonly host = input<string>(undefined)
updateRedundancyState () {
this.redundancyService.updateRedundancy(this.host, this.redundancyAllowed)
.subscribe({
next: () => {
const stateLabel = this.redundancyAllowed ? $localize`enabled` : $localize`disabled`
this.redundancyService.updateRedundancy(this.host(), this.redundancyAllowed())
.subscribe({
next: () => {
const stateLabel = this.redundancyAllowed() ? $localize`enabled` : $localize`disabled`
this.notifier.success($localize`Redundancy for ${this.host} is ${stateLabel}`)
},
this.notifier.success($localize`Redundancy for ${this.host()} is ${stateLabel}`)
},
error: err => this.notifier.error(err.message)
})
error: err => this.notifier.error(err.message)
})
}
}

View File

@ -1,5 +1,5 @@
import { NgFor, NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { ConfirmService, Notifier, RestPagination, RestTable, ServerService } from '@app/core'
import { BytesPipe } from '@app/shared/shared-main/common/bytes.pipe'
@ -38,6 +38,11 @@ import { VideoRedundancyInformationComponent } from './video-redundancy-informat
]
})
export class VideoRedundanciesListComponent extends RestTable implements OnInit {
private notifier = inject(Notifier)
private confirmService = inject(ConfirmService)
private redundancyService = inject(RedundancyService)
private serverService = inject(ServerService)
private static LS_DISPLAY_TYPE = 'video-redundancies-list-display-type'
videoRedundancies: VideoRedundancy[] = []
@ -56,12 +61,7 @@ export class VideoRedundanciesListComponent extends RestTable implements OnInit
private bytesPipe: BytesPipe
constructor (
private notifier: Notifier,
private confirmService: ConfirmService,
private redundancyService: RedundancyService,
private serverService: ServerService
) {
constructor () {
super()
this.bytesPipe = new BytesPipe()
@ -77,15 +77,15 @@ export class VideoRedundanciesListComponent extends RestTable implements OnInit
this.initialize()
this.serverService.getServerStats()
.subscribe(res => {
const redundancies = res.videosRedundancy
.subscribe(res => {
const redundancies = res.videosRedundancy
if (redundancies.length === 0) this.noRedundancies = true
if (redundancies.length === 0) this.noRedundancies = true
for (const r of redundancies) {
this.buildPieData(r)
}
})
for (const r of redundancies) {
this.buildPieData(r)
}
})
}
isDisplayingRemoteVideos () {
@ -184,7 +184,6 @@ export class VideoRedundanciesListComponent extends RestTable implements OnInit
error: err => this.notifier.error(err.message)
})
}
protected reloadDataInternal () {
@ -197,16 +196,16 @@ export class VideoRedundanciesListComponent extends RestTable implements OnInit
}
this.redundancyService.listVideoRedundancies(options)
.subscribe({
next: resultList => {
this.videoRedundancies = resultList.data
this.totalRecords = resultList.total
.subscribe({
next: resultList => {
this.videoRedundancies = resultList.data
this.totalRecords = resultList.total
this.dataLoaded = true
},
this.dataLoaded = true
},
error: err => this.notifier.error(err.message)
})
error: err => this.notifier.error(err.message)
})
}
private loadSelectLocalStorage () {

View File

@ -1,19 +1,19 @@
<div>
<span class="label">Url</span>
<a target="_blank" rel="noopener noreferrer" [href]="redundancyElement.fileUrl">{{ redundancyElement.fileUrl }}</a>
<a target="_blank" rel="noopener noreferrer" [href]="redundancyElement().fileUrl">{{ redundancyElement().fileUrl }}</a>
</div>
<div>
<span class="label">Created on</span>
<span>{{ redundancyElement.createdAt | ptDate: 'medium' }}</span>
<span>{{ redundancyElement().createdAt | ptDate: 'medium' }}</span>
</div>
<div>
<span class="label">Expires on</span>
<span>{{ redundancyElement.expiresOn | ptDate: 'medium' }}</span>
<span>{{ redundancyElement().expiresOn | ptDate: 'medium' }}</span>
</div>
<div>
<span class="label">Size</span>
<span>{{ redundancyElement.size | bytes: 1 }}</span>
<span>{{ redundancyElement().size | bytes: 1 }}</span>
</div>

View File

@ -1,4 +1,4 @@
import { Component, Input } from '@angular/core'
import { Component, input } from '@angular/core'
import { PTDatePipe } from '@app/shared/shared-main/common/date.pipe'
import { RedundancyInformation } from '@peertube/peertube-models'
import { BytesPipe } from '../../../shared/shared-main/common/bytes.pipe'
@ -10,5 +10,5 @@ import { BytesPipe } from '../../../shared/shared-main/common/bytes.pipe'
imports: [ PTDatePipe, BytesPipe ]
})
export class VideoRedundancyInformationComponent {
@Input() redundancyElement: RedundancyInformation
readonly redundancyElement = input<RedundancyInformation>(undefined)
}

View File

@ -1,13 +1,11 @@
import { Component } from '@angular/core'
import { AbuseListTableComponent } from '../../../shared/shared-abuse-list/abuse-list-table.component'
import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.component'
@Component({
selector: 'my-abuse-list',
templateUrl: './abuse-list.component.html',
styleUrls: [],
imports: [ GlobalIconComponent, AbuseListTableComponent ]
imports: [ AbuseListTableComponent ]
})
export class AbuseListComponent {
}

View File

@ -2,7 +2,7 @@ import { SortMeta } from 'primeng/api'
import { from } from 'rxjs'
import { catchError, concatMap, toArray } from 'rxjs/operators'
import { HttpClient, HttpParams } from '@angular/common/http'
import { Injectable } from '@angular/core'
import { Injectable, inject } from '@angular/core'
import { RestExtractor, RestPagination, RestService } from '@app/core'
import { arrayify } from '@peertube/peertube-core-utils'
import { ResultList, UserRegistration, UserRegistrationUpdateState } from '@peertube/peertube-models'
@ -10,13 +10,11 @@ import { environment } from '../../../../environments/environment'
@Injectable()
export class AdminRegistrationService {
private static BASE_REGISTRATION_URL = environment.apiUrl + '/api/v1/users/registrations'
private authHttp = inject(HttpClient)
private restExtractor = inject(RestExtractor)
private restService = inject(RestService)
constructor (
private authHttp: HttpClient,
private restExtractor: RestExtractor,
private restService: RestService
) { }
private static BASE_REGISTRATION_URL = environment.apiUrl + '/api/v1/users/registrations'
listRegistrations (options: {
pagination: RestPagination

View File

@ -1,5 +1,5 @@
import { NgClass, NgIf } from '@angular/common'
import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'
import { Component, OnInit, inject, output, viewChild } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Notifier, ServerService } from '@app/core'
import { FormReactive } from '@app/shared/shared-forms/form-reactive'
@ -19,25 +19,21 @@ import { REGISTRATION_MODERATION_RESPONSE_VALIDATOR } from './process-registrati
imports: [ NgIf, GlobalIconComponent, FormsModule, ReactiveFormsModule, NgClass, PeertubeCheckboxComponent, AlertComponent ]
})
export class ProcessRegistrationModalComponent extends FormReactive implements OnInit {
@ViewChild('modal', { static: true }) modal: NgbModal
protected formReactiveService = inject(FormReactiveService)
private server = inject(ServerService)
private modalService = inject(NgbModal)
private notifier = inject(Notifier)
private registrationService = inject(AdminRegistrationService)
@Output() registrationProcessed = new EventEmitter()
readonly modal = viewChild<NgbModal>('modal')
readonly registrationProcessed = output()
registration: UserRegistration
private openedModal: NgbModalRef
private processMode: 'accept' | 'reject'
constructor (
protected formReactiveService: FormReactiveService,
private server: ServerService,
private modalService: NgbModal,
private notifier: Notifier,
private registrationService: AdminRegistrationService
) {
super()
}
ngOnInit () {
this.buildForm({
moderationResponse: REGISTRATION_MODERATION_RESPONSE_VALIDATOR,
@ -61,7 +57,7 @@ export class ProcessRegistrationModalComponent extends FormReactive implements O
preventEmailDelivery: !this.isEmailEnabled() || registration.emailVerified !== true
})
this.openedModal = this.modalService.open(this.modal, { centered: true })
this.openedModal = this.modalService.open(this.modal(), { centered: true })
}
hide () {

View File

@ -1,5 +1,5 @@
import { NgClass, NgIf } from '@angular/common'
import { Component, OnInit, ViewChild } from '@angular/core'
import { Component, OnInit, inject, viewChild } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable, ServerService } from '@app/core'
import { formatICU } from '@app/helpers'
@ -37,8 +37,16 @@ import { ProcessRegistrationModalComponent } from './process-registration-modal.
PTDatePipe
]
})
export class RegistrationListComponent extends RestTable <UserRegistration> implements OnInit {
@ViewChild('processRegistrationModal', { static: true }) processRegistrationModal: ProcessRegistrationModalComponent
export class RegistrationListComponent extends RestTable<UserRegistration> implements OnInit {
protected route = inject(ActivatedRoute)
protected router = inject(Router)
private server = inject(ServerService)
private notifier = inject(Notifier)
private markdownRenderer = inject(MarkdownService)
private confirmService = inject(ConfirmService)
private adminRegistrationService = inject(AdminRegistrationService)
readonly processRegistrationModal = viewChild<ProcessRegistrationModalComponent>('processRegistrationModal')
registrations: (UserRegistration & { registrationReasonHTML?: string, moderationResponseHTML?: string })[] = []
totalRecords = 0
@ -52,15 +60,7 @@ export class RegistrationListComponent extends RestTable <UserRegistration> impl
requiresEmailVerification: boolean
constructor (
protected route: ActivatedRoute,
protected router: Router,
private server: ServerService,
private notifier: Notifier,
private markdownRenderer: MarkdownService,
private confirmService: ConfirmService,
private adminRegistrationService: AdminRegistrationService
) {
constructor () {
super()
this.registrationActions = [
@ -137,7 +137,7 @@ export class RegistrationListComponent extends RestTable <UserRegistration> impl
}
private openRegistrationRequestProcessModal (registration: UserRegistration, mode: 'accept' | 'reject') {
this.processRegistrationModal.openModal(registration, mode)
this.processRegistrationModal().openModal(registration, mode)
}
private async removeRegistrations (registrations: UserRegistration[]) {

View File

@ -1,5 +1,5 @@
import { NgClass, NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable, ServerService } from '@app/core'
import { PTDatePipe } from '@app/shared/shared-main/common/date.pipe'
@ -42,6 +42,15 @@ import { VideoCellComponent } from '../../../shared/shared-tables/video-cell.com
]
})
export class VideoBlockListComponent extends RestTable implements OnInit {
protected route = inject(ActivatedRoute)
protected router = inject(Router)
private notifier = inject(Notifier)
private serverService = inject(ServerService)
private confirmService = inject(ConfirmService)
private videoBlocklistService = inject(VideoBlockService)
private markdownRenderer = inject(MarkdownService)
private videoService = inject(VideoService)
blocklist: (VideoBlacklist & { reasonHtml?: string })[] = []
totalRecords = 0
sort: SortMeta = { field: 'createdAt', order: -1 }
@ -66,16 +75,7 @@ export class VideoBlockListComponent extends RestTable implements OnInit {
}
]
constructor (
protected route: ActivatedRoute,
protected router: Router,
private notifier: Notifier,
private serverService: ServerService,
private confirmService: ConfirmService,
private videoBlocklistService: VideoBlockService,
private markdownRenderer: MarkdownService,
private videoService: VideoService
) {
constructor () {
super()
this.videoBlocklistActions = [

View File

@ -1,12 +1,11 @@
import { Component } from '@angular/core'
import { GlobalIconComponent } from '@app/shared/shared-icons/global-icon.component'
import { WatchedWordsListAdminOwnerComponent } from '@app/shared/standalone-watched-words/watched-words-list-admin-owner.component'
@Component({
templateUrl: './watched-words-list-admin.component.html',
imports: [
GlobalIconComponent,
WatchedWordsListAdminOwnerComponent
]
})
export class WatchedWordsListAdminComponent { }
export class WatchedWordsListAdminComponent {}

View File

@ -1,16 +1,13 @@
import { Component } from '@angular/core'
import { VideoCommentService } from '@app/shared/shared-video-comment/video-comment.service'
import { FeedFormat } from '@peertube/peertube-models'
import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.component'
import { FeedComponent } from '../../../shared/shared-main/feeds/feed.component'
import { VideoCommentListAdminOwnerComponent } from '../../../shared/shared-video-comment/video-comment-list-admin-owner.component'
@Component({
selector: 'my-video-comment-list',
templateUrl: './video-comment-list.component.html',
imports: [
GlobalIconComponent,
FeedComponent,
VideoCommentListAdminOwnerComponent
]
})

View File

@ -1,5 +1,5 @@
import { NgClass, NgFor, NgIf, NgTemplateOutlet } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Router, RouterLink } from '@angular/router'
import { ConfigService } from '@app/+admin/config/shared/config.service'
@ -54,18 +54,18 @@ import { UserPasswordComponent } from './user-password.component'
]
})
export class UserCreateComponent extends UserEdit implements OnInit {
protected serverService = inject(ServerService)
protected formReactiveService = inject(FormReactiveService)
protected configService = inject(ConfigService)
protected screenService = inject(ScreenService)
protected auth = inject(AuthService)
private router = inject(Router)
private notifier = inject(Notifier)
private userAdminService = inject(UserAdminService)
error: string
constructor (
protected serverService: ServerService,
protected formReactiveService: FormReactiveService,
protected configService: ConfigService,
protected screenService: ScreenService,
protected auth: AuthService,
private router: Router,
private notifier: Notifier,
private userAdminService: UserAdminService
) {
constructor () {
super()
this.buildQuotaOptions()

View File

@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core'
import { Component, OnInit, inject, input } from '@angular/core'
import { Notifier } from '@app/core'
import { USER_PASSWORD_VALIDATOR } from '@app/shared/form-validators/user-validators'
import { FormReactive } from '@app/shared/shared-forms/form-reactive'
@ -15,20 +15,16 @@ import { UserAdminService } from '@app/shared/shared-users/user-admin.service'
imports: [ FormsModule, ReactiveFormsModule, NgClass, NgIf ]
})
export class UserPasswordComponent extends FormReactive implements OnInit {
@Input() userId: number
@Input() username: string
protected formReactiveService = inject(FormReactiveService)
private notifier = inject(Notifier)
private userAdminService = inject(UserAdminService)
readonly userId = input<number>(undefined)
readonly username = input<string>(undefined)
error: string
showPassword = false
constructor (
protected formReactiveService: FormReactiveService,
private notifier: Notifier,
private userAdminService: UserAdminService
) {
super()
}
ngOnInit () {
this.buildForm({
password: USER_PASSWORD_VALIDATOR
@ -40,9 +36,9 @@ export class UserPasswordComponent extends FormReactive implements OnInit {
const userUpdate: UserUpdate = this.form.value
this.userAdminService.updateUser(this.userId, userUpdate)
this.userAdminService.updateUser(this.userId(), userUpdate)
.subscribe({
next: () => this.notifier.success($localize`Password changed for user ${this.username}.`),
next: () => this.notifier.success($localize`Password changed for user ${this.username()}.`),
error: err => {
this.error = err.message

View File

@ -1,5 +1,5 @@
import { NgClass, NgFor, NgIf, NgTemplateOutlet } from '@angular/common'
import { Component, OnDestroy, OnInit } from '@angular/core'
import { Component, OnDestroy, OnInit, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { ActivatedRoute, Router, RouterLink } from '@angular/router'
import { ConfigService } from '@app/+admin/config/shared/config.service'
@ -52,23 +52,23 @@ import { UserPasswordComponent } from './user-password.component'
]
})
export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy {
protected formReactiveService = inject(FormReactiveService)
protected serverService = inject(ServerService)
protected configService = inject(ConfigService)
protected screenService = inject(ScreenService)
protected auth = inject(AuthService)
private route = inject(ActivatedRoute)
private router = inject(Router)
private notifier = inject(Notifier)
private userService = inject(UserService)
private twoFactorService = inject(TwoFactorService)
private userAdminService = inject(UserAdminService)
error: string
private paramsSub: Subscription
constructor (
protected formReactiveService: FormReactiveService,
protected serverService: ServerService,
protected configService: ConfigService,
protected screenService: ScreenService,
protected auth: AuthService,
private route: ActivatedRoute,
private router: Router,
private notifier: Notifier,
private userService: UserService,
private twoFactorService: TwoFactorService,
private userAdminService: UserAdminService
) {
constructor () {
super()
this.buildQuotaOptions()
@ -168,7 +168,6 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy {
error: err => this.notifier.error(err.message)
})
}
private onUserFetched (userJson: UserType) {

View File

@ -1,5 +1,5 @@
import { NgClass, NgIf } from '@angular/common'
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'
import { Component, OnDestroy, OnInit, inject, viewChild } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { ActivatedRoute, Router, RouterLink } from '@angular/router'
import {
@ -79,10 +79,21 @@ type UserForList = User & {
ProgressBarComponent
]
})
export class UserListComponent extends RestTable <User> implements OnInit, OnDestroy {
export class UserListComponent extends RestTable<User> implements OnInit, OnDestroy {
protected route = inject(ActivatedRoute)
protected router = inject(Router)
private notifier = inject(Notifier)
private confirmService = inject(ConfirmService)
private auth = inject(AuthService)
private blocklist = inject(BlocklistService)
private userAdminService = inject(UserAdminService)
private peertubeLocalStorage = inject(LocalStorageService)
private hooks = inject(HooksService)
private pluginService = inject(PluginService)
private static readonly LS_SELECTED_COLUMNS_KEY = 'admin-user-list-selected-columns'
@ViewChild('userBanModal', { static: true }) userBanModal: UserBanModalComponent
readonly userBanModal = viewChild<UserBanModalComponent>('userBanModal')
users: (User & { accountMutedStatus: AccountMutedStatus })[] = []
@ -115,21 +126,6 @@ export class UserListComponent extends RestTable <User> implements OnInit, OnDes
private _selectedColumns: string[] = []
constructor (
protected route: ActivatedRoute,
protected router: Router,
private notifier: Notifier,
private confirmService: ConfirmService,
private auth: AuthService,
private blocklist: BlocklistService,
private userAdminService: UserAdminService,
private peertubeLocalStorage: LocalStorageService,
private hooks: HooksService,
private pluginService: PluginService
) {
super()
}
get authUser () {
return this.auth.getUser()
}
@ -262,7 +258,7 @@ export class UserListComponent extends RestTable <User> implements OnInit, OnDes
}
}
this.userBanModal.openModal(users)
this.userBanModal().openModal(users)
}
onUserChanged () {
@ -281,19 +277,19 @@ export class UserListComponent extends RestTable <User> implements OnInit, OnDes
if (res === false) return
this.userAdminService.unbanUsers(users)
.subscribe({
next: () => {
this.notifier.success(
formatICU(
$localize`{count, plural, =1 {1 user unbanned.} other {{count} users unbanned.}}`,
{ count: users.length }
)
.subscribe({
next: () => {
this.notifier.success(
formatICU(
$localize`{count, plural, =1 {1 user unbanned.} other {{count} users unbanned.}}`,
{ count: users.length }
)
this.reloadData()
},
)
this.reloadData()
},
error: err => this.notifier.error(err.message)
})
error: err => this.notifier.error(err.message)
})
}
async removeUsers (users: User[]) {

View File

@ -1,5 +1,5 @@
import { HttpClient, HttpParams } from '@angular/common/http'
import { Injectable } from '@angular/core'
import { Injectable, inject } from '@angular/core'
import { RestExtractor, RestPagination, RestService } from '@app/core'
import { AdvancedInputFilter } from '@app/shared/shared-forms/advanced-input-filter.component'
import { Video } from '@app/shared/shared-main/video/video.model'
@ -11,13 +11,10 @@ import { catchError, switchMap } from 'rxjs/operators'
@Injectable()
export class VideoAdminService {
constructor (
private videoService: VideoService,
private authHttp: HttpClient,
private restExtractor: RestExtractor,
private restService: RestService
) {}
private videoService = inject(VideoService)
private authHttp = inject(HttpClient)
private restExtractor = inject(RestExtractor)
private restService = inject(RestService)
getAdminVideos (
options: CommonVideoParams & { pagination: RestPagination, search?: string }
@ -28,16 +25,16 @@ export class VideoAdminService {
params = this.videoService.buildCommonVideosParams({ params, ...omit(options, [ 'search', 'pagination' ]) })
params = params.set('start', pagination.start.toString())
.set('count', pagination.count.toString())
.set('count', pagination.count.toString())
params = this.buildAdminParamsFromSearch(search, params)
return this.authHttp
.get<ResultList<Video>>(VideoService.BASE_VIDEO_URL, { params })
.pipe(
switchMap(res => this.videoService.extractVideos(res)),
catchError(err => this.restExtractor.handleError(err))
)
.get<ResultList<Video>>(VideoService.BASE_VIDEO_URL, { params })
.pipe(
switchMap(res => this.videoService.extractVideos(res)),
catchError(err => this.restExtractor.handleError(err))
)
}
buildAdminInputFilter (): AdvancedInputFilter[] {

View File

@ -1,5 +1,5 @@
import { NgClass, NgFor, NgIf } from '@angular/common'
import { Component, OnInit, ViewChild } from '@angular/core'
import { Component, OnInit, inject, viewChild } from '@angular/core'
import { ActivatedRoute, Router, RouterLink } from '@angular/router'
import { AuthService, ConfirmService, Notifier, RestPagination, RestTable, ServerService } from '@app/core'
import { formatICU } from '@app/helpers'
@ -59,8 +59,20 @@ import { VideoAdminService } from './video-admin.service'
BytesPipe
]
})
export class VideoListComponent extends RestTable <Video> implements OnInit {
@ViewChild('videoBlockModal') videoBlockModal: VideoBlockComponent
export class VideoListComponent extends RestTable<Video> implements OnInit {
protected route = inject(ActivatedRoute)
protected router = inject(Router)
private confirmService = inject(ConfirmService)
private auth = inject(AuthService)
private notifier = inject(Notifier)
private videoService = inject(VideoService)
private videoAdminService = inject(VideoAdminService)
private videoBlockService = inject(VideoBlockService)
private videoCaptionService = inject(VideoCaptionService)
private server = inject(ServerService)
private videoFileTokenService = inject(VideoFileTokenService)
readonly videoBlockModal = viewChild<VideoBlockComponent>('videoBlockModal')
videos: Video[] = []
@ -91,23 +103,7 @@ export class VideoListComponent extends RestTable <Video> implements OnInit {
loading = true
private videoFileTokens: { [ videoId: number ]: string } = {}
constructor (
protected route: ActivatedRoute,
protected router: Router,
private confirmService: ConfirmService,
private auth: AuthService,
private notifier: Notifier,
private videoService: VideoService,
private videoAdminService: VideoAdminService,
private videoBlockService: VideoBlockService,
private videoCaptionService: VideoCaptionService,
private server: ServerService,
private videoFileTokenService: VideoFileTokenService
) {
super()
}
private videoFileTokens: { [videoId: number]: string } = {}
get authUser () {
return this.auth.getUser()
@ -132,7 +128,7 @@ export class VideoListComponent extends RestTable <Video> implements OnInit {
},
{
label: $localize`Block`,
handler: videos => this.videoBlockModal.show(videos),
handler: videos => this.videoBlockModal().show(videos),
isDisplayed: videos => this.authUser.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST) && videos.every(v => !v.blacklisted),
iconName: 'no'
},

View File

@ -1,5 +1,5 @@
import { NgFor, NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service'
import { ComponentPagination, ConfirmService, hasMoreItems, Notifier, resetCurrentPage, updatePaginationOnDelete } from '@app/core'
@ -26,6 +26,13 @@ import { PluginCardComponent } from '../shared/plugin-card.component'
]
})
export class PluginListInstalledComponent implements OnInit {
private pluginService = inject(PluginService)
private pluginApiService = inject(PluginApiService)
private notifier = inject(Notifier)
private confirmService = inject(ConfirmService)
private router = inject(Router)
private route = inject(ActivatedRoute)
pluginType: PluginType_Type
pagination: ComponentPagination = {
@ -41,16 +48,6 @@ export class PluginListInstalledComponent implements OnInit {
onDataSubject = new Subject<any[]>()
constructor (
private pluginService: PluginService,
private pluginApiService: PluginApiService,
private notifier: Notifier,
private confirmService: ConfirmService,
private router: Router,
private route: ActivatedRoute
) {
}
ngOnInit () {
if (!this.route.snapshot.queryParams['pluginType']) {
const queryParams = { pluginType: PluginType.PLUGIN }
@ -76,16 +73,16 @@ export class PluginListInstalledComponent implements OnInit {
loadMorePlugins () {
this.pluginApiService.getPlugins(this.pluginType, this.pagination, this.sort)
.subscribe({
next: res => {
this.plugins = this.plugins.concat(res.data)
this.pagination.totalItems = res.total
.subscribe({
next: res => {
this.plugins = this.plugins.concat(res.data)
this.pagination.totalItems = res.total
this.onDataSubject.next(res.data)
},
this.onDataSubject.next(res.data)
},
error: err => this.notifier.error(err.message)
})
error: err => this.notifier.error(err.message)
})
}
onNearOfBottom () {
@ -171,21 +168,21 @@ export class PluginListInstalledComponent implements OnInit {
this.updating[pluginKey] = true
this.pluginApiService.update(plugin.name, plugin.type)
.pipe()
.subscribe({
next: res => {
this.updating[pluginKey] = false
.pipe()
.subscribe({
next: res => {
this.updating[pluginKey] = false
this.notifier.success($localize`${plugin.name} updated.`)
this.notifier.success($localize`${plugin.name} updated.`)
Object.assign(plugin, res)
},
Object.assign(plugin, res)
},
error: err => {
this.notifier.error(err.message)
this.updating[pluginKey] = false
}
})
error: err => {
this.notifier.error(err.message)
this.updating[pluginKey] = false
}
})
}
getShowRouterLink (plugin: PeerTubePlugin) {

View File

@ -1,5 +1,5 @@
import { NgFor, NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service'
import { ComponentPagination, ConfirmService, hasMoreItems, Notifier, PluginService, resetCurrentPage } from '@app/core'
@ -32,6 +32,13 @@ import { PluginCardComponent } from '../shared/plugin-card.component'
]
})
export class PluginSearchComponent implements OnInit {
private pluginService = inject(PluginService)
private pluginApiService = inject(PluginApiService)
private notifier = inject(Notifier)
private confirmService = inject(ConfirmService)
private router = inject(Router)
private route = inject(ActivatedRoute)
pluginType: PluginType_Type
pagination: ComponentPagination = {
@ -52,16 +59,6 @@ export class PluginSearchComponent implements OnInit {
private searchSubject = new Subject<string>()
constructor (
private pluginService: PluginService,
private pluginApiService: PluginApiService,
private notifier: Notifier,
private confirmService: ConfirmService,
private router: Router,
private route: ActivatedRoute
) {
}
ngOnInit () {
if (!this.route.snapshot.queryParams['pluginType']) {
const queryParams = { pluginType: PluginType.PLUGIN }
@ -79,11 +76,11 @@ export class PluginSearchComponent implements OnInit {
})
this.searchSubject.asObservable()
.pipe(
debounceTime(400),
distinctUntilChanged()
)
.subscribe(search => this.router.navigate([], { queryParams: { search }, queryParamsHandling: 'merge' }))
.pipe(
debounceTime(400),
distinctUntilChanged()
)
.subscribe(search => this.router.navigate([], { queryParams: { search }, queryParamsHandling: 'merge' }))
}
onSearchChange (event: Event) {
@ -103,23 +100,23 @@ export class PluginSearchComponent implements OnInit {
this.isSearching = true
this.pluginApiService.searchAvailablePlugins(this.pluginType, this.pagination, this.sort, this.search)
.subscribe({
next: res => {
this.isSearching = false
.subscribe({
next: res => {
this.isSearching = false
this.plugins = this.plugins.concat(res.data)
this.pagination.totalItems = res.total
this.plugins = this.plugins.concat(res.data)
this.pagination.totalItems = res.total
this.onDataSubject.next(res.data)
},
this.onDataSubject.next(res.data)
},
error: err => {
logger.error(err)
error: err => {
logger.error(err)
const message = $localize`The plugin index is not available. Please retry later.`
this.notifier.error(message)
}
})
const message = $localize`The plugin index is not available. Please retry later.`
this.notifier.error(message)
}
})
}
onNearOfBottom () {
@ -154,21 +151,21 @@ export class PluginSearchComponent implements OnInit {
this.installing[plugin.npmName] = true
this.pluginApiService.install(plugin.npmName)
.subscribe({
next: () => {
this.installing[plugin.npmName] = false
this.pluginInstalled = true
.subscribe({
next: () => {
this.installing[plugin.npmName] = false
this.pluginInstalled = true
this.notifier.success($localize`${plugin.name} installed.`)
this.notifier.success($localize`${plugin.name} installed.`)
plugin.installed = true
},
plugin.installed = true
},
error: err => {
this.installing[plugin.npmName] = false
error: err => {
this.installing[plugin.npmName] = false
this.notifier.error(err.message)
}
})
this.notifier.error(err.message)
}
})
}
}

View File

@ -1,6 +1,6 @@
import { Subscription } from 'rxjs'
import { map, switchMap } from 'rxjs/operators'
import { Component, OnDestroy, OnInit } from '@angular/core'
import { Component, OnDestroy, OnInit, inject } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { HooksService, Notifier, PluginService } from '@app/core'
import { FormReactive } from '@app/shared/shared-forms/form-reactive'
@ -18,6 +18,13 @@ import { BuildFormArgument } from '@app/shared/form-validators/form-validator.mo
imports: [ NgIf, FormsModule, ReactiveFormsModule, NgFor, DynamicFormFieldComponent ]
})
export class PluginShowInstalledComponent extends FormReactive implements OnInit, OnDestroy {
protected formReactiveService = inject(FormReactiveService)
private pluginService = inject(PluginService)
private pluginAPIService = inject(PluginApiService)
private notifier = inject(Notifier)
private hooks = inject(HooksService)
private route = inject(ActivatedRoute)
plugin: PeerTubePlugin
registeredSettings: RegisterServerSettingOptions[] = []
pluginTypeLabel: string
@ -25,17 +32,6 @@ export class PluginShowInstalledComponent extends FormReactive implements OnInit
private sub: Subscription
private npmName: string
constructor (
protected formReactiveService: FormReactiveService,
private pluginService: PluginService,
private pluginAPIService: PluginApiService,
private notifier: Notifier,
private hooks: HooksService,
private route: ActivatedRoute
) {
super()
}
ngOnInit () {
this.sub = this.route.params.subscribe(
routeParams => {
@ -54,13 +50,13 @@ export class PluginShowInstalledComponent extends FormReactive implements OnInit
const settings = this.form.value
this.pluginAPIService.updatePluginSettings(this.plugin.name, this.plugin.type, settings)
.subscribe({
next: () => {
this.notifier.success($localize`Settings updated.`)
},
.subscribe({
next: () => {
this.notifier.success($localize`Settings updated.`)
},
error: err => this.notifier.error(err.message)
})
error: err => this.notifier.error(err.message)
})
}
hasRegisteredSettings () {
@ -83,23 +79,23 @@ export class PluginShowInstalledComponent extends FormReactive implements OnInit
private loadPlugin (npmName: string) {
this.pluginAPIService.getPlugin(npmName)
.pipe(switchMap(plugin => {
return this.pluginAPIService.getPluginRegisteredSettings(plugin.name, plugin.type)
.pipe(map(data => ({ plugin, registeredSettings: data.registeredSettings })))
}))
.subscribe({
next: async ({ plugin, registeredSettings }) => {
this.plugin = plugin
.pipe(switchMap(plugin => {
return this.pluginAPIService.getPluginRegisteredSettings(plugin.name, plugin.type)
.pipe(map(data => ({ plugin, registeredSettings: data.registeredSettings })))
}))
.subscribe({
next: async ({ plugin, registeredSettings }) => {
this.plugin = plugin
this.registeredSettings = await this.translateSettings(registeredSettings)
this.registeredSettings = await this.translateSettings(registeredSettings)
this.pluginTypeLabel = this.pluginAPIService.getPluginTypeLabel(this.plugin.type)
this.pluginTypeLabel = this.pluginAPIService.getPluginTypeLabel(this.plugin.type)
this.buildSettingsForm()
},
this.buildSettingsForm()
},
error: err => this.notifier.error(err.message)
})
error: err => this.notifier.error(err.message)
})
}
private buildSettingsForm () {

View File

@ -1,6 +1,6 @@
import { catchError } from 'rxjs/operators'
import { HttpClient, HttpParams } from '@angular/common/http'
import { Injectable } from '@angular/core'
import { Injectable, inject } from '@angular/core'
import { ComponentPagination, RestExtractor, RestService } from '@app/core'
import { PluginService } from '@app/core/plugins/plugin.service'
import {
@ -17,14 +17,12 @@ import { environment } from '../../../../environments/environment'
@Injectable()
export class PluginApiService {
private static BASE_PLUGIN_URL = environment.apiUrl + '/api/v1/plugins'
private authHttp = inject(HttpClient)
private restExtractor = inject(RestExtractor)
private restService = inject(RestService)
private pluginService = inject(PluginService)
constructor (
private authHttp: HttpClient,
private restExtractor: RestExtractor,
private restService: RestService,
private pluginService: PluginService
) { }
private static BASE_PLUGIN_URL = environment.apiUrl + '/api/v1/plugins'
getPluginTypeLabel (type: PluginType_Type) {
if (type === PluginType.PLUGIN) {
@ -46,7 +44,7 @@ export class PluginApiService {
params = params.append('pluginType', pluginType.toString())
return this.authHttp.get<ResultList<PeerTubePlugin>>(PluginApiService.BASE_PLUGIN_URL, { params })
.pipe(catchError(res => this.restExtractor.handleError(res)))
.pipe(catchError(res => this.restExtractor.handleError(res)))
}
searchAvailablePlugins (
@ -64,14 +62,14 @@ export class PluginApiService {
if (search) params = params.append('search', search)
return this.authHttp.get<ResultList<PeerTubePluginIndex>>(PluginApiService.BASE_PLUGIN_URL + '/available', { params })
.pipe(catchError(res => this.restExtractor.handleError(res)))
.pipe(catchError(res => this.restExtractor.handleError(res)))
}
getPlugin (npmName: string) {
const path = PluginApiService.BASE_PLUGIN_URL + '/' + npmName
return this.authHttp.get<PeerTubePlugin>(path)
.pipe(catchError(res => this.restExtractor.handleError(res)))
.pipe(catchError(res => this.restExtractor.handleError(res)))
}
getPluginRegisteredSettings (pluginName: string, pluginType: PluginType_Type) {
@ -79,9 +77,9 @@ export class PluginApiService {
const path = PluginApiService.BASE_PLUGIN_URL + '/' + npmName + '/registered-settings'
return this.authHttp.get<RegisteredServerSettings>(path)
.pipe(
catchError(res => this.restExtractor.handleError(res))
)
.pipe(
catchError(res => this.restExtractor.handleError(res))
)
}
updatePluginSettings (pluginName: string, pluginType: PluginType_Type, settings: any) {
@ -89,7 +87,7 @@ export class PluginApiService {
const path = PluginApiService.BASE_PLUGIN_URL + '/' + npmName + '/settings'
return this.authHttp.put(path, { settings })
.pipe(catchError(res => this.restExtractor.handleError(res)))
.pipe(catchError(res => this.restExtractor.handleError(res)))
}
uninstall (pluginName: string, pluginType: PluginType_Type) {
@ -98,7 +96,7 @@ export class PluginApiService {
}
return this.authHttp.post(PluginApiService.BASE_PLUGIN_URL + '/uninstall', body)
.pipe(catchError(res => this.restExtractor.handleError(res)))
.pipe(catchError(res => this.restExtractor.handleError(res)))
}
update (pluginName: string, pluginType: PluginType_Type) {
@ -107,7 +105,7 @@ export class PluginApiService {
}
return this.authHttp.post(PluginApiService.BASE_PLUGIN_URL + '/update', body)
.pipe(catchError(res => this.restExtractor.handleError(res)))
.pipe(catchError(res => this.restExtractor.handleError(res)))
}
install (npmName: string) {
@ -116,7 +114,7 @@ export class PluginApiService {
}
return this.authHttp.post(PluginApiService.BASE_PLUGIN_URL + '/install', body)
.pipe(catchError(res => this.restExtractor.handleError(res)))
.pipe(catchError(res => this.restExtractor.handleError(res)))
}
getPluginOrThemeHref (type: PluginType_Type, name: string) {

View File

@ -1,15 +1,15 @@
<div class="card plugin">
<div class="card-body">
<div class="first-row">
<span class="plugin-name">{{ plugin.name }}</span>
<span class="plugin-name">{{ plugin().name }}</span>
<span class="plugin-version">{{ version }}</span>
<span class="plugin-version">{{ version() }}</span>
<a class="plugin-icon" target="_blank" rel="noopener noreferrer" [href]="plugin.homepage" i18n-title title="Homepage (new window)">
<a class="plugin-icon" target="_blank" rel="noopener noreferrer" [href]="plugin().homepage" i18n-title title="Homepage (new window)">
<my-global-icon iconName="home"></my-global-icon>
</a>
<a class="plugin-icon" target="_blank" rel="noopener noreferrer" [href]="getPluginOrThemeHref(plugin.name)" i18n-title title="NPM page (new window)">
<a class="plugin-icon" target="_blank" rel="noopener noreferrer" [href]="getPluginOrThemeHref(plugin().name)" i18n-title title="NPM page (new window)">
<my-global-icon iconName="registry"></my-global-icon>
</a>
@ -21,7 +21,7 @@
</div>
<div class="second-row">
<div dir="auto" class="description">{{ plugin.description }}</div>
<div dir="auto" class="description">{{ plugin().description }}</div>
</div>
</div>
</div>

View File

@ -1,4 +1,4 @@
import { Component, Input } from '@angular/core'
import { Component, inject, input } from '@angular/core'
import { PeerTubePlugin, PeerTubePluginIndex, PluginType_Type } from '@peertube/peertube-models'
import { PluginApiService } from './plugin-api.service'
import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.component'
@ -9,18 +9,14 @@ import { GlobalIconComponent } from '../../../shared/shared-icons/global-icon.co
styleUrls: [ './plugin-card.component.scss' ],
imports: [ GlobalIconComponent ]
})
export class PluginCardComponent {
@Input() plugin: PeerTubePluginIndex | PeerTubePlugin
@Input() version: string
@Input() pluginType: PluginType_Type
private pluginApiService = inject(PluginApiService)
constructor (
private pluginApiService: PluginApiService
) {
}
readonly plugin = input<PeerTubePluginIndex | PeerTubePlugin>(undefined)
readonly version = input<string>(undefined)
readonly pluginType = input<PluginType_Type>(undefined)
getPluginOrThemeHref (name: string) {
return this.pluginApiService.getPluginOrThemeHref(this.pluginType, name)
return this.pluginApiService.getPluginOrThemeHref(this.pluginType(), name)
}
}

View File

@ -1,13 +1,13 @@
<ng-container>
<a [href]="'mailto:' + entry.email" [title]="getTitle()">
@if (showEmailVerifyInformation) {
@if (entry.emailVerified === true) {
&#x2713; {{ entry.email }}
<a [href]="'mailto:' + entry().email" [title]="getTitle()">
@if (showEmailVerifyInformation()) {
@if (entry().emailVerified === true) {
&#x2713; {{ entry().email }}
} @else {
<em *ngIf="!entry.emailVerified">? {{ entry.email }}</em>
<em *ngIf="!entry().emailVerified">? {{ entry().email }}</em>
}
} @else {
{{ entry.email }}
{{ entry().email }}
}
</a>
</ng-container>

View File

@ -1,4 +1,4 @@
import { Component, Input, booleanAttribute } from '@angular/core'
import { Component, booleanAttribute, input } from '@angular/core'
import { User, UserRegistration } from '@peertube/peertube-models'
import { NgIf } from '@angular/common'
@ -9,11 +9,11 @@ import { NgIf } from '@angular/common'
imports: [ NgIf ]
})
export class UserEmailInfoComponent {
@Input() entry: User | UserRegistration
@Input({ transform: booleanAttribute }) showEmailVerifyInformation: boolean
readonly entry = input<User | UserRegistration>(undefined)
readonly showEmailVerifyInformation = input<boolean, unknown>(undefined, { transform: booleanAttribute })
getTitle () {
if (this.entry.emailVerified) {
if (this.entry().emailVerified) {
return $localize`User email has been verified`
}

View File

@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core'
import { Component, OnInit, inject, input } from '@angular/core'
import { ServerService } from '@app/core'
import { HTMLServerConfig, VideoResolution } from '@peertube/peertube-models'
import { BytesPipe } from '../../shared/shared-main/common/bytes.pipe'
@ -10,12 +10,12 @@ import { NgIf } from '@angular/common'
imports: [ NgIf, BytesPipe ]
})
export class UserRealQuotaInfoComponent implements OnInit {
@Input() videoQuota: number | string
private server = inject(ServerService)
readonly videoQuota = input<number | string>(undefined)
private serverConfig: HTMLServerConfig
constructor (private server: ServerService) { }
ngOnInit () {
this.serverConfig = this.server.getHTMLConfig()
}
@ -41,6 +41,6 @@ export class UserRealQuotaInfoComponent implements OnInit {
}
getQuotaAsNumber () {
return parseInt(this.videoQuota + '', 10)
return parseInt(this.videoQuota() + '', 10)
}
}

View File

@ -1,24 +1,18 @@
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { Notifier } from '@app/core'
import { Debug } from '@peertube/peertube-models'
import { DebugService } from './debug.service'
import { GlobalIconComponent } from '@app/shared/shared-icons/global-icon.component'
@Component({
templateUrl: './debug.component.html',
styleUrls: [ './debug.component.scss' ],
imports: [
GlobalIconComponent
]
imports: []
})
export class DebugComponent implements OnInit {
debug: Debug
private debugService = inject(DebugService)
private notifier = inject(Notifier)
constructor (
private debugService: DebugService,
private notifier: Notifier
) {
}
debug: Debug
ngOnInit (): void {
this.load()
@ -26,10 +20,10 @@ export class DebugComponent implements OnInit {
load () {
this.debugService.getDebug()
.subscribe({
next: debug => this.debug = debug,
.subscribe({
next: debug => this.debug = debug,
error: err => this.notifier.error(err.message)
})
error: err => this.notifier.error(err.message)
})
}
}

View File

@ -1,24 +1,22 @@
import { Observable } from 'rxjs'
import { catchError } from 'rxjs/operators'
import { HttpClient } from '@angular/common/http'
import { Injectable } from '@angular/core'
import { Injectable, inject } from '@angular/core'
import { RestExtractor } from '@app/core'
import { Debug } from '@peertube/peertube-models'
import { environment } from '../../../../environments/environment'
@Injectable()
export class DebugService {
private static BASE_DEBUG_URL = environment.apiUrl + '/api/v1/server/debug'
private authHttp = inject(HttpClient)
private restExtractor = inject(RestExtractor)
constructor (
private authHttp: HttpClient,
private restExtractor: RestExtractor
) {}
private static BASE_DEBUG_URL = environment.apiUrl + '/api/v1/server/debug'
getDebug (): Observable<Debug> {
return this.authHttp.get<Debug>(DebugService.BASE_DEBUG_URL)
.pipe(
catchError(err => this.restExtractor.handleError(err))
)
.pipe(
catchError(err => this.restExtractor.handleError(err))
)
}
}

View File

@ -2,7 +2,7 @@ import { SortMeta } from 'primeng/api'
import { Observable } from 'rxjs'
import { catchError, map } from 'rxjs/operators'
import { HttpClient, HttpParams } from '@angular/common/http'
import { Injectable } from '@angular/core'
import { Injectable, inject } from '@angular/core'
import { RestExtractor, RestPagination, RestService } from '@app/core'
import { Job, ResultList } from '@peertube/peertube-models'
import { environment } from '../../../../environments/environment'
@ -11,13 +11,11 @@ import { JobTypeClient } from '../../../../types/job-type-client.type'
@Injectable()
export class JobService {
private static BASE_JOB_URL = environment.apiUrl + '/api/v1/jobs'
private authHttp = inject(HttpClient)
private restService = inject(RestService)
private restExtractor = inject(RestExtractor)
constructor (
private authHttp: HttpClient,
private restService: RestService,
private restExtractor: RestExtractor
) {}
private static BASE_JOB_URL = environment.apiUrl + '/api/v1/jobs'
listJobs (options: {
jobState?: JobStateClient
@ -33,12 +31,12 @@ export class JobService {
if (jobType !== 'all') params = params.append('jobType', jobType)
return this.authHttp.get<ResultList<Job>>(JobService.BASE_JOB_URL + `/${jobState || ''}`, { params })
.pipe(
map(res => this.restExtractor.convertResultListDateToHuman(res, [ 'createdAt', 'processedOn', 'finishedOn' ], 'precise')),
map(res => this.restExtractor.applyToResultListData(res, this.prettyPrintData.bind(this))),
map(res => this.restExtractor.applyToResultListData(res, this.buildUniqId.bind(this))),
catchError(err => this.restExtractor.handleError(err))
)
.pipe(
map(res => this.restExtractor.convertResultListDateToHuman(res, [ 'createdAt', 'processedOn', 'finishedOn' ], 'precise')),
map(res => this.restExtractor.applyToResultListData(res, this.prettyPrintData.bind(this))),
map(res => this.restExtractor.applyToResultListData(res, this.buildUniqId.bind(this))),
catchError(err => this.restExtractor.handleError(err))
)
}
private prettyPrintData (obj: Job) {

View File

@ -1,9 +1,9 @@
import { NgClass, NgFor, NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { NgClass, NgIf } from '@angular/common'
import { Component, OnInit, inject } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { Notifier, RestPagination, RestTable } from '@app/core'
import { SelectOptionsComponent } from '@app/shared/shared-forms/select/select-options.component'
import { GlobalIconComponent } from '@app/shared/shared-icons/global-icon.component'
import { AutoColspanDirective } from '@app/shared/shared-main/common/auto-colspan.directive'
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'
import { Job, JobState, JobType } from '@peertube/peertube-models'
@ -23,7 +23,6 @@ import { JobService } from './job.service'
styleUrls: [ './jobs.component.scss' ],
imports: [
FormsModule,
NgFor,
NgClass,
ButtonComponent,
TableModule,
@ -31,12 +30,14 @@ import { JobService } from './job.service'
NgIf,
NgbTooltip,
TableExpanderIconComponent,
GlobalIconComponent,
SelectOptionsComponent,
AutoColspanDirective
]
})
export class JobsComponent extends RestTable implements OnInit {
private notifier = inject(Notifier)
private jobsService = inject(JobService)
private static LS_STATE = 'jobs-list-state'
private static LS_TYPE = 'jobs-list-type'
@ -87,13 +88,6 @@ export class JobsComponent extends RestTable implements OnInit {
sort: SortMeta = { field: 'createdAt', order: -1 }
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
constructor (
private notifier: Notifier,
private jobsService: JobService
) {
super()
}
ngOnInit () {
this.loadJobStateAndType()
this.initialize()

View File

@ -1,5 +1,5 @@
import { NgClass, NgFor, NgIf } from '@angular/common'
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'
import { Component, ElementRef, OnInit, inject, viewChild } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { LocalStorageService, Notifier } from '@app/core'
import { SelectOptionsComponent } from '@app/shared/shared-forms/select/select-options.component'
@ -29,10 +29,14 @@ import { LogsService } from './logs.service'
]
})
export class LogsComponent implements OnInit {
private logsService = inject(LogsService)
private notifier = inject(Notifier)
private localStorage = inject(LocalStorageService)
private static LS_LOG_TYPE_CHOICE_KEY = 'admin-logs-log-type-choice'
@ViewChild('logsElement', { static: true }) logsElement: ElementRef<HTMLElement>
@ViewChild('logsContent', { static: true }) logsContent: ElementRef<HTMLElement>
readonly logsElement = viewChild<ElementRef<HTMLElement>>('logsElement')
readonly logsContent = viewChild<ElementRef<HTMLElement>>('logsContent')
loading = false
@ -48,12 +52,6 @@ export class LogsComponent implements OnInit {
logType: 'audit' | 'standard'
tagsOneOf: string[] = []
constructor (
private logsService: LogsService,
private notifier: Notifier,
private localStorage: LocalStorageService
) { }
ngOnInit (): void {
this.buildTimeChoices()
this.buildLevelChoices()
@ -91,7 +89,7 @@ export class LogsComponent implements OnInit {
this.rawLogs = this.logs.map(l => `${l.level} ${l.localeDate} ${l.message} ${l.meta}`).join('\n')
setTimeout(() => {
this.logsElement.nativeElement.scrollIntoView({ block: 'end', inline: 'nearest' })
this.logsElement().nativeElement.scrollIntoView({ block: 'end', inline: 'nearest' })
})
},

View File

@ -1,5 +1,5 @@
import { HttpClient, HttpParams } from '@angular/common/http'
import { Injectable } from '@angular/core'
import { Injectable, inject } from '@angular/core'
import { RestExtractor, RestService } from '@app/core'
import { ServerLogLevel } from '@peertube/peertube-models'
import { catchError, map } from 'rxjs/operators'
@ -8,15 +8,13 @@ import { LogRow } from './log-row.model'
@Injectable()
export class LogsService {
private authHttp = inject(HttpClient)
private restService = inject(RestService)
private restExtractor = inject(RestExtractor)
private static BASE_LOG_URL = environment.apiUrl + '/api/v1/server/logs'
private static BASE_AUDIT_LOG_URL = environment.apiUrl + '/api/v1/server/audit-logs'
constructor (
private authHttp: HttpClient,
private restService: RestService,
private restExtractor: RestExtractor
) {}
getLogs (options: {
isAuditLog: boolean
startDate: string
@ -38,9 +36,9 @@ export class LogsService {
: LogsService.BASE_LOG_URL
return this.authHttp.get<LogRow[]>(path, { params })
.pipe(
map(rows => rows.map(r => new LogRow(r))),
catchError(err => this.restExtractor.handleError(err))
)
.pipe(
map(rows => rows.map(r => new LogRow(r))),
catchError(err => this.restExtractor.handleError(err))
)
}
}

View File

@ -1,6 +1,6 @@
import { NgClass, NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { RouterLink } from '@angular/router'
import { Component, OnInit, inject } from '@angular/core'
import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core'
import { formatICU } from '@app/helpers'
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'
@ -8,7 +8,7 @@ import { RunnerJob, RunnerJobState } from '@peertube/peertube-models'
import { SharedModule, SortMeta } from 'primeng/api'
import { TableModule } from 'primeng/table'
import { AdvancedInputFilter, AdvancedInputFilterComponent } from '../../../../shared/shared-forms/advanced-input-filter.component'
import { GlobalIconComponent } from '../../../../shared/shared-icons/global-icon.component'
import { AutoColspanDirective } from '../../../../shared/shared-main/common/auto-colspan.directive'
import { ActionDropdownComponent, DropdownAction } from '../../../../shared/shared-main/buttons/action-dropdown.component'
import { ButtonComponent } from '../../../../shared/shared-main/buttons/button.component'
@ -19,8 +19,6 @@ import { RunnerJobFormatted, RunnerService } from '../runner.service'
selector: 'my-runner-job-list',
templateUrl: './runner-job-list.component.html',
imports: [
GlobalIconComponent,
RouterLink,
TableModule,
SharedModule,
NgbTooltip,
@ -33,7 +31,11 @@ import { RunnerJobFormatted, RunnerService } from '../runner.service'
AutoColspanDirective
]
})
export class RunnerJobListComponent extends RestTable <RunnerJob> implements OnInit {
export class RunnerJobListComponent extends RestTable<RunnerJob> implements OnInit {
private runnerService = inject(RunnerService)
private notifier = inject(Notifier)
private confirmService = inject(ConfirmService)
runnerJobs: RunnerJobFormatted[] = []
totalRecords = 0
@ -67,14 +69,6 @@ export class RunnerJobListComponent extends RestTable <RunnerJob> implements OnI
}
]
constructor (
private runnerService: RunnerService,
private notifier: Notifier,
private confirmService: ConfirmService
) {
super()
}
ngOnInit () {
this.actions = [
[
@ -126,20 +120,20 @@ export class RunnerJobListComponent extends RestTable <RunnerJob> implements OnI
if (res === false) return
this.runnerService.cancelJobs(jobs)
.subscribe({
next: () => {
this.reloadData()
.subscribe({
next: () => {
this.reloadData()
this.notifier.success(
formatICU(
$localize`{count, plural, =1 {Job cancelled} other {{count} jobs cancelled}}`,
{ count: jobs.length }
)
this.notifier.success(
formatICU(
$localize`{count, plural, =1 {Job cancelled} other {{count} jobs cancelled}}`,
{ count: jobs.length }
)
},
)
},
error: err => this.notifier.error(err.message)
})
error: err => this.notifier.error(err.message)
})
}
async removeJobs (jobs: RunnerJob[]) {
@ -153,20 +147,20 @@ export class RunnerJobListComponent extends RestTable <RunnerJob> implements OnI
if (res === false) return
this.runnerService.removeJobs(jobs)
.subscribe({
next: () => {
this.reloadData()
.subscribe({
next: () => {
this.reloadData()
this.notifier.success(
formatICU(
$localize`{count, plural, =1 {Job removed} other {{count} jobs removed}}`,
{ count: jobs.length }
)
this.notifier.success(
formatICU(
$localize`{count, plural, =1 {Job removed} other {{count} jobs removed}}`,
{ count: jobs.length }
)
},
)
},
error: err => this.notifier.error(err.message)
})
error: err => this.notifier.error(err.message)
})
}
getStateBadgeColor (job: RunnerJob) {

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core'
import { PTDatePipe } from '@app/shared/shared-main/common/date.pipe'
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'
@ -21,7 +21,11 @@ import { RunnerService } from '../runner.service'
PTDatePipe
]
})
export class RunnerListComponent extends RestTable <Runner> implements OnInit {
export class RunnerListComponent extends RestTable<Runner> implements OnInit {
private runnerService = inject(RunnerService)
private notifier = inject(Notifier)
private confirmService = inject(ConfirmService)
runners: Runner[] = []
totalRecords = 0
@ -30,14 +34,6 @@ export class RunnerListComponent extends RestTable <Runner> implements OnInit {
actions: DropdownAction<Runner>[][] = []
constructor (
private runnerService: RunnerService,
private notifier: Notifier,
private confirmService: ConfirmService
) {
super()
}
ngOnInit () {
this.actions = [
[
@ -64,14 +60,14 @@ export class RunnerListComponent extends RestTable <Runner> implements OnInit {
if (res === false) return
this.runnerService.deleteRunner(runner)
.subscribe({
next: () => {
this.reloadData()
this.notifier.success($localize`Runner removed.`)
},
.subscribe({
next: () => {
this.reloadData()
this.notifier.success($localize`Runner removed.`)
},
error: err => this.notifier.error(err.message)
})
error: err => this.notifier.error(err.message)
})
}
protected reloadDataInternal () {

View File

@ -1,12 +1,12 @@
import { Component, OnInit } from '@angular/core'
import { RouterLink } from '@angular/router'
import { Component, OnInit, inject } from '@angular/core'
import { ConfirmService, Notifier, RestPagination, RestTable } from '@app/core'
import { PTDatePipe } from '@app/shared/shared-main/common/date.pipe'
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'
import { RunnerRegistrationToken } from '@peertube/peertube-models'
import { SharedModule, SortMeta } from 'primeng/api'
import { TableModule } from 'primeng/table'
import { GlobalIconComponent } from '../../../../shared/shared-icons/global-icon.component'
import { ActionDropdownComponent, DropdownAction } from '../../../../shared/shared-main/buttons/action-dropdown.component'
import { ButtonComponent } from '../../../../shared/shared-main/buttons/button.component'
import { CopyButtonComponent } from '../../../../shared/shared-main/buttons/copy-button.component'
@ -18,8 +18,6 @@ import { RunnerService } from '../runner.service'
styleUrls: [ './runner-registration-token-list.component.scss' ],
templateUrl: './runner-registration-token-list.component.html',
imports: [
GlobalIconComponent,
RouterLink,
TableModule,
SharedModule,
NgbTooltip,
@ -30,7 +28,11 @@ import { RunnerService } from '../runner.service'
PTDatePipe
]
})
export class RunnerRegistrationTokenListComponent extends RestTable <RunnerRegistrationToken> implements OnInit {
export class RunnerRegistrationTokenListComponent extends RestTable<RunnerRegistrationToken> implements OnInit {
private runnerService = inject(RunnerService)
private notifier = inject(Notifier)
private confirmService = inject(ConfirmService)
registrationTokens: RunnerRegistrationToken[] = []
totalRecords = 0
@ -39,14 +41,6 @@ export class RunnerRegistrationTokenListComponent extends RestTable <RunnerRegis
actions: DropdownAction<RunnerRegistrationToken>[][] = []
constructor (
private runnerService: RunnerService,
private notifier: Notifier,
private confirmService: ConfirmService
) {
super()
}
ngOnInit () {
this.actions = [
[
@ -85,14 +79,14 @@ export class RunnerRegistrationTokenListComponent extends RestTable <RunnerRegis
if (res === false) return
this.runnerService.removeToken(token)
.subscribe({
next: () => {
this.reloadData()
this.notifier.success($localize`Registration token removed.`)
},
.subscribe({
next: () => {
this.reloadData()
this.notifier.success($localize`Registration token removed.`)
},
error: err => this.notifier.error(err.message)
})
error: err => this.notifier.error(err.message)
})
}
protected reloadDataInternal () {

View File

@ -1,7 +1,7 @@
import { SortMeta } from 'primeng/api'
import { catchError, concatMap, forkJoin, from, map, toArray } from 'rxjs'
import { HttpClient, HttpParams } from '@angular/common/http'
import { Injectable } from '@angular/core'
import { Injectable, inject } from '@angular/core'
import { RestExtractor, RestPagination, RestService, ServerService } from '@app/core'
import { arrayify, peertubeTranslate } from '@peertube/peertube-core-utils'
import { ResultList, Runner, RunnerJob, RunnerJobAdmin, RunnerJobState, RunnerRegistrationToken } from '@peertube/peertube-models'
@ -14,14 +14,12 @@ export type RunnerJobFormatted = RunnerJob & {
@Injectable()
export class RunnerService {
private static BASE_RUNNER_URL = environment.apiUrl + '/api/v1/runners'
private authHttp = inject(HttpClient)
private server = inject(ServerService)
private restService = inject(RestService)
private restExtractor = inject(RestExtractor)
constructor (
private authHttp: HttpClient,
private server: ServerService,
private restService: RestService,
private restExtractor: RestExtractor
) {}
private static BASE_RUNNER_URL = environment.apiUrl + '/api/v1/runners'
listRegistrationTokens (options: {
pagination: RestPagination
@ -33,7 +31,7 @@ export class RunnerService {
params = this.restService.addRestGetParams(params, pagination, sort)
return this.authHttp.get<ResultList<RunnerRegistrationToken>>(RunnerService.BASE_RUNNER_URL + '/registration-tokens', { params })
.pipe(catchError(res => this.restExtractor.handleError(res)))
.pipe(catchError(res => this.restExtractor.handleError(res)))
}
generateToken () {
@ -147,7 +145,7 @@ export class RunnerService {
params = this.restService.addRestGetParams(params, pagination, sort)
return this.authHttp.get<ResultList<Runner>>(RunnerService.BASE_RUNNER_URL + '/', { params })
.pipe(catchError(res => this.restExtractor.handleError(res)))
.pipe(catchError(res => this.restExtractor.handleError(res)))
}
deleteRunner (runner: Runner) {

View File

@ -1,5 +1,4 @@
import { NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { Title } from '@angular/platform-browser'
import { Router } from '@angular/router'
import { LoginLinkComponent } from '@app/shared/shared-main/users/login-link.component'
@ -9,16 +8,16 @@ import { HttpStatusCode, HttpStatusCodeType } from '@peertube/peertube-models'
selector: 'my-error-page',
templateUrl: './error-page.component.html',
styleUrls: [ './error-page.component.scss' ],
imports: [ NgIf, LoginLinkComponent ]
imports: [ LoginLinkComponent ]
})
export class ErrorPageComponent implements OnInit {
private titleService = inject(Title)
private router = inject(Router)
status: HttpStatusCodeType = HttpStatusCode.NOT_FOUND_404
type: 'video' | 'other' = 'other'
public constructor (
private titleService: Title,
private router: Router
) {
public constructor () {
const state = this.router.getCurrentNavigation()?.extras.state
this.type = state?.type || this.type
this.status = state?.obj.status || this.status

View File

@ -1,4 +1,4 @@
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'
import { Component, ElementRef, OnInit, inject, viewChild } from '@angular/core'
import { CustomPageService } from '@app/shared/shared-main/custom-page/custom-page.service'
import { CustomMarkupContainerComponent } from '../shared/shared-custom-markup/custom-markup-container.component'
@ -6,16 +6,13 @@ import { CustomMarkupContainerComponent } from '../shared/shared-custom-markup/c
templateUrl: './home.component.html',
imports: [ CustomMarkupContainerComponent ]
})
export class HomeComponent implements OnInit {
@ViewChild('contentWrapper') contentWrapper: ElementRef<HTMLInputElement>
private customPageService = inject(CustomPageService)
readonly contentWrapper = viewChild<ElementRef<HTMLInputElement>>('contentWrapper')
homepageContent: string
constructor (
private customPageService: CustomPageService
) { }
ngOnInit () {
this.customPageService.getInstanceHomepage()
.subscribe(({ content }) => this.homepageContent = content)

View File

@ -1,5 +1,5 @@
import { NgClass, NgFor, NgIf, NgTemplateOutlet } from '@angular/common'
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core'
import { NgClass, NgFor, NgIf } from '@angular/common'
import { AfterViewInit, Component, ElementRef, OnInit, inject, viewChild } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { ActivatedRoute, Router, RouterLink } from '@angular/router'
import { AuthService, Notifier, RedirectService, SessionStorageService, UserService } from '@app/core'
@ -32,7 +32,6 @@ import { PluginSelectorDirective } from '../shared/shared-main/plugins/plugin-se
ReactiveFormsModule,
AutofocusDirective,
NgClass,
NgTemplateOutlet,
InputTextComponent,
NgFor,
InstanceBannerComponent,
@ -41,13 +40,23 @@ import { PluginSelectorDirective } from '../shared/shared-main/plugins/plugin-se
AlertComponent
]
})
export class LoginComponent extends FormReactive implements OnInit, AfterViewInit {
protected formReactiveService = inject(FormReactiveService)
private route = inject(ActivatedRoute)
private modalService = inject(NgbModal)
private authService = inject(AuthService)
private userService = inject(UserService)
private redirectService = inject(RedirectService)
private notifier = inject(Notifier)
private hooks = inject(HooksService)
private storage = inject(SessionStorageService)
private router = inject(Router)
private static SESSION_STORAGE_REDIRECT_URL_KEY = 'login-previous-url'
@ViewChild('forgotPasswordModal', { static: true }) forgotPasswordModal: ElementRef
@ViewChild('otpTokenInput') otpTokenInput: InputTextComponent
@ViewChild('instanceAboutAccordion') instanceAboutAccordion: InstanceAboutAccordionComponent
readonly forgotPasswordModal = viewChild<ElementRef>('forgotPasswordModal')
readonly otpTokenInput = viewChild<InputTextComponent>('otpTokenInput')
readonly instanceAboutAccordion = viewChild<InstanceAboutAccordionComponent>('instanceAboutAccordion')
accordion: NgbAccordionDirective
error: string = null
@ -72,21 +81,6 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni
private openedForgotPasswordModal: NgbModalRef
private serverConfig: ServerConfig
constructor (
protected formReactiveService: FormReactiveService,
private route: ActivatedRoute,
private modalService: NgbModal,
private authService: AuthService,
private userService: UserService,
private redirectService: RedirectService,
private notifier: Notifier,
private hooks: HooksService,
private storage: SessionStorageService,
private router: Router
) {
super()
}
get signupAllowed () {
return this.serverConfig.signup.allowed === true
}
@ -98,8 +92,9 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni
onTermsClick (event: Event, instanceInformation: HTMLElement) {
event.preventDefault()
if (this.instanceAboutAccordion) {
this.instanceAboutAccordion.expandTerms()
const instanceAboutAccordion = this.instanceAboutAccordion()
if (instanceAboutAccordion) {
instanceAboutAccordion.expandTerms()
instanceInformation.scrollIntoView({ behavior: 'smooth' })
}
}
@ -191,7 +186,7 @@ The link will expire within 1 hour.`
}
openForgotPasswordModal () {
this.openedForgotPasswordModal = this.modalService.open(this.forgotPasswordModal)
this.openedForgotPasswordModal = this.modalService.open(this.forgotPasswordModal())
}
hideForgotPasswordModal () {
@ -199,7 +194,7 @@ The link will expire within 1 hour.`
}
onInstanceAboutAccordionInit (instanceAboutAccordion: InstanceAboutAccordionComponent) {
this.accordion = instanceAboutAccordion.accordion
this.accordion = instanceAboutAccordion.accordion()
}
private loadExternalAuthToken (username: string, token: string) {
@ -230,7 +225,7 @@ The link will expire within 1 hour.`
setTimeout(() => {
this.form.get('otp-token').setValidators(USER_OTP_TOKEN_VALIDATOR.VALIDATORS)
this.otpTokenInput.focus()
this.otpTokenInput().focus()
})
return

View File

@ -1,13 +1,11 @@
import { Component } from '@angular/core'
import { AbuseListTableComponent } from '../../shared/shared-abuse-list/abuse-list-table.component'
import { GlobalIconComponent } from '../../shared/shared-icons/global-icon.component'
@Component({
selector: 'my-account-abuses-list',
templateUrl: './my-account-abuses-list.component.html',
styleUrls: [],
imports: [ GlobalIconComponent, AbuseListTableComponent ]
imports: [ AbuseListTableComponent ]
})
export class MyAccountAbusesListComponent {
}

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { AuthService, ConfirmService, Notifier, ScopedTokensService } from '@app/core'
import { VideoService } from '@app/shared/shared-main/video/video.service'
import { FeedFormat, ScopedToken } from '@peertube/peertube-models'
@ -12,19 +12,17 @@ import { InputTextComponent } from '../../shared/shared-forms/input-text.compone
imports: [ InputTextComponent ]
})
export class MyAccountApplicationsComponent implements OnInit {
private authService = inject(AuthService)
private scopedTokensService = inject(ScopedTokensService)
private videoService = inject(VideoService)
private notifier = inject(Notifier)
private confirmService = inject(ConfirmService)
feedUrl: string
feedToken: string
private baseURL = environment.originServerUrl || window.location.origin
constructor (
private authService: AuthService,
private scopedTokensService: ScopedTokensService,
private videoService: VideoService,
private notifier: Notifier,
private confirmService: ConfirmService
) {}
ngOnInit () {
this.feedUrl = this.baseURL

View File

@ -1,5 +1,5 @@
import { NgFor, NgIf } from '@angular/common'
import { Component, Input, OnInit, ViewChild } from '@angular/core'
import { Component, OnInit, inject, input, viewChild } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { AuthService, ServerService } from '@app/core'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
@ -19,9 +19,14 @@ import { UserImportExportService } from './user-import-export.service'
imports: [ NgIf, NgFor, GlobalIconComponent, PeertubeCheckboxComponent, FormsModule, PTDatePipe, BytesPipe, AlertComponent ]
})
export class MyAccountExportComponent implements OnInit {
@ViewChild('exportModal', { static: true }) exportModal: NgbModal
private authService = inject(AuthService)
private server = inject(ServerService)
private userImportExportService = inject(UserImportExportService)
private modalService = inject(NgbModal)
@Input() videoQuotaUsed: number
readonly exportModal = viewChild<NgbModal>('exportModal')
readonly videoQuotaUsed = input<number>(undefined)
userExports: UserExport[] = []
@ -33,15 +38,8 @@ export class MyAccountExportComponent implements OnInit {
private exportModalOpened: NgbModalRef
private requestingArchive = false
constructor (
private authService: AuthService,
private server: ServerService,
private userImportExportService: UserImportExportService,
private modalService: NgbModal
) {}
ngOnInit () {
this.archiveWeightEstimation = this.videoQuotaUsed
this.archiveWeightEstimation = this.videoQuotaUsed()
this.reloadUserExports()
}
@ -70,7 +68,7 @@ export class MyAccountExportComponent implements OnInit {
this.exportWithVideosFiles = false
this.errorInModal = undefined
this.exportModalOpened = this.modalService.open(this.exportModal, { centered: true })
this.exportModalOpened = this.modalService.open(this.exportModal(), { centered: true })
}
requestNewArchive () {
@ -105,8 +103,9 @@ export class MyAccountExportComponent implements OnInit {
const error = err.body as PeerTubeProblemDocument
if (error.code === ServerErrorCode.MAX_USER_VIDEO_QUOTA_EXCEEDED_FOR_USER_EXPORT) {
// eslint-disable-next-line max-len
this.errorInModal = $localize`Video files cannot be included in the export because you have exceeded the maximum video quota allowed by your administrator to export this archive.`
this.errorInModal =
// eslint-disable-next-line max-len
$localize`Video files cannot be included in the export because you have exceeded the maximum video quota allowed by your administrator to export this archive.`
return
}

View File

@ -1,29 +1,27 @@
import { Component, OnInit, ViewChild } from '@angular/core'
import { Component, OnInit, inject, viewChild } from '@angular/core'
import { CanComponentDeactivate, UserService } from '@app/core'
import { GlobalIconComponent } from '../../shared/shared-icons/global-icon.component'
import { MyAccountExportComponent } from './my-account-export.component'
import { MyAccountImportComponent } from './my-account-import.component'
@Component({
selector: 'my-account-import-export',
templateUrl: './my-account-import-export.component.html',
imports: [ GlobalIconComponent, MyAccountImportComponent, MyAccountExportComponent ]
imports: [ MyAccountImportComponent, MyAccountExportComponent ]
})
export class MyAccountImportExportComponent implements OnInit, CanComponentDeactivate {
@ViewChild('accountImport') accountImport: MyAccountImportComponent
private userService = inject(UserService)
readonly accountImport = viewChild<MyAccountImportComponent>('accountImport')
videoQuotaUsed: number
constructor (
private userService: UserService
) {}
ngOnInit () {
this.userService.getMyVideoQuotaUsed()
.subscribe(res => this.videoQuotaUsed = res.videoQuotaUsed)
}
canDeactivate () {
return this.accountImport?.canDeactivate() || { canDeactivate: true }
return this.accountImport()?.canDeactivate() || { canDeactivate: true }
}
}

View File

@ -1,6 +1,6 @@
import { NgIf } from '@angular/common'
import { HttpErrorResponse } from '@angular/common/http'
import { Component, Input, OnDestroy, OnInit } from '@angular/core'
import { Component, OnDestroy, OnInit, inject, input } from '@angular/core'
import { AuthService, CanComponentDeactivate, Notifier, ServerService } from '@app/core'
import { buildHTTPErrorResponse, genericUploadErrorHandler, getUploadXRetryConfig } from '@app/helpers'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
@ -20,7 +20,13 @@ import { UserImportExportService } from './user-import-export.service'
imports: [ NgIf, UploadProgressComponent, NgbTooltip, PTDatePipe, AlertComponent ]
})
export class MyAccountImportComponent implements OnInit, OnDestroy, CanComponentDeactivate {
@Input() videoQuotaUsed: number
private authService = inject(AuthService)
private server = inject(ServerService)
private userImportExportService = inject(UserImportExportService)
private resumableUploadService = inject(UploadxService)
private notifier = inject(Notifier)
readonly videoQuotaUsed = input<number>(undefined)
uploadingArchive = false
archiveUploadFinished = false
@ -35,14 +41,6 @@ export class MyAccountImportComponent implements OnInit, OnDestroy, CanComponent
private uploadServiceSubscription: Subscription
private alreadyRefreshedToken = false
constructor (
private authService: AuthService,
private server: ServerService,
private userImportExportService: UserImportExportService,
private resumableUploadService: UploadxService,
private notifier: Notifier
) {}
ngOnInit () {
this.userImportExportService.getLatestImport({ userId: this.authService.getUser().id })
.subscribe(res => this.latestImport = res)
@ -113,10 +111,10 @@ export class MyAccountImportComponent implements OnInit, OnDestroy, CanComponent
const user = this.authService.getUser()
if (user.videoQuota !== -1 && this.videoQuotaUsed + file.size > user.videoQuota) {
if (user.videoQuota !== -1 && this.videoQuotaUsed() + file.size > user.videoQuota) {
const bytePipes = new BytesPipe()
const fileSizeBytes = bytePipes.transform(file.size, 0)
const videoQuotaUsedBytes = bytePipes.transform(this.videoQuotaUsed, 0)
const videoQuotaUsedBytes = bytePipes.transform(this.videoQuotaUsed(), 0)
const videoQuotaBytes = bytePipes.transform(user.videoQuota, 0)
this.notifier.error(

View File

@ -1,6 +1,6 @@
import { catchError, map } from 'rxjs/operators'
import { HttpClient } from '@angular/common/http'
import { Injectable } from '@angular/core'
import { Injectable, inject } from '@angular/core'
import { RestExtractor, ServerService } from '@app/core'
import { environment } from 'src/environments/environment'
import { HttpStatusCode, ResultList, UserExport, UserImport } from '@peertube/peertube-models'
@ -9,15 +9,13 @@ import { peertubeTranslate } from '@peertube/peertube-core-utils'
@Injectable()
export class UserImportExportService {
private authHttp = inject(HttpClient)
private restExtractor = inject(RestExtractor)
private server = inject(ServerService)
static BASE_USER_EXPORTS_URL = environment.apiUrl + '/api/v1/users/'
static BASE_USER_IMPORTS_URL = environment.apiUrl + '/api/v1/users/'
constructor (
private authHttp: HttpClient,
private restExtractor: RestExtractor,
private server: ServerService
) { }
// ---------------------------------------------------------------------------
listUserExports (options: {

View File

@ -1,4 +1,4 @@
import { Component, ViewChild } from '@angular/core'
import { Component, viewChild } from '@angular/core'
import { UserNotificationsComponent } from '@app/shared/standalone-notifications/user-notifications.component'
import { NgIf } from '@angular/common'
import { FormsModule } from '@angular/forms'
@ -13,7 +13,7 @@ type NotificationSortType = 'createdAt' | 'read'
imports: [ RouterLink, GlobalIconComponent, FormsModule, NgIf, UserNotificationsComponent ]
})
export class MyAccountNotificationsComponent {
@ViewChild('userNotification', { static: true }) userNotification: UserNotificationsComponent
readonly userNotification = viewChild<UserNotificationsComponent>('userNotification')
_notificationSortType: NotificationSortType = 'createdAt'
@ -28,14 +28,14 @@ export class MyAccountNotificationsComponent {
}
markAllAsRead () {
this.userNotification.markAllAsRead()
this.userNotification().markAllAsRead()
}
hasUnreadNotifications () {
return this.userNotification.notifications.filter(n => n.read === false).length !== 0
return this.userNotification().notifications.filter(n => n.read === false).length !== 0
}
onChangeSortColumn () {
this.userNotification.changeSortColumn(this.notificationSortType)
this.userNotification().changeSortColumn(this.notificationSortType)
}
}

View File

@ -1,5 +1,5 @@
import { NgClass, NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { AuthService, ServerService, UserService } from '@app/core'
import { USER_EMAIL_VALIDATOR, USER_PASSWORD_VALIDATOR } from '@app/shared/form-validators/user-validators'
@ -18,19 +18,15 @@ import { InputTextComponent } from '../../../shared/shared-forms/input-text.comp
imports: [ NgIf, FormsModule, ReactiveFormsModule, NgClass, InputTextComponent, AlertComponent ]
})
export class MyAccountChangeEmailComponent extends FormReactive implements OnInit {
protected formReactiveService = inject(FormReactiveService)
private authService = inject(AuthService)
private userService = inject(UserService)
private serverService = inject(ServerService)
error: string
success: string
user: User
constructor (
protected formReactiveService: FormReactiveService,
private authService: AuthService,
private userService: UserService,
private serverService: ServerService
) {
super()
}
ngOnInit () {
this.buildForm({
'new-email': USER_EMAIL_VALIDATOR,

View File

@ -1,5 +1,5 @@
import { NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { AuthService, Notifier, UserService } from '@app/core'
import {
@ -21,18 +21,14 @@ import { InputTextComponent } from '../../../shared/shared-forms/input-text.comp
imports: [ NgIf, FormsModule, ReactiveFormsModule, InputTextComponent, AlertComponent ]
})
export class MyAccountChangePasswordComponent extends FormReactive implements OnInit {
protected formReactiveService = inject(FormReactiveService)
private notifier = inject(Notifier)
private authService = inject(AuthService)
private userService = inject(UserService)
error: string
user: User
constructor (
protected formReactiveService: FormReactiveService,
private notifier: Notifier,
private authService: AuthService,
private userService: UserService
) {
super()
}
ngOnInit () {
this.buildForm({
'current-password': USER_EXISTING_PASSWORD_VALIDATOR,
@ -45,8 +41,8 @@ export class MyAccountChangePasswordComponent extends FormReactive implements On
const confirmPasswordControl = this.form.get('new-confirmed-password')
confirmPasswordControl.valueChanges
.pipe(filter(v => v !== this.form.value['new-password']))
.subscribe(() => confirmPasswordControl.setErrors({ matchPassword: true }))
.pipe(filter(v => v !== this.form.value['new-password']))
.subscribe(() => confirmPasswordControl.setErrors({ matchPassword: true }))
}
changePassword () {

View File

@ -1,4 +1,4 @@
import { Component, Input } from '@angular/core'
import { Component, inject, input } from '@angular/core'
import { AuthService, ConfirmService, Notifier, RedirectService, User, UserService } from '@app/core'
@Component({
@ -7,27 +7,24 @@ import { AuthService, ConfirmService, Notifier, RedirectService, User, UserServi
standalone: true
})
export class MyAccountDangerZoneComponent {
@Input() user: User
private authService = inject(AuthService)
private notifier = inject(Notifier)
private userService = inject(UserService)
private confirmService = inject(ConfirmService)
private redirectService = inject(RedirectService)
constructor (
private authService: AuthService,
private notifier: Notifier,
private userService: UserService,
private confirmService: ConfirmService,
private redirectService: RedirectService
) { }
readonly user = input<User>(undefined)
async deleteMe () {
const res = await this.confirmService.confirmWithExpectedInput(
$localize`Are you sure you want to delete your account?` +
'<br /><br />' +
// eslint-disable-next-line max-len
$localize`This will delete all your data, including channels, videos, comments and you won't be able to create another user on this instance with "${this.user.username}" username.` +
$localize`This will delete all your data, including channels, videos, comments and you won't be able to create another user on this instance with "${this.user().username}" username.` +
'<br /><br />' +
$localize`Content cached by other servers and other third-parties might make longer to be deleted.`,
$localize`Type your username to confirm`,
this.user.username,
this.user().username,
$localize`Delete your account`,
$localize`Delete my account`
)

View File

@ -7,7 +7,7 @@
>
<ng-container ngProjectAs="description">
<p class="mb-0">
@if (user.emailVerified) {
@if (user().emailVerified) {
<ng-container i18n>Necessary to claim podcast RSS feeds.</ng-container>
} @else {
<ng-container i18n>⚠️ Your email cannot be used in podcast RSS feeds because it has not yet been verified.</ng-container>

View File

@ -1,4 +1,4 @@
import { Component, Input, OnInit } from '@angular/core'
import { Component, OnInit, inject, input } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Notifier, UserService } from '@app/core'
import { FormReactive } from '@app/shared/shared-forms/form-reactive'
@ -13,22 +13,18 @@ import { PeertubeCheckboxComponent } from '../../../shared/shared-forms/peertube
imports: [ FormsModule, ReactiveFormsModule, PeertubeCheckboxComponent ]
})
export class MyAccountEmailPreferencesComponent extends FormReactive implements OnInit {
@Input() user: User
protected formReactiveService = inject(FormReactiveService)
private userService = inject(UserService)
private notifier = inject(Notifier)
constructor (
protected formReactiveService: FormReactiveService,
private userService: UserService,
private notifier: Notifier
) {
super()
}
readonly user = input<User>(undefined)
ngOnInit () {
this.buildForm({
'email-public': null
})
this.form.patchValue({ 'email-public': this.user.emailPublic })
this.form.patchValue({ 'email-public': this.user().emailPublic })
}
updateEmailPublic () {
@ -42,7 +38,7 @@ export class MyAccountEmailPreferencesComponent extends FormReactive implements
if (details.emailPublic) this.notifier.success($localize`Email is now public`)
else this.notifier.success($localize`Email is now private`)
this.user.emailPublic = details.emailPublic
this.user().emailPublic = details.emailPublic
},
error: err => this.notifier.error(err.message)

View File

@ -1,5 +1,5 @@
import { NgFor, NgIf } from '@angular/common'
import { Component, Input, OnInit } from '@angular/core'
import { Component, OnInit, inject, input } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { Notifier, ServerService, User } from '@app/core'
import { UserNotificationService } from '@app/shared/shared-main/users/user-notification.service'
@ -15,22 +15,22 @@ import { InputSwitchComponent } from '../../../shared/shared-forms/input-switch.
imports: [ NgIf, NgFor, InputSwitchComponent, FormsModule ]
})
export class MyAccountNotificationPreferencesComponent implements OnInit {
@Input() user: User
private userNotificationService = inject(UserNotificationService)
private serverService = inject(ServerService)
private notifier = inject(Notifier)
readonly user = input<User>(undefined)
notificationSettingGroups: { label: string, keys: (keyof UserNotificationSetting)[] }[] = []
emailNotifications: { [ id in keyof UserNotificationSetting ]?: boolean } = {}
webNotifications: { [ id in keyof UserNotificationSetting ]?: boolean } = {}
labelNotifications: { [ id in keyof UserNotificationSetting ]?: string } = {}
rightNotifications: { [ id in keyof Partial<UserNotificationSetting> ]?: UserRightType } = {}
emailNotifications: { [id in keyof UserNotificationSetting]?: boolean } = {}
webNotifications: { [id in keyof UserNotificationSetting]?: boolean } = {}
labelNotifications: { [id in keyof UserNotificationSetting]?: string } = {}
rightNotifications: { [id in keyof Partial<UserNotificationSetting>]?: UserRightType } = {}
emailEnabled = false
private savePreferences = debounce(this.savePreferencesImpl.bind(this), 500)
constructor (
private userNotificationService: UserNotificationService,
private serverService: ServerService,
private notifier: Notifier
) {
constructor () {
this.notificationSettingGroups = [
{
label: $localize`Social`,
@ -118,7 +118,7 @@ export class MyAccountNotificationPreferencesComponent implements OnInit {
const rightToHave = this.rightNotifications[field]
if (!rightToHave) return true // No rights needed
return this.user.hasRight(rightToHave)
return this.user().hasRight(rightToHave)
}
hasNotificationsInGroup (group: { keys: (keyof UserNotificationSetting)[] }) {
@ -134,21 +134,21 @@ export class MyAccountNotificationPreferencesComponent implements OnInit {
}
updateEmailSetting (field: keyof UserNotificationSetting, value: boolean) {
if (value === true) this.user.notificationSettings[field] |= UserNotificationSettingValue.EMAIL
else this.user.notificationSettings[field] &= ~UserNotificationSettingValue.EMAIL
if (value === true) this.user().notificationSettings[field] |= UserNotificationSettingValue.EMAIL
else this.user().notificationSettings[field] &= ~UserNotificationSettingValue.EMAIL
this.savePreferences()
}
updateWebSetting (field: keyof UserNotificationSetting, value: boolean) {
if (value === true) this.user.notificationSettings[field] |= UserNotificationSettingValue.WEB
else this.user.notificationSettings[field] &= ~UserNotificationSettingValue.WEB
if (value === true) this.user().notificationSettings[field] |= UserNotificationSettingValue.WEB
else this.user().notificationSettings[field] &= ~UserNotificationSettingValue.WEB
this.savePreferences()
}
private savePreferencesImpl () {
this.userNotificationService.updateNotificationSettings(this.user.notificationSettings)
this.userNotificationService.updateNotificationSettings(this.user().notificationSettings)
.subscribe({
next: () => {
this.notifier.success($localize`Preferences saved`, undefined, 2000)
@ -159,8 +159,8 @@ export class MyAccountNotificationPreferencesComponent implements OnInit {
}
private loadNotificationSettings () {
for (const key of objectKeysTyped(this.user.notificationSettings)) {
const value = this.user.notificationSettings[key]
for (const key of objectKeysTyped(this.user().notificationSettings)) {
const value = this.user().notificationSettings[key]
this.emailNotifications[key] = !!(value & UserNotificationSettingValue.EMAIL)
this.webNotifications[key] = !!(value & UserNotificationSettingValue.WEB)

View File

@ -9,7 +9,7 @@
formControlName="username" readonly
>
<div class="form-group-description" i18n>
People can find you using &#64;{{ user.username }}&#64;{{ instanceHost }}
People can find you using &#64;{{ user().username }}&#64;{{ instanceHost }}
</div>
</div>

View File

@ -1,5 +1,5 @@
import { NgClass, NgIf } from '@angular/common'
import { Component, Input, OnInit } from '@angular/core'
import { Component, OnInit, inject, input } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Notifier, User, UserService } from '@app/core'
import { USER_DESCRIPTION_VALIDATOR, USER_DISPLAY_NAME_REQUIRED_VALIDATOR } from '@app/shared/form-validators/user-validators'
@ -16,18 +16,14 @@ import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
imports: [ NgIf, FormsModule, ReactiveFormsModule, NgClass, AlertComponent, HelpComponent, MarkdownTextareaComponent ]
})
export class MyAccountProfileComponent extends FormReactive implements OnInit {
@Input() user: User = null
protected formReactiveService = inject(FormReactiveService)
private notifier = inject(Notifier)
private userService = inject(UserService)
readonly user = input<User>(null)
error: string = null
constructor (
protected formReactiveService: FormReactiveService,
private notifier: Notifier,
private userService: UserService
) {
super()
}
ngOnInit () {
this.buildForm({
'username': null,
@ -37,9 +33,9 @@ export class MyAccountProfileComponent extends FormReactive implements OnInit {
this.form.controls['username'].disable()
this.form.patchValue({
'username': this.user.username,
'display-name': this.user.account.displayName,
'description': this.user.account.description
'username': this.user().username,
'display-name': this.user().account.displayName,
'description': this.user().account.description
})
}
@ -54,15 +50,16 @@ export class MyAccountProfileComponent extends FormReactive implements OnInit {
this.error = null
this.userService.updateMyProfile({ displayName, description })
.subscribe({
next: () => {
this.user.account.displayName = displayName
this.user.account.description = description
.subscribe({
next: () => {
const user = this.user()
user.account.displayName = displayName
user.account.description = description
this.notifier.success($localize`Profile updated.`)
},
this.notifier.success($localize`Profile updated.`)
},
error: err => this.error = err.message
})
error: err => this.error = err.message
})
}
}

View File

@ -1,6 +1,6 @@
import { ViewportScroller, NgIf } from '@angular/common'
import { HttpErrorResponse } from '@angular/common/http'
import { AfterViewChecked, Component, OnInit } from '@angular/core'
import { AfterViewChecked, Component, OnInit, inject } from '@angular/core'
import { AuthService, Notifier, User, UserService } from '@app/core'
import { genericUploadErrorHandler } from '@app/helpers'
import { shallowCopy } from '@peertube/peertube-core-utils'
@ -38,17 +38,15 @@ import { ActorAvatarEditComponent } from '../../shared/shared-actor-image-edit/a
]
})
export class MyAccountSettingsComponent implements OnInit, AfterViewChecked {
private viewportScroller = inject(ViewportScroller)
private userService = inject(UserService)
private authService = inject(AuthService)
private notifier = inject(Notifier)
user: User
private lastScrollHash: string
constructor (
private viewportScroller: ViewportScroller,
private userService: UserService,
private authService: AuthService,
private notifier: Notifier
) {}
get userInformationLoaded () {
return this.authService.userInformationLoaded
}
@ -77,11 +75,12 @@ export class MyAccountSettingsComponent implements OnInit, AfterViewChecked {
this.user.account = shallowCopy(this.user.account)
},
error: (err: HttpErrorResponse) => genericUploadErrorHandler({
err,
name: $localize`avatar`,
notifier: this.notifier
})
error: (err: HttpErrorResponse) =>
genericUploadErrorHandler({
err,
name: $localize`avatar`,
notifier: this.notifier
})
})
}

View File

@ -1,5 +1,5 @@
import { NgIf } from '@angular/common'
import { Component, Input, OnInit } from '@angular/core'
import { Component, OnInit, inject, input } from '@angular/core'
import { AuthService, ConfirmService, Notifier, User } from '@app/core'
import { TwoFactorService } from '@app/shared/shared-users/two-factor.service'
import { ButtonComponent } from '../../../shared/shared-main/buttons/button.component'
@ -10,20 +10,17 @@ import { ButtonComponent } from '../../../shared/shared-main/buttons/button.comp
imports: [ NgIf, ButtonComponent ]
})
export class MyAccountTwoFactorButtonComponent implements OnInit {
@Input() user: User
private notifier = inject(Notifier)
private twoFactorService = inject(TwoFactorService)
private confirmService = inject(ConfirmService)
private auth = inject(AuthService)
readonly user = input<User>(undefined)
twoFactorEnabled = false
constructor (
private notifier: Notifier,
private twoFactorService: TwoFactorService,
private confirmService: ConfirmService,
private auth: AuthService
) {
}
ngOnInit () {
this.twoFactorEnabled = this.user.twoFactorEnabled
this.twoFactorEnabled = this.user().twoFactorEnabled
}
async disableTwoFactor () {
@ -32,7 +29,7 @@ export class MyAccountTwoFactorButtonComponent implements OnInit {
const { confirmed, password } = await this.confirmService.confirmWithPassword({ message, title: $localize`Disable two factor` })
if (confirmed === false) return
this.twoFactorService.disableTwoFactor({ userId: this.user.id, currentPassword: password })
this.twoFactorService.disableTwoFactor({ userId: this.user().id, currentPassword: password })
.subscribe({
next: () => {
this.twoFactorEnabled = false

View File

@ -1,5 +1,5 @@
import { NgIf } from '@angular/common'
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Router } from '@angular/router'
import { AuthService, Notifier, User } from '@app/core'
@ -16,6 +16,12 @@ import { InputTextComponent } from '../../../shared/shared-forms/input-text.comp
imports: [ NgIf, FormsModule, ReactiveFormsModule, InputTextComponent, QRCodeComponent ]
})
export class MyAccountTwoFactorComponent implements OnInit {
private notifier = inject(Notifier)
private twoFactorService = inject(TwoFactorService)
private formReactiveService = inject(FormReactiveService)
private auth = inject(AuthService)
private router = inject(Router)
twoFactorAlreadyEnabled: boolean
step: 'request' | 'confirm' | 'confirmed' = 'request'
@ -34,15 +40,6 @@ export class MyAccountTwoFactorComponent implements OnInit {
private user: User
private requestToken: string
constructor (
private notifier: Notifier,
private twoFactorService: TwoFactorService,
private formReactiveService: FormReactiveService,
private auth: AuthService,
private router: Router
) {
}
ngOnInit () {
this.buildPasswordForm()
this.buildOTPForm()

View File

@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core'
import { Component, OnInit, inject } from '@angular/core'
import { RouterOutlet } from '@angular/router'
import { AuthUser, PluginService } from '@app/core'
import { HorizontalMenuComponent, HorizontalMenuEntry } from '@app/shared/shared-main/menu/horizontal-menu.component'
@ -8,13 +8,11 @@ import { HorizontalMenuComponent, HorizontalMenuEntry } from '@app/shared/shared
imports: [ HorizontalMenuComponent, RouterOutlet ]
})
export class MyAccountComponent implements OnInit {
private pluginService = inject(PluginService)
menuEntries: HorizontalMenuEntry[] = []
user: AuthUser
constructor (
private pluginService: PluginService
) { }
ngOnInit (): void {
this.pluginService.ensurePluginsAreLoaded('my-account')
.then(() => this.buildMenu())

View File

@ -1,5 +1,5 @@
import { NgFor, NgIf } from '@angular/common'
import { Component } from '@angular/core'
import { Component, inject } from '@angular/core'
import { RouterLink } from '@angular/router'
import {
AuthService,
@ -28,7 +28,7 @@ import { DeferLoadingDirective } from '../../shared/shared-main/common/defer-loa
import { InfiniteScrollerDirective } from '../../shared/shared-main/common/infinite-scroller.directive'
import { NumberFormatterPipe } from '../../shared/shared-main/common/number-formatter.pipe'
type CustomChartData = (ChartData & { startDate: string, total: number })
type CustomChartData = ChartData & { startDate: string, total: number }
@Component({
templateUrl: './my-video-channels.component.html',
@ -50,6 +50,12 @@ type CustomChartData = (ChartData & { startDate: string, total: number })
]
})
export class MyVideoChannelsComponent {
private authService = inject(AuthService)
private notifier = inject(Notifier)
private confirmService = inject(ConfirmService)
private videoChannelService = inject(VideoChannelService)
private screenService = inject(ScreenService)
videoChannels: VideoChannel[] = []
videoChannelsChartData: CustomChartData[]
@ -68,14 +74,6 @@ export class MyVideoChannelsComponent {
private pagesDone = new Set<number>()
constructor (
private authService: AuthService,
private notifier: Notifier,
private confirmService: ConfirmService,
private videoChannelService: VideoChannelService,
private screenService: ScreenService
) {}
get isInSmallView () {
return this.screenService.isInSmallView()
}
@ -93,17 +91,14 @@ export class MyVideoChannelsComponent {
async deleteVideoChannel (videoChannel: VideoChannel) {
const res = await this.confirmService.confirmWithExpectedInput(
$localize`Do you really want to delete ${videoChannel.displayName}?` +
`<br />` +
formatICU(
// eslint-disable-next-line max-len
$localize`It will delete {count, plural, =1 {1 video} other {{count} videos}} uploaded in this channel, and you will not be able to create another channel or account with the same name (${videoChannel.name})!`,
{ count: videoChannel.videosCount }
),
`<br />` +
formatICU(
// eslint-disable-next-line max-len
$localize`It will delete {count, plural, =1 {1 video} other {{count} videos}} uploaded in this channel, and you will not be able to create another channel or account with the same name (${videoChannel.name})!`,
{ count: videoChannel.videosCount }
),
$localize`Please type the name of the video channel (${videoChannel.name}) to confirm`,
videoChannel.name,
$localize`Delete`
)
if (res === false) return

View File

@ -1,11 +1,10 @@
import { Component } from '@angular/core'
import { GlobalIconComponent } from '../../shared/shared-icons/global-icon.component'
import { VideoCommentListAdminOwnerComponent } from '../../shared/shared-video-comment/video-comment-list-admin-owner.component'
@Component({
templateUrl: './comments-on-my-videos.component.html',
imports: [
GlobalIconComponent,
VideoCommentListAdminOwnerComponent
]
})

Some files were not shown because too many files have changed in this diff Show More