diff options
Diffstat (limited to 'client/src/app/+admin')
21 files changed, 157 insertions, 100 deletions
diff --git a/client/src/app/+admin/admin.component.ts b/client/src/app/+admin/admin.component.ts index b8a957d1c..746549555 100644 --- a/client/src/app/+admin/admin.component.ts +++ b/client/src/app/+admin/admin.component.ts | |||
@@ -52,6 +52,14 @@ export class AdminComponent implements OnInit { | |||
52 | }) | 52 | }) |
53 | } | 53 | } |
54 | 54 | ||
55 | if (this.hasVideoCommentsRight()) { | ||
56 | overviewItems.children.push({ | ||
57 | label: $localize`Comments`, | ||
58 | routerLink: '/admin/comments', | ||
59 | iconName: 'message-circle' | ||
60 | }) | ||
61 | } | ||
62 | |||
55 | if (overviewItems.children.length !== 0) { | 63 | if (overviewItems.children.length !== 0) { |
56 | this.menuEntries.push(overviewItems) | 64 | this.menuEntries.push(overviewItems) |
57 | } | 65 | } |
@@ -104,14 +112,6 @@ export class AdminComponent implements OnInit { | |||
104 | }) | 112 | }) |
105 | } | 113 | } |
106 | 114 | ||
107 | if (this.hasVideoCommentsRight()) { | ||
108 | moderationItems.children.push({ | ||
109 | label: $localize`Video comments`, | ||
110 | routerLink: '/admin/moderation/video-comments/list', | ||
111 | iconName: 'message-circle' | ||
112 | }) | ||
113 | } | ||
114 | |||
115 | if (this.hasAccountsBlocklistRight()) { | 115 | if (this.hasAccountsBlocklistRight()) { |
116 | moderationItems.children.push({ | 116 | moderationItems.children.push({ |
117 | label: $localize`Muted accounts`, | 117 | label: $localize`Muted accounts`, |
diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts index c672fa280..366e29883 100644 --- a/client/src/app/+admin/admin.module.ts +++ b/client/src/app/+admin/admin.module.ts | |||
@@ -32,13 +32,13 @@ import { RedundancyCheckboxComponent } from './follows/shared/redundancy-checkbo | |||
32 | import { VideoRedundancyInformationComponent } from './follows/video-redundancies-list/video-redundancy-information.component' | 32 | import { VideoRedundancyInformationComponent } from './follows/video-redundancies-list/video-redundancy-information.component' |
33 | import { AbuseListComponent, VideoBlockListComponent } from './moderation' | 33 | import { AbuseListComponent, VideoBlockListComponent } from './moderation' |
34 | import { InstanceAccountBlocklistComponent, InstanceServerBlocklistComponent } from './moderation/instance-blocklist' | 34 | import { InstanceAccountBlocklistComponent, InstanceServerBlocklistComponent } from './moderation/instance-blocklist' |
35 | import { VideoCommentListComponent } from './moderation/video-comment-list' | ||
36 | import { | 35 | import { |
37 | UserCreateComponent, | 36 | UserCreateComponent, |
38 | UserListComponent, | 37 | UserListComponent, |
39 | UserPasswordComponent, | 38 | UserPasswordComponent, |
40 | UserUpdateComponent, | 39 | UserUpdateComponent, |
41 | VideoAdminService, | 40 | VideoAdminService, |
41 | VideoCommentListComponent, | ||
42 | VideoListComponent | 42 | VideoListComponent |
43 | } from './overview' | 43 | } from './overview' |
44 | import { | 44 | import { |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts index f2eaa3033..e3b6f8305 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts | |||
@@ -197,6 +197,9 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { | |||
197 | resolutions: {} | 197 | resolutions: {} |
198 | } | 198 | } |
199 | }, | 199 | }, |
200 | videoEditor: { | ||
201 | enabled: null | ||
202 | }, | ||
200 | autoBlacklist: { | 203 | autoBlacklist: { |
201 | videos: { | 204 | videos: { |
202 | ofUsers: { | 205 | ofUsers: { |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-vod-transcoding.component.html b/client/src/app/+admin/config/edit-custom-config/edit-vod-transcoding.component.html index 1158f027b..2be855756 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-vod-transcoding.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-vod-transcoding.component.html | |||
@@ -192,4 +192,29 @@ | |||
192 | 192 | ||
193 | </div> | 193 | </div> |
194 | </div> | 194 | </div> |
195 | |||
196 | <div class="form-row mt-2"> <!-- video editor grid --> | ||
197 | <div class="form-group col-12 col-lg-4 col-xl-3"> | ||
198 | <div i18n class="inner-form-title">VIDEO EDITOR</div> | ||
199 | <div i18n class="inner-form-description"> | ||
200 | Allows your users to edit their video (cut, add intro/outro, add a watermark etc) | ||
201 | </div> | ||
202 | </div> | ||
203 | |||
204 | <div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> | ||
205 | |||
206 | <ng-container formGroupName="videoEditor"> | ||
207 | <div class="form-group" [ngClass]="getTranscodingDisabledClass()"> | ||
208 | <my-peertube-checkbox | ||
209 | inputName="videoEditorEnabled" formControlName="enabled" | ||
210 | i18n-labelText labelText="Enable video editor" | ||
211 | > | ||
212 | <ng-container ngProjectAs="description" *ngIf="!isTranscodingEnabled()"> | ||
213 | <span i18n>⚠️ You need to enable transcoding first to enable video editor</span> | ||
214 | </ng-container> | ||
215 | </my-peertube-checkbox> | ||
216 | </div> | ||
217 | </ng-container> | ||
218 | </div> | ||
219 | </div> | ||
195 | </ng-container> | 220 | </ng-container> |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-vod-transcoding.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-vod-transcoding.component.ts index 3397c3dbd..948c10b69 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-vod-transcoding.component.ts +++ b/client/src/app/+admin/config/edit-custom-config/edit-vod-transcoding.component.ts | |||
@@ -71,6 +71,8 @@ export class EditVODTranscodingComponent implements OnInit, OnChanges { | |||
71 | } | 71 | } |
72 | 72 | ||
73 | private checkTranscodingFields () { | 73 | private checkTranscodingFields () { |
74 | const transcodingControl = this.form.get('transcoding.enabled') | ||
75 | const videoEditorControl = this.form.get('videoEditor.enabled') | ||
74 | const hlsControl = this.form.get('transcoding.hls.enabled') | 76 | const hlsControl = this.form.get('transcoding.hls.enabled') |
75 | const webtorrentControl = this.form.get('transcoding.webtorrent.enabled') | 77 | const webtorrentControl = this.form.get('transcoding.webtorrent.enabled') |
76 | 78 | ||
@@ -95,5 +97,12 @@ export class EditVODTranscodingComponent implements OnInit, OnChanges { | |||
95 | webtorrentControl.enable() | 97 | webtorrentControl.enable() |
96 | } | 98 | } |
97 | }) | 99 | }) |
100 | |||
101 | transcodingControl.valueChanges | ||
102 | .subscribe(newValue => { | ||
103 | if (newValue === false) { | ||
104 | videoEditorControl.setValue(false) | ||
105 | } | ||
106 | }) | ||
98 | } | 107 | } |
99 | } | 108 | } |
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html deleted file mode 100644 index feade0c26..000000000 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html +++ /dev/null | |||
@@ -1,56 +0,0 @@ | |||
1 | <p-table | ||
2 | [value]="blockedAccounts" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" | ||
3 | [sortField]="sort.field" [sortOrder]="sort.order" | ||
4 | [lazy]="true" (onLazyLoad)="loadLazy($event)" [lazyLoadOnInit]="false" | ||
5 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | ||
6 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} muted accounts" | ||
7 | > | ||
8 | <ng-template pTemplate="caption"> | ||
9 | <div class="caption"> | ||
10 | <div class="ml-auto"> | ||
11 | <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter> | ||
12 | </div> | ||
13 | </div> | ||
14 | </ng-template> | ||
15 | |||
16 | <ng-template pTemplate="header"> | ||
17 | <tr> | ||
18 | <th style="width: 150px;">Action</th> <!-- column for action buttons --> | ||
19 | <th style="width: calc(100% - 300px);" i18n>Account</th> | ||
20 | <th style="width: 150px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th> | ||
21 | </tr> | ||
22 | </ng-template> | ||
23 | |||
24 | <ng-template pTemplate="body" let-accountBlock> | ||
25 | <tr> | ||
26 | <td class="action-cell"> | ||
27 | <button class="unblock-button" (click)="unblockAccount(accountBlock)" i18n>Unmute</button> | ||
28 | </td> | ||
29 | |||
30 | <td> | ||
31 | <a [href]="accountBlock.blockedAccount.url" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer"> | ||
32 | <div class="chip two-lines"> | ||
33 | <my-actor-avatar [account]="accountBlock.blockedAccount"></my-actor-avatar> | ||
34 | <div> | ||
35 | {{ accountBlock.blockedAccount.displayName }} | ||
36 | <span class="text-muted">{{ accountBlock.blockedAccount.nameWithHost }}</span> | ||
37 | </div> | ||
38 | </div> | ||
39 | </a> | ||
40 | </td> | ||
41 | |||
42 | <td>{{ accountBlock.createdAt | date: 'short' }}</td> | ||
43 | </tr> | ||
44 | </ng-template> | ||
45 | |||
46 | <ng-template pTemplate="emptymessage"> | ||
47 | <tr> | ||
48 | <td colspan="6"> | ||
49 | <div class="no-results"> | ||
50 | <ng-container *ngIf="search" i18n>No account found matching current filters.</ng-container> | ||
51 | <ng-container *ngIf="!search" i18n>No account found.</ng-container> | ||
52 | </div> | ||
53 | </td> | ||
54 | </tr> | ||
55 | </ng-template> | ||
56 | </p-table> | ||
diff --git a/client/src/app/+admin/moderation/moderation.routes.ts b/client/src/app/+admin/moderation/moderation.routes.ts index 5c39ff366..1ad301039 100644 --- a/client/src/app/+admin/moderation/moderation.routes.ts +++ b/client/src/app/+admin/moderation/moderation.routes.ts | |||
@@ -2,7 +2,6 @@ import { Routes } from '@angular/router' | |||
2 | import { AbuseListComponent } from '@app/+admin/moderation/abuse-list' | 2 | import { AbuseListComponent } from '@app/+admin/moderation/abuse-list' |
3 | import { InstanceAccountBlocklistComponent, InstanceServerBlocklistComponent } from '@app/+admin/moderation/instance-blocklist' | 3 | import { InstanceAccountBlocklistComponent, InstanceServerBlocklistComponent } from '@app/+admin/moderation/instance-blocklist' |
4 | import { VideoBlockListComponent } from '@app/+admin/moderation/video-block-list' | 4 | import { VideoBlockListComponent } from '@app/+admin/moderation/video-block-list' |
5 | import { VideoCommentListComponent } from './video-comment-list' | ||
6 | import { UserRightGuard } from '@app/core' | 5 | import { UserRightGuard } from '@app/core' |
7 | import { UserRight } from '@shared/models' | 6 | import { UserRight } from '@shared/models' |
8 | 7 | ||
@@ -69,6 +68,7 @@ export const ModerationRoutes: Routes = [ | |||
69 | } | 68 | } |
70 | }, | 69 | }, |
71 | 70 | ||
71 | // We move this component in admin overview pages | ||
72 | { | 72 | { |
73 | path: 'video-comments', | 73 | path: 'video-comments', |
74 | redirectTo: 'video-comments/list', | 74 | redirectTo: 'video-comments/list', |
@@ -76,14 +76,8 @@ export const ModerationRoutes: Routes = [ | |||
76 | }, | 76 | }, |
77 | { | 77 | { |
78 | path: 'video-comments/list', | 78 | path: 'video-comments/list', |
79 | component: VideoCommentListComponent, | 79 | redirectTo: '/admin/comments/list', |
80 | canActivate: [ UserRightGuard ], | 80 | pathMatch: 'full' |
81 | data: { | ||
82 | userRight: UserRight.SEE_ALL_COMMENTS, | ||
83 | meta: { | ||
84 | title: $localize`Video comments` | ||
85 | } | ||
86 | } | ||
87 | }, | 81 | }, |
88 | 82 | ||
89 | { | 83 | { |
diff --git a/client/src/app/+admin/moderation/video-comment-list/index.ts b/client/src/app/+admin/overview/comments/index.ts index eb08b4177..c487f7a81 100644 --- a/client/src/app/+admin/moderation/video-comment-list/index.ts +++ b/client/src/app/+admin/overview/comments/index.ts | |||
@@ -1 +1,2 @@ | |||
1 | export * from './video-comment-list.component' | 1 | export * from './video-comment-list.component' |
2 | export * from './video-comment.routes' | ||
diff --git a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.html b/client/src/app/+admin/overview/comments/video-comment-list.component.html index 9bf23c21a..27a5d82ff 100644 --- a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.html +++ b/client/src/app/+admin/overview/comments/video-comment-list.component.html | |||
@@ -25,8 +25,10 @@ | |||
25 | </my-action-dropdown> | 25 | </my-action-dropdown> |
26 | </div> | 26 | </div> |
27 | 27 | ||
28 | <div class="ml-auto"> | 28 | <div class="ml-auto right-form"> |
29 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> | 29 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> |
30 | |||
31 | <my-button i18n-label label="Refresh" icon="refresh" (click)="reloadData()"></my-button> | ||
30 | </div> | 32 | </div> |
31 | </div> | 33 | </div> |
32 | </ng-template> | 34 | </ng-template> |
@@ -66,7 +68,7 @@ | |||
66 | <td> | 68 | <td> |
67 | <a [href]="videoComment.account.localUrl" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer"> | 69 | <a [href]="videoComment.account.localUrl" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer"> |
68 | <div class="chip two-lines"> | 70 | <div class="chip two-lines"> |
69 | <my-actor-avatar [account]="videoComment.account"></my-actor-avatar> | 71 | <my-actor-avatar [account]="videoComment.account" size="32"></my-actor-avatar> |
70 | <div> | 72 | <div> |
71 | {{ videoComment.account.displayName }} | 73 | {{ videoComment.account.displayName }} |
72 | <span>{{ videoComment.by }}</span> | 74 | <span>{{ videoComment.by }}</span> |
diff --git a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.scss b/client/src/app/+admin/overview/comments/video-comment-list.component.scss index 3cf7b8db6..d7eb02142 100644 --- a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.scss +++ b/client/src/app/+admin/overview/comments/video-comment-list.component.scss | |||
@@ -45,6 +45,14 @@ my-global-icon { | |||
45 | } | 45 | } |
46 | } | 46 | } |
47 | 47 | ||
48 | .right-form { | ||
49 | display: flex; | ||
50 | |||
51 | > *:not(:last-child) { | ||
52 | @include margin-right(10px); | ||
53 | } | ||
54 | } | ||
55 | |||
48 | @media screen and (max-width: $primeng-breakpoint) { | 56 | @media screen and (max-width: $primeng-breakpoint) { |
49 | .video { | 57 | .video { |
50 | align-items: flex-start !important; | 58 | align-items: flex-start !important; |
diff --git a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts b/client/src/app/+admin/overview/comments/video-comment-list.component.ts index 25fe65133..f3f43a900 100644 --- a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts +++ b/client/src/app/+admin/overview/comments/video-comment-list.component.ts | |||
@@ -117,7 +117,7 @@ export class VideoCommentListComponent extends RestTable implements OnInit { | |||
117 | return this.selectedComments.length !== 0 | 117 | return this.selectedComments.length !== 0 |
118 | } | 118 | } |
119 | 119 | ||
120 | protected reloadData () { | 120 | reloadData () { |
121 | this.videoCommentService.getAdminVideoComments({ | 121 | this.videoCommentService.getAdminVideoComments({ |
122 | pagination: this.pagination, | 122 | pagination: this.pagination, |
123 | sort: this.sort, | 123 | sort: this.sort, |
diff --git a/client/src/app/+admin/overview/comments/video-comment.routes.ts b/client/src/app/+admin/overview/comments/video-comment.routes.ts new file mode 100644 index 000000000..f0bd440ad --- /dev/null +++ b/client/src/app/+admin/overview/comments/video-comment.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 { VideoCommentListComponent } from './video-comment-list.component' | ||
5 | |||
6 | export const commentRoutes: Routes = [ | ||
7 | { | ||
8 | path: 'comments', | ||
9 | canActivate: [ UserRightGuard ], | ||
10 | data: { | ||
11 | userRight: UserRight.SEE_ALL_COMMENTS | ||
12 | }, | ||
13 | children: [ | ||
14 | { | ||
15 | path: '', | ||
16 | redirectTo: 'list', | ||
17 | pathMatch: 'full' | ||
18 | }, | ||
19 | { | ||
20 | path: 'list', | ||
21 | component: VideoCommentListComponent, | ||
22 | data: { | ||
23 | meta: { | ||
24 | title: $localize`Comments list` | ||
25 | } | ||
26 | } | ||
27 | } | ||
28 | ] | ||
29 | } | ||
30 | ] | ||
diff --git a/client/src/app/+admin/overview/index.ts b/client/src/app/+admin/overview/index.ts index a9c46893f..111360734 100644 --- a/client/src/app/+admin/overview/index.ts +++ b/client/src/app/+admin/overview/index.ts | |||
@@ -1,3 +1,4 @@ | |||
1 | export * from './comments' | ||
1 | export * from './users' | 2 | export * from './users' |
2 | export * from './videos' | 3 | export * from './videos' |
3 | export * from './overview.routes' | 4 | 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 1e6686d16..72d6835d7 100644 --- a/client/src/app/+admin/overview/overview.routes.ts +++ b/client/src/app/+admin/overview/overview.routes.ts | |||
@@ -1,8 +1,10 @@ | |||
1 | import { Routes } from '@angular/router' | 1 | import { Routes } from '@angular/router' |
2 | import { UsersRoutes } from './users' | 2 | import { commentRoutes } from './comments' |
3 | import { VideosRoutes } from './videos' | 3 | import { usersRoutes } from './users' |
4 | import { videosRoutes } from './videos' | ||
4 | 5 | ||
5 | export const OverviewRoutes: Routes = [ | 6 | export const OverviewRoutes: Routes = [ |
6 | ...UsersRoutes, | 7 | ...commentRoutes, |
7 | ...VideosRoutes | 8 | ...usersRoutes, |
9 | ...videosRoutes | ||
8 | ] | 10 | ] |
diff --git a/client/src/app/+admin/overview/users/user-list/user-list.component.html b/client/src/app/+admin/overview/users/user-list/user-list.component.html index 7eb89fea1..0662e3ac3 100644 --- a/client/src/app/+admin/overview/users/user-list/user-list.component.html +++ b/client/src/app/+admin/overview/users/user-list/user-list.component.html | |||
@@ -62,10 +62,10 @@ | |||
62 | </div> | 62 | </div> |
63 | </th> | 63 | </th> |
64 | <th *ngIf="isSelected('username')" pResizableColumn pSortableColumn="username">{{ getColumn('username').label }} <p-sortIcon field="username"></p-sortIcon></th> | 64 | <th *ngIf="isSelected('username')" pResizableColumn pSortableColumn="username">{{ getColumn('username').label }} <p-sortIcon field="username"></p-sortIcon></th> |
65 | <th *ngIf="isSelected('role')" style="width: 120px;" pSortableColumn="role">{{ getColumn('role').label }} <p-sortIcon field="role"></p-sortIcon></th> | ||
65 | <th *ngIf="isSelected('email')">{{ getColumn('email').label }}</th> | 66 | <th *ngIf="isSelected('email')">{{ getColumn('email').label }}</th> |
66 | <th *ngIf="isSelected('quota')" style="width: 160px;" pSortableColumn="videoQuotaUsed">{{ getColumn('quota').label }} <p-sortIcon field="videoQuotaUsed"></p-sortIcon></th> | 67 | <th *ngIf="isSelected('quota')" style="width: 160px;" pSortableColumn="videoQuotaUsed">{{ getColumn('quota').label }} <p-sortIcon field="videoQuotaUsed"></p-sortIcon></th> |
67 | <th *ngIf="isSelected('quotaDaily')" style="width: 160px;">{{ getColumn('quotaDaily').label }}</th> | 68 | <th *ngIf="isSelected('quotaDaily')" style="width: 160px;">{{ getColumn('quotaDaily').label }}</th> |
68 | <th *ngIf="isSelected('role')" style="width: 120px;" pSortableColumn="role">{{ getColumn('role').label }} <p-sortIcon field="role"></p-sortIcon></th> | ||
69 | <th *ngIf="isSelected('pluginAuth')" style="width: 140px;" pResizableColumn >{{ getColumn('pluginAuth').label }}</th> | 69 | <th *ngIf="isSelected('pluginAuth')" style="width: 140px;" pResizableColumn >{{ getColumn('pluginAuth').label }}</th> |
70 | <th *ngIf="isSelected('createdAt')" style="width: 150px;" pSortableColumn="createdAt">{{ getColumn('createdAt').label }} <p-sortIcon field="createdAt"></p-sortIcon></th> | 70 | <th *ngIf="isSelected('createdAt')" style="width: 150px;" pSortableColumn="createdAt">{{ getColumn('createdAt').label }} <p-sortIcon field="createdAt"></p-sortIcon></th> |
71 | <th *ngIf="isSelected('lastLoginDate')" style="width: 150px;" pSortableColumn="lastLoginDate">{{ getColumn('lastLoginDate').label }} <p-sortIcon field="lastLoginDate"></p-sortIcon></th> | 71 | <th *ngIf="isSelected('lastLoginDate')" style="width: 150px;" pSortableColumn="lastLoginDate">{{ getColumn('lastLoginDate').label }} <p-sortIcon field="lastLoginDate"></p-sortIcon></th> |
@@ -84,8 +84,9 @@ | |||
84 | </td> | 84 | </td> |
85 | 85 | ||
86 | <td class="action-cell"> | 86 | <td class="action-cell"> |
87 | <my-user-moderation-dropdown *ngIf="!isInSelectionMode()" [user]="user" container="body" | 87 | <my-user-moderation-dropdown |
88 | (userChanged)="onUserChanged()" (userDeleted)="onUserChanged()"> | 88 | *ngIf="!isInSelectionMode()" [user]="user" [account]="user.accountMutedStatus" [displayOptions]="userModerationDisplayOptions" |
89 | container="body" (userChanged)="onUserChanged()" (userDeleted)="onUserChanged()"> | ||
89 | </my-user-moderation-dropdown> | 90 | </my-user-moderation-dropdown> |
90 | </td> | 91 | </td> |
91 | 92 | ||
@@ -99,6 +100,14 @@ | |||
99 | </div> | 100 | </div> |
100 | </div> | 101 | </div> |
101 | </a> | 102 | </a> |
103 | |||
104 | <div *ngIf="user.accountMutedStatus.mutedByInstance" class="badges-username badge badge-red" i18n>Muted</div> | ||
105 | <div *ngIf="user.blocked" class="badges-username badge badge-red" i18n>Banned</div> | ||
106 | </td> | ||
107 | |||
108 | <td *ngIf="isSelected('role')"> | ||
109 | <span *ngIf="user.blocked" class="badge badge-banned" i18n-title title="The user was banned">{{ user.roleLabel }}</span> | ||
110 | <span *ngIf="!user.blocked" class="badge" [ngClass]="getRoleClass(user.role)">{{ user.roleLabel }}</span> | ||
102 | </td> | 111 | </td> |
103 | 112 | ||
104 | <td *ngIf="isSelected('email')" [title]="user.email"> | 113 | <td *ngIf="isSelected('email')" [title]="user.email"> |
@@ -138,11 +147,6 @@ | |||
138 | </div> | 147 | </div> |
139 | </td> | 148 | </td> |
140 | 149 | ||
141 | <td *ngIf="isSelected('role')"> | ||
142 | <span *ngIf="user.blocked" class="badge badge-banned" i18n-title title="The user was banned">{{ user.roleLabel }}</span> | ||
143 | <span *ngIf="!user.blocked" class="badge" [ngClass]="getRoleClass(user.role)">{{ user.roleLabel }}</span> | ||
144 | </td> | ||
145 | |||
146 | <td *ngIf="isSelected('pluginAuth')"> | 150 | <td *ngIf="isSelected('pluginAuth')"> |
147 | <ng-container *ngIf="user.pluginAuth">{{ user.pluginAuth }}</ng-container> | 151 | <ng-container *ngIf="user.pluginAuth">{{ user.pluginAuth }}</ng-container> |
148 | </td> | 152 | </td> |
diff --git a/client/src/app/+admin/overview/users/user-list/user-list.component.scss b/client/src/app/+admin/overview/users/user-list/user-list.component.scss index 335bd2995..8160703f0 100644 --- a/client/src/app/+admin/overview/users/user-list/user-list.component.scss +++ b/client/src/app/+admin/overview/users/user-list/user-list.component.scss | |||
@@ -23,6 +23,10 @@ tr.banned > td { | |||
23 | font-weight: $font-semibold; | 23 | font-weight: $font-semibold; |
24 | } | 24 | } |
25 | 25 | ||
26 | .badges-username { | ||
27 | margin-left: 15px; | ||
28 | } | ||
29 | |||
26 | .user-table-primary-text .glyphicon { | 30 | .user-table-primary-text .glyphicon { |
27 | @include margin-left(0.1rem); | 31 | @include margin-left(0.1rem); |
28 | 32 | ||
diff --git a/client/src/app/+admin/overview/users/user-list/user-list.component.ts b/client/src/app/+admin/overview/users/user-list/user-list.component.ts index 9a9d0f5c6..d22e1355e 100644 --- a/client/src/app/+admin/overview/users/user-list/user-list.component.ts +++ b/client/src/app/+admin/overview/users/user-list/user-list.component.ts | |||
@@ -2,9 +2,10 @@ import { SortMeta } from 'primeng/api' | |||
2 | import { Component, OnInit, ViewChild } from '@angular/core' | 2 | import { Component, OnInit, ViewChild } from '@angular/core' |
3 | import { ActivatedRoute, Router } from '@angular/router' | 3 | import { ActivatedRoute, Router } from '@angular/router' |
4 | import { AuthService, ConfirmService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' | 4 | import { AuthService, ConfirmService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' |
5 | import { getAPIHost } from '@app/helpers' | ||
5 | import { AdvancedInputFilter } from '@app/shared/shared-forms' | 6 | import { AdvancedInputFilter } from '@app/shared/shared-forms' |
6 | import { DropdownAction } from '@app/shared/shared-main' | 7 | import { Actor, DropdownAction } from '@app/shared/shared-main' |
7 | import { UserBanModalComponent } from '@app/shared/shared-moderation' | 8 | import { AccountMutedStatus, BlocklistService, UserBanModalComponent, UserModerationDisplayType } from '@app/shared/shared-moderation' |
8 | import { UserAdminService } from '@app/shared/shared-users' | 9 | import { UserAdminService } from '@app/shared/shared-users' |
9 | import { User, UserRole } from '@shared/models' | 10 | import { User, UserRole } from '@shared/models' |
10 | 11 | ||
@@ -23,7 +24,7 @@ type UserForList = User & { | |||
23 | export class UserListComponent extends RestTable implements OnInit { | 24 | export class UserListComponent extends RestTable implements OnInit { |
24 | @ViewChild('userBanModal', { static: true }) userBanModal: UserBanModalComponent | 25 | @ViewChild('userBanModal', { static: true }) userBanModal: UserBanModalComponent |
25 | 26 | ||
26 | users: User[] = [] | 27 | users: (User & { accountMutedStatus: AccountMutedStatus })[] = [] |
27 | 28 | ||
28 | totalRecords = 0 | 29 | totalRecords = 0 |
29 | sort: SortMeta = { field: 'createdAt', order: 1 } | 30 | sort: SortMeta = { field: 'createdAt', order: 1 } |
@@ -47,6 +48,12 @@ export class UserListComponent extends RestTable implements OnInit { | |||
47 | } | 48 | } |
48 | ] | 49 | ] |
49 | 50 | ||
51 | userModerationDisplayOptions: UserModerationDisplayType = { | ||
52 | instanceAccount: true, | ||
53 | instanceUser: true, | ||
54 | myAccount: false | ||
55 | } | ||
56 | |||
50 | requiresEmailVerification = false | 57 | requiresEmailVerification = false |
51 | 58 | ||
52 | private _selectedColumns: string[] | 59 | private _selectedColumns: string[] |
@@ -58,6 +65,7 @@ export class UserListComponent extends RestTable implements OnInit { | |||
58 | private confirmService: ConfirmService, | 65 | private confirmService: ConfirmService, |
59 | private serverService: ServerService, | 66 | private serverService: ServerService, |
60 | private auth: AuthService, | 67 | private auth: AuthService, |
68 | private blocklist: BlocklistService, | ||
61 | private userAdminService: UserAdminService | 69 | private userAdminService: UserAdminService |
62 | ) { | 70 | ) { |
63 | super() | 71 | super() |
@@ -115,9 +123,9 @@ export class UserListComponent extends RestTable implements OnInit { | |||
115 | 123 | ||
116 | this.columns = [ | 124 | this.columns = [ |
117 | { id: 'username', label: $localize`Username` }, | 125 | { id: 'username', label: $localize`Username` }, |
126 | { id: 'role', label: $localize`Role` }, | ||
118 | { id: 'email', label: $localize`Email` }, | 127 | { id: 'email', label: $localize`Email` }, |
119 | { id: 'quota', label: $localize`Video quota` }, | 128 | { id: 'quota', label: $localize`Video quota` }, |
120 | { id: 'role', label: $localize`Role` }, | ||
121 | { id: 'createdAt', label: $localize`Created` } | 129 | { id: 'createdAt', label: $localize`Created` } |
122 | ] | 130 | ] |
123 | 131 | ||
@@ -237,11 +245,35 @@ export class UserListComponent extends RestTable implements OnInit { | |||
237 | search: this.search | 245 | search: this.search |
238 | }).subscribe({ | 246 | }).subscribe({ |
239 | next: resultList => { | 247 | next: resultList => { |
240 | this.users = resultList.data | 248 | this.users = resultList.data.map(u => ({ |
249 | ...u, | ||
250 | |||
251 | accountMutedStatus: { | ||
252 | ...u.account, | ||
253 | |||
254 | nameWithHost: Actor.CREATE_BY_STRING(u.account.name, u.account.host), | ||
255 | |||
256 | mutedByInstance: false, | ||
257 | mutedByUser: false, | ||
258 | mutedServerByInstance: false, | ||
259 | mutedServerByUser: false | ||
260 | } | ||
261 | })) | ||
241 | this.totalRecords = resultList.total | 262 | this.totalRecords = resultList.total |
263 | |||
264 | this.loadMutedStatus() | ||
242 | }, | 265 | }, |
243 | 266 | ||
244 | error: err => this.notifier.error(err.message) | 267 | error: err => this.notifier.error(err.message) |
245 | }) | 268 | }) |
246 | } | 269 | } |
270 | |||
271 | private loadMutedStatus () { | ||
272 | this.blocklist.getStatus({ accounts: this.users.map(u => u.username + '@' + getAPIHost()) }) | ||
273 | .subscribe(blockStatus => { | ||
274 | for (const user of this.users) { | ||
275 | user.accountMutedStatus.mutedByInstance = blockStatus.accounts[user.username + '@' + getAPIHost()].blockedByServer | ||
276 | } | ||
277 | }) | ||
278 | } | ||
247 | } | 279 | } |
diff --git a/client/src/app/+admin/overview/users/users.routes.ts b/client/src/app/+admin/overview/users/users.routes.ts index 8b63f5bc7..c9724e5fb 100644 --- a/client/src/app/+admin/overview/users/users.routes.ts +++ b/client/src/app/+admin/overview/users/users.routes.ts | |||
@@ -4,7 +4,7 @@ import { UserRight } from '@shared/models' | |||
4 | import { UserCreateComponent, UserUpdateComponent } from './user-edit' | 4 | import { UserCreateComponent, UserUpdateComponent } from './user-edit' |
5 | import { UserListComponent } from './user-list' | 5 | import { UserListComponent } from './user-list' |
6 | 6 | ||
7 | export const UsersRoutes: Routes = [ | 7 | export const usersRoutes: Routes = [ |
8 | { | 8 | { |
9 | path: 'users', | 9 | path: 'users', |
10 | canActivate: [ UserRightGuard ], | 10 | canActivate: [ UserRightGuard ], |
diff --git a/client/src/app/+admin/overview/videos/video-list.component.html b/client/src/app/+admin/overview/videos/video-list.component.html index 974912b32..75d9be5f1 100644 --- a/client/src/app/+admin/overview/videos/video-list.component.html +++ b/client/src/app/+admin/overview/videos/video-list.component.html | |||
@@ -24,9 +24,7 @@ | |||
24 | <div class="ml-auto right-form"> | 24 | <div class="ml-auto right-form"> |
25 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> | 25 | <my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter> |
26 | 26 | ||
27 | <div class="button-filter-block"> | 27 | <my-button i18n-label label="Refresh" icon="refresh" (click)="reloadData()"></my-button> |
28 | <my-button i18n-label label="Refresh" icon="refresh" (click)="reloadData()"></my-button> | ||
29 | </div> | ||
30 | </div> | 28 | </div> |
31 | 29 | ||
32 | </div> | 30 | </div> |
diff --git a/client/src/app/+admin/overview/videos/video-list.component.scss b/client/src/app/+admin/overview/videos/video-list.component.scss index 543cb433c..cb47b6548 100644 --- a/client/src/app/+admin/overview/videos/video-list.component.scss +++ b/client/src/app/+admin/overview/videos/video-list.component.scss | |||
@@ -1,5 +1,6 @@ | |||
1 | @use '_variables' as *; | 1 | @use '_variables' as *; |
2 | @use '_mixins' as *; | 2 | @use '_mixins' as *; |
3 | |||
3 | my-embed { | 4 | my-embed { |
4 | display: block; | 5 | display: block; |
5 | max-width: 500px; | 6 | max-width: 500px; |
@@ -27,4 +28,3 @@ my-embed { | |||
27 | @include margin-right(10px); | 28 | @include margin-right(10px); |
28 | } | 29 | } |
29 | } | 30 | } |
30 | |||
diff --git a/client/src/app/+admin/overview/videos/video.routes.ts b/client/src/app/+admin/overview/videos/video.routes.ts index 984df7b82..01cb5b497 100644 --- a/client/src/app/+admin/overview/videos/video.routes.ts +++ b/client/src/app/+admin/overview/videos/video.routes.ts | |||
@@ -3,7 +3,7 @@ import { UserRightGuard } from '@app/core' | |||
3 | import { UserRight } from '@shared/models' | 3 | import { UserRight } from '@shared/models' |
4 | import { VideoListComponent } from './video-list.component' | 4 | import { VideoListComponent } from './video-list.component' |
5 | 5 | ||
6 | export const VideosRoutes: Routes = [ | 6 | export const videosRoutes: Routes = [ |
7 | { | 7 | { |
8 | path: 'videos', | 8 | path: 'videos', |
9 | canActivate: [ UserRightGuard ], | 9 | canActivate: [ UserRightGuard ], |