mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-04-02 13:45:10 -05:00
Bulk editor enabling/disabling by permissions
This commit is contained in:
parent
6ece5240a5
commit
bf34c955ff
@ -1,5 +1,5 @@
|
|||||||
<div class="btn-group w-100" ngbDropdown role="group" (openChange)="dropdownOpenChange($event)" #dropdown="ngbDropdown">
|
<div class="btn-group w-100" ngbDropdown role="group" (openChange)="dropdownOpenChange($event)" #dropdown="ngbDropdown">
|
||||||
<button class="btn btn-sm" id="dropdown{{title}}" ngbDropdownToggle [ngClass]="!editing && selectionModel.selectionSize() > 0 ? 'btn-primary' : 'btn-outline-primary'">
|
<button class="btn btn-sm" id="dropdown{{title}}" ngbDropdownToggle [ngClass]="!editing && selectionModel.selectionSize() > 0 ? 'btn-primary' : 'btn-outline-primary'" [disabled]="disabled">
|
||||||
<svg class="toolbaricon" fill="currentColor">
|
<svg class="toolbaricon" fill="currentColor">
|
||||||
<use attr.xlink:href="assets/bootstrap-icons.svg#{{icon}}" />
|
<use attr.xlink:href="assets/bootstrap-icons.svg#{{icon}}" />
|
||||||
</svg>
|
</svg>
|
||||||
@ -25,10 +25,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div *ngIf="selectionModel.items" class="items">
|
<div *ngIf="selectionModel.items" class="items">
|
||||||
<ng-container *ngFor="let item of selectionModel.itemsSorted | filter: filterText">
|
<ng-container *ngFor="let item of selectionModel.itemsSorted | filter: filterText">
|
||||||
<app-toggleable-dropdown-button *ngIf="allowSelectNone || item.id" [item]="item" [state]="selectionModel.get(item.id)" (toggle)="selectionModel.toggle(item.id)" (exclude)="excludeClicked(item.id)"></app-toggleable-dropdown-button>
|
<app-toggleable-dropdown-button *ngIf="allowSelectNone || item.id" [item]="item" [state]="selectionModel.get(item.id)" (toggle)="selectionModel.toggle(item.id)" (exclude)="excludeClicked(item.id)" [disabled]="disabled"></app-toggleable-dropdown-button>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
<button *ngIf="editing" class="list-group-item list-group-item-action bg-light" (click)="applyClicked()" [disabled]="!modelIsDirty">
|
<button *ngIf="editing" class="list-group-item list-group-item-action bg-light" (click)="applyClicked()" [disabled]="!modelIsDirty || disabled">
|
||||||
<small class="ms-2" [ngClass]="{'fw-bold': modelIsDirty}" i18n>Apply</small>
|
<small class="ms-2" [ngClass]="{'fw-bold': modelIsDirty}" i18n>Apply</small>
|
||||||
<svg width="1.5em" height="1em" viewBox="0 0 16 16" fill="currentColor">
|
<svg width="1.5em" height="1em" viewBox="0 0 16 16" fill="currentColor">
|
||||||
<use xlink:href="assets/bootstrap-icons.svg#arrow-right" />
|
<use xlink:href="assets/bootstrap-icons.svg#arrow-right" />
|
||||||
|
@ -317,6 +317,9 @@ export class FilterableDropdownComponent {
|
|||||||
@Input()
|
@Input()
|
||||||
applyOnClose = false
|
applyOnClose = false
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
disabled = false
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
apply = new EventEmitter<ChangedItems>()
|
apply = new EventEmitter<ChangedItems>()
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<button class="list-group-item list-group-item-action d-flex align-items-center p-2 border-top-0 border-start-0 border-end-0 border-bottom" role="menuitem" (click)="toggleItem($event)">
|
<button class="list-group-item list-group-item-action d-flex align-items-center p-2 border-top-0 border-start-0 border-end-0 border-bottom" role="menuitem" (click)="toggleItem($event)" [disabled]="disabled">
|
||||||
<div class="selected-icon me-1">
|
<div class="selected-icon me-1">
|
||||||
<ng-container *ngIf="isChecked()">
|
<ng-container *ngIf="isChecked()">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" class="bi bi-check" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" class="bi bi-check" viewBox="0 0 16 16">
|
||||||
|
@ -23,6 +23,9 @@ export class ToggleableDropdownButtonComponent {
|
|||||||
@Input()
|
@Input()
|
||||||
count: number
|
count: number
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
disabled: boolean = false
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
toggle = new EventEmitter()
|
toggle = new EventEmitter()
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
<app-filterable-dropdown class="me-2 me-md-3" title="Tags" icon="tag-fill" i18n-title
|
<app-filterable-dropdown class="me-2 me-md-3" title="Tags" icon="tag-fill" i18n-title
|
||||||
filterPlaceholder="Filter tags" i18n-filterPlaceholder
|
filterPlaceholder="Filter tags" i18n-filterPlaceholder
|
||||||
[items]="tags"
|
[items]="tags"
|
||||||
|
[disabled]="!userCanEditAll"
|
||||||
[editing]="true"
|
[editing]="true"
|
||||||
[multiple]="true"
|
[multiple]="true"
|
||||||
[applyOnClose]="applyOnClose"
|
[applyOnClose]="applyOnClose"
|
||||||
@ -38,6 +39,7 @@
|
|||||||
<app-filterable-dropdown class="me-2 me-md-3" title="Correspondent" icon="person-fill" i18n-title
|
<app-filterable-dropdown class="me-2 me-md-3" title="Correspondent" icon="person-fill" i18n-title
|
||||||
filterPlaceholder="Filter correspondents" i18n-filterPlaceholder
|
filterPlaceholder="Filter correspondents" i18n-filterPlaceholder
|
||||||
[items]="correspondents"
|
[items]="correspondents"
|
||||||
|
[disabled]="!userCanEditAll"
|
||||||
[editing]="true"
|
[editing]="true"
|
||||||
[applyOnClose]="applyOnClose"
|
[applyOnClose]="applyOnClose"
|
||||||
(open)="openCorrespondentDropdown()"
|
(open)="openCorrespondentDropdown()"
|
||||||
@ -47,6 +49,7 @@
|
|||||||
<app-filterable-dropdown class="me-2 me-md-3" title="Document type" icon="file-earmark-fill" i18n-title
|
<app-filterable-dropdown class="me-2 me-md-3" title="Document type" icon="file-earmark-fill" i18n-title
|
||||||
filterPlaceholder="Filter document types" i18n-filterPlaceholder
|
filterPlaceholder="Filter document types" i18n-filterPlaceholder
|
||||||
[items]="documentTypes"
|
[items]="documentTypes"
|
||||||
|
[disabled]="!userCanEditAll"
|
||||||
[editing]="true"
|
[editing]="true"
|
||||||
[applyOnClose]="applyOnClose"
|
[applyOnClose]="applyOnClose"
|
||||||
(open)="openDocumentTypeDropdown()"
|
(open)="openDocumentTypeDropdown()"
|
||||||
@ -56,6 +59,7 @@
|
|||||||
<app-filterable-dropdown class="me-2 me-md-3" title="Storage path" icon="folder-fill" i18n-title
|
<app-filterable-dropdown class="me-2 me-md-3" title="Storage path" icon="folder-fill" i18n-title
|
||||||
filterPlaceholder="Filter storage paths" i18n-filterPlaceholder
|
filterPlaceholder="Filter storage paths" i18n-filterPlaceholder
|
||||||
[items]="storagePaths"
|
[items]="storagePaths"
|
||||||
|
[disabled]="!userCanEditAll"
|
||||||
[editing]="true"
|
[editing]="true"
|
||||||
[applyOnClose]="applyOnClose"
|
[applyOnClose]="applyOnClose"
|
||||||
(open)="openStoragePathDropdown()"
|
(open)="openStoragePathDropdown()"
|
||||||
@ -67,7 +71,7 @@
|
|||||||
<div class="col-auto ms-auto mb-2 mb-xl-0 d-flex">
|
<div class="col-auto ms-auto mb-2 mb-xl-0 d-flex">
|
||||||
<div class="btn-toolbar me-2">
|
<div class="btn-toolbar me-2">
|
||||||
|
|
||||||
<button type="button" class="btn btn-sm btn-outline-primary me-2" (click)="setPermissions()">
|
<button type="button" class="btn btn-sm btn-outline-primary me-2" (click)="setPermissions()" [disabled]="!userOwnsAll">
|
||||||
<svg width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor">
|
<svg width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor">
|
||||||
<use xlink:href="assets/bootstrap-icons.svg#person-fill-lock" />
|
<use xlink:href="assets/bootstrap-icons.svg#person-fill-lock" />
|
||||||
</svg> <ng-container i18n>Permissions</ng-container>
|
</svg> <ng-container i18n>Permissions</ng-container>
|
||||||
@ -93,11 +97,11 @@
|
|||||||
<span class="visually-hidden">Preparing download...</span>
|
<span class="visually-hidden">Preparing download...</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<button ngbDropdownItem (click)="redoOcrSelected()" i18n>Redo OCR</button>
|
<button ngbDropdownItem (click)="redoOcrSelected()" [disabled]="!userCanEditAll" i18n>Redo OCR</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button" class="btn btn-sm btn-outline-danger" (click)="applyDelete()" *ifPermissions="{ action: PermissionAction.Delete, type: PermissionType.Document }">
|
<button type="button" class="btn btn-sm btn-outline-danger" (click)="applyDelete()" *ifPermissions="{ action: PermissionAction.Delete, type: PermissionType.Document }" [disabled]="!userOwnsAll">
|
||||||
<svg width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor">
|
<svg width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor">
|
||||||
<use xlink:href="assets/bootstrap-icons.svg#trash" />
|
<use xlink:href="assets/bootstrap-icons.svg#trash" />
|
||||||
</svg> <ng-container i18n>Delete</ng-container>
|
</svg> <ng-container i18n>Delete</ng-container>
|
||||||
|
@ -27,6 +27,7 @@ import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
|
|||||||
import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings'
|
import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings'
|
||||||
import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component'
|
import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component'
|
||||||
import { PermissionsDialogComponent } from '../../common/permissions-dialog/permissions-dialog.component'
|
import { PermissionsDialogComponent } from '../../common/permissions-dialog/permissions-dialog.component'
|
||||||
|
import { PermissionsService } from 'src/app/services/permissions.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-bulk-editor',
|
selector: 'app-bulk-editor',
|
||||||
@ -55,7 +56,8 @@ export class BulkEditorComponent extends ComponentWithPermissions {
|
|||||||
private openDocumentService: OpenDocumentsService,
|
private openDocumentService: OpenDocumentsService,
|
||||||
private settings: SettingsService,
|
private settings: SettingsService,
|
||||||
private toastService: ToastService,
|
private toastService: ToastService,
|
||||||
private storagePathService: StoragePathService
|
private storagePathService: StoragePathService,
|
||||||
|
private permissionService: PermissionsService
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
@ -67,6 +69,25 @@ export class BulkEditorComponent extends ComponentWithPermissions {
|
|||||||
SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS
|
SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS
|
||||||
)
|
)
|
||||||
|
|
||||||
|
get userCanEditAll(): boolean {
|
||||||
|
let canEdit: boolean = true
|
||||||
|
const docs = this.list.documents.filter((d) => this.list.selected.has(d.id))
|
||||||
|
canEdit = docs.every((d) =>
|
||||||
|
this.permissionService.currentUserHasObjectPermissions(
|
||||||
|
this.PermissionAction.Change,
|
||||||
|
d
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return canEdit
|
||||||
|
}
|
||||||
|
|
||||||
|
get userOwnsAll(): boolean {
|
||||||
|
let ownsAll: boolean = true
|
||||||
|
const docs = this.list.documents.filter((d) => this.list.selected.has(d.id))
|
||||||
|
ownsAll = docs.every((d) => this.permissionService.currentUserOwnsObject(d))
|
||||||
|
return ownsAll
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.tagService
|
this.tagService
|
||||||
.listAll()
|
.listAll()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user