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/+admin | |
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/+admin')
11 files changed, 284 insertions, 34 deletions
diff --git a/client/src/app/+admin/admin.component.ts b/client/src/app/+admin/admin.component.ts index 27d5e0a10..b8a957d1c 100644 --- a/client/src/app/+admin/admin.component.ts +++ b/client/src/app/+admin/admin.component.ts | |||
@@ -44,6 +44,14 @@ export class AdminComponent implements OnInit { | |||
44 | }) | 44 | }) |
45 | } | 45 | } |
46 | 46 | ||
47 | if (this.hasVideosRight()) { | ||
48 | overviewItems.children.push({ | ||
49 | label: $localize`Videos`, | ||
50 | routerLink: '/admin/videos', | ||
51 | iconName: 'videos' | ||
52 | }) | ||
53 | } | ||
54 | |||
47 | if (overviewItems.children.length !== 0) { | 55 | if (overviewItems.children.length !== 0) { |
48 | this.menuEntries.push(overviewItems) | 56 | this.menuEntries.push(overviewItems) |
49 | } | 57 | } |
@@ -217,4 +225,8 @@ export class AdminComponent implements OnInit { | |||
217 | private hasVideoCommentsRight () { | 225 | private hasVideoCommentsRight () { |
218 | return this.auth.getUser().hasRight(UserRight.SEE_ALL_COMMENTS) | 226 | return this.auth.getUser().hasRight(UserRight.SEE_ALL_COMMENTS) |
219 | } | 227 | } |
228 | |||
229 | private hasVideosRight () { | ||
230 | return this.auth.getUser().hasRight(UserRight.SEE_ALL_VIDEOS) | ||
231 | } | ||
220 | } | 232 | } |
diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts index a2bd88880..d04c11a20 100644 --- a/client/src/app/+admin/admin.module.ts +++ b/client/src/app/+admin/admin.module.ts | |||
@@ -10,7 +10,9 @@ import { SharedFormModule } from '@app/shared/shared-forms' | |||
10 | import { SharedGlobalIconModule } from '@app/shared/shared-icons' | 10 | import { SharedGlobalIconModule } from '@app/shared/shared-icons' |
11 | import { SharedMainModule } from '@app/shared/shared-main' | 11 | import { SharedMainModule } from '@app/shared/shared-main' |
12 | import { SharedModerationModule } from '@app/shared/shared-moderation' | 12 | import { SharedModerationModule } from '@app/shared/shared-moderation' |
13 | import { SharedTablesModule } from '@app/shared/shared-tables' | ||
13 | import { SharedVideoCommentModule } from '@app/shared/shared-video-comment' | 14 | import { SharedVideoCommentModule } from '@app/shared/shared-video-comment' |
15 | import { SharedVideoMiniatureModule } from '@app/shared/shared-video-miniature' | ||
14 | import { AdminRoutingModule } from './admin-routing.module' | 16 | import { AdminRoutingModule } from './admin-routing.module' |
15 | import { AdminComponent } from './admin.component' | 17 | import { AdminComponent } from './admin.component' |
16 | import { | 18 | import { |
@@ -33,7 +35,7 @@ import { AbuseListComponent, VideoBlockListComponent } from './moderation' | |||
33 | import { InstanceAccountBlocklistComponent, InstanceServerBlocklistComponent } from './moderation/instance-blocklist' | 35 | import { InstanceAccountBlocklistComponent, InstanceServerBlocklistComponent } from './moderation/instance-blocklist' |
34 | import { ModerationComponent } from './moderation/moderation.component' | 36 | import { ModerationComponent } from './moderation/moderation.component' |
35 | import { VideoCommentListComponent } from './moderation/video-comment-list' | 37 | import { VideoCommentListComponent } from './moderation/video-comment-list' |
36 | import { UserCreateComponent, UserListComponent, UserPasswordComponent, UserUpdateComponent } from './overview' | 38 | import { UserCreateComponent, UserListComponent, UserPasswordComponent, UserUpdateComponent, VideoListComponent } from './overview' |
37 | import { PluginListInstalledComponent } from './plugins/plugin-list-installed/plugin-list-installed.component' | 39 | import { PluginListInstalledComponent } from './plugins/plugin-list-installed/plugin-list-installed.component' |
38 | import { PluginSearchComponent } from './plugins/plugin-search/plugin-search.component' | 40 | import { PluginSearchComponent } from './plugins/plugin-search/plugin-search.component' |
39 | import { PluginShowInstalledComponent } from './plugins/plugin-show-installed/plugin-show-installed.component' | 41 | import { PluginShowInstalledComponent } from './plugins/plugin-show-installed/plugin-show-installed.component' |
@@ -56,6 +58,8 @@ import { JobsComponent } from './system/jobs/jobs.component' | |||
56 | SharedActorImageModule, | 58 | SharedActorImageModule, |
57 | SharedActorImageEditModule, | 59 | SharedActorImageEditModule, |
58 | SharedCustomMarkupModule, | 60 | SharedCustomMarkupModule, |
61 | SharedVideoMiniatureModule, | ||
62 | SharedTablesModule, | ||
59 | 63 | ||
60 | TableModule, | 64 | TableModule, |
61 | SelectButtonModule, | 65 | SelectButtonModule, |
@@ -65,6 +69,8 @@ import { JobsComponent } from './system/jobs/jobs.component' | |||
65 | declarations: [ | 69 | declarations: [ |
66 | AdminComponent, | 70 | AdminComponent, |
67 | 71 | ||
72 | VideoListComponent, | ||
73 | |||
68 | FollowsComponent, | 74 | FollowsComponent, |
69 | FollowersListComponent, | 75 | FollowersListComponent, |
70 | FollowingListComponent, | 76 | FollowingListComponent, |
diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html index 7efa87dd0..3cd69cfbc 100644 --- a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html +++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html | |||
@@ -34,9 +34,7 @@ | |||
34 | <tr> | 34 | <tr> |
35 | <td *ngIf="!videoBlock.reason"></td> | 35 | <td *ngIf="!videoBlock.reason"></td> |
36 | <td *ngIf="videoBlock.reason" class="expand-cell c-hand" [pRowToggler]="videoBlock" i18n-ngbTooltip ngbTooltip="More information" placement="top-left" container="body"> | 36 | <td *ngIf="videoBlock.reason" class="expand-cell c-hand" [pRowToggler]="videoBlock" i18n-ngbTooltip ngbTooltip="More information" placement="top-left" container="body"> |
37 | <span class="expander"> | 37 | <my-table-expander-icon [expanded]="expanded"></my-table-expander-icon> |
38 | <i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i> | ||
39 | </span> | ||
40 | </td> | 38 | </td> |
41 | 39 | ||
42 | <td class="action-cell"> | 40 | <td class="action-cell"> |
@@ -47,22 +45,11 @@ | |||
47 | </td> | 45 | </td> |
48 | 46 | ||
49 | <td> | 47 | <td> |
50 | <a [href]="getVideoUrl(videoBlock)" class="table-video-link" [title]="videoBlock.video.name" target="_blank" rel="noopener noreferrer"> | 48 | <my-video-cell [video]="videoBlock.video"> |
51 | <div class="table-video"> | 49 | <span name> |
52 | <div class="table-video-image"> | 50 | <my-global-icon *ngIf="videoBlock.type === 2" i18n-title title="The video was blocked due to automatic blocking of new videos" iconName="robot"></my-global-icon> |
53 | <img [src]="videoBlock.video.thumbnailPath"> | 51 | </span> |
54 | </div> | 52 | </my-video-cell> |
55 | |||
56 | <div class="table-video-text"> | ||
57 | <div> | ||
58 | <my-global-icon i18n-title title="The video was blocked due to automatic blocking of new videos" *ngIf="videoBlock.type === 2" iconName="robot"></my-global-icon> | ||
59 | {{ videoBlock.video.name }} | ||
60 | </div> | ||
61 | |||
62 | <div class="text-muted">by {{ videoBlock.video.channel?.displayName }} on {{ videoBlock.video.channel?.host }} </div> | ||
63 | </div> | ||
64 | </div> | ||
65 | </a> | ||
66 | </td> | 53 | </td> |
67 | 54 | ||
68 | <td> | 55 | <td> |
@@ -90,9 +77,7 @@ | |||
90 | </div> | 77 | </div> |
91 | 78 | ||
92 | <div class="right"> | 79 | <div class="right"> |
93 | <div class="screenratio"> | 80 | <my-embed [video]="videoBlock.video"></my-embed> |
94 | <div [innerHTML]="videoBlock.embedHtml"></div> | ||
95 | </div> | ||
96 | </div> | 81 | </div> |
97 | 82 | ||
98 | </div> | 83 | </div> |
diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts index 7baf34ca2..1fe8d0f9d 100644 --- a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts +++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts | |||
@@ -3,11 +3,10 @@ import { switchMap } from 'rxjs/operators' | |||
3 | import { buildVideoOrPlaylistEmbed } from 'src/assets/player/utils' | 3 | import { buildVideoOrPlaylistEmbed } from 'src/assets/player/utils' |
4 | import { environment } from 'src/environments/environment' | 4 | import { environment } from 'src/environments/environment' |
5 | import { Component, OnInit } from '@angular/core' | 5 | import { Component, OnInit } from '@angular/core' |
6 | import { DomSanitizer } from '@angular/platform-browser' | ||
7 | import { ActivatedRoute, Router } from '@angular/router' | 6 | import { ActivatedRoute, Router } from '@angular/router' |
8 | import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' | 7 | import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' |
9 | import { AdvancedInputFilter } from '@app/shared/shared-forms' | 8 | import { AdvancedInputFilter } from '@app/shared/shared-forms' |
10 | import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' | 9 | import { DropdownAction, VideoService } from '@app/shared/shared-main' |
11 | import { VideoBlockService } from '@app/shared/shared-moderation' | 10 | import { VideoBlockService } from '@app/shared/shared-moderation' |
12 | import { buildVideoEmbedLink, decorateVideoLink } from '@shared/core-utils' | 11 | import { buildVideoEmbedLink, decorateVideoLink } from '@shared/core-utils' |
13 | import { VideoBlacklist, VideoBlacklistType } from '@shared/models' | 12 | import { VideoBlacklist, VideoBlacklistType } from '@shared/models' |
@@ -18,7 +17,7 @@ import { VideoBlacklist, VideoBlacklistType } from '@shared/models' | |||
18 | styleUrls: [ '../../../shared/shared-moderation/moderation.scss', './video-block-list.component.scss' ] | 17 | styleUrls: [ '../../../shared/shared-moderation/moderation.scss', './video-block-list.component.scss' ] |
19 | }) | 18 | }) |
20 | export class VideoBlockListComponent extends RestTable implements OnInit { | 19 | export class VideoBlockListComponent extends RestTable implements OnInit { |
21 | blocklist: (VideoBlacklist & { reasonHtml?: string, embedHtml?: string })[] = [] | 20 | blocklist: (VideoBlacklist & { reasonHtml?: string })[] = [] |
22 | totalRecords = 0 | 21 | totalRecords = 0 |
23 | sort: SortMeta = { field: 'createdAt', order: -1 } | 22 | sort: SortMeta = { field: 'createdAt', order: -1 } |
24 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | 23 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } |
@@ -50,7 +49,6 @@ export class VideoBlockListComponent extends RestTable implements OnInit { | |||
50 | private confirmService: ConfirmService, | 49 | private confirmService: ConfirmService, |
51 | private videoBlocklistService: VideoBlockService, | 50 | private videoBlocklistService: VideoBlockService, |
52 | private markdownRenderer: MarkdownService, | 51 | private markdownRenderer: MarkdownService, |
53 | private sanitizer: DomSanitizer, | ||
54 | private videoService: VideoService | 52 | private videoService: VideoService |
55 | ) { | 53 | ) { |
56 | super() | 54 | super() |
@@ -125,10 +123,6 @@ export class VideoBlockListComponent extends RestTable implements OnInit { | |||
125 | return 'VideoBlockListComponent' | 123 | return 'VideoBlockListComponent' |
126 | } | 124 | } |
127 | 125 | ||
128 | getVideoUrl (videoBlock: VideoBlacklist) { | ||
129 | return Video.buildWatchUrl(videoBlock.video) | ||
130 | } | ||
131 | |||
132 | toHtml (text: string) { | 126 | toHtml (text: string) { |
133 | return this.markdownRenderer.textMarkdownToHTML(text) | 127 | return this.markdownRenderer.textMarkdownToHTML(text) |
134 | } | 128 | } |
@@ -176,8 +170,7 @@ export class VideoBlockListComponent extends RestTable implements OnInit { | |||
176 | 170 | ||
177 | for (const element of this.blocklist) { | 171 | for (const element of this.blocklist) { |
178 | Object.assign(element, { | 172 | Object.assign(element, { |
179 | reasonHtml: await this.toHtml(element.reason), | 173 | reasonHtml: await this.toHtml(element.reason) |
180 | embedHtml: this.sanitizer.bypassSecurityTrustHtml(this.getVideoEmbed(element)) | ||
181 | }) | 174 | }) |
182 | } | 175 | } |
183 | }, | 176 | }, |
diff --git a/client/src/app/+admin/overview/index.ts b/client/src/app/+admin/overview/index.ts index b71a6a45f..a9c46893f 100644 --- a/client/src/app/+admin/overview/index.ts +++ b/client/src/app/+admin/overview/index.ts | |||
@@ -1,2 +1,3 @@ | |||
1 | export * from './users' | 1 | export * from './users' |
2 | export * from './videos' | ||
2 | export * from './overview.routes' | 3 | export * from './overview.routes' |
diff --git a/client/src/app/+admin/overview/overview.routes.ts b/client/src/app/+admin/overview/overview.routes.ts index cb5986072..1e6686d16 100644 --- a/client/src/app/+admin/overview/overview.routes.ts +++ b/client/src/app/+admin/overview/overview.routes.ts | |||
@@ -1,6 +1,8 @@ | |||
1 | import { Routes } from '@angular/router' | 1 | import { Routes } from '@angular/router' |
2 | import { UsersRoutes } from './users' | 2 | import { UsersRoutes } from './users' |
3 | import { VideosRoutes } from './videos' | ||
3 | 4 | ||
4 | export const OverviewRoutes: Routes = [ | 5 | export const OverviewRoutes: Routes = [ |
5 | ...UsersRoutes | 6 | ...UsersRoutes, |
7 | ...VideosRoutes | ||
6 | ] | 8 | ] |
diff --git a/client/src/app/+admin/overview/videos/index.ts b/client/src/app/+admin/overview/videos/index.ts new file mode 100644 index 000000000..40c2ffe72 --- /dev/null +++ b/client/src/app/+admin/overview/videos/index.ts | |||
@@ -0,0 +1,2 @@ | |||
1 | export * from './video-list.component' | ||
2 | export * from './video.routes' | ||
diff --git a/client/src/app/+admin/overview/videos/video-list.component.html b/client/src/app/+admin/overview/videos/video-list.component.html new file mode 100644 index 000000000..1f1e9cc6e --- /dev/null +++ b/client/src/app/+admin/overview/videos/video-list.component.html | |||
@@ -0,0 +1,86 @@ | |||
1 | <h1> | ||
2 | <my-global-icon iconName="videos" aria-hidden="true"></my-global-icon> | ||
3 | <ng-container i18n>Videos</ng-container> | ||
4 | </h1> | ||
5 | |||
6 | <p-table | ||
7 | [value]="videos" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" | ||
8 | [sortField]="sort.field" [sortOrder]="sort.order" dataKey="id" [resizableColumns]="true" [(selection)]="selectedVideos" | ||
9 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" | ||
10 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | ||
11 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} videos" | ||
12 | (onPage)="onPage($event)" [expandedRowKeys]="expandedRows" | ||
13 | > | ||
14 | <ng-template pTemplate="caption"> | ||
15 | <div class="caption"> | ||
16 | <div class="left-buttons"> | ||
17 | <my-action-dropdown | ||
18 | *ngIf="isInSelectionMode()" i18n-label label="Batch actions" theme="orange" | ||
19 | [actions]="bulkVideoActions" [entry]="selectedVideos" | ||
20 | > | ||
21 | </my-action-dropdown> | ||
22 | </div> | ||
23 | |||
24 | <div class="ml-auto"> | ||
25 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> | ||
26 | </div> | ||
27 | |||
28 | </div> | ||
29 | </ng-template> | ||
30 | |||
31 | <ng-template pTemplate="header"> | ||
32 | <tr> | ||
33 | <th style="width: 40px"> | ||
34 | <p-tableHeaderCheckbox ariaLabel="Select all rows" i18n-ariaLabel></p-tableHeaderCheckbox> | ||
35 | </th> | ||
36 | <th style="width: 40px"></th> | ||
37 | <th style="width: 60px;"></th> | ||
38 | <th i18n>Video</th> | ||
39 | <th i18n>Info</th> | ||
40 | <th style="width: 150px;" i18n pSortableColumn="publishedAt">Published <p-sortIcon field="publishedAt"></p-sortIcon></th> | ||
41 | </tr> | ||
42 | </ng-template> | ||
43 | |||
44 | <ng-template pTemplate="body" let-expanded="expanded" let-video> | ||
45 | |||
46 | <tr [pSelectableRow]="video"> | ||
47 | <td class="checkbox-cell"> | ||
48 | <p-tableCheckbox [value]="video" ariaLabel="Select this row" i18n-ariaLabel></p-tableCheckbox> | ||
49 | </td> | ||
50 | |||
51 | <td class="expand-cell" [pRowToggler]="video"> | ||
52 | <my-table-expander-icon [expanded]="expanded"></my-table-expander-icon> | ||
53 | </td> | ||
54 | |||
55 | <td class="action-cell"> | ||
56 | <my-video-actions-dropdown | ||
57 | placement="bottom auto" buttonDirection="horizontal" [buttonStyled]="true" [video]="video" | ||
58 | [displayOptions]="videoActionsOptions" (videoRemoved)="onVideoRemoved()" | ||
59 | ></my-video-actions-dropdown> | ||
60 | </td> | ||
61 | |||
62 | <td> | ||
63 | <my-video-cell [video]="video"></my-video-cell> | ||
64 | </td> | ||
65 | |||
66 | <td> | ||
67 | <span class="badge badge-blue" i18n>{{ video.privacy.label }}</span> | ||
68 | <span *ngIf="video.nsfw" class="badge badge-red" i18n>NSFW</span> | ||
69 | <span *ngIf="video.blocked" class="badge badge-red" i18n>NSFW</span> | ||
70 | </td> | ||
71 | |||
72 | <td> | ||
73 | {{ video.publishedAt | date: 'short' }} | ||
74 | </td> | ||
75 | |||
76 | </tr> | ||
77 | </ng-template> | ||
78 | |||
79 | <ng-template pTemplate="rowexpansion" let-video> | ||
80 | <tr> | ||
81 | <td colspan="50"> | ||
82 | <my-embed [video]="video"></my-embed> | ||
83 | </td> | ||
84 | </tr> | ||
85 | </ng-template> | ||
86 | </p-table> | ||
diff --git a/client/src/app/+admin/overview/videos/video-list.component.scss b/client/src/app/+admin/overview/videos/video-list.component.scss new file mode 100644 index 000000000..fcdb457f2 --- /dev/null +++ b/client/src/app/+admin/overview/videos/video-list.component.scss | |||
@@ -0,0 +1,10 @@ | |||
1 | @use '_variables' as *; | ||
2 | @use '_mixins' as *; | ||
3 | my-embed { | ||
4 | display: block; | ||
5 | max-width: 500px; | ||
6 | } | ||
7 | |||
8 | .badge { | ||
9 | @include table-badge; | ||
10 | } | ||
diff --git a/client/src/app/+admin/overview/videos/video-list.component.ts b/client/src/app/+admin/overview/videos/video-list.component.ts new file mode 100644 index 000000000..a445bc209 --- /dev/null +++ b/client/src/app/+admin/overview/videos/video-list.component.ts | |||
@@ -0,0 +1,123 @@ | |||
1 | import { SortMeta } from 'primeng/api' | ||
2 | import { Component, OnInit } from '@angular/core' | ||
3 | import { ActivatedRoute, Router } from '@angular/router' | ||
4 | import { AuthService, ConfirmService, Notifier, RestPagination, RestTable } from '@app/core' | ||
5 | import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' | ||
6 | import { UserRight } from '@shared/models' | ||
7 | import { AdvancedInputFilter } from '@app/shared/shared-forms' | ||
8 | import { VideoActionsDisplayType } from '@app/shared/shared-video-miniature' | ||
9 | |||
10 | @Component({ | ||
11 | selector: 'my-video-list', | ||
12 | templateUrl: './video-list.component.html', | ||
13 | styleUrls: [ './video-list.component.scss' ] | ||
14 | }) | ||
15 | export class VideoListComponent extends RestTable implements OnInit { | ||
16 | videos: Video[] = [] | ||
17 | |||
18 | totalRecords = 0 | ||
19 | sort: SortMeta = { field: 'publishedAt', order: 1 } | ||
20 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
21 | |||
22 | bulkVideoActions: DropdownAction<Video[]>[][] = [] | ||
23 | |||
24 | selectedVideos: Video[] = [] | ||
25 | |||
26 | inputFilters: AdvancedInputFilter[] = [ | ||
27 | { | ||
28 | title: $localize`Advanced filters`, | ||
29 | children: [ | ||
30 | { | ||
31 | queryParams: { search: 'local:true' }, | ||
32 | label: $localize`Only local videos` | ||
33 | } | ||
34 | ] | ||
35 | } | ||
36 | ] | ||
37 | |||
38 | videoActionsOptions: VideoActionsDisplayType = { | ||
39 | playlist: false, | ||
40 | download: false, | ||
41 | update: true, | ||
42 | blacklist: true, | ||
43 | delete: true, | ||
44 | report: false, | ||
45 | duplicate: true, | ||
46 | mute: true, | ||
47 | liveInfo: false | ||
48 | } | ||
49 | |||
50 | constructor ( | ||
51 | protected route: ActivatedRoute, | ||
52 | protected router: Router, | ||
53 | private confirmService: ConfirmService, | ||
54 | private auth: AuthService, | ||
55 | private notifier: Notifier, | ||
56 | private videoService: VideoService | ||
57 | ) { | ||
58 | super() | ||
59 | } | ||
60 | |||
61 | get authUser () { | ||
62 | return this.auth.getUser() | ||
63 | } | ||
64 | |||
65 | ngOnInit () { | ||
66 | this.initialize() | ||
67 | |||
68 | this.bulkVideoActions = [ | ||
69 | [ | ||
70 | { | ||
71 | label: $localize`Delete`, | ||
72 | handler: videos => this.removeVideos(videos), | ||
73 | isDisplayed: () => this.authUser.hasRight(UserRight.REMOVE_ANY_VIDEO) | ||
74 | } | ||
75 | ] | ||
76 | ] | ||
77 | } | ||
78 | |||
79 | getIdentifier () { | ||
80 | return 'VideoListComponent' | ||
81 | } | ||
82 | |||
83 | isInSelectionMode () { | ||
84 | return this.selectedVideos.length !== 0 | ||
85 | } | ||
86 | |||
87 | onVideoRemoved () { | ||
88 | this.reloadData() | ||
89 | } | ||
90 | |||
91 | protected reloadData () { | ||
92 | this.selectedVideos = [] | ||
93 | |||
94 | this.videoService.getAdminVideos({ | ||
95 | pagination: this.pagination, | ||
96 | sort: this.sort, | ||
97 | search: this.search | ||
98 | }).subscribe({ | ||
99 | next: resultList => { | ||
100 | this.videos = resultList.data | ||
101 | this.totalRecords = resultList.total | ||
102 | }, | ||
103 | |||
104 | error: err => this.notifier.error(err.message) | ||
105 | }) | ||
106 | } | ||
107 | |||
108 | private async removeVideos (videos: Video[]) { | ||
109 | const message = $localize`Are you sure you want to delete these ${videos.length} videos?` | ||
110 | const res = await this.confirmService.confirm(message, $localize`Delete`) | ||
111 | if (res === false) return | ||
112 | |||
113 | this.videoService.removeVideo(videos.map(v => v.id)) | ||
114 | .subscribe({ | ||
115 | next: () => { | ||
116 | this.notifier.success($localize`${videos.length} videos deleted.`) | ||
117 | this.reloadData() | ||
118 | }, | ||
119 | |||
120 | error: err => this.notifier.error(err.message) | ||
121 | }) | ||
122 | } | ||
123 | } | ||
diff --git a/client/src/app/+admin/overview/videos/video.routes.ts b/client/src/app/+admin/overview/videos/video.routes.ts new file mode 100644 index 000000000..984df7b82 --- /dev/null +++ b/client/src/app/+admin/overview/videos/video.routes.ts | |||
@@ -0,0 +1,30 @@ | |||
1 | import { Routes } from '@angular/router' | ||
2 | import { UserRightGuard } from '@app/core' | ||
3 | import { UserRight } from '@shared/models' | ||
4 | import { VideoListComponent } from './video-list.component' | ||
5 | |||
6 | export const VideosRoutes: Routes = [ | ||
7 | { | ||
8 | path: 'videos', | ||
9 | canActivate: [ UserRightGuard ], | ||
10 | data: { | ||
11 | userRight: UserRight.SEE_ALL_VIDEOS | ||
12 | }, | ||
13 | children: [ | ||
14 | { | ||
15 | path: '', | ||
16 | redirectTo: 'list', | ||
17 | pathMatch: 'full' | ||
18 | }, | ||
19 | { | ||
20 | path: 'list', | ||
21 | component: VideoListComponent, | ||
22 | data: { | ||
23 | meta: { | ||
24 | title: $localize`Videos list` | ||
25 | } | ||
26 | } | ||
27 | } | ||
28 | ] | ||
29 | } | ||
30 | ] | ||