diff options
author | Chocobozzz <me@florianbigard.com> | 2021-10-27 11:42:05 +0200 |
---|---|---|
committer | Chocobozzz <chocobozzz@cpy.re> | 2021-10-29 11:48:21 +0200 |
commit | 33f6dce136ca6e969fe374efa099bee3f2a3599d (patch) | |
tree | 7a0d6228bab085944015a01267ad31aa1ec6082e /client/src/app/shared | |
parent | 00004f7f6b966a975498612117212b5373f4103c (diff) | |
download | PeerTube-33f6dce136ca6e969fe374efa099bee3f2a3599d.tar.gz PeerTube-33f6dce136ca6e969fe374efa099bee3f2a3599d.tar.zst PeerTube-33f6dce136ca6e969fe374efa099bee3f2a3599d.zip |
Add videos list admin component
Diffstat (limited to 'client/src/app/shared')
21 files changed, 298 insertions, 177 deletions
diff --git a/client/src/app/shared/shared-abuse-list/abuse-details.component.html b/client/src/app/shared/shared-abuse-list/abuse-details.component.html index 2f0bc5ae5..a1a4586f0 100644 --- a/client/src/app/shared/shared-abuse-list/abuse-details.component.html +++ b/client/src/app/shared/shared-abuse-list/abuse-details.component.html | |||
@@ -85,9 +85,9 @@ | |||
85 | 85 | ||
86 | <!-- report right part (video/comment details) --> | 86 | <!-- report right part (video/comment details) --> |
87 | <div class="right"> | 87 | <div class="right"> |
88 | <div *ngIf="abuse.video" class="screenratio"> | 88 | <div *ngIf="abuse.video"> |
89 | <div *ngIf="abuse.video.deleted" i18n>The video was deleted</div> | 89 | <div *ngIf="abuse.video.deleted" i18n>The video was deleted</div> |
90 | <div *ngIf="!abuse.video.deleted" [innerHTML]="abuse.embedHtml"></div> | 90 | <my-embed *ngIf="!abuse.video.deleted" [video]="abuse.video"></my-embed> |
91 | </div> | 91 | </div> |
92 | 92 | ||
93 | <div *ngIf="abuse.comment" class="comment-html"> | 93 | <div *ngIf="abuse.comment" class="comment-html"> |
diff --git a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.html b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.html index 4bf83316b..d957eaeab 100644 --- a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.html +++ b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.html | |||
@@ -30,9 +30,7 @@ | |||
30 | <ng-template pTemplate="body" let-expanded="expanded" let-abuse> | 30 | <ng-template pTemplate="body" let-expanded="expanded" let-abuse> |
31 | <tr> | 31 | <tr> |
32 | <td class="expand-cell c-hand" [pRowToggler]="abuse" i18n-ngbTooltip ngbTooltip="More information" placement="top-left" container="body"> | 32 | <td class="expand-cell c-hand" [pRowToggler]="abuse" i18n-ngbTooltip ngbTooltip="More information" placement="top-left" container="body"> |
33 | <span class="expander"> | 33 | <my-table-expander-icon [expanded]="expanded"></my-table-expander-icon> |
34 | <i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i> | ||
35 | </span> | ||
36 | </td> | 34 | </td> |
37 | 35 | ||
38 | <td class="action-cell"> | 36 | <td class="action-cell"> |
@@ -61,28 +59,20 @@ | |||
61 | <ng-container *ngIf="abuse.video"> | 59 | <ng-container *ngIf="abuse.video"> |
62 | 60 | ||
63 | <td *ngIf="!abuse.video.deleted"> | 61 | <td *ngIf="!abuse.video.deleted"> |
64 | <a [href]="getVideoUrl(abuse)" class="table-video-link" [title]="abuse.video.name" target="_blank" rel="noopener noreferrer"> | 62 | <my-video-cell [video]="abuse.video"> |
65 | <div class="table-video"> | 63 | <span image> |
66 | <div class="table-video-image"> | 64 | <span |
67 | <img [src]="abuse.video.thumbnailPath"> | 65 | class="table-video-image-label" *ngIf="abuse.count > 1" |
68 | <span | 66 | i18n-title title="This video has been reported multiple times." |
69 | class="table-video-image-label" *ngIf="abuse.count > 1" | 67 | > |
70 | i18n-title title="This video has been reported multiple times." | 68 | {{ abuse.nth }}/{{ abuse.count }} |
71 | > | 69 | </span> |
72 | {{ abuse.nth }}/{{ abuse.count }} | 70 | </span> |
73 | </span> | 71 | |
74 | </div> | 72 | <span name> |
75 | 73 | <span *ngIf="abuse.video.blacklisted" i18n-title title="The video was blocked" class="glyphicon glyphicon-ban-circle"></span> | |
76 | <div class="table-video-text"> | 74 | </span> |
77 | <div> | 75 | </my-video-cell> |
78 | <span *ngIf="!abuse.video.blacklisted" class="glyphicon glyphicon-new-window"></span> | ||
79 | <span *ngIf="abuse.video.blacklisted" i18n-title title="The video was blocked" class="glyphicon glyphicon-ban-circle"></span> | ||
80 | {{ abuse.video.name }} | ||
81 | </div> | ||
82 | <div i18n>by {{ abuse.video.channel?.displayName }} on {{ abuse.video.channel?.host }} </div> | ||
83 | </div> | ||
84 | </div> | ||
85 | </a> | ||
86 | </td> | 76 | </td> |
87 | 77 | ||
88 | <td *ngIf="abuse.video.deleted" class="c-hand" [pRowToggler]="abuse"> | 78 | <td *ngIf="abuse.video.deleted" class="c-hand" [pRowToggler]="abuse"> |
diff --git a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts index 297993e39..10f5861b9 100644 --- a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts +++ b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts | |||
@@ -1,8 +1,6 @@ | |||
1 | import * as debug from 'debug' | 1 | import * as debug from 'debug' |
2 | import truncate from 'lodash-es/truncate' | 2 | import truncate from 'lodash-es/truncate' |
3 | import { SortMeta } from 'primeng/api' | 3 | import { SortMeta } from 'primeng/api' |
4 | import { buildVideoOrPlaylistEmbed } from 'src/assets/player/utils' | ||
5 | import { environment } from 'src/environments/environment' | ||
6 | import { Component, Input, OnInit, ViewChild } from '@angular/core' | 4 | import { Component, Input, OnInit, ViewChild } from '@angular/core' |
7 | import { DomSanitizer } from '@angular/platform-browser' | 5 | import { DomSanitizer } from '@angular/platform-browser' |
8 | import { ActivatedRoute, Router } from '@angular/router' | 6 | import { ActivatedRoute, Router } from '@angular/router' |
@@ -10,7 +8,6 @@ import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable } | |||
10 | import { Account, Actor, DropdownAction, Video, VideoService } from '@app/shared/shared-main' | 8 | import { Account, Actor, DropdownAction, Video, VideoService } from '@app/shared/shared-main' |
11 | import { AbuseService, BlocklistService, VideoBlockService } from '@app/shared/shared-moderation' | 9 | import { AbuseService, BlocklistService, VideoBlockService } from '@app/shared/shared-moderation' |
12 | import { VideoCommentService } from '@app/shared/shared-video-comment' | 10 | import { VideoCommentService } from '@app/shared/shared-video-comment' |
13 | import { buildVideoEmbedLink, decorateVideoLink } from '@shared/core-utils' | ||
14 | import { AbuseState, AdminAbuse } from '@shared/models' | 11 | import { AbuseState, AdminAbuse } from '@shared/models' |
15 | import { AdvancedInputFilter } from '../shared-forms' | 12 | import { AdvancedInputFilter } from '../shared-forms' |
16 | import { AbuseMessageModalComponent } from './abuse-message-modal.component' | 13 | import { AbuseMessageModalComponent } from './abuse-message-modal.component' |
@@ -133,19 +130,6 @@ export class AbuseListTableComponent extends RestTable implements OnInit { | |||
133 | return '/a/' + abuse.flaggedAccount.nameWithHost | 130 | return '/a/' + abuse.flaggedAccount.nameWithHost |
134 | } | 131 | } |
135 | 132 | ||
136 | getVideoEmbed (abuse: AdminAbuse) { | ||
137 | return buildVideoOrPlaylistEmbed( | ||
138 | decorateVideoLink({ | ||
139 | url: buildVideoEmbedLink(abuse.video, environment.originServerUrl), | ||
140 | title: false, | ||
141 | warningTitle: false, | ||
142 | startTime: abuse.video.startAt, | ||
143 | stopTime: abuse.video.endAt | ||
144 | }), | ||
145 | abuse.video.name | ||
146 | ) | ||
147 | } | ||
148 | |||
149 | async removeAbuse (abuse: AdminAbuse) { | 133 | async removeAbuse (abuse: AdminAbuse) { |
150 | const res = await this.confirmService.confirm($localize`Do you really want to delete this abuse report?`, $localize`Delete`) | 134 | const res = await this.confirmService.confirm($localize`Do you really want to delete this abuse report?`, $localize`Delete`) |
151 | if (res === false) return | 135 | if (res === false) return |
@@ -220,8 +204,6 @@ export class AbuseListTableComponent extends RestTable implements OnInit { | |||
220 | } | 204 | } |
221 | 205 | ||
222 | if (abuse.video) { | 206 | if (abuse.video) { |
223 | abuse.embedHtml = this.sanitizer.bypassSecurityTrustHtml(this.getVideoEmbed(abuse)) | ||
224 | |||
225 | if (abuse.video.channel?.ownerAccount) { | 207 | if (abuse.video.channel?.ownerAccount) { |
226 | abuse.video.channel.ownerAccount = new Account(abuse.video.channel.ownerAccount) | 208 | abuse.video.channel.ownerAccount = new Account(abuse.video.channel.ownerAccount) |
227 | } | 209 | } |
diff --git a/client/src/app/shared/shared-abuse-list/processed-abuse.model.ts b/client/src/app/shared/shared-abuse-list/processed-abuse.model.ts index 194d52a33..b9a9bd889 100644 --- a/client/src/app/shared/shared-abuse-list/processed-abuse.model.ts +++ b/client/src/app/shared/shared-abuse-list/processed-abuse.model.ts | |||
@@ -1,13 +1,11 @@ | |||
1 | import { SafeHtml } from '@angular/platform-browser' | ||
2 | import { AdminAbuse } from '@shared/models' | ||
3 | import { Account } from '@app/shared/shared-main' | 1 | import { Account } from '@app/shared/shared-main' |
2 | import { AdminAbuse } from '@shared/models' | ||
4 | 3 | ||
5 | // Don't use an abuse model because we need external services to compute some properties | 4 | // Don't use an abuse model because we need external services to compute some properties |
6 | // And this model is only used in this component | 5 | // And this model is only used in this component |
7 | export type ProcessedAbuse = AdminAbuse & { | 6 | export type ProcessedAbuse = AdminAbuse & { |
8 | moderationCommentHtml?: string | 7 | moderationCommentHtml?: string |
9 | reasonHtml?: string | 8 | reasonHtml?: string |
10 | embedHtml?: SafeHtml | ||
11 | updatedAt?: Date | 9 | updatedAt?: Date |
12 | 10 | ||
13 | // override bare server-side definitions with rich client-side definitions | 11 | // override bare server-side definitions with rich client-side definitions |
diff --git a/client/src/app/shared/shared-abuse-list/shared-abuse-list.module.ts b/client/src/app/shared/shared-abuse-list/shared-abuse-list.module.ts index 8f3830a17..eeda27fa6 100644 --- a/client/src/app/shared/shared-abuse-list/shared-abuse-list.module.ts +++ b/client/src/app/shared/shared-abuse-list/shared-abuse-list.module.ts | |||
@@ -1,16 +1,17 @@ | |||
1 | 1 | ||
2 | import { TableModule } from 'primeng/table' | 2 | import { TableModule } from 'primeng/table' |
3 | import { NgModule } from '@angular/core' | 3 | import { NgModule } from '@angular/core' |
4 | import { SharedActorImageModule } from '../shared-actor-image/shared-actor-image.module' | ||
4 | import { SharedFormModule } from '../shared-forms/shared-form.module' | 5 | import { SharedFormModule } from '../shared-forms/shared-form.module' |
5 | import { SharedGlobalIconModule } from '../shared-icons' | 6 | import { SharedGlobalIconModule } from '../shared-icons' |
6 | import { SharedMainModule } from '../shared-main/shared-main.module' | 7 | import { SharedMainModule } from '../shared-main/shared-main.module' |
7 | import { SharedModerationModule } from '../shared-moderation' | 8 | import { SharedModerationModule } from '../shared-moderation' |
9 | import { SharedTablesModule } from '../shared-tables' | ||
8 | import { SharedVideoCommentModule } from '../shared-video-comment' | 10 | import { SharedVideoCommentModule } from '../shared-video-comment' |
9 | import { AbuseDetailsComponent } from './abuse-details.component' | 11 | import { AbuseDetailsComponent } from './abuse-details.component' |
10 | import { AbuseListTableComponent } from './abuse-list-table.component' | 12 | import { AbuseListTableComponent } from './abuse-list-table.component' |
11 | import { AbuseMessageModalComponent } from './abuse-message-modal.component' | 13 | import { AbuseMessageModalComponent } from './abuse-message-modal.component' |
12 | import { ModerationCommentModalComponent } from './moderation-comment-modal.component' | 14 | import { ModerationCommentModalComponent } from './moderation-comment-modal.component' |
13 | import { SharedActorImageModule } from '../shared-actor-image/shared-actor-image.module' | ||
14 | 15 | ||
15 | @NgModule({ | 16 | @NgModule({ |
16 | imports: [ | 17 | imports: [ |
@@ -21,7 +22,8 @@ import { SharedActorImageModule } from '../shared-actor-image/shared-actor-image | |||
21 | SharedModerationModule, | 22 | SharedModerationModule, |
22 | SharedGlobalIconModule, | 23 | SharedGlobalIconModule, |
23 | SharedVideoCommentModule, | 24 | SharedVideoCommentModule, |
24 | SharedActorImageModule | 25 | SharedActorImageModule, |
26 | SharedTablesModule | ||
25 | ], | 27 | ], |
26 | 28 | ||
27 | declarations: [ | 29 | declarations: [ |
diff --git a/client/src/app/shared/shared-main/shared-main.module.ts b/client/src/app/shared/shared-main/shared-main.module.ts index 93989780d..a90b59e41 100644 --- a/client/src/app/shared/shared-main/shared-main.module.ts +++ b/client/src/app/shared/shared-main/shared-main.module.ts | |||
@@ -43,13 +43,8 @@ import { | |||
43 | } from './misc' | 43 | } from './misc' |
44 | import { PluginPlaceholderComponent } from './plugins' | 44 | import { PluginPlaceholderComponent } from './plugins' |
45 | import { ActorRedirectGuard } from './router' | 45 | import { ActorRedirectGuard } from './router' |
46 | import { | 46 | import { UserHistoryService, UserNotificationsComponent, UserNotificationService, UserQuotaComponent } from './users' |
47 | UserHistoryService, | 47 | import { EmbedComponent, RedundancyService, VideoImportService, VideoOwnershipService, VideoService } from './video' |
48 | UserNotificationsComponent, | ||
49 | UserNotificationService, | ||
50 | UserQuotaComponent | ||
51 | } from './users' | ||
52 | import { RedundancyService, VideoImportService, VideoOwnershipService, VideoService } from './video' | ||
53 | import { VideoCaptionService } from './video-caption' | 48 | import { VideoCaptionService } from './video-caption' |
54 | import { VideoChannelService } from './video-channel' | 49 | import { VideoChannelService } from './video-channel' |
55 | 50 | ||
@@ -111,6 +106,8 @@ import { VideoChannelService } from './video-channel' | |||
111 | UserQuotaComponent, | 106 | UserQuotaComponent, |
112 | UserNotificationsComponent, | 107 | UserNotificationsComponent, |
113 | 108 | ||
109 | EmbedComponent, | ||
110 | |||
114 | PluginPlaceholderComponent | 111 | PluginPlaceholderComponent |
115 | ], | 112 | ], |
116 | 113 | ||
@@ -167,6 +164,8 @@ import { VideoChannelService } from './video-channel' | |||
167 | UserQuotaComponent, | 164 | UserQuotaComponent, |
168 | UserNotificationsComponent, | 165 | UserNotificationsComponent, |
169 | 166 | ||
167 | EmbedComponent, | ||
168 | |||
170 | PluginPlaceholderComponent | 169 | PluginPlaceholderComponent |
171 | ], | 170 | ], |
172 | 171 | ||
diff --git a/client/src/app/shared/shared-main/video/embed.component.html b/client/src/app/shared/shared-main/video/embed.component.html new file mode 100644 index 000000000..3b088d058 --- /dev/null +++ b/client/src/app/shared/shared-main/video/embed.component.html | |||
@@ -0,0 +1,3 @@ | |||
1 | <div class="screenratio"> | ||
2 | <div [innerHTML]="embedHTML"></div> | ||
3 | </div> | ||
diff --git a/client/src/app/shared/shared-main/video/embed.component.scss b/client/src/app/shared/shared-main/video/embed.component.scss new file mode 100644 index 000000000..420ba6f23 --- /dev/null +++ b/client/src/app/shared/shared-main/video/embed.component.scss | |||
@@ -0,0 +1,10 @@ | |||
1 | @use '_mixins' as *; | ||
2 | @use '_variables' as *; | ||
3 | |||
4 | .screenratio { | ||
5 | @include block-ratio($selector: 'div, ::ng-deep iframe') { | ||
6 | width: 100% !important; | ||
7 | height: 100% !important; | ||
8 | left: 0; | ||
9 | }; | ||
10 | } | ||
diff --git a/client/src/app/shared/shared-main/video/embed.component.ts b/client/src/app/shared/shared-main/video/embed.component.ts new file mode 100644 index 000000000..4732efa44 --- /dev/null +++ b/client/src/app/shared/shared-main/video/embed.component.ts | |||
@@ -0,0 +1,35 @@ | |||
1 | import { buildVideoOrPlaylistEmbed } from 'src/assets/player/utils' | ||
2 | import { environment } from 'src/environments/environment' | ||
3 | import { Component, Input, OnInit } from '@angular/core' | ||
4 | import { DomSanitizer, SafeHtml } from '@angular/platform-browser' | ||
5 | import { buildVideoEmbedLink, decorateVideoLink } from '@shared/core-utils' | ||
6 | import { Video } from '@shared/models' | ||
7 | |||
8 | @Component({ | ||
9 | selector: 'my-embed', | ||
10 | styleUrls: [ './embed.component.scss' ], | ||
11 | templateUrl: './embed.component.html' | ||
12 | }) | ||
13 | export class EmbedComponent implements OnInit { | ||
14 | @Input() video: Pick<Video, 'name' | 'uuid'> | ||
15 | |||
16 | embedHTML: SafeHtml | ||
17 | |||
18 | constructor (private sanitizer: DomSanitizer) { | ||
19 | |||
20 | } | ||
21 | |||
22 | ngOnInit () { | ||
23 | const html = buildVideoOrPlaylistEmbed( | ||
24 | decorateVideoLink({ | ||
25 | url: buildVideoEmbedLink(this.video, environment.originServerUrl), | ||
26 | |||
27 | title: false, | ||
28 | warningTitle: false | ||
29 | }), | ||
30 | this.video.name | ||
31 | ) | ||
32 | |||
33 | this.embedHTML = this.sanitizer.bypassSecurityTrustHtml(html) | ||
34 | } | ||
35 | } | ||
diff --git a/client/src/app/shared/shared-main/video/index.ts b/client/src/app/shared/shared-main/video/index.ts index 3053df4ef..e72c0c3d6 100644 --- a/client/src/app/shared/shared-main/video/index.ts +++ b/client/src/app/shared/shared-main/video/index.ts | |||
@@ -1,3 +1,4 @@ | |||
1 | export * from './embed.component' | ||
1 | export * from './redundancy.service' | 2 | export * from './redundancy.service' |
2 | export * from './video-details.model' | 3 | export * from './video-details.model' |
3 | export * from './video-edit.model' | 4 | export * from './video-edit.model' |
diff --git a/client/src/app/shared/shared-main/video/video.service.ts b/client/src/app/shared/shared-main/video/video.service.ts index 7935569e7..9e3aa1e6a 100644 --- a/client/src/app/shared/shared-main/video/video.service.ts +++ b/client/src/app/shared/shared-main/video/video.service.ts | |||
@@ -1,8 +1,9 @@ | |||
1 | import { Observable } from 'rxjs' | 1 | import { SortMeta } from 'primeng/api' |
2 | import { catchError, map, switchMap } from 'rxjs/operators' | 2 | import { from, Observable } from 'rxjs' |
3 | import { catchError, concatMap, map, switchMap, toArray } from 'rxjs/operators' | ||
3 | import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http' | 4 | import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http' |
4 | import { Injectable } from '@angular/core' | 5 | import { Injectable } from '@angular/core' |
5 | import { ComponentPaginationLight, RestExtractor, RestService, ServerService, UserService } from '@app/core' | 6 | import { ComponentPaginationLight, RestExtractor, RestPagination, RestService, ServerService, UserService } from '@app/core' |
6 | import { objectToFormData } from '@app/helpers' | 7 | import { objectToFormData } from '@app/helpers' |
7 | import { | 8 | import { |
8 | BooleanBothQuery, | 9 | BooleanBothQuery, |
@@ -31,8 +32,8 @@ import { VideoEdit } from './video-edit.model' | |||
31 | import { Video } from './video.model' | 32 | import { Video } from './video.model' |
32 | 33 | ||
33 | export type CommonVideoParams = { | 34 | export type CommonVideoParams = { |
34 | videoPagination: ComponentPaginationLight | 35 | videoPagination?: ComponentPaginationLight |
35 | sort: VideoSortField | 36 | sort: VideoSortField | SortMeta |
36 | filter?: VideoFilter | 37 | filter?: VideoFilter |
37 | categoryOneOf?: number[] | 38 | categoryOneOf?: number[] |
38 | languageOneOf?: string[] | 39 | languageOneOf?: string[] |
@@ -200,6 +201,31 @@ export class VideoService { | |||
200 | ) | 201 | ) |
201 | } | 202 | } |
202 | 203 | ||
204 | getAdminVideos ( | ||
205 | parameters: Omit<CommonVideoParams, 'filter'> & { pagination: RestPagination, search?: string } | ||
206 | ): Observable<ResultList<Video>> { | ||
207 | const { pagination, search } = parameters | ||
208 | |||
209 | let params = new HttpParams() | ||
210 | params = this.buildCommonVideosParams({ params, ...parameters }) | ||
211 | |||
212 | params = params.set('start', pagination.start.toString()) | ||
213 | .set('count', pagination.count.toString()) | ||
214 | |||
215 | if (search) { | ||
216 | params = this.buildAdminParamsFromSearch(search, params) | ||
217 | } | ||
218 | |||
219 | if (!params.has('filter')) params = params.set('filter', 'all') | ||
220 | |||
221 | return this.authHttp | ||
222 | .get<ResultList<Video>>(VideoService.BASE_VIDEO_URL, { params }) | ||
223 | .pipe( | ||
224 | switchMap(res => this.extractVideos(res)), | ||
225 | catchError(err => this.restExtractor.handleError(err)) | ||
226 | ) | ||
227 | } | ||
228 | |||
203 | getVideos (parameters: CommonVideoParams): Observable<ResultList<Video>> { | 229 | getVideos (parameters: CommonVideoParams): Observable<ResultList<Video>> { |
204 | let params = new HttpParams() | 230 | let params = new HttpParams() |
205 | params = this.buildCommonVideosParams({ params, ...parameters }) | 231 | params = this.buildCommonVideosParams({ params, ...parameters }) |
@@ -284,13 +310,15 @@ export class VideoService { | |||
284 | ) | 310 | ) |
285 | } | 311 | } |
286 | 312 | ||
287 | removeVideo (id: number) { | 313 | removeVideo (idArg: number | number[]) { |
288 | return this.authHttp | 314 | const ids = Array.isArray(idArg) ? idArg : [ idArg ] |
289 | .delete(VideoService.BASE_VIDEO_URL + id) | 315 | |
290 | .pipe( | 316 | return from(ids) |
291 | map(this.restExtractor.extractDataBool), | 317 | .pipe( |
292 | catchError(err => this.restExtractor.handleError(err)) | 318 | concatMap(id => this.authHttp.delete(VideoService.BASE_VIDEO_URL + id)), |
293 | ) | 319 | toArray(), |
320 | catchError(err => this.restExtractor.handleError(err)) | ||
321 | ) | ||
294 | } | 322 | } |
295 | 323 | ||
296 | loadCompleteDescription (descriptionPath: string) { | 324 | loadCompleteDescription (descriptionPath: string) { |
@@ -393,9 +421,23 @@ export class VideoService { | |||
393 | } | 421 | } |
394 | 422 | ||
395 | private buildCommonVideosParams (options: CommonVideoParams & { params: HttpParams }) { | 423 | private buildCommonVideosParams (options: CommonVideoParams & { params: HttpParams }) { |
396 | const { params, videoPagination, sort, filter, categoryOneOf, languageOneOf, skipCount, nsfwPolicy, isLive, nsfw } = options | 424 | const { |
425 | params, | ||
426 | videoPagination, | ||
427 | sort, | ||
428 | filter, | ||
429 | categoryOneOf, | ||
430 | languageOneOf, | ||
431 | skipCount, | ||
432 | nsfwPolicy, | ||
433 | isLive, | ||
434 | nsfw | ||
435 | } = options | ||
436 | |||
437 | const pagination = videoPagination | ||
438 | ? this.restService.componentToRestPagination(videoPagination) | ||
439 | : undefined | ||
397 | 440 | ||
398 | const pagination = this.restService.componentToRestPagination(videoPagination) | ||
399 | let newParams = this.restService.addRestGetParams(params, pagination, sort) | 441 | let newParams = this.restService.addRestGetParams(params, pagination, sort) |
400 | 442 | ||
401 | if (filter) newParams = newParams.set('filter', filter) | 443 | if (filter) newParams = newParams.set('filter', filter) |
@@ -409,4 +451,19 @@ export class VideoService { | |||
409 | 451 | ||
410 | return newParams | 452 | return newParams |
411 | } | 453 | } |
454 | |||
455 | private buildAdminParamsFromSearch (search: string, params: HttpParams) { | ||
456 | const filters = this.restService.parseQueryStringFilter(search, { | ||
457 | filter: { | ||
458 | prefix: 'local:', | ||
459 | handler: v => { | ||
460 | if (v === 'true') return 'all-local' | ||
461 | |||
462 | return 'all' | ||
463 | } | ||
464 | } | ||
465 | }) | ||
466 | |||
467 | return this.restService.addObjectParams(params, filters) | ||
468 | } | ||
412 | } | 469 | } |
diff --git a/client/src/app/shared/shared-moderation/moderation.scss b/client/src/app/shared/shared-moderation/moderation.scss index 815e2791f..eaf5a8250 100644 --- a/client/src/app/shared/shared-moderation/moderation.scss +++ b/client/src/app/shared/shared-moderation/moderation.scss | |||
@@ -40,14 +40,6 @@ | |||
40 | } | 40 | } |
41 | } | 41 | } |
42 | 42 | ||
43 | .screenratio { | ||
44 | @include block-ratio($selector: 'div, ::ng-deep iframe') { | ||
45 | width: 100% !important; | ||
46 | height: 100% !important; | ||
47 | left: 0; | ||
48 | }; | ||
49 | } | ||
50 | |||
51 | .chip { | 43 | .chip { |
52 | @include chip; | 44 | @include chip; |
53 | } | 45 | } |
@@ -58,13 +50,6 @@ my-action-dropdown.show { | |||
58 | } | 50 | } |
59 | } | 51 | } |
60 | 52 | ||
61 | .table-video-link { | ||
62 | @include disable-outline; | ||
63 | |||
64 | position: relative; | ||
65 | top: 3px; | ||
66 | } | ||
67 | |||
68 | .table-comment-link, | 53 | .table-comment-link, |
69 | .table-account-link { | 54 | .table-account-link { |
70 | @include disable-outline; | 55 | @include disable-outline; |
@@ -81,68 +66,6 @@ my-action-dropdown.show { | |||
81 | flex-direction: column; | 66 | flex-direction: column; |
82 | } | 67 | } |
83 | 68 | ||
84 | .table-video { | ||
85 | display: inline-flex; | ||
86 | |||
87 | .table-video-image { | ||
88 | $image-height: 45px; | ||
89 | |||
90 | @include miniature-thumbnail; | ||
91 | @include margin-right(0.5rem); | ||
92 | |||
93 | height: $image-height; | ||
94 | width: #{math.div(16, 9) * $image-height}; | ||
95 | border-radius: 2px; | ||
96 | border: 0; | ||
97 | background: transparent; | ||
98 | display: inline-flex; | ||
99 | justify-content: center; | ||
100 | position: relative; | ||
101 | |||
102 | img { | ||
103 | height: 100%; | ||
104 | width: 100%; | ||
105 | border-radius: 2px; | ||
106 | } | ||
107 | |||
108 | span { | ||
109 | color: pvar(--inputPlaceholderColor); | ||
110 | } | ||
111 | |||
112 | .table-video-image-label { | ||
113 | @include static-thumbnail-overlay; | ||
114 | position: absolute; | ||
115 | border-radius: 3px; | ||
116 | font-size: 10px; | ||
117 | padding: 0 3px; | ||
118 | line-height: 1.3; | ||
119 | bottom: 2px; | ||
120 | right: 2px; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | .table-video-text { | ||
125 | display: inline-flex; | ||
126 | flex-direction: column; | ||
127 | justify-content: center; | ||
128 | font-size: 90%; | ||
129 | color: pvar(--mainForegroundColor); | ||
130 | line-height: 1rem; | ||
131 | |||
132 | div .glyphicon { | ||
133 | @include margin-left(0.1rem); | ||
134 | |||
135 | font-size: 80%; | ||
136 | color: #808080; | ||
137 | } | ||
138 | |||
139 | div + div { | ||
140 | color: var(--greyForegroundColor); | ||
141 | font-size: 11px; | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | |||
146 | my-abuse-details { | 69 | my-abuse-details { |
147 | width: 100%; | 70 | width: 100%; |
148 | } | 71 | } |
diff --git a/client/src/app/shared/shared-moderation/report-modals/report.component.scss b/client/src/app/shared/shared-moderation/report-modals/report.component.scss index 06e50ac2d..76ec0a6ed 100644 --- a/client/src/app/shared/shared-moderation/report-modals/report.component.scss +++ b/client/src/app/shared/shared-moderation/report-modals/report.component.scss | |||
@@ -19,9 +19,3 @@ textarea { | |||
19 | @include margin-left(10px); | 19 | @include margin-left(10px); |
20 | } | 20 | } |
21 | } | 21 | } |
22 | |||
23 | .screenratio { | ||
24 | @include block-ratio($selector: 'div, ::ng-deep iframe') { | ||
25 | left: 0; | ||
26 | }; | ||
27 | } | ||
diff --git a/client/src/app/shared/shared-moderation/report-modals/video-report.component.html b/client/src/app/shared/shared-moderation/report-modals/video-report.component.html index 1aae64bff..afac108fc 100644 --- a/client/src/app/shared/shared-moderation/report-modals/video-report.component.html +++ b/client/src/app/shared/shared-moderation/report-modals/video-report.component.html | |||
@@ -35,9 +35,7 @@ | |||
35 | <div class="col-7"> | 35 | <div class="col-7"> |
36 | <div class="row justify-content-center"> | 36 | <div class="row justify-content-center"> |
37 | <div class="col-12 col-lg-9 mb-2"> | 37 | <div class="col-12 col-lg-9 mb-2"> |
38 | <div class="screenratio"> | 38 | <my-embed [video]="video"></my-embed> |
39 | <div [innerHTML]="embedHtml"></div> | ||
40 | </div> | ||
41 | </div> | 39 | </div> |
42 | </div> | 40 | </div> |
43 | 41 | ||
diff --git a/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts b/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts index 278d60ac6..38dd92910 100644 --- a/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts +++ b/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts | |||
@@ -1,13 +1,11 @@ | |||
1 | import { mapValues, pickBy } from 'lodash-es' | 1 | import { mapValues, pickBy } from 'lodash-es' |
2 | import { buildVideoOrPlaylistEmbed } from 'src/assets/player/utils' | ||
3 | import { Component, Input, OnInit, ViewChild } from '@angular/core' | 2 | import { Component, Input, OnInit, ViewChild } from '@angular/core' |
4 | import { DomSanitizer, SafeHtml } from '@angular/platform-browser' | 3 | import { DomSanitizer } from '@angular/platform-browser' |
5 | import { Notifier } from '@app/core' | 4 | import { Notifier } from '@app/core' |
6 | import { ABUSE_REASON_VALIDATOR } from '@app/shared/form-validators/abuse-validators' | 5 | import { ABUSE_REASON_VALIDATOR } from '@app/shared/form-validators/abuse-validators' |
7 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' | 6 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' |
8 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | 7 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' |
9 | import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' | 8 | import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' |
10 | import { decorateVideoLink } from '@shared/core-utils' | ||
11 | import { abusePredefinedReasonsMap } from '@shared/core-utils/abuse' | 9 | import { abusePredefinedReasonsMap } from '@shared/core-utils/abuse' |
12 | import { AbusePredefinedReasonsString } from '@shared/models' | 10 | import { AbusePredefinedReasonsString } from '@shared/models' |
13 | import { Video } from '../../shared-main' | 11 | import { Video } from '../../shared-main' |
@@ -25,7 +23,6 @@ export class VideoReportComponent extends FormReactive implements OnInit { | |||
25 | 23 | ||
26 | error: string = null | 24 | error: string = null |
27 | predefinedReasons: { id: AbusePredefinedReasonsString, label: string, description?: string, help?: string }[] = [] | 25 | predefinedReasons: { id: AbusePredefinedReasonsString, label: string, description?: string, help?: string }[] = [] |
28 | embedHtml: SafeHtml | ||
29 | 26 | ||
30 | private openedModal: NgbModalRef | 27 | private openedModal: NgbModalRef |
31 | 28 | ||
@@ -55,20 +52,6 @@ export class VideoReportComponent extends FormReactive implements OnInit { | |||
55 | return this.form.get('timestamp').value | 52 | return this.form.get('timestamp').value |
56 | } | 53 | } |
57 | 54 | ||
58 | getVideoEmbed () { | ||
59 | return this.sanitizer.bypassSecurityTrustHtml( | ||
60 | buildVideoOrPlaylistEmbed( | ||
61 | decorateVideoLink({ | ||
62 | url: this.video.embedUrl, | ||
63 | title: false, | ||
64 | warningTitle: false | ||
65 | }), | ||
66 | |||
67 | this.video.name | ||
68 | ) | ||
69 | ) | ||
70 | } | ||
71 | |||
72 | ngOnInit () { | 55 | ngOnInit () { |
73 | this.buildForm({ | 56 | this.buildForm({ |
74 | reason: ABUSE_REASON_VALIDATOR, | 57 | reason: ABUSE_REASON_VALIDATOR, |
@@ -82,8 +65,6 @@ export class VideoReportComponent extends FormReactive implements OnInit { | |||
82 | }) | 65 | }) |
83 | 66 | ||
84 | this.predefinedReasons = this.abuseService.getPrefefinedReasons('video') | 67 | this.predefinedReasons = this.abuseService.getPrefefinedReasons('video') |
85 | |||
86 | this.embedHtml = this.getVideoEmbed() | ||
87 | } | 68 | } |
88 | 69 | ||
89 | show () { | 70 | show () { |
diff --git a/client/src/app/shared/shared-tables/index.ts b/client/src/app/shared/shared-tables/index.ts new file mode 100644 index 000000000..e7b593257 --- /dev/null +++ b/client/src/app/shared/shared-tables/index.ts | |||
@@ -0,0 +1,3 @@ | |||
1 | export * from './table-expander-icon.component' | ||
2 | export * from './video-cell.component' | ||
3 | export * from './shared-tables.module' | ||
diff --git a/client/src/app/shared/shared-tables/shared-tables.module.ts b/client/src/app/shared/shared-tables/shared-tables.module.ts new file mode 100644 index 000000000..c528365a0 --- /dev/null +++ b/client/src/app/shared/shared-tables/shared-tables.module.ts | |||
@@ -0,0 +1,25 @@ | |||
1 | |||
2 | import { NgModule } from '@angular/core' | ||
3 | import { SharedMainModule } from '../shared-main/shared-main.module' | ||
4 | import { TableExpanderIconComponent } from './table-expander-icon.component' | ||
5 | import { VideoCellComponent } from './video-cell.component' | ||
6 | |||
7 | @NgModule({ | ||
8 | imports: [ | ||
9 | SharedMainModule | ||
10 | ], | ||
11 | |||
12 | declarations: [ | ||
13 | VideoCellComponent, | ||
14 | TableExpanderIconComponent | ||
15 | ], | ||
16 | |||
17 | exports: [ | ||
18 | VideoCellComponent, | ||
19 | TableExpanderIconComponent | ||
20 | ], | ||
21 | |||
22 | providers: [ | ||
23 | ] | ||
24 | }) | ||
25 | export class SharedTablesModule { } | ||
diff --git a/client/src/app/shared/shared-tables/table-expander-icon.component.ts b/client/src/app/shared/shared-tables/table-expander-icon.component.ts new file mode 100644 index 000000000..3756b475a --- /dev/null +++ b/client/src/app/shared/shared-tables/table-expander-icon.component.ts | |||
@@ -0,0 +1,12 @@ | |||
1 | import { Component, Input } from '@angular/core' | ||
2 | |||
3 | @Component({ | ||
4 | selector: 'my-table-expander-icon', | ||
5 | template: ` | ||
6 | <span class="expander"> | ||
7 | <i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i> | ||
8 | </span>` | ||
9 | }) | ||
10 | export class TableExpanderIconComponent { | ||
11 | @Input() expanded: boolean | ||
12 | } | ||
diff --git a/client/src/app/shared/shared-tables/video-cell.component.html b/client/src/app/shared/shared-tables/video-cell.component.html new file mode 100644 index 000000000..fb7d852ab --- /dev/null +++ b/client/src/app/shared/shared-tables/video-cell.component.html | |||
@@ -0,0 +1,19 @@ | |||
1 | <a [href]="getVideoUrl()" class="table-video-link" [title]="video.name" target="_blank" rel="noopener noreferrer"> | ||
2 | <div class="table-video"> | ||
3 | <div class="table-video-image"> | ||
4 | <img [src]="video.thumbnailPath"> | ||
5 | |||
6 | <ng-content select="[image]"></ng-content> | ||
7 | </div> | ||
8 | |||
9 | <div class="table-video-text"> | ||
10 | <div> | ||
11 | <ng-content select="[name]"></ng-content> | ||
12 | |||
13 | {{ video.name }} | ||
14 | </div> | ||
15 | |||
16 | <div class="text-muted">by {{ video.channel?.displayName }} on {{ video.channel?.host }} </div> | ||
17 | </div> | ||
18 | </div> | ||
19 | </a> | ||
diff --git a/client/src/app/shared/shared-tables/video-cell.component.scss b/client/src/app/shared/shared-tables/video-cell.component.scss new file mode 100644 index 000000000..7efb61502 --- /dev/null +++ b/client/src/app/shared/shared-tables/video-cell.component.scss | |||
@@ -0,0 +1,74 @@ | |||
1 | @use 'sass:math'; | ||
2 | @use '_mixins' as *; | ||
3 | @use '_variables' as *; | ||
4 | @use '_miniature' as *; | ||
5 | |||
6 | .table-video-link { | ||
7 | @include disable-outline; | ||
8 | |||
9 | position: relative; | ||
10 | top: 3px; | ||
11 | } | ||
12 | |||
13 | .table-video { | ||
14 | display: inline-flex; | ||
15 | |||
16 | .table-video-image { | ||
17 | $image-height: 45px; | ||
18 | |||
19 | @include miniature-thumbnail; | ||
20 | @include margin-right(0.5rem); | ||
21 | |||
22 | height: $image-height; | ||
23 | width: #{math.div(16, 9) * $image-height}; | ||
24 | border-radius: 2px; | ||
25 | border: 0; | ||
26 | background: transparent; | ||
27 | display: inline-flex; | ||
28 | justify-content: center; | ||
29 | position: relative; | ||
30 | |||
31 | img { | ||
32 | height: 100%; | ||
33 | width: 100%; | ||
34 | border-radius: 2px; | ||
35 | } | ||
36 | |||
37 | span { | ||
38 | color: pvar(--inputPlaceholderColor); | ||
39 | } | ||
40 | |||
41 | .table-video-image-label { | ||
42 | @include static-thumbnail-overlay; | ||
43 | |||
44 | position: absolute; | ||
45 | border-radius: 3px; | ||
46 | font-size: 10px; | ||
47 | padding: 0 3px; | ||
48 | line-height: 1.3; | ||
49 | bottom: 2px; | ||
50 | right: 2px; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | .table-video-text { | ||
55 | display: inline-flex; | ||
56 | flex-direction: column; | ||
57 | justify-content: center; | ||
58 | font-size: 90%; | ||
59 | color: pvar(--mainForegroundColor); | ||
60 | line-height: 1rem; | ||
61 | |||
62 | div .glyphicon { | ||
63 | @include margin-left(0.1rem); | ||
64 | |||
65 | font-size: 80%; | ||
66 | color: #808080; | ||
67 | } | ||
68 | |||
69 | div + div { | ||
70 | color: var(--greyForegroundColor); | ||
71 | font-size: 11px; | ||
72 | } | ||
73 | } | ||
74 | } | ||
diff --git a/client/src/app/shared/shared-tables/video-cell.component.ts b/client/src/app/shared/shared-tables/video-cell.component.ts new file mode 100644 index 000000000..62984180d --- /dev/null +++ b/client/src/app/shared/shared-tables/video-cell.component.ts | |||
@@ -0,0 +1,15 @@ | |||
1 | import { Component, Input } from '@angular/core' | ||
2 | import { Video } from '@app/shared/shared-main' | ||
3 | |||
4 | @Component({ | ||
5 | selector: 'my-video-cell', | ||
6 | styleUrls: [ 'video-cell.component.scss' ], | ||
7 | templateUrl: 'video-cell.component.html' | ||
8 | }) | ||
9 | export class VideoCellComponent { | ||
10 | @Input() video: Video | ||
11 | |||
12 | getVideoUrl () { | ||
13 | return Video.buildWatchUrl(this.video) | ||
14 | } | ||
15 | } | ||