+
@if (horizontal) {
diff --git a/src-ui/src/app/components/common/permissions-dialog/permissions-dialog.component.html b/src-ui/src/app/components/common/permissions-dialog/permissions-dialog.component.html
index 37ab7efbd..fd88002ba 100644
--- a/src-ui/src/app/components/common/permissions-dialog/permissions-dialog.component.html
+++ b/src-ui/src/app/components/common/permissions-dialog/permissions-dialog.component.html
@@ -5,12 +5,15 @@
- @if (!object && message) {
-
- }
-
@@ -20,5 +23,5 @@
Loading...
}
-
+
diff --git a/src-ui/src/app/components/common/permissions-dialog/permissions-dialog.component.spec.ts b/src-ui/src/app/components/common/permissions-dialog/permissions-dialog.component.spec.ts
index 3f601d771..bc8ccdecb 100644
--- a/src-ui/src/app/components/common/permissions-dialog/permissions-dialog.component.spec.ts
+++ b/src-ui/src/app/components/common/permissions-dialog/permissions-dialog.component.spec.ts
@@ -11,6 +11,7 @@ import { NgSelectModule } from '@ng-select/ng-select'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { PermissionsUserComponent } from '../input/permissions/permissions-user/permissions-user.component'
import { PermissionsGroupComponent } from '../input/permissions/permissions-group/permissions-group.component'
+import { SwitchComponent } from '../input/switch/switch.component'
const set_permissions = {
owner: 10,
@@ -37,6 +38,7 @@ describe('PermissionsDialogComponent', () => {
PermissionsDialogComponent,
SafeHtmlPipe,
SelectComponent,
+ SwitchComponent,
PermissionsFormComponent,
PermissionsUserComponent,
PermissionsGroupComponent,
@@ -112,4 +114,23 @@ describe('PermissionsDialogComponent', () => {
expect(component.title).toEqual(`Edit permissions for ${obj.name}`)
expect(component.permissions).toEqual(set_permissions)
})
+
+ it('should toggle hint based on object existence (if editing) or merge flag', () => {
+ component.form.get('merge').setValue(true)
+ expect(component.hint.includes('Existing')).toBeTruthy()
+ component.form.get('merge').setValue(false)
+ expect(component.hint.includes('will be replaced')).toBeTruthy()
+ component.object = {}
+ expect(component.hint).toBeNull()
+ })
+
+ it('should emit permissions and merge flag on confirm', () => {
+ const confirmSpy = jest.spyOn(component.confirmClicked, 'emit')
+ component.form.get('permissions_form').setValue(set_permissions)
+ component.confirm()
+ expect(confirmSpy).toHaveBeenCalledWith({
+ permissions: set_permissions,
+ merge: true,
+ })
+ })
})
diff --git a/src-ui/src/app/components/common/permissions-dialog/permissions-dialog.component.ts b/src-ui/src/app/components/common/permissions-dialog/permissions-dialog.component.ts
index 9a514387c..afe1bebb3 100644
--- a/src-ui/src/app/components/common/permissions-dialog/permissions-dialog.component.ts
+++ b/src-ui/src/app/components/common/permissions-dialog/permissions-dialog.component.ts
@@ -32,6 +32,7 @@ export class PermissionsDialogComponent {
this.o = o
this.title = $localize`Edit permissions for ` + o['name']
this.form.patchValue({
+ merge: true,
permissions_form: {
owner: o.owner,
set_permissions: o.permissions,
@@ -43,8 +44,9 @@ export class PermissionsDialogComponent {
return this.o
}
- form = new FormGroup({
+ public form = new FormGroup({
permissions_form: new FormControl(),
+ merge: new FormControl(true),
})
buttonsEnabled: boolean = true
@@ -66,11 +68,21 @@ export class PermissionsDialogComponent {
}
}
- @Input()
- message =
- $localize`Note that permissions set here will override any existing permissions`
+ get hint(): string {
+ if (this.object) return null
+ return this.form.get('merge').value
+ ? $localize`Existing owner, user and group permissions will be merged with these settings.`
+ : $localize`Any and all existing owner, user and group permissions will be replaced.`
+ }
cancelClicked() {
this.activeModal.close()
}
+
+ confirm() {
+ this.confirmClicked.emit({
+ permissions: this.permissions,
+ merge: this.form.get('merge').value,
+ })
+ }
}
diff --git a/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.spec.ts b/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.spec.ts
index 8edfcc7e1..42f8b6d1d 100644
--- a/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.spec.ts
+++ b/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.spec.ts
@@ -41,6 +41,7 @@ import { PermissionsUserComponent } from '../../common/input/permissions/permiss
import { NgSelectModule } from '@ng-select/ng-select'
import { GroupService } from 'src/app/services/rest/group.service'
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
+import { SwitchComponent } from '../../common/input/switch/switch.component'
const selectionData: SelectionData = {
selected_tags: [
@@ -81,6 +82,7 @@ describe('BulkEditorComponent', () => {
SelectComponent,
PermissionsGroupComponent,
PermissionsUserComponent,
+ SwitchComponent,
],
providers: [
PermissionsService,
@@ -851,7 +853,18 @@ describe('BulkEditorComponent', () => {
fixture.detectChanges()
component.setPermissions()
expect(modal).not.toBeUndefined()
- modal.componentInstance.confirmClicked.next()
+ const perms = {
+ permissions: {
+ view_users: [],
+ change_users: [],
+ view_groups: [],
+ change_groups: [],
+ },
+ }
+ modal.componentInstance.confirmClicked.emit({
+ permissions: perms,
+ merge: true,
+ })
let req = httpTestingController.expectOne(
`${environment.apiBaseUrl}documents/bulk_edit/`
)
@@ -859,7 +872,10 @@ describe('BulkEditorComponent', () => {
expect(req.request.body).toEqual({
documents: [3, 4],
method: 'set_permissions',
- parameters: undefined,
+ parameters: {
+ permissions: perms.permissions,
+ merge: true,
+ },
})
httpTestingController.match(
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
diff --git a/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.ts b/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.ts
index 1c7e0b9c6..49d4c070f 100644
--- a/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.ts
+++ b/src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.ts
@@ -540,9 +540,14 @@ export class BulkEditorComponent
let modal = this.modalService.open(PermissionsDialogComponent, {
backdrop: 'static',
})
- modal.componentInstance.confirmClicked.subscribe((permissions) => {
- modal.componentInstance.buttonsEnabled = false
- this.executeBulkOperation(modal, 'set_permissions', permissions)
- })
+ modal.componentInstance.confirmClicked.subscribe(
+ ({ permissions, merge }) => {
+ modal.componentInstance.buttonsEnabled = false
+ this.executeBulkOperation(modal, 'set_permissions', {
+ ...permissions,
+ merge,
+ })
+ }
+ )
}
}
diff --git a/src-ui/src/app/components/manage/mail/mail.component.spec.ts b/src-ui/src/app/components/manage/mail/mail.component.spec.ts
index 5680d8faa..fcc5bcc6b 100644
--- a/src-ui/src/app/components/manage/mail/mail.component.spec.ts
+++ b/src-ui/src/app/components/manage/mail/mail.component.spec.ts
@@ -41,6 +41,7 @@ import { TagsComponent } from '../../common/input/tags/tags.component'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { EditDialogMode } from '../../common/edit-dialog/edit-dialog.component'
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
+import { SwitchComponent } from '../../common/input/switch/switch.component'
const mailAccounts = [
{ id: 1, name: 'account1' },
@@ -82,6 +83,7 @@ describe('MailComponent', () => {
PermissionsGroupComponent,
PermissionsDialogComponent,
PermissionsFormComponent,
+ SwitchComponent,
],
providers: [CustomDatePipe, DatePipe, PermissionsGuard],
imports: [
@@ -267,11 +269,11 @@ describe('MailComponent', () => {
rulePatchSpy.mockReturnValueOnce(
throwError(() => new Error('error saving perms'))
)
- dialog.confirmClicked.emit(perms)
+ dialog.confirmClicked.emit({ permissions: perms, merge: true })
expect(rulePatchSpy).toHaveBeenCalled()
expect(toastErrorSpy).toHaveBeenCalled()
rulePatchSpy.mockReturnValueOnce(of(mailRules[0] as MailRule))
- dialog.confirmClicked.emit(perms)
+ dialog.confirmClicked.emit({ permissions: perms, merge: true })
expect(toastInfoSpy).toHaveBeenCalledWith('Permissions updated')
modalService.dismissAll()
@@ -299,8 +301,7 @@ describe('MailComponent', () => {
expect(modal).not.toBeUndefined()
let dialog = modal.componentInstance as PermissionsDialogComponent
expect(dialog.object).toEqual(mailAccounts[0])
- dialog = modal.componentInstance as PermissionsDialogComponent
- dialog.confirmClicked.emit(perms)
+ dialog.confirmClicked.emit({ permissions: perms, merge: true })
expect(accountPatchSpy).toHaveBeenCalled()
})
})
diff --git a/src-ui/src/app/components/manage/mail/mail.component.ts b/src-ui/src/app/components/manage/mail/mail.component.ts
index 9bb33c03b..d8820ed38 100644
--- a/src-ui/src/app/components/manage/mail/mail.component.ts
+++ b/src-ui/src/app/components/manage/mail/mail.component.ts
@@ -200,22 +200,27 @@ export class MailComponent
const dialog: PermissionsDialogComponent =
modal.componentInstance as PermissionsDialogComponent
dialog.object = object
- modal.componentInstance.confirmClicked.subscribe((permissions) => {
- modal.componentInstance.buttonsEnabled = false
- const service: AbstractPaperlessService
=
- 'account' in object ? this.mailRuleService : this.mailAccountService
- object.owner = permissions['owner']
- object['set_permissions'] = permissions['set_permissions']
- service.patch(object).subscribe({
- next: () => {
- this.toastService.showInfo($localize`Permissions updated`)
- modal.close()
- },
- error: (e) => {
- this.toastService.showError($localize`Error updating permissions`, e)
- },
- })
- })
+ modal.componentInstance.confirmClicked.subscribe(
+ ({ permissions, merge }) => {
+ modal.componentInstance.buttonsEnabled = false
+ const service: AbstractPaperlessService =
+ 'account' in object ? this.mailRuleService : this.mailAccountService
+ object.owner = permissions['owner']
+ object['set_permissions'] = permissions['set_permissions']
+ service.patch(object).subscribe({
+ next: () => {
+ this.toastService.showInfo($localize`Permissions updated`)
+ modal.close()
+ },
+ error: (e) => {
+ this.toastService.showError(
+ $localize`Error updating permissions`,
+ e
+ )
+ },
+ })
+ }
+ )
}
userCanEdit(obj: ObjectWithPermissions): boolean {
diff --git a/src-ui/src/app/components/manage/management-list/management-list.component.spec.ts b/src-ui/src/app/components/manage/management-list/management-list.component.spec.ts
index 44a3452d7..6196a3c8a 100644
--- a/src-ui/src/app/components/manage/management-list/management-list.component.spec.ts
+++ b/src-ui/src/app/components/manage/management-list/management-list.component.spec.ts
@@ -264,13 +264,19 @@ describe('ManagementListComponent', () => {
throwError(() => new Error('error setting permissions'))
)
const errorToastSpy = jest.spyOn(toastService, 'showError')
- modal.componentInstance.confirmClicked.emit()
+ modal.componentInstance.confirmClicked.emit({
+ permissions: {},
+ merge: true,
+ })
expect(bulkEditPermsSpy).toHaveBeenCalled()
expect(errorToastSpy).toHaveBeenCalled()
const successToastSpy = jest.spyOn(toastService, 'showInfo')
bulkEditPermsSpy.mockReturnValueOnce(of('OK'))
- modal.componentInstance.confirmClicked.emit()
+ modal.componentInstance.confirmClicked.emit({
+ permissions: {},
+ merge: true,
+ })
expect(bulkEditPermsSpy).toHaveBeenCalled()
expect(successToastSpy).toHaveBeenCalled()
})
diff --git a/src-ui/src/app/components/manage/management-list/management-list.component.ts b/src-ui/src/app/components/manage/management-list/management-list.component.ts
index e20b5d4a7..a89b5e4f6 100644
--- a/src-ui/src/app/components/manage/management-list/management-list.component.ts
+++ b/src-ui/src/app/components/manage/management-list/management-list.component.ts
@@ -279,12 +279,13 @@ export abstract class ManagementListComponent
backdrop: 'static',
})
modal.componentInstance.confirmClicked.subscribe(
- (permissions: { owner: number; set_permissions: PermissionsObject }) => {
+ ({ permissions, merge }) => {
modal.componentInstance.buttonsEnabled = false
this.service
.bulk_update_permissions(
Array.from(this.selectedObjects),
- permissions
+ permissions,
+ merge
)
.subscribe({
next: () => {
diff --git a/src-ui/src/app/services/rest/abstract-name-filter-service.spec.ts b/src-ui/src/app/services/rest/abstract-name-filter-service.spec.ts
index 70ae211e5..e09270701 100644
--- a/src-ui/src/app/services/rest/abstract-name-filter-service.spec.ts
+++ b/src-ui/src/app/services/rest/abstract-name-filter-service.spec.ts
@@ -53,10 +53,14 @@ export const commonAbstractNameFilterPaperlessServiceTests = (
},
}
subscription = service
- .bulk_update_permissions([1, 2], {
- owner,
- set_permissions: permissions,
- })
+ .bulk_update_permissions(
+ [1, 2],
+ {
+ owner,
+ set_permissions: permissions,
+ },
+ true
+ )
.subscribe()
const req = httpTestingController.expectOne(
`${environment.apiBaseUrl}bulk_edit_object_perms/`
diff --git a/src-ui/src/app/services/rest/abstract-name-filter-service.ts b/src-ui/src/app/services/rest/abstract-name-filter-service.ts
index 5e0377cb9..b38994086 100644
--- a/src-ui/src/app/services/rest/abstract-name-filter-service.ts
+++ b/src-ui/src/app/services/rest/abstract-name-filter-service.ts
@@ -26,13 +26,15 @@ export abstract class AbstractNameFilterService<
bulk_update_permissions(
objects: Array,
- permissions: { owner: number; set_permissions: PermissionsObject }
+ permissions: { owner: number; set_permissions: PermissionsObject },
+ merge: boolean
): Observable {
return this.http.post(`${this.baseUrl}bulk_edit_object_perms/`, {
objects,
object_type: this.resourceName,
owner: permissions.owner,
permissions: permissions.set_permissions,
+ merge,
})
}
}