diff options
author | Chocobozzz <me@florianbigard.com> | 2020-05-19 10:24:36 +0200 |
---|---|---|
committer | Chocobozzz <chocobozzz@cpy.re> | 2020-05-29 09:21:26 +0200 |
commit | 923ff87da2761fd88a8ca269ac1ef403abb583d2 (patch) | |
tree | 506ee2a83cb21e5303d486afefde7542f3207dbf /client/src | |
parent | 444c0a0e017824fb4ce526281a22c4abe0a13c50 (diff) | |
download | PeerTube-923ff87da2761fd88a8ca269ac1ef403abb583d2.tar.gz PeerTube-923ff87da2761fd88a8ca269ac1ef403abb583d2.tar.zst PeerTube-923ff87da2761fd88a8ca269ac1ef403abb583d2.zip |
Add bulk comment actions on account dropdown
Diffstat (limited to 'client/src')
-rw-r--r-- | client/src/app/shared/bulk/bulk.service.ts | 24 | ||||
-rw-r--r-- | client/src/app/shared/moderation/user-moderation-dropdown.component.ts | 38 | ||||
-rw-r--r-- | client/src/app/shared/shared.module.ts | 145 |
3 files changed, 132 insertions, 75 deletions
diff --git a/client/src/app/shared/bulk/bulk.service.ts b/client/src/app/shared/bulk/bulk.service.ts new file mode 100644 index 000000000..b00db31ec --- /dev/null +++ b/client/src/app/shared/bulk/bulk.service.ts | |||
@@ -0,0 +1,24 @@ | |||
1 | import { HttpClient } from '@angular/common/http' | ||
2 | import { Injectable } from '@angular/core' | ||
3 | import { environment } from '../../../environments/environment' | ||
4 | import { RestExtractor, RestService } from '../rest' | ||
5 | import { BulkRemoveCommentsOfBody } from '../../../../../shared' | ||
6 | import { catchError } from 'rxjs/operators' | ||
7 | |||
8 | @Injectable() | ||
9 | export class BulkService { | ||
10 | static BASE_BULK_URL = environment.apiUrl + '/api/v1/bulk' | ||
11 | |||
12 | constructor ( | ||
13 | private authHttp: HttpClient, | ||
14 | private restExtractor: RestExtractor, | ||
15 | private restService: RestService | ||
16 | ) { } | ||
17 | |||
18 | removeCommentsOf (body: BulkRemoveCommentsOfBody) { | ||
19 | const url = BulkService.BASE_BULK_URL + '/remove-comments-of' | ||
20 | |||
21 | return this.authHttp.post(url, body) | ||
22 | .pipe(catchError(err => this.restExtractor.handleError(err))) | ||
23 | } | ||
24 | } | ||
diff --git a/client/src/app/shared/moderation/user-moderation-dropdown.component.ts b/client/src/app/shared/moderation/user-moderation-dropdown.component.ts index f8ad7ce13..82f39050e 100644 --- a/client/src/app/shared/moderation/user-moderation-dropdown.component.ts +++ b/client/src/app/shared/moderation/user-moderation-dropdown.component.ts | |||
@@ -7,7 +7,8 @@ import { AuthService, ConfirmService, Notifier, ServerService } from '@app/core' | |||
7 | import { User, UserRight } from '../../../../../shared/models/users' | 7 | import { User, UserRight } from '../../../../../shared/models/users' |
8 | import { Account } from '@app/shared/account/account.model' | 8 | import { Account } from '@app/shared/account/account.model' |
9 | import { BlocklistService } from '@app/shared/blocklist' | 9 | import { BlocklistService } from '@app/shared/blocklist' |
10 | import { ServerConfig } from '@shared/models' | 10 | import { ServerConfig, BulkRemoveCommentsOfBody } from '@shared/models' |
11 | import { BulkService } from '../bulk/bulk.service' | ||
11 | 12 | ||
12 | @Component({ | 13 | @Component({ |
13 | selector: 'my-user-moderation-dropdown', | 14 | selector: 'my-user-moderation-dropdown', |
@@ -38,6 +39,7 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges { | |||
38 | private serverService: ServerService, | 39 | private serverService: ServerService, |
39 | private userService: UserService, | 40 | private userService: UserService, |
40 | private blocklistService: BlocklistService, | 41 | private blocklistService: BlocklistService, |
42 | private bulkService: BulkService, | ||
41 | private i18n: I18n | 43 | private i18n: I18n |
42 | ) { } | 44 | ) { } |
43 | 45 | ||
@@ -229,6 +231,21 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges { | |||
229 | ) | 231 | ) |
230 | } | 232 | } |
231 | 233 | ||
234 | async bulkRemoveCommentsOf (body: BulkRemoveCommentsOfBody) { | ||
235 | const message = this.i18n('Are you sure you want to remove all the comments of this account?') | ||
236 | const res = await this.confirmService.confirm(message, this.i18n('Delete account comments')) | ||
237 | if (res === false) return | ||
238 | |||
239 | this.bulkService.removeCommentsOf(body) | ||
240 | .subscribe( | ||
241 | () => { | ||
242 | this.notifier.success(this.i18n('Will remove comments of this account (may take several minutes).')) | ||
243 | }, | ||
244 | |||
245 | err => this.notifier.error(err.message) | ||
246 | ) | ||
247 | } | ||
248 | |||
232 | getRouterUserEditLink (user: User) { | 249 | getRouterUserEditLink (user: User) { |
233 | return [ '/admin', 'users', 'update', user.id ] | 250 | return [ '/admin', 'users', 'update', user.id ] |
234 | } | 251 | } |
@@ -300,12 +317,17 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges { | |||
300 | description: this.i18n('Show back content from that instance for you.'), | 317 | description: this.i18n('Show back content from that instance for you.'), |
301 | isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === true, | 318 | isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === true, |
302 | handler: ({ account }) => this.unblockServerByUser(account.host) | 319 | handler: ({ account }) => this.unblockServerByUser(account.host) |
320 | }, | ||
321 | { | ||
322 | label: this.i18n('Remove comments from your videos'), | ||
323 | description: this.i18n('Remove comments of this account from your videos.'), | ||
324 | handler: ({ account }) => this.bulkRemoveCommentsOf({ accountName: account.nameWithHost, scope: 'my-videos' }) | ||
303 | } | 325 | } |
304 | ]) | 326 | ]) |
305 | 327 | ||
306 | let instanceActions: DropdownAction<{ user: User, account: Account }>[] = [] | 328 | let instanceActions: DropdownAction<{ user: User, account: Account }>[] = [] |
307 | 329 | ||
308 | // Instance actions | 330 | // Instance actions on account blocklists |
309 | if (authUser.hasRight(UserRight.MANAGE_ACCOUNTS_BLOCKLIST)) { | 331 | if (authUser.hasRight(UserRight.MANAGE_ACCOUNTS_BLOCKLIST)) { |
310 | instanceActions = instanceActions.concat([ | 332 | instanceActions = instanceActions.concat([ |
311 | { | 333 | { |
@@ -323,7 +345,7 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges { | |||
323 | ]) | 345 | ]) |
324 | } | 346 | } |
325 | 347 | ||
326 | // Instance actions | 348 | // Instance actions on server blocklists |
327 | if (authUser.hasRight(UserRight.MANAGE_SERVERS_BLOCKLIST)) { | 349 | if (authUser.hasRight(UserRight.MANAGE_SERVERS_BLOCKLIST)) { |
328 | instanceActions = instanceActions.concat([ | 350 | instanceActions = instanceActions.concat([ |
329 | { | 351 | { |
@@ -341,6 +363,16 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges { | |||
341 | ]) | 363 | ]) |
342 | } | 364 | } |
343 | 365 | ||
366 | if (authUser.hasRight(UserRight.REMOVE_ANY_VIDEO_COMMENT)) { | ||
367 | instanceActions = instanceActions.concat([ | ||
368 | { | ||
369 | label: this.i18n('Remove comments from your instance'), | ||
370 | description: this.i18n('Remove comments of this account from your instance.'), | ||
371 | handler: ({ account }) => this.bulkRemoveCommentsOf({ accountName: account.nameWithHost, scope: 'instance' }) | ||
372 | } | ||
373 | ]) | ||
374 | } | ||
375 | |||
344 | if (instanceActions.length !== 0) { | 376 | if (instanceActions.length !== 0) { |
345 | this.userActions.push(instanceActions) | 377 | this.userActions.push(instanceActions) |
346 | } | 378 | } |
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index 01735c187..813f76672 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts | |||
@@ -1,32 +1,30 @@ | |||
1 | import { BytesPipe, KeysPipe, NgPipesModule } from 'ngx-pipes' | ||
2 | import { SharedModule as PrimeSharedModule } from 'primeng/api' | ||
3 | import { InputMaskModule } from 'primeng/inputmask' | ||
4 | import { InputSwitchModule } from 'primeng/inputswitch' | ||
5 | import { MultiSelectModule } from 'primeng/multiselect' | ||
6 | import { ClipboardModule } from '@angular/cdk/clipboard' | ||
1 | import { CommonModule } from '@angular/common' | 7 | import { CommonModule } from '@angular/common' |
2 | import { HttpClientModule } from '@angular/common/http' | 8 | import { HttpClientModule } from '@angular/common/http' |
3 | import { NgModule } from '@angular/core' | 9 | import { NgModule } from '@angular/core' |
4 | import { FormsModule, ReactiveFormsModule } from '@angular/forms' | 10 | import { FormsModule, ReactiveFormsModule } from '@angular/forms' |
5 | import { RouterModule } from '@angular/router' | 11 | import { RouterModule } from '@angular/router' |
6 | import { MarkdownTextareaComponent } from '@app/shared/forms/markdown-textarea.component' | 12 | import { BatchDomainsValidatorsService } from '@app/+admin/config/shared/batch-domains-validators.service' |
7 | import { HelpComponent } from '@app/shared/misc/help.component' | 13 | import { MyAccountInterfaceSettingsComponent } from '@app/+my-account/my-account-settings/my-account-interface' |
8 | import { ListOverflowComponent } from '@app/shared/misc/list-overflow.component' | 14 | import { MyAccountVideoSettingsComponent } from '@app/+my-account/my-account-settings/my-account-video-settings' |
9 | import { InfiniteScrollerDirective } from '@app/shared/video/infinite-scroller.directive' | 15 | import { ActorAvatarInfoComponent } from '@app/+my-account/shared/actor-avatar-info.component' |
10 | import { BytesPipe, KeysPipe, NgPipesModule } from 'ngx-pipes' | ||
11 | import { SharedModule as PrimeSharedModule } from 'primeng/api' | ||
12 | import { AUTH_INTERCEPTOR_PROVIDER } from './auth' | ||
13 | import { ButtonComponent } from './buttons/button.component' | ||
14 | import { DeleteButtonComponent } from './buttons/delete-button.component' | ||
15 | import { EditButtonComponent } from './buttons/edit-button.component' | ||
16 | import { LoaderComponent } from './misc/loader.component' | ||
17 | import { RestExtractor, RestService } from './rest' | ||
18 | import { UserService } from './users' | ||
19 | import { VideoAbuseService } from './video-abuse' | ||
20 | import { VideoBlacklistService } from './video-blacklist' | ||
21 | import { VideoOwnershipService } from './video-ownership' | ||
22 | import { VideoMiniatureComponent } from './video/video-miniature.component' | ||
23 | import { FeedComponent } from './video/feed.component' | ||
24 | import { VideoThumbnailComponent } from './video/video-thumbnail.component' | ||
25 | import { VideoService } from './video/video.service' | ||
26 | import { AccountService } from '@app/shared/account/account.service' | 16 | import { AccountService } from '@app/shared/account/account.service' |
27 | import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' | 17 | import { FromNowPipe } from '@app/shared/angular/from-now.pipe' |
28 | import { I18n } from '@ngx-translate/i18n-polyfill' | 18 | import { HighlightPipe } from '@app/shared/angular/highlight.pipe' |
29 | import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' | 19 | import { NumberFormatterPipe } from '@app/shared/angular/number-formatter.pipe' |
20 | import { ObjectLengthPipe } from '@app/shared/angular/object-length.pipe' | ||
21 | import { PeerTubeTemplateDirective } from '@app/shared/angular/peertube-template.directive' | ||
22 | import { VideoDurationPipe } from '@app/shared/angular/video-duration-formatter.pipe' | ||
23 | import { BlocklistService } from '@app/shared/blocklist' | ||
24 | import { ActionDropdownComponent } from '@app/shared/buttons/action-dropdown.component' | ||
25 | import { AvatarComponent } from '@app/shared/channel/avatar.component' | ||
26 | import { ConfirmComponent } from '@app/shared/confirm/confirm.component' | ||
27 | import { DateToggleComponent } from '@app/shared/date/date-toggle.component' | ||
30 | import { | 28 | import { |
31 | CustomConfigValidatorsService, | 29 | CustomConfigValidatorsService, |
32 | InstanceValidatorsService, | 30 | InstanceValidatorsService, |
@@ -44,70 +42,72 @@ import { | |||
44 | VideoPlaylistValidatorsService, | 42 | VideoPlaylistValidatorsService, |
45 | VideoValidatorsService | 43 | VideoValidatorsService |
46 | } from '@app/shared/forms' | 44 | } from '@app/shared/forms' |
47 | import { I18nPrimengCalendarService } from '@app/shared/i18n/i18n-primeng-calendar' | 45 | import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' |
48 | import { InputMaskModule } from 'primeng/inputmask' | ||
49 | import { ScreenService } from '@app/shared/misc/screen.service' | ||
50 | import { LocalStorageService, SessionStorageService } from '@app/shared/misc/storage.service' | ||
51 | import { VideoCaptionsValidatorsService } from '@app/shared/forms/form-validators/video-captions-validators.service' | 46 | import { VideoCaptionsValidatorsService } from '@app/shared/forms/form-validators/video-captions-validators.service' |
52 | import { VideoCaptionService } from '@app/shared/video-caption' | 47 | import { InputReadonlyCopyComponent } from '@app/shared/forms/input-readonly-copy.component' |
48 | import { MarkdownTextareaComponent } from '@app/shared/forms/markdown-textarea.component' | ||
53 | import { PeertubeCheckboxComponent } from '@app/shared/forms/peertube-checkbox.component' | 49 | import { PeertubeCheckboxComponent } from '@app/shared/forms/peertube-checkbox.component' |
54 | import { VideoImportService } from '@app/shared/video-import/video-import.service' | 50 | import { TimestampInputComponent } from '@app/shared/forms/timestamp-input.component' |
55 | import { ActionDropdownComponent } from '@app/shared/buttons/action-dropdown.component' | 51 | import { I18nPrimengCalendarService } from '@app/shared/i18n/i18n-primeng-calendar' |
56 | import { | 52 | import { GlobalIconComponent } from '@app/shared/images/global-icon.component' |
57 | NgbCollapseModule, | 53 | import { PreviewUploadComponent } from '@app/shared/images/preview-upload.component' |
58 | NgbDropdownModule, | 54 | import { FeatureBooleanComponent } from '@app/shared/instance/feature-boolean.component' |
59 | NgbModalModule, | 55 | import { FollowService } from '@app/shared/instance/follow.service' |
60 | NgbPopoverModule, | ||
61 | NgbNavModule, | ||
62 | NgbTooltipModule | ||
63 | } from '@ng-bootstrap/ng-bootstrap' | ||
64 | import { RemoteSubscribeComponent, SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/user-subscription' | ||
65 | import { InstanceFeaturesTableComponent } from '@app/shared/instance/instance-features-table.component' | 56 | import { InstanceFeaturesTableComponent } from '@app/shared/instance/instance-features-table.component' |
66 | import { InstanceStatisticsComponent } from '@app/shared/instance/instance-statistics.component' | 57 | import { InstanceStatisticsComponent } from '@app/shared/instance/instance-statistics.component' |
67 | import { OverviewService } from '@app/shared/overview' | 58 | import { InstanceService } from '@app/shared/instance/instance.service' |
59 | import { TopMenuDropdownComponent } from '@app/shared/menu/top-menu-dropdown.component' | ||
60 | import { HelpComponent } from '@app/shared/misc/help.component' | ||
61 | import { ListOverflowComponent } from '@app/shared/misc/list-overflow.component' | ||
62 | import { ScreenService } from '@app/shared/misc/screen.service' | ||
63 | import { SmallLoaderComponent } from '@app/shared/misc/small-loader.component' | ||
64 | import { LocalStorageService, SessionStorageService } from '@app/shared/misc/storage.service' | ||
68 | import { UserBanModalComponent } from '@app/shared/moderation' | 65 | import { UserBanModalComponent } from '@app/shared/moderation' |
69 | import { UserModerationDropdownComponent } from '@app/shared/moderation/user-moderation-dropdown.component' | 66 | import { UserModerationDropdownComponent } from '@app/shared/moderation/user-moderation-dropdown.component' |
70 | import { BlocklistService } from '@app/shared/blocklist' | 67 | import { OverviewService } from '@app/shared/overview' |
71 | import { AvatarComponent } from '@app/shared/channel/avatar.component' | 68 | import { HtmlRendererService, LinkifierService, MarkdownService } from '@app/shared/renderer' |
72 | import { TopMenuDropdownComponent } from '@app/shared/menu/top-menu-dropdown.component' | 69 | import { RemoteSubscribeComponent, SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/user-subscription' |
73 | import { UserHistoryService } from '@app/shared/users/user-history.service' | 70 | import { UserHistoryService } from '@app/shared/users/user-history.service' |
74 | import { UserNotificationService } from '@app/shared/users/user-notification.service' | 71 | import { UserNotificationService } from '@app/shared/users/user-notification.service' |
75 | import { UserNotificationsComponent } from '@app/shared/users/user-notifications.component' | 72 | import { UserNotificationsComponent } from '@app/shared/users/user-notifications.component' |
76 | import { InstanceService } from '@app/shared/instance/instance.service' | 73 | import { VideoCaptionService } from '@app/shared/video-caption' |
77 | import { HtmlRendererService, LinkifierService, MarkdownService } from '@app/shared/renderer' | 74 | import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' |
78 | import { ConfirmComponent } from '@app/shared/confirm/confirm.component' | 75 | import { VideoImportService } from '@app/shared/video-import/video-import.service' |
79 | import { DateToggleComponent } from '@app/shared/date/date-toggle.component' | ||
80 | import { SmallLoaderComponent } from '@app/shared/misc/small-loader.component' | ||
81 | import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' | ||
82 | import { PreviewUploadComponent } from '@app/shared/images/preview-upload.component' | ||
83 | import { GlobalIconComponent } from '@app/shared/images/global-icon.component' | ||
84 | import { VideoPlaylistMiniatureComponent } from '@app/shared/video-playlist/video-playlist-miniature.component' | ||
85 | import { VideoAddToPlaylistComponent } from '@app/shared/video-playlist/video-add-to-playlist.component' | 76 | import { VideoAddToPlaylistComponent } from '@app/shared/video-playlist/video-add-to-playlist.component' |
86 | import { TimestampInputComponent } from '@app/shared/forms/timestamp-input.component' | ||
87 | import { VideoPlaylistElementMiniatureComponent } from '@app/shared/video-playlist/video-playlist-element-miniature.component' | 77 | import { VideoPlaylistElementMiniatureComponent } from '@app/shared/video-playlist/video-playlist-element-miniature.component' |
88 | import { VideosSelectionComponent } from '@app/shared/video/videos-selection.component' | 78 | import { VideoPlaylistMiniatureComponent } from '@app/shared/video-playlist/video-playlist-miniature.component' |
89 | import { NumberFormatterPipe } from '@app/shared/angular/number-formatter.pipe' | 79 | import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' |
90 | import { VideoDurationPipe } from '@app/shared/angular/video-duration-formatter.pipe' | 80 | import { InfiniteScrollerDirective } from '@app/shared/video/infinite-scroller.directive' |
91 | import { ObjectLengthPipe } from '@app/shared/angular/object-length.pipe' | ||
92 | import { FromNowPipe } from '@app/shared/angular/from-now.pipe' | ||
93 | import { HighlightPipe } from '@app/shared/angular/highlight.pipe' | ||
94 | import { PeerTubeTemplateDirective } from '@app/shared/angular/peertube-template.directive' | ||
95 | import { VideoActionsDropdownComponent } from '@app/shared/video/video-actions-dropdown.component' | ||
96 | import { VideoBlacklistComponent } from '@app/shared/video/modals/video-blacklist.component' | 81 | import { VideoBlacklistComponent } from '@app/shared/video/modals/video-blacklist.component' |
97 | import { VideoDownloadComponent } from '@app/shared/video/modals/video-download.component' | 82 | import { VideoDownloadComponent } from '@app/shared/video/modals/video-download.component' |
98 | import { VideoReportComponent } from '@app/shared/video/modals/video-report.component' | 83 | import { VideoReportComponent } from '@app/shared/video/modals/video-report.component' |
99 | import { FollowService } from '@app/shared/instance/follow.service' | ||
100 | import { MultiSelectModule } from 'primeng/multiselect' | ||
101 | import { FeatureBooleanComponent } from '@app/shared/instance/feature-boolean.component' | ||
102 | import { InputReadonlyCopyComponent } from '@app/shared/forms/input-readonly-copy.component' | ||
103 | import { RedundancyService } from '@app/shared/video/redundancy.service' | 84 | import { RedundancyService } from '@app/shared/video/redundancy.service' |
104 | import { ClipboardModule } from '@angular/cdk/clipboard' | 85 | import { VideoActionsDropdownComponent } from '@app/shared/video/video-actions-dropdown.component' |
105 | import { InputSwitchModule } from 'primeng/inputswitch' | 86 | import { VideosSelectionComponent } from '@app/shared/video/videos-selection.component' |
106 | 87 | import { | |
107 | import { MyAccountVideoSettingsComponent } from '@app/+my-account/my-account-settings/my-account-video-settings' | 88 | NgbCollapseModule, |
108 | import { MyAccountInterfaceSettingsComponent } from '@app/+my-account/my-account-settings/my-account-interface' | 89 | NgbDropdownModule, |
109 | import { ActorAvatarInfoComponent } from '@app/+my-account/shared/actor-avatar-info.component' | 90 | NgbModalModule, |
110 | import { BatchDomainsValidatorsService } from '@app/+admin/config/shared/batch-domains-validators.service' | 91 | NgbNavModule, |
92 | NgbPopoverModule, | ||
93 | NgbTooltipModule | ||
94 | } from '@ng-bootstrap/ng-bootstrap' | ||
95 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
96 | import { AUTH_INTERCEPTOR_PROVIDER } from './auth' | ||
97 | import { BulkService } from './bulk/bulk.service' | ||
98 | import { ButtonComponent } from './buttons/button.component' | ||
99 | import { DeleteButtonComponent } from './buttons/delete-button.component' | ||
100 | import { EditButtonComponent } from './buttons/edit-button.component' | ||
101 | import { LoaderComponent } from './misc/loader.component' | ||
102 | import { RestExtractor, RestService } from './rest' | ||
103 | import { UserService } from './users' | ||
104 | import { VideoAbuseService } from './video-abuse' | ||
105 | import { VideoBlacklistService } from './video-blacklist' | ||
106 | import { VideoOwnershipService } from './video-ownership' | ||
107 | import { FeedComponent } from './video/feed.component' | ||
108 | import { VideoMiniatureComponent } from './video/video-miniature.component' | ||
109 | import { VideoThumbnailComponent } from './video/video-thumbnail.component' | ||
110 | import { VideoService } from './video/video.service' | ||
111 | 111 | ||
112 | @NgModule({ | 112 | @NgModule({ |
113 | imports: [ | 113 | imports: [ |
@@ -313,6 +313,7 @@ import { BatchDomainsValidatorsService } from '@app/+admin/config/shared/batch-d | |||
313 | BlocklistService, | 313 | BlocklistService, |
314 | UserHistoryService, | 314 | UserHistoryService, |
315 | InstanceService, | 315 | InstanceService, |
316 | BulkService, | ||
316 | 317 | ||
317 | MarkdownService, | 318 | MarkdownService, |
318 | LinkifierService, | 319 | LinkifierService, |