mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-02-24 00:59:35 -06:00
Add permissions ui stuff for saved views
This commit is contained in:
@@ -27,6 +27,12 @@
|
|||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
@if (canDeleteSavedView(view)) {
|
@if (canDeleteSavedView(view)) {
|
||||||
<label class="form-label" for="name_{{view.id}}" i18n>Actions</label>
|
<label class="form-label" for="name_{{view.id}}" i18n>Actions</label>
|
||||||
|
<button
|
||||||
|
class="btn btn-sm btn-outline-secondary form-control mb-2"
|
||||||
|
type="button"
|
||||||
|
(click)="editPermissions(view)"
|
||||||
|
*pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.SavedView }"
|
||||||
|
i18n>Permissions</button>
|
||||||
<pngx-confirm-button
|
<pngx-confirm-button
|
||||||
label="Delete"
|
label="Delete"
|
||||||
i18n-label
|
i18n-label
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
|
|||||||
import { provideHttpClientTesting } from '@angular/common/http/testing'
|
import { provideHttpClientTesting } from '@angular/common/http/testing'
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
||||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbModal, NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
||||||
import { of, throwError } from 'rxjs'
|
import { Subject, of, throwError } from 'rxjs'
|
||||||
import { SavedView } from 'src/app/data/saved-view'
|
import { SavedView } from 'src/app/data/saved-view'
|
||||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||||
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
|
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
|
||||||
@@ -32,6 +32,7 @@ describe('SavedViewsComponent', () => {
|
|||||||
let fixture: ComponentFixture<SavedViewsComponent>
|
let fixture: ComponentFixture<SavedViewsComponent>
|
||||||
let savedViewService: SavedViewService
|
let savedViewService: SavedViewService
|
||||||
let toastService: ToastService
|
let toastService: ToastService
|
||||||
|
let modalService: NgbModal
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
@@ -79,10 +80,11 @@ describe('SavedViewsComponent', () => {
|
|||||||
|
|
||||||
savedViewService = TestBed.inject(SavedViewService)
|
savedViewService = TestBed.inject(SavedViewService)
|
||||||
toastService = TestBed.inject(ToastService)
|
toastService = TestBed.inject(ToastService)
|
||||||
|
modalService = TestBed.inject(NgbModal)
|
||||||
fixture = TestBed.createComponent(SavedViewsComponent)
|
fixture = TestBed.createComponent(SavedViewsComponent)
|
||||||
component = fixture.componentInstance
|
component = fixture.componentInstance
|
||||||
|
|
||||||
jest.spyOn(savedViewService, 'listAll').mockReturnValue(
|
jest.spyOn(savedViewService, 'list').mockReturnValue(
|
||||||
of({
|
of({
|
||||||
all: savedViews.map((v) => v.id),
|
all: savedViews.map((v) => v.id),
|
||||||
count: savedViews.length,
|
count: savedViews.length,
|
||||||
@@ -179,4 +181,42 @@ describe('SavedViewsComponent', () => {
|
|||||||
.get('show_on_dashboard').value
|
.get('show_on_dashboard').value
|
||||||
).toEqual(view.show_on_dashboard)
|
).toEqual(view.show_on_dashboard)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should support editing permissions', () => {
|
||||||
|
const confirmClicked = new Subject<any>()
|
||||||
|
const modalRef = {
|
||||||
|
componentInstance: {
|
||||||
|
confirmClicked,
|
||||||
|
buttonsEnabled: true,
|
||||||
|
},
|
||||||
|
close: jest.fn(),
|
||||||
|
} as any
|
||||||
|
jest.spyOn(modalService, 'open').mockReturnValue(modalRef)
|
||||||
|
const patchSpy = jest.spyOn(savedViewService, 'patch')
|
||||||
|
patchSpy.mockReturnValue(of(savedViews[0] as SavedView))
|
||||||
|
|
||||||
|
component.editPermissions(savedViews[0] as SavedView)
|
||||||
|
confirmClicked.next({
|
||||||
|
permissions: {
|
||||||
|
owner: 1,
|
||||||
|
set_permissions: {
|
||||||
|
view: { users: [2], groups: [] },
|
||||||
|
change: { users: [], groups: [3] },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
merge: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(patchSpy).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: savedViews[0].id,
|
||||||
|
owner: 1,
|
||||||
|
set_permissions: {
|
||||||
|
view: { users: [2], groups: [] },
|
||||||
|
change: { users: [], groups: [3] },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
expect(modalRef.close).toHaveBeenCalled()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ import {
|
|||||||
FormsModule,
|
FormsModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
} from '@angular/forms'
|
} from '@angular/forms'
|
||||||
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { dirtyCheck } from '@ngneat/dirty-check-forms'
|
import { dirtyCheck } from '@ngneat/dirty-check-forms'
|
||||||
import { BehaviorSubject, Observable, takeUntil } from 'rxjs'
|
import { BehaviorSubject, Observable, takeUntil } from 'rxjs'
|
||||||
|
import { PermissionsDialogComponent } from 'src/app/components/common/permissions-dialog/permissions-dialog.component'
|
||||||
import { DisplayMode } from 'src/app/data/document'
|
import { DisplayMode } from 'src/app/data/document'
|
||||||
import { SavedView } from 'src/app/data/saved-view'
|
import { SavedView } from 'src/app/data/saved-view'
|
||||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||||
@@ -48,6 +50,7 @@ export class SavedViewsComponent
|
|||||||
private permissionsService = inject(PermissionsService)
|
private permissionsService = inject(PermissionsService)
|
||||||
private settings = inject(SettingsService)
|
private settings = inject(SettingsService)
|
||||||
private toastService = inject(ToastService)
|
private toastService = inject(ToastService)
|
||||||
|
private modalService = inject(NgbModal)
|
||||||
|
|
||||||
DisplayMode = DisplayMode
|
DisplayMode = DisplayMode
|
||||||
|
|
||||||
@@ -70,11 +73,7 @@ export class SavedViewsComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.loading = true
|
this.reloadViews()
|
||||||
this.savedViewService.listAll().subscribe((r) => {
|
|
||||||
this.savedViews = r.results
|
|
||||||
this.initialize()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
@@ -145,10 +144,7 @@ export class SavedViewsComponent
|
|||||||
$localize`Saved view "${savedView.name}" deleted.`
|
$localize`Saved view "${savedView.name}" deleted.`
|
||||||
)
|
)
|
||||||
this.savedViewService.clearCache()
|
this.savedViewService.clearCache()
|
||||||
this.savedViewService.listAll().subscribe((r) => {
|
this.reloadViews()
|
||||||
this.savedViews = r.results
|
|
||||||
this.initialize()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +164,7 @@ export class SavedViewsComponent
|
|||||||
this.savedViewService.patchMany(changed).subscribe({
|
this.savedViewService.patchMany(changed).subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
this.toastService.showInfo($localize`Views saved successfully.`)
|
this.toastService.showInfo($localize`Views saved successfully.`)
|
||||||
this.store.next(this.savedViewsForm.value)
|
this.reloadViews()
|
||||||
},
|
},
|
||||||
error: (error) => {
|
error: (error) => {
|
||||||
this.toastService.showError(
|
this.toastService.showError(
|
||||||
@@ -190,4 +186,47 @@ export class SavedViewsComponent
|
|||||||
public canDeleteSavedView(view: SavedView): boolean {
|
public canDeleteSavedView(view: SavedView): boolean {
|
||||||
return this.permissionsService.currentUserOwnsObject(view)
|
return this.permissionsService.currentUserOwnsObject(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public editPermissions(savedView: SavedView): void {
|
||||||
|
if (!this.canDeleteSavedView(savedView)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const modal = this.modalService.open(PermissionsDialogComponent, {
|
||||||
|
backdrop: 'static',
|
||||||
|
})
|
||||||
|
const dialog = modal.componentInstance as PermissionsDialogComponent
|
||||||
|
dialog.object = savedView
|
||||||
|
|
||||||
|
modal.componentInstance.confirmClicked.subscribe(({ permissions }) => {
|
||||||
|
modal.componentInstance.buttonsEnabled = false
|
||||||
|
const view = {
|
||||||
|
id: savedView.id,
|
||||||
|
owner: permissions.owner,
|
||||||
|
}
|
||||||
|
view['set_permissions'] = permissions.set_permissions
|
||||||
|
this.savedViewService.patch(view as SavedView).subscribe({
|
||||||
|
next: () => {
|
||||||
|
this.toastService.showInfo($localize`Permissions updated`)
|
||||||
|
modal.close()
|
||||||
|
this.reloadViews()
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
this.toastService.showError(
|
||||||
|
$localize`Error updating permissions`,
|
||||||
|
error
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private reloadViews(): void {
|
||||||
|
this.loading = true
|
||||||
|
this.savedViewService
|
||||||
|
.listAll(null, null, { full_perms: true })
|
||||||
|
.subscribe((r) => {
|
||||||
|
this.savedViews = r.results
|
||||||
|
this.initialize()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user