diff options
Diffstat (limited to 'client/src/app/+admin')
3 files changed, 251 insertions, 136 deletions
diff --git a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html index 1ad73e38a..99502304d 100644 --- a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html +++ b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html | |||
@@ -1,6 +1,6 @@ | |||
1 | <p-table | 1 | <p-table |
2 | [value]="abuses" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" | 2 | [value]="abuses" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" |
3 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" [resizableColumns]="true" | 3 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" [resizableColumns]="true" [lazyLoadOnInit]="false" |
4 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 4 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
5 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} reports" | 5 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} reports" |
6 | (onPage)="onPage($event)" [expandedRowKeys]="expandedRows" | 6 | (onPage)="onPage($event)" [expandedRowKeys]="expandedRows" |
@@ -128,6 +128,22 @@ | |||
128 | </td> | 128 | </td> |
129 | </ng-container> | 129 | </ng-container> |
130 | 130 | ||
131 | <ng-container *ngIf="!abuse.comment && !abuse.video"> | ||
132 | <td *ngIf="abuse.flaggedAccount"> | ||
133 | <a [href]="getAccountUrl(abuse)" class="table-account-link" target="_blank" rel="noopener noreferrer"> | ||
134 | <span>{{ abuse.flaggedAccount.displayName }}</span> | ||
135 | |||
136 | <span class="account-flagged-handle">{{ abuse.flaggedAccount.nameWithHostForced }}</span> | ||
137 | </a> | ||
138 | </td> | ||
139 | |||
140 | <td i18n *ngIf="!abuse.flaggedAccount"> | ||
141 | Account deleted | ||
142 | </td> | ||
143 | |||
144 | </ng-container> | ||
145 | |||
146 | |||
131 | <td class="c-hand" [pRowToggler]="abuse">{{ abuse.createdAt | date: 'short' }}</td> | 147 | <td class="c-hand" [pRowToggler]="abuse">{{ abuse.createdAt | date: 'short' }}</td> |
132 | 148 | ||
133 | <td class="c-hand abuse-states" [pRowToggler]="abuse"> | 149 | <td class="c-hand abuse-states" [pRowToggler]="abuse"> |
diff --git a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.ts b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.ts index 1ea61ed37..74c5fe2b3 100644 --- a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.ts +++ b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.ts | |||
@@ -1,3 +1,5 @@ | |||
1 | import * as debug from 'debug' | ||
2 | import truncate from 'lodash-es/truncate' | ||
1 | import { SortMeta } from 'primeng/api' | 3 | import { SortMeta } from 'primeng/api' |
2 | import { buildVideoEmbed, buildVideoLink } from 'src/assets/player/utils' | 4 | import { buildVideoEmbed, buildVideoLink } from 'src/assets/player/utils' |
3 | import { environment } from 'src/environments/environment' | 5 | import { environment } from 'src/environments/environment' |
@@ -7,11 +9,15 @@ import { ActivatedRoute, Params, Router } from '@angular/router' | |||
7 | import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable } from '@app/core' | 9 | import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable } from '@app/core' |
8 | import { Account, Actor, DropdownAction, Video, VideoService } from '@app/shared/shared-main' | 10 | import { Account, Actor, DropdownAction, Video, VideoService } from '@app/shared/shared-main' |
9 | import { AbuseService, BlocklistService, VideoBlockService } from '@app/shared/shared-moderation' | 11 | import { AbuseService, BlocklistService, VideoBlockService } from '@app/shared/shared-moderation' |
12 | import { VideoCommentService } from '@app/shared/shared-video-comment' | ||
10 | import { I18n } from '@ngx-translate/i18n-polyfill' | 13 | import { I18n } from '@ngx-translate/i18n-polyfill' |
11 | import { Abuse, AbuseState } from '@shared/models' | 14 | import { Abuse, AbuseState } from '@shared/models' |
12 | import { ModerationCommentModalComponent } from './moderation-comment-modal.component' | 15 | import { ModerationCommentModalComponent } from './moderation-comment-modal.component' |
13 | import truncate from 'lodash-es/truncate' | ||
14 | 16 | ||
17 | const logger = debug('peertube:moderation:AbuseListComponent') | ||
18 | |||
19 | // Don't use an abuse model because we need external services to compute some properties | ||
20 | // And this model is only used in this component | ||
15 | export type ProcessedAbuse = Abuse & { | 21 | export type ProcessedAbuse = Abuse & { |
16 | moderationCommentHtml?: string, | 22 | moderationCommentHtml?: string, |
17 | reasonHtml?: string | 23 | reasonHtml?: string |
@@ -45,12 +51,13 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn | |||
45 | sort: SortMeta = { field: 'createdAt', order: 1 } | 51 | sort: SortMeta = { field: 'createdAt', order: 1 } |
46 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | 52 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } |
47 | 53 | ||
48 | abuseActions: DropdownAction<Abuse>[][] = [] | 54 | abuseActions: DropdownAction<ProcessedAbuse>[][] = [] |
49 | 55 | ||
50 | constructor ( | 56 | constructor ( |
51 | private notifier: Notifier, | 57 | private notifier: Notifier, |
52 | private abuseService: AbuseService, | 58 | private abuseService: AbuseService, |
53 | private blocklistService: BlocklistService, | 59 | private blocklistService: BlocklistService, |
60 | private commentService: VideoCommentService, | ||
54 | private videoService: VideoService, | 61 | private videoService: VideoService, |
55 | private videoBlocklistService: VideoBlockService, | 62 | private videoBlocklistService: VideoBlockService, |
56 | private confirmService: ConfirmService, | 63 | private confirmService: ConfirmService, |
@@ -63,140 +70,15 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn | |||
63 | super() | 70 | super() |
64 | 71 | ||
65 | this.abuseActions = [ | 72 | this.abuseActions = [ |
66 | [ | 73 | this.buildInternalActions(), |
67 | { | ||
68 | label: this.i18n('Internal actions'), | ||
69 | isHeader: true | ||
70 | }, | ||
71 | { | ||
72 | label: this.i18n('Delete report'), | ||
73 | handler: abuse => this.removeAbuse(abuse) | ||
74 | }, | ||
75 | { | ||
76 | label: this.i18n('Add note'), | ||
77 | handler: abuse => this.openModerationCommentModal(abuse), | ||
78 | isDisplayed: abuse => !abuse.moderationComment | ||
79 | }, | ||
80 | { | ||
81 | label: this.i18n('Update note'), | ||
82 | handler: abuse => this.openModerationCommentModal(abuse), | ||
83 | isDisplayed: abuse => !!abuse.moderationComment | ||
84 | }, | ||
85 | { | ||
86 | label: this.i18n('Mark as accepted'), | ||
87 | handler: abuse => this.updateAbuseState(abuse, AbuseState.ACCEPTED), | ||
88 | isDisplayed: abuse => !this.isAbuseAccepted(abuse) | ||
89 | }, | ||
90 | { | ||
91 | label: this.i18n('Mark as rejected'), | ||
92 | handler: abuse => this.updateAbuseState(abuse, AbuseState.REJECTED), | ||
93 | isDisplayed: abuse => !this.isAbuseRejected(abuse) | ||
94 | } | ||
95 | ], | ||
96 | [ | ||
97 | { | ||
98 | label: this.i18n('Actions for the video'), | ||
99 | isHeader: true, | ||
100 | isDisplayed: abuse => abuse.video && !abuse.video.deleted | ||
101 | }, | ||
102 | { | ||
103 | label: this.i18n('Block video'), | ||
104 | isDisplayed: abuse => abuse.video && !abuse.video.deleted && !abuse.video.blacklisted, | ||
105 | handler: abuse => { | ||
106 | this.videoBlocklistService.blockVideo(abuse.video.id, undefined, true) | ||
107 | .subscribe( | ||
108 | () => { | ||
109 | this.notifier.success(this.i18n('Video blocked.')) | ||
110 | |||
111 | this.updateAbuseState(abuse, AbuseState.ACCEPTED) | ||
112 | }, | ||
113 | |||
114 | err => this.notifier.error(err.message) | ||
115 | ) | ||
116 | } | ||
117 | }, | ||
118 | { | ||
119 | label: this.i18n('Unblock video'), | ||
120 | isDisplayed: abuse => abuse.video && !abuse.video.deleted && abuse.video.blacklisted, | ||
121 | handler: abuse => { | ||
122 | this.videoBlocklistService.unblockVideo(abuse.video.id) | ||
123 | .subscribe( | ||
124 | () => { | ||
125 | this.notifier.success(this.i18n('Video unblocked.')) | ||
126 | |||
127 | this.updateAbuseState(abuse, AbuseState.ACCEPTED) | ||
128 | }, | ||
129 | |||
130 | err => this.notifier.error(err.message) | ||
131 | ) | ||
132 | } | ||
133 | }, | ||
134 | { | ||
135 | label: this.i18n('Delete video'), | ||
136 | isDisplayed: abuse => abuse.video && !abuse.video.deleted, | ||
137 | handler: async abuse => { | ||
138 | const res = await this.confirmService.confirm( | ||
139 | this.i18n('Do you really want to delete this video?'), | ||
140 | this.i18n('Delete') | ||
141 | ) | ||
142 | if (res === false) return | ||
143 | 74 | ||
144 | this.videoService.removeVideo(abuse.video.id) | 75 | this.buildFlaggedAccountActions(), |
145 | .subscribe( | ||
146 | () => { | ||
147 | this.notifier.success(this.i18n('Video deleted.')) | ||
148 | 76 | ||
149 | this.updateAbuseState(abuse, AbuseState.ACCEPTED) | 77 | this.buildCommentActions(), |
150 | }, | ||
151 | 78 | ||
152 | err => this.notifier.error(err.message) | 79 | this.buildVideoActions(), |
153 | ) | 80 | |
154 | } | 81 | this.buildAccountActions() |
155 | } | ||
156 | ], | ||
157 | [ | ||
158 | { | ||
159 | label: this.i18n('Actions for the reporter'), | ||
160 | isHeader: true, | ||
161 | isDisplayed: abuse => !!abuse.reporterAccount | ||
162 | }, | ||
163 | { | ||
164 | label: this.i18n('Mute reporter'), | ||
165 | isDisplayed: abuse => !!abuse.reporterAccount, | ||
166 | handler: async abuse => { | ||
167 | const account = abuse.reporterAccount as Account | ||
168 | |||
169 | this.blocklistService.blockAccountByInstance(account) | ||
170 | .subscribe( | ||
171 | () => { | ||
172 | this.notifier.success( | ||
173 | this.i18n('Account {{nameWithHost}} muted by the instance.', { nameWithHost: account.nameWithHost }) | ||
174 | ) | ||
175 | |||
176 | account.mutedByInstance = true | ||
177 | }, | ||
178 | |||
179 | err => this.notifier.error(err.message) | ||
180 | ) | ||
181 | } | ||
182 | }, | ||
183 | { | ||
184 | label: this.i18n('Mute server'), | ||
185 | isDisplayed: abuse => abuse.reporterAccount && !abuse.reporterAccount.userId, | ||
186 | handler: async abuse => { | ||
187 | this.blocklistService.blockServerByInstance(abuse.reporterAccount.host) | ||
188 | .subscribe( | ||
189 | () => { | ||
190 | this.notifier.success( | ||
191 | this.i18n('Server {{host}} muted by the instance.', { host: abuse.reporterAccount.host }) | ||
192 | ) | ||
193 | }, | ||
194 | |||
195 | err => this.notifier.error(err.message) | ||
196 | ) | ||
197 | } | ||
198 | } | ||
199 | ] | ||
200 | ] | 82 | ] |
201 | } | 83 | } |
202 | 84 | ||
@@ -207,6 +89,8 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn | |||
207 | .subscribe(params => { | 89 | .subscribe(params => { |
208 | this.search = params.search || '' | 90 | this.search = params.search || '' |
209 | 91 | ||
92 | logger('On URL change (search: %s).', this.search) | ||
93 | |||
210 | this.setTableFilter(this.search) | 94 | this.setTableFilter(this.search) |
211 | this.loadData() | 95 | this.loadData() |
212 | }) | 96 | }) |
@@ -264,6 +148,10 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn | |||
264 | return Video.buildClientUrl(abuse.comment.video.uuid) + ';threadId=' + abuse.comment.threadId | 148 | return Video.buildClientUrl(abuse.comment.video.uuid) + ';threadId=' + abuse.comment.threadId |
265 | } | 149 | } |
266 | 150 | ||
151 | getAccountUrl (abuse: ProcessedAbuse) { | ||
152 | return '/accounts/' + abuse.flaggedAccount.nameWithHost | ||
153 | } | ||
154 | |||
267 | getVideoEmbed (abuse: Abuse) { | 155 | getVideoEmbed (abuse: Abuse) { |
268 | return buildVideoEmbed( | 156 | return buildVideoEmbed( |
269 | buildVideoLink({ | 157 | buildVideoLink({ |
@@ -304,6 +192,8 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn | |||
304 | } | 192 | } |
305 | 193 | ||
306 | protected loadData () { | 194 | protected loadData () { |
195 | logger('Load data.') | ||
196 | |||
307 | return this.abuseService.getAbuses({ | 197 | return this.abuseService.getAbuses({ |
308 | pagination: this.pagination, | 198 | pagination: this.pagination, |
309 | sort: this.sort, | 199 | sort: this.sort, |
@@ -356,6 +246,208 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn | |||
356 | ) | 246 | ) |
357 | } | 247 | } |
358 | 248 | ||
249 | private buildInternalActions (): DropdownAction<ProcessedAbuse>[] { | ||
250 | return [ | ||
251 | { | ||
252 | label: this.i18n('Internal actions'), | ||
253 | isHeader: true | ||
254 | }, | ||
255 | { | ||
256 | label: this.i18n('Delete report'), | ||
257 | handler: abuse => this.removeAbuse(abuse) | ||
258 | }, | ||
259 | { | ||
260 | label: this.i18n('Add note'), | ||
261 | handler: abuse => this.openModerationCommentModal(abuse), | ||
262 | isDisplayed: abuse => !abuse.moderationComment | ||
263 | }, | ||
264 | { | ||
265 | label: this.i18n('Update note'), | ||
266 | handler: abuse => this.openModerationCommentModal(abuse), | ||
267 | isDisplayed: abuse => !!abuse.moderationComment | ||
268 | }, | ||
269 | { | ||
270 | label: this.i18n('Mark as accepted'), | ||
271 | handler: abuse => this.updateAbuseState(abuse, AbuseState.ACCEPTED), | ||
272 | isDisplayed: abuse => !this.isAbuseAccepted(abuse) | ||
273 | }, | ||
274 | { | ||
275 | label: this.i18n('Mark as rejected'), | ||
276 | handler: abuse => this.updateAbuseState(abuse, AbuseState.REJECTED), | ||
277 | isDisplayed: abuse => !this.isAbuseRejected(abuse) | ||
278 | } | ||
279 | ] | ||
280 | } | ||
281 | |||
282 | private buildFlaggedAccountActions (): DropdownAction<ProcessedAbuse>[] { | ||
283 | return [ | ||
284 | { | ||
285 | label: this.i18n('Actions for the flagged account'), | ||
286 | isHeader: true, | ||
287 | isDisplayed: abuse => abuse.flaggedAccount && !abuse.comment && !abuse.video | ||
288 | }, | ||
289 | |||
290 | { | ||
291 | label: this.i18n('Mute account'), | ||
292 | isDisplayed: abuse => abuse.flaggedAccount && !abuse.comment && !abuse.video, | ||
293 | handler: abuse => this.muteAccountHelper(abuse.flaggedAccount) | ||
294 | }, | ||
295 | |||
296 | { | ||
297 | label: this.i18n('Mute server account'), | ||
298 | isDisplayed: abuse => abuse.flaggedAccount && !abuse.comment && !abuse.video, | ||
299 | handler: abuse => this.muteServerHelper(abuse.flaggedAccount.host) | ||
300 | } | ||
301 | ] | ||
302 | } | ||
303 | |||
304 | private buildAccountActions (): DropdownAction<ProcessedAbuse>[] { | ||
305 | return [ | ||
306 | { | ||
307 | label: this.i18n('Actions for the reporter'), | ||
308 | isHeader: true, | ||
309 | isDisplayed: abuse => !!abuse.reporterAccount | ||
310 | }, | ||
311 | |||
312 | { | ||
313 | label: this.i18n('Mute reporter'), | ||
314 | isDisplayed: abuse => !!abuse.reporterAccount, | ||
315 | handler: abuse => this.muteAccountHelper(abuse.reporterAccount) | ||
316 | }, | ||
317 | |||
318 | { | ||
319 | label: this.i18n('Mute server'), | ||
320 | isDisplayed: abuse => abuse.reporterAccount && !abuse.reporterAccount.userId, | ||
321 | handler: abuse => this.muteServerHelper(abuse.reporterAccount.host) | ||
322 | } | ||
323 | ] | ||
324 | } | ||
325 | |||
326 | private buildVideoActions (): DropdownAction<ProcessedAbuse>[] { | ||
327 | return [ | ||
328 | { | ||
329 | label: this.i18n('Actions for the video'), | ||
330 | isHeader: true, | ||
331 | isDisplayed: abuse => abuse.video && !abuse.video.deleted | ||
332 | }, | ||
333 | { | ||
334 | label: this.i18n('Block video'), | ||
335 | isDisplayed: abuse => abuse.video && !abuse.video.deleted && !abuse.video.blacklisted, | ||
336 | handler: abuse => { | ||
337 | this.videoBlocklistService.blockVideo(abuse.video.id, undefined, true) | ||
338 | .subscribe( | ||
339 | () => { | ||
340 | this.notifier.success(this.i18n('Video blocked.')) | ||
341 | |||
342 | this.updateAbuseState(abuse, AbuseState.ACCEPTED) | ||
343 | }, | ||
344 | |||
345 | err => this.notifier.error(err.message) | ||
346 | ) | ||
347 | } | ||
348 | }, | ||
349 | { | ||
350 | label: this.i18n('Unblock video'), | ||
351 | isDisplayed: abuse => abuse.video && !abuse.video.deleted && abuse.video.blacklisted, | ||
352 | handler: abuse => { | ||
353 | this.videoBlocklistService.unblockVideo(abuse.video.id) | ||
354 | .subscribe( | ||
355 | () => { | ||
356 | this.notifier.success(this.i18n('Video unblocked.')) | ||
357 | |||
358 | this.updateAbuseState(abuse, AbuseState.ACCEPTED) | ||
359 | }, | ||
360 | |||
361 | err => this.notifier.error(err.message) | ||
362 | ) | ||
363 | } | ||
364 | }, | ||
365 | { | ||
366 | label: this.i18n('Delete video'), | ||
367 | isDisplayed: abuse => abuse.video && !abuse.video.deleted, | ||
368 | handler: async abuse => { | ||
369 | const res = await this.confirmService.confirm( | ||
370 | this.i18n('Do you really want to delete this video?'), | ||
371 | this.i18n('Delete') | ||
372 | ) | ||
373 | if (res === false) return | ||
374 | |||
375 | this.videoService.removeVideo(abuse.video.id) | ||
376 | .subscribe( | ||
377 | () => { | ||
378 | this.notifier.success(this.i18n('Video deleted.')) | ||
379 | |||
380 | this.updateAbuseState(abuse, AbuseState.ACCEPTED) | ||
381 | }, | ||
382 | |||
383 | err => this.notifier.error(err.message) | ||
384 | ) | ||
385 | } | ||
386 | } | ||
387 | ] | ||
388 | } | ||
389 | |||
390 | private buildCommentActions (): DropdownAction<ProcessedAbuse>[] { | ||
391 | return [ | ||
392 | { | ||
393 | label: this.i18n('Actions for the comment'), | ||
394 | isHeader: true, | ||
395 | isDisplayed: abuse => abuse.comment && !abuse.comment.deleted | ||
396 | }, | ||
397 | |||
398 | { | ||
399 | label: this.i18n('Delete comment'), | ||
400 | isDisplayed: abuse => abuse.comment && !abuse.comment.deleted, | ||
401 | handler: async abuse => { | ||
402 | const res = await this.confirmService.confirm( | ||
403 | this.i18n('Do you really want to delete this comment?'), | ||
404 | this.i18n('Delete') | ||
405 | ) | ||
406 | if (res === false) return | ||
407 | |||
408 | this.commentService.deleteVideoComment(abuse.comment.video.id, abuse.comment.id) | ||
409 | .subscribe( | ||
410 | () => { | ||
411 | this.notifier.success(this.i18n('Comment deleted.')) | ||
412 | |||
413 | this.updateAbuseState(abuse, AbuseState.ACCEPTED) | ||
414 | }, | ||
415 | |||
416 | err => this.notifier.error(err.message) | ||
417 | ) | ||
418 | } | ||
419 | } | ||
420 | ] | ||
421 | } | ||
422 | |||
423 | private muteAccountHelper (account: Account) { | ||
424 | this.blocklistService.blockAccountByInstance(account) | ||
425 | .subscribe( | ||
426 | () => { | ||
427 | this.notifier.success( | ||
428 | this.i18n('Account {{nameWithHost}} muted by the instance.', { nameWithHost: account.nameWithHost }) | ||
429 | ) | ||
430 | |||
431 | account.mutedByInstance = true | ||
432 | }, | ||
433 | |||
434 | err => this.notifier.error(err.message) | ||
435 | ) | ||
436 | } | ||
437 | |||
438 | private muteServerHelper (host: string) { | ||
439 | this.blocklistService.blockServerByInstance(host) | ||
440 | .subscribe( | ||
441 | () => { | ||
442 | this.notifier.success( | ||
443 | this.i18n('Server {{host}} muted by the instance.', { host: host }) | ||
444 | ) | ||
445 | }, | ||
446 | |||
447 | err => this.notifier.error(err.message) | ||
448 | ) | ||
449 | } | ||
450 | |||
359 | private toHtml (text: string) { | 451 | private toHtml (text: string) { |
360 | return this.markdownRenderer.textMarkdownToHTML(text) | 452 | return this.markdownRenderer.textMarkdownToHTML(text) |
361 | } | 453 | } |
diff --git a/client/src/app/+admin/moderation/moderation.component.scss b/client/src/app/+admin/moderation/moderation.component.scss index f73c71dc5..65fe94d39 100644 --- a/client/src/app/+admin/moderation/moderation.component.scss +++ b/client/src/app/+admin/moderation/moderation.component.scss | |||
@@ -96,7 +96,8 @@ my-action-dropdown.show { | |||
96 | top: 3px; | 96 | top: 3px; |
97 | } | 97 | } |
98 | 98 | ||
99 | .table-comment-link { | 99 | .table-comment-link, |
100 | .table-account-link { | ||
100 | @include disable-outline; | 101 | @include disable-outline; |
101 | 102 | ||
102 | color: var(--mainForegroundColor); | 103 | color: var(--mainForegroundColor); |
@@ -106,7 +107,13 @@ my-action-dropdown.show { | |||
106 | } | 107 | } |
107 | } | 108 | } |
108 | 109 | ||
109 | .comment-flagged-account { | 110 | .table-account-link { |
111 | display: flex; | ||
112 | flex-direction: column; | ||
113 | } | ||
114 | |||
115 | .comment-flagged-account, | ||
116 | .account-flagged-handle { | ||
110 | font-size: 11px; | 117 | font-size: 11px; |
111 | color: var(--greyForegroundColor); | 118 | color: var(--greyForegroundColor); |
112 | } | 119 | } |