Add permissions ui stuff for saved views

This commit is contained in:
shamoon
2026-02-20 10:22:47 -08:00
parent e69e543ba2
commit 77554f6b36
3 changed files with 98 additions and 13 deletions

View File

@@ -27,6 +27,12 @@
<div class="col-auto">
@if (canDeleteSavedView(view)) {
<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
label="Delete"
i18n-label

View File

@@ -3,9 +3,9 @@ import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
import { provideHttpClientTesting } from '@angular/common/http/testing'
import { ComponentFixture, TestBed } from '@angular/core/testing'
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 { of, throwError } from 'rxjs'
import { Subject, of, throwError } from 'rxjs'
import { SavedView } from 'src/app/data/saved-view'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
@@ -32,6 +32,7 @@ describe('SavedViewsComponent', () => {
let fixture: ComponentFixture<SavedViewsComponent>
let savedViewService: SavedViewService
let toastService: ToastService
let modalService: NgbModal
beforeEach(async () => {
TestBed.configureTestingModule({
@@ -79,10 +80,11 @@ describe('SavedViewsComponent', () => {
savedViewService = TestBed.inject(SavedViewService)
toastService = TestBed.inject(ToastService)
modalService = TestBed.inject(NgbModal)
fixture = TestBed.createComponent(SavedViewsComponent)
component = fixture.componentInstance
jest.spyOn(savedViewService, 'listAll').mockReturnValue(
jest.spyOn(savedViewService, 'list').mockReturnValue(
of({
all: savedViews.map((v) => v.id),
count: savedViews.length,
@@ -179,4 +181,42 @@ describe('SavedViewsComponent', () => {
.get('show_on_dashboard').value
).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()
})
})

View File

@@ -6,8 +6,10 @@ import {
FormsModule,
ReactiveFormsModule,
} from '@angular/forms'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { dirtyCheck } from '@ngneat/dirty-check-forms'
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 { SavedView } from 'src/app/data/saved-view'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
@@ -48,6 +50,7 @@ export class SavedViewsComponent
private permissionsService = inject(PermissionsService)
private settings = inject(SettingsService)
private toastService = inject(ToastService)
private modalService = inject(NgbModal)
DisplayMode = DisplayMode
@@ -70,11 +73,7 @@ export class SavedViewsComponent
}
ngOnInit(): void {
this.loading = true
this.savedViewService.listAll().subscribe((r) => {
this.savedViews = r.results
this.initialize()
})
this.reloadViews()
}
ngOnDestroy(): void {
@@ -145,10 +144,7 @@ export class SavedViewsComponent
$localize`Saved view "${savedView.name}" deleted.`
)
this.savedViewService.clearCache()
this.savedViewService.listAll().subscribe((r) => {
this.savedViews = r.results
this.initialize()
})
this.reloadViews()
})
}
@@ -168,7 +164,7 @@ export class SavedViewsComponent
this.savedViewService.patchMany(changed).subscribe({
next: () => {
this.toastService.showInfo($localize`Views saved successfully.`)
this.store.next(this.savedViewsForm.value)
this.reloadViews()
},
error: (error) => {
this.toastService.showError(
@@ -190,4 +186,47 @@ export class SavedViewsComponent
public canDeleteSavedView(view: SavedView): boolean {
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()
})
}
}