Only reset selection / filters if no menus open
This commit is contained in:
parent
ae5639cf96
commit
1f25d7aa69
@ -135,4 +135,10 @@ describe('DateDropdownComponent', () => {
|
|||||||
input.dispatchEvent(event)
|
input.dispatchEvent(event)
|
||||||
expect(eventSpy).toHaveBeenCalled()
|
expect(eventSpy).toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should correctly pass open state', () => {
|
||||||
|
expect(component.isOpen()).toBeFalsy()
|
||||||
|
component.dropdown.open()
|
||||||
|
expect(component.isOpen()).toBeTruthy()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -5,8 +5,9 @@ import {
|
|||||||
Output,
|
Output,
|
||||||
OnInit,
|
OnInit,
|
||||||
OnDestroy,
|
OnDestroy,
|
||||||
|
ViewChild,
|
||||||
} from '@angular/core'
|
} from '@angular/core'
|
||||||
import { NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbDateAdapter, NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { Subject, Subscription } from 'rxjs'
|
import { Subject, Subscription } from 'rxjs'
|
||||||
import { debounceTime } from 'rxjs/operators'
|
import { debounceTime } from 'rxjs/operators'
|
||||||
import { SettingsService } from 'src/app/services/settings.service'
|
import { SettingsService } from 'src/app/services/settings.service'
|
||||||
@ -88,6 +89,8 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
|
|||||||
@Input()
|
@Input()
|
||||||
disabled: boolean = false
|
disabled: boolean = false
|
||||||
|
|
||||||
|
@ViewChild(NgbDropdown) dropdown: NgbDropdown
|
||||||
|
|
||||||
get isActive(): boolean {
|
get isActive(): boolean {
|
||||||
return (
|
return (
|
||||||
this.relativeDate !== null ||
|
this.relativeDate !== null ||
|
||||||
@ -96,6 +99,10 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isOpen(): boolean {
|
||||||
|
return this.dropdown.isOpen()
|
||||||
|
}
|
||||||
|
|
||||||
private datesSetDebounce$ = new Subject()
|
private datesSetDebounce$ = new Subject()
|
||||||
|
|
||||||
private sub: Subscription
|
private sub: Subscription
|
||||||
|
@ -577,4 +577,13 @@ describe('FilterableDropdownComponent & FilterableDropdownSelectionModel', () =>
|
|||||||
expect(selectionModel.getSelectedItems()).toEqual([items[0]])
|
expect(selectionModel.getSelectedItems()).toEqual([items[0]])
|
||||||
expect(selectionModel.getExcludedItems()).toEqual([items[1]])
|
expect(selectionModel.getExcludedItems()).toEqual([items[1]])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should correctly pass open state', () => {
|
||||||
|
component.items = items
|
||||||
|
component.icon = 'tag-fill'
|
||||||
|
fixture.detectChanges()
|
||||||
|
expect(component.isOpen()).toBeFalsy()
|
||||||
|
component.dropdown.open()
|
||||||
|
expect(component.isOpen()).toBeTruthy()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -425,6 +425,10 @@ export class FilterableDropdownComponent {
|
|||||||
|
|
||||||
modelIsDirty: boolean = false
|
modelIsDirty: boolean = false
|
||||||
|
|
||||||
|
public isOpen(): boolean {
|
||||||
|
return this.dropdown.isOpen()
|
||||||
|
}
|
||||||
|
|
||||||
private keyboardIndex: number
|
private keyboardIndex: number
|
||||||
|
|
||||||
constructor(private filterPipe: FilterPipe) {
|
constructor(private filterPipe: FilterPipe) {
|
||||||
|
@ -165,4 +165,10 @@ describe('PermissionsFilterDropdownComponent', () => {
|
|||||||
userID: null,
|
userID: null,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should correctly pass open state', () => {
|
||||||
|
expect(component.isOpen()).toBeFalsy()
|
||||||
|
component.dropdown.open()
|
||||||
|
expect(component.isOpen()).toBeTruthy()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
import { Component, EventEmitter, Input, Output } from '@angular/core'
|
import {
|
||||||
|
Component,
|
||||||
|
EventEmitter,
|
||||||
|
Input,
|
||||||
|
Output,
|
||||||
|
ViewChild,
|
||||||
|
} from '@angular/core'
|
||||||
import { first } from 'rxjs'
|
import { first } from 'rxjs'
|
||||||
import { User } from 'src/app/data/user'
|
import { User } from 'src/app/data/user'
|
||||||
import {
|
import {
|
||||||
@ -9,6 +15,7 @@ import {
|
|||||||
import { UserService } from 'src/app/services/rest/user.service'
|
import { UserService } from 'src/app/services/rest/user.service'
|
||||||
import { SettingsService } from 'src/app/services/settings.service'
|
import { SettingsService } from 'src/app/services/settings.service'
|
||||||
import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component'
|
import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component'
|
||||||
|
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
|
||||||
export class PermissionsSelectionModel {
|
export class PermissionsSelectionModel {
|
||||||
ownerFilter: OwnerFilterType
|
ownerFilter: OwnerFilterType
|
||||||
@ -59,6 +66,8 @@ export class PermissionsFilterDropdownComponent extends ComponentWithPermissions
|
|||||||
|
|
||||||
hideUnowned: boolean
|
hideUnowned: boolean
|
||||||
|
|
||||||
|
@ViewChild(NgbDropdown) dropdown: NgbDropdown
|
||||||
|
|
||||||
get isActive(): boolean {
|
get isActive(): boolean {
|
||||||
return (
|
return (
|
||||||
this.selectionModel.ownerFilter !== OwnerFilterType.NONE ||
|
this.selectionModel.ownerFilter !== OwnerFilterType.NONE ||
|
||||||
@ -66,6 +75,10 @@ export class PermissionsFilterDropdownComponent extends ComponentWithPermissions
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isOpen(): boolean {
|
||||||
|
return this.dropdown.isOpen()
|
||||||
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public permissionsService: PermissionsService,
|
public permissionsService: PermissionsService,
|
||||||
userService: UserService,
|
userService: UserService,
|
||||||
|
@ -1179,4 +1179,16 @@ describe('BulkEditorComponent', () => {
|
|||||||
)
|
)
|
||||||
expect(component.storagePaths).toEqual(storagePaths.results)
|
expect(component.storagePaths).toEqual(storagePaths.results)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should correctly pass open state from dropdowns', () => {
|
||||||
|
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||||
|
fixture.detectChanges()
|
||||||
|
expect(component.hasOpenMenu).toBeFalsy()
|
||||||
|
component.filterableDropdowns = [
|
||||||
|
{
|
||||||
|
isOpen: () => true,
|
||||||
|
} as any,
|
||||||
|
]
|
||||||
|
expect(component.hasOpenMenu).toBeTruthy()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, OnDestroy, OnInit } from '@angular/core'
|
import { Component, OnDestroy, OnInit, ViewChildren } from '@angular/core'
|
||||||
import { Tag } from 'src/app/data/tag'
|
import { Tag } from 'src/app/data/tag'
|
||||||
import { Correspondent } from 'src/app/data/correspondent'
|
import { Correspondent } from 'src/app/data/correspondent'
|
||||||
import { DocumentType } from 'src/app/data/document-type'
|
import { DocumentType } from 'src/app/data/document-type'
|
||||||
@ -6,7 +6,7 @@ import { TagService } from 'src/app/services/rest/tag.service'
|
|||||||
import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
|
import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
|
||||||
import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
|
import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
|
||||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
|
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
|
||||||
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbDropdown, NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import {
|
import {
|
||||||
DocumentService,
|
DocumentService,
|
||||||
SelectionDataItem,
|
SelectionDataItem,
|
||||||
@ -15,6 +15,7 @@ import { OpenDocumentsService } from 'src/app/services/open-documents.service'
|
|||||||
import { ConfirmDialogComponent } from 'src/app/components/common/confirm-dialog/confirm-dialog.component'
|
import { ConfirmDialogComponent } from 'src/app/components/common/confirm-dialog/confirm-dialog.component'
|
||||||
import {
|
import {
|
||||||
ChangedItems,
|
ChangedItems,
|
||||||
|
FilterableDropdownComponent,
|
||||||
FilterableDropdownSelectionModel,
|
FilterableDropdownSelectionModel,
|
||||||
} from '../../common/filterable-dropdown/filterable-dropdown.component'
|
} from '../../common/filterable-dropdown/filterable-dropdown.component'
|
||||||
import { ToggleableItemState } from '../../common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component'
|
import { ToggleableItemState } from '../../common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component'
|
||||||
@ -74,6 +75,10 @@ export class BulkEditorComponent
|
|||||||
downloadUseFormatting: new FormControl(false),
|
downloadUseFormatting: new FormControl(false),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ViewChildren(NgbDropdown) dropdowns: NgbDropdown[]
|
||||||
|
@ViewChildren(FilterableDropdownComponent)
|
||||||
|
filterableDropdowns: FilterableDropdownComponent[]
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private documentTypeService: DocumentTypeService,
|
private documentTypeService: DocumentTypeService,
|
||||||
private tagService: TagService,
|
private tagService: TagService,
|
||||||
@ -121,6 +126,13 @@ export class BulkEditorComponent
|
|||||||
return ownsAll
|
return ownsAll
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get hasOpenMenu(): boolean {
|
||||||
|
return (
|
||||||
|
this.filterableDropdowns.some((d) => d.isOpen()) ||
|
||||||
|
this.dropdowns.some((d) => d.isOpen())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (
|
if (
|
||||||
this.permissionService.currentUserCan(
|
this.permissionService.currentUserCan(
|
||||||
|
@ -81,7 +81,7 @@
|
|||||||
|
|
||||||
<div class="row sticky-top py-3 mt-n2 mt-md-n3 bg-body">
|
<div class="row sticky-top py-3 mt-n2 mt-md-n3 bg-body">
|
||||||
<pngx-filter-editor [hidden]="isBulkEditing" [(filterRules)]="list.filterRules" [unmodifiedFilterRules]="unmodifiedFilterRules" [selectionData]="list.selectionData" #filterEditor></pngx-filter-editor>
|
<pngx-filter-editor [hidden]="isBulkEditing" [(filterRules)]="list.filterRules" [unmodifiedFilterRules]="unmodifiedFilterRules" [selectionData]="list.selectionData" #filterEditor></pngx-filter-editor>
|
||||||
<pngx-bulk-editor [hidden]="!isBulkEditing"></pngx-bulk-editor>
|
<pngx-bulk-editor [hidden]="!isBulkEditing" #bulkEditor></pngx-bulk-editor>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
@ -630,4 +630,15 @@ describe('DocumentListComponent', () => {
|
|||||||
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'o' }))
|
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'o' }))
|
||||||
expect(detailSpy).toHaveBeenCalledWith(docs[0])
|
expect(detailSpy).toHaveBeenCalledWith(docs[0])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should ignore escape hotkey if there is a filter or bulk editor menu to close', () => {
|
||||||
|
fixture.detectChanges()
|
||||||
|
jest
|
||||||
|
.spyOn(component['filterEditor'], 'hasOpenMenu', 'get')
|
||||||
|
.mockReturnValue(true)
|
||||||
|
const resetSpy = jest.spyOn(component['filterEditor'], 'resetSelected')
|
||||||
|
component.clickTag(1)
|
||||||
|
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'escape' }))
|
||||||
|
expect(resetSpy).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
ViewChildren,
|
ViewChildren,
|
||||||
} from '@angular/core'
|
} from '@angular/core'
|
||||||
import { ActivatedRoute, convertToParamMap, Router } from '@angular/router'
|
import { ActivatedRoute, convertToParamMap, Router } from '@angular/router'
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbDropdown, NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { filter, first, map, Subject, switchMap, takeUntil } from 'rxjs'
|
import { filter, first, map, Subject, switchMap, takeUntil } from 'rxjs'
|
||||||
import { FilterRule } from 'src/app/data/filter-rule'
|
import { FilterRule } from 'src/app/data/filter-rule'
|
||||||
import {
|
import {
|
||||||
@ -37,6 +37,7 @@ import { ComponentWithPermissions } from '../with-permissions/with-permissions.c
|
|||||||
import { FilterEditorComponent } from './filter-editor/filter-editor.component'
|
import { FilterEditorComponent } from './filter-editor/filter-editor.component'
|
||||||
import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component'
|
import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component'
|
||||||
import { HotKeyService } from 'src/app/services/hot-key.service'
|
import { HotKeyService } from 'src/app/services/hot-key.service'
|
||||||
|
import { BulkEditorComponent } from './bulk-editor/bulk-editor.component'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'pngx-document-list',
|
selector: 'pngx-document-list',
|
||||||
@ -66,8 +67,13 @@ export class DocumentListComponent
|
|||||||
@ViewChild('filterEditor')
|
@ViewChild('filterEditor')
|
||||||
private filterEditor: FilterEditorComponent
|
private filterEditor: FilterEditorComponent
|
||||||
|
|
||||||
|
@ViewChild('bulkEditor')
|
||||||
|
private bulkEditor: BulkEditorComponent
|
||||||
|
|
||||||
@ViewChildren(SortableDirective) headers: QueryList<SortableDirective>
|
@ViewChildren(SortableDirective) headers: QueryList<SortableDirective>
|
||||||
|
|
||||||
|
@ViewChildren(NgbDropdown) dropdowns: QueryList<NgbDropdown>
|
||||||
|
|
||||||
displayMode = 'smallCards' // largeCards, smallCards, details
|
displayMode = 'smallCards' // largeCards, smallCards, details
|
||||||
|
|
||||||
unmodifiedFilterRules: FilterRule[] = []
|
unmodifiedFilterRules: FilterRule[] = []
|
||||||
@ -129,6 +135,14 @@ export class DocumentListComponent
|
|||||||
return this.list.selected.size > 0
|
return this.list.selected.size > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get hasOpenMenu(): boolean {
|
||||||
|
return (
|
||||||
|
this.dropdowns.some((d) => d.isOpen()) ||
|
||||||
|
this.filterEditor.hasOpenMenu ||
|
||||||
|
this.bulkEditor.hasOpenMenu
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
saveDisplayMode() {
|
saveDisplayMode() {
|
||||||
localStorage.setItem('document-list:displayMode', this.displayMode)
|
localStorage.setItem('document-list:displayMode', this.displayMode)
|
||||||
}
|
}
|
||||||
@ -192,7 +206,10 @@ export class DocumentListComponent
|
|||||||
keys: 'escape',
|
keys: 'escape',
|
||||||
description: $localize`Reset filters / selection`,
|
description: $localize`Reset filters / selection`,
|
||||||
})
|
})
|
||||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
.pipe(
|
||||||
|
takeUntil(this.unsubscribeNotifier),
|
||||||
|
filter(() => !this.hasOpenMenu)
|
||||||
|
)
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
if (this.list.selected.size > 0) {
|
if (this.list.selected.size > 0) {
|
||||||
this.list.selectNone()
|
this.list.selectNone()
|
||||||
|
@ -1870,4 +1870,14 @@ describe('FilterEditorComponent', () => {
|
|||||||
component.itemSelected({ item: 'world', preventDefault: () => true })
|
component.itemSelected({ item: 'world', preventDefault: () => true })
|
||||||
expect(component.textFilter).toEqual('hello world ')
|
expect(component.textFilter).toEqual('hello world ')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should correctly pass open state from dropdowns', () => {
|
||||||
|
expect(component.hasOpenMenu).toBeFalsy()
|
||||||
|
component.filterableDropdowns = [
|
||||||
|
{
|
||||||
|
isOpen: () => true,
|
||||||
|
} as any,
|
||||||
|
]
|
||||||
|
expect(component.hasOpenMenu).toBeTruthy()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
ViewChild,
|
ViewChild,
|
||||||
ElementRef,
|
ElementRef,
|
||||||
AfterViewInit,
|
AfterViewInit,
|
||||||
|
ViewChildren,
|
||||||
} from '@angular/core'
|
} from '@angular/core'
|
||||||
import { Tag } from 'src/app/data/tag'
|
import { Tag } from 'src/app/data/tag'
|
||||||
import { Correspondent } from 'src/app/data/correspondent'
|
import { Correspondent } from 'src/app/data/correspondent'
|
||||||
@ -61,6 +62,7 @@ import {
|
|||||||
FILTER_SHARED_BY_USER,
|
FILTER_SHARED_BY_USER,
|
||||||
} from 'src/app/data/filter-rule-type'
|
} from 'src/app/data/filter-rule-type'
|
||||||
import {
|
import {
|
||||||
|
FilterableDropdownComponent,
|
||||||
FilterableDropdownSelectionModel,
|
FilterableDropdownSelectionModel,
|
||||||
Intersection,
|
Intersection,
|
||||||
LogicalOperator,
|
LogicalOperator,
|
||||||
@ -74,9 +76,13 @@ import {
|
|||||||
import { Document } from 'src/app/data/document'
|
import { Document } from 'src/app/data/document'
|
||||||
import { StoragePath } from 'src/app/data/storage-path'
|
import { StoragePath } from 'src/app/data/storage-path'
|
||||||
import { StoragePathService } from 'src/app/services/rest/storage-path.service'
|
import { StoragePathService } from 'src/app/services/rest/storage-path.service'
|
||||||
import { RelativeDate } from '../../common/date-dropdown/date-dropdown.component'
|
import {
|
||||||
|
DateDropdownComponent,
|
||||||
|
RelativeDate,
|
||||||
|
} from '../../common/date-dropdown/date-dropdown.component'
|
||||||
import {
|
import {
|
||||||
OwnerFilterType,
|
OwnerFilterType,
|
||||||
|
PermissionsFilterDropdownComponent,
|
||||||
PermissionsSelectionModel,
|
PermissionsSelectionModel,
|
||||||
} from '../../common/permissions-filter-dropdown/permissions-filter-dropdown.component'
|
} from '../../common/permissions-filter-dropdown/permissions-filter-dropdown.component'
|
||||||
import {
|
import {
|
||||||
@ -86,6 +92,7 @@ import {
|
|||||||
} from 'src/app/services/permissions.service'
|
} from 'src/app/services/permissions.service'
|
||||||
import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component'
|
import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component'
|
||||||
import { SearchService } from 'src/app/services/rest/search.service'
|
import { SearchService } from 'src/app/services/rest/search.service'
|
||||||
|
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
|
||||||
|
|
||||||
const TEXT_FILTER_TARGET_TITLE = 'title'
|
const TEXT_FILTER_TARGET_TITLE = 'title'
|
||||||
const TEXT_FILTER_TARGET_TITLE_CONTENT = 'title-content'
|
const TEXT_FILTER_TARGET_TITLE_CONTENT = 'title-content'
|
||||||
@ -269,6 +276,13 @@ export class FilterEditorComponent
|
|||||||
|
|
||||||
unsubscribeNotifier: Subject<any> = new Subject()
|
unsubscribeNotifier: Subject<any> = new Subject()
|
||||||
|
|
||||||
|
@ViewChild(NgbDropdown) textFilterDropdown: NgbDropdown
|
||||||
|
@ViewChildren(FilterableDropdownComponent)
|
||||||
|
filterableDropdowns: FilterableDropdownComponent[]
|
||||||
|
@ViewChildren(DateDropdownComponent) dateDropdowns: DateDropdownComponent[]
|
||||||
|
@ViewChild(PermissionsFilterDropdownComponent)
|
||||||
|
permissionsDropdown: PermissionsFilterDropdownComponent
|
||||||
|
|
||||||
get textFilterTargets() {
|
get textFilterTargets() {
|
||||||
if (this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_MORELIKE) {
|
if (this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_MORELIKE) {
|
||||||
return DEFAULT_TEXT_FILTER_TARGET_OPTIONS.concat([
|
return DEFAULT_TEXT_FILTER_TARGET_OPTIONS.concat([
|
||||||
@ -876,6 +890,15 @@ export class FilterEditorComponent
|
|||||||
|
|
||||||
textFilterDebounce: Subject<string>
|
textFilterDebounce: Subject<string>
|
||||||
|
|
||||||
|
get hasOpenMenu(): boolean {
|
||||||
|
return (
|
||||||
|
this.textFilterDropdown.isOpen() ||
|
||||||
|
this.filterableDropdowns.some((d) => d.isOpen()) ||
|
||||||
|
this.dateDropdowns.some((d) => d.isOpen()) ||
|
||||||
|
this.permissionsDropdown.isOpen()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (
|
if (
|
||||||
this.permissionsService.currentUserCan(
|
this.permissionsService.currentUserCan(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user