mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-09-16 21:55:37 -05:00
Enhancement: settings reorganization & improvements, separate admin section (#4251)
* Separate admin / manage sections * Move mail settings to its own component * Move users and groups to its own component * Move default permissions to its own settings tab * Unify list styling, add tour step, refactor components * Only patch saved views that have changed on settings save * Update messages.xlf * Remove unused methods in settings.component.ts * Drop admin section to bottom of sidebar, cleanup outdated, add docs link to dropdown * Better visually unify management list & other list pages
This commit is contained in:
107
src-ui/src/app/components/manage/mail/mail.component.html
Normal file
107
src-ui/src/app/components/manage/mail/mail.component.html
Normal file
@@ -0,0 +1,107 @@
|
||||
<pngx-page-header title="Mail Settings" i18n-title>
|
||||
</pngx-page-header>
|
||||
|
||||
<ng-container *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.MailAccount }">
|
||||
<h4>
|
||||
<ng-container i18n>Mail accounts</ng-container>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary ms-4" (click)="editMailAccount()" *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.MailAccount }">
|
||||
<svg class="sidebaricon me-1" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#plus-circle" />
|
||||
</svg>
|
||||
<ng-container i18n>Add Account</ng-container>
|
||||
</button>
|
||||
</h4>
|
||||
<ul class="list-group">
|
||||
|
||||
<li class="list-group-item">
|
||||
<div class="row">
|
||||
<div class="col" i18n>Name</div>
|
||||
<div class="col" i18n>Server</div>
|
||||
<div class="col" i18n>Actions</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li *ngFor="let account of mailAccounts" class="list-group-item">
|
||||
<div class="row">
|
||||
<div class="col d-flex align-items-center"><button class="btn btn-link p-0" type="button" (click)="editMailAccount(account)" [disabled]="!permissionsService.currentUserCan(PermissionAction.Change, PermissionType.MailAccount)">{{account.name}}</button></div>
|
||||
<div class="col d-flex align-items-center">{{account.imap_server}}</div>
|
||||
<div class="col">
|
||||
<div class="btn-group">
|
||||
<button *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.MailAccount }" [disabled]="!userCanEdit(account)" class="btn btn-sm btn-outline-secondary" type="button" (click)="editMailAccount(account)">
|
||||
<svg class="buttonicon-sm" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#pencil" />
|
||||
</svg> <ng-container i18n>Edit</ng-container>
|
||||
</button>
|
||||
<button *pngxIfOwner="account" class="btn btn-sm btn-outline-secondary" type="button" (click)="editPermissions(account)">
|
||||
<svg class="buttonicon-sm" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#person-lock" />
|
||||
</svg> <ng-container i18n>Permissions</ng-container>
|
||||
</button>
|
||||
<button *pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.MailAccount }" [disabled]="!userIsOwner(account)" class="btn btn-sm btn-outline-danger" type="button" (click)="deleteMailAccount(account)">
|
||||
<svg class="buttonicon-sm" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#trash" />
|
||||
</svg> <ng-container i18n>Delete</ng-container>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<div *ngIf="mailAccounts.length === 0" i18n>No mail accounts defined.</div>
|
||||
</ul>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.MailRule }">
|
||||
<h4 class="mt-4">
|
||||
<ng-container i18n>Mail rules</ng-container>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary ms-4" (click)="editMailRule()" *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.MailRule }">
|
||||
<svg class="sidebaricon me-1" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#plus-circle" />
|
||||
</svg>
|
||||
<ng-container i18n>Add Rule</ng-container>
|
||||
</button>
|
||||
</h4>
|
||||
<ul class="list-group">
|
||||
|
||||
<li class="list-group-item">
|
||||
<div class="row">
|
||||
<div class="col" i18n>Name</div>
|
||||
<div class="col" i18n>Account</div>
|
||||
<div class="col" i18n>Actions</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li *ngFor="let rule of mailRules" class="list-group-item">
|
||||
<div class="row">
|
||||
<div class="col d-flex align-items-center"><button class="btn btn-link p-0" type="button" (click)="editMailRule(rule)" [disabled]="!permissionsService.currentUserCan(PermissionAction.Change, PermissionType.MailRule)">{{rule.name}}</button></div>
|
||||
<div class="col d-flex align-items-center">{{(mailAccountService.getCached(rule.account) | async)?.name}}</div>
|
||||
<div class="col">
|
||||
<div class="btn-group">
|
||||
<button *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.MailRule }" [disabled]="!userCanEdit(rule)" class="btn btn-sm btn-outline-secondary" type="button" (click)="editMailRule(rule)">
|
||||
<svg class="buttonicon-sm" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#pencil" />
|
||||
</svg> <ng-container i18n>Edit</ng-container>
|
||||
</button>
|
||||
<button *pngxIfOwner="rule" class="btn btn-sm btn-outline-secondary" type="button" (click)="editPermissions(rule)">
|
||||
<svg class="buttonicon-sm" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#person-lock" />
|
||||
</svg> <ng-container i18n>Permissions</ng-container>
|
||||
</button>
|
||||
<button *pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.MailRule }" [disabled]="!userIsOwner(rule)" class="btn btn-sm btn-outline-danger" type="button" (click)="deleteMailRule(rule)">
|
||||
<svg class="buttonicon-sm" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#trash" />
|
||||
</svg> <ng-container i18n>Delete</ng-container>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<div *ngIf="mailRules.length === 0" i18n>No mail rules defined.</div>
|
||||
</ul>
|
||||
</ng-container>
|
||||
|
||||
<div *ngIf="!mailAccounts || !mailRules">
|
||||
<div class="spinner-border spinner-border-sm fw-normal ms-2 me-auto" role="status"></div>
|
||||
<div class="visually-hidden" i18n>Loading...</div>
|
||||
</div>
|
304
src-ui/src/app/components/manage/mail/mail.component.spec.ts
Normal file
304
src-ui/src/app/components/manage/mail/mail.component.spec.ts
Normal file
@@ -0,0 +1,304 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
||||
|
||||
import { MailComponent } from './mail.component'
|
||||
import { DatePipe } from '@angular/common'
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing'
|
||||
import { RouterTestingModule } from '@angular/router/testing'
|
||||
import {
|
||||
NgbModule,
|
||||
NgbAlertModule,
|
||||
NgbModalRef,
|
||||
NgbModal,
|
||||
} from '@ng-bootstrap/ng-bootstrap'
|
||||
import { NgSelectModule } from '@ng-select/ng-select'
|
||||
import { of, throwError } from 'rxjs'
|
||||
import { routes } from 'src/app/app-routing.module'
|
||||
import { PaperlessMailAccount } from 'src/app/data/paperless-mail-account'
|
||||
import { PaperlessMailRule } from 'src/app/data/paperless-mail-rule'
|
||||
import { IfOwnerDirective } from 'src/app/directives/if-owner.directive'
|
||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
|
||||
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
||||
import { MailAccountService } from 'src/app/services/rest/mail-account.service'
|
||||
import { MailRuleService } from 'src/app/services/rest/mail-rule.service'
|
||||
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
|
||||
import { MailAccountEditDialogComponent } from '../../common/edit-dialog/mail-account-edit-dialog/mail-account-edit-dialog.component'
|
||||
import { MailRuleEditDialogComponent } from '../../common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component'
|
||||
import { CheckComponent } from '../../common/input/check/check.component'
|
||||
import { NumberComponent } from '../../common/input/number/number.component'
|
||||
import { PasswordComponent } from '../../common/input/password/password.component'
|
||||
import { PermissionsFormComponent } from '../../common/input/permissions/permissions-form/permissions-form.component'
|
||||
import { PermissionsGroupComponent } from '../../common/input/permissions/permissions-group/permissions-group.component'
|
||||
import { PermissionsUserComponent } from '../../common/input/permissions/permissions-user/permissions-user.component'
|
||||
import { SelectComponent } from '../../common/input/select/select.component'
|
||||
import { TextComponent } from '../../common/input/text/text.component'
|
||||
import { PageHeaderComponent } from '../../common/page-header/page-header.component'
|
||||
import { PermissionsDialogComponent } from '../../common/permissions-dialog/permissions-dialog.component'
|
||||
import { PermissionsService } from 'src/app/services/permissions.service'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
import { TagsComponent } from '../../common/input/tags/tags.component'
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
||||
import { EditDialogMode } from '../../common/edit-dialog/edit-dialog.component'
|
||||
|
||||
const mailAccounts = [
|
||||
{ id: 1, name: 'account1' },
|
||||
{ id: 2, name: 'account2' },
|
||||
]
|
||||
const mailRules = [
|
||||
{ id: 1, name: 'rule1', owner: 1, account: 1 },
|
||||
{ id: 2, name: 'rule2', owner: 2, account: 2 },
|
||||
]
|
||||
|
||||
describe('MailComponent', () => {
|
||||
let component: MailComponent
|
||||
let fixture: ComponentFixture<MailComponent>
|
||||
let mailAccountService: MailAccountService
|
||||
let mailRuleService: MailRuleService
|
||||
let modalService: NgbModal
|
||||
let toastService: ToastService
|
||||
let permissionsService: PermissionsService
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
MailComponent,
|
||||
PageHeaderComponent,
|
||||
IfPermissionsDirective,
|
||||
CustomDatePipe,
|
||||
ConfirmDialogComponent,
|
||||
CheckComponent,
|
||||
SafeHtmlPipe,
|
||||
SelectComponent,
|
||||
TextComponent,
|
||||
PasswordComponent,
|
||||
NumberComponent,
|
||||
MailAccountEditDialogComponent,
|
||||
MailRuleEditDialogComponent,
|
||||
IfOwnerDirective,
|
||||
TagsComponent,
|
||||
PermissionsUserComponent,
|
||||
PermissionsGroupComponent,
|
||||
PermissionsDialogComponent,
|
||||
PermissionsFormComponent,
|
||||
],
|
||||
providers: [CustomDatePipe, DatePipe, PermissionsGuard],
|
||||
imports: [
|
||||
NgbModule,
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule.withRoutes(routes),
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
NgbAlertModule,
|
||||
NgSelectModule,
|
||||
],
|
||||
}).compileComponents()
|
||||
|
||||
mailAccountService = TestBed.inject(MailAccountService)
|
||||
mailRuleService = TestBed.inject(MailRuleService)
|
||||
modalService = TestBed.inject(NgbModal)
|
||||
toastService = TestBed.inject(ToastService)
|
||||
permissionsService = TestBed.inject(PermissionsService)
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserOwnsObject')
|
||||
.mockReturnValue(true)
|
||||
|
||||
fixture = TestBed.createComponent(MailComponent)
|
||||
component = fixture.componentInstance
|
||||
fixture.detectChanges()
|
||||
})
|
||||
|
||||
function completeSetup(excludeService = null) {
|
||||
if (excludeService !== mailAccountService) {
|
||||
jest.spyOn(mailAccountService, 'listAll').mockReturnValue(
|
||||
of({
|
||||
all: mailAccounts.map((a) => a.id),
|
||||
count: mailAccounts.length,
|
||||
results: (mailAccounts as PaperlessMailAccount[]).concat([]),
|
||||
})
|
||||
)
|
||||
}
|
||||
if (excludeService !== mailRuleService) {
|
||||
jest.spyOn(mailRuleService, 'listAll').mockReturnValue(
|
||||
of({
|
||||
all: mailRules.map((r) => r.id),
|
||||
count: mailRules.length,
|
||||
results: (mailRules as PaperlessMailRule[]).concat([]),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
fixture = TestBed.createComponent(MailComponent)
|
||||
component = fixture.componentInstance
|
||||
fixture.detectChanges()
|
||||
}
|
||||
|
||||
it('should show errors on load if load mailAccounts failure', () => {
|
||||
const toastErrorSpy = jest.spyOn(toastService, 'showError')
|
||||
jest
|
||||
.spyOn(mailAccountService, 'listAll')
|
||||
.mockImplementation(() =>
|
||||
throwError(() => new Error('failed to load mail accounts'))
|
||||
)
|
||||
completeSetup(mailAccountService)
|
||||
expect(toastErrorSpy).toBeCalled()
|
||||
})
|
||||
|
||||
it('should show errors on load if load mailRules failure', () => {
|
||||
const toastErrorSpy = jest.spyOn(toastService, 'showError')
|
||||
jest
|
||||
.spyOn(mailRuleService, 'listAll')
|
||||
.mockImplementation(() =>
|
||||
throwError(() => new Error('failed to load mail rules'))
|
||||
)
|
||||
completeSetup(mailRuleService)
|
||||
expect(toastErrorSpy).toBeCalled()
|
||||
})
|
||||
|
||||
it('should support edit / create mail account, show error if needed', () => {
|
||||
completeSetup()
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((refs) => (modal = refs[0]))
|
||||
component.editMailAccount(mailAccounts[0] as PaperlessMailAccount)
|
||||
let editDialog = modal.componentInstance as MailAccountEditDialogComponent
|
||||
const toastErrorSpy = jest.spyOn(toastService, 'showError')
|
||||
const toastInfoSpy = jest.spyOn(toastService, 'showInfo')
|
||||
editDialog.failed.emit()
|
||||
expect(toastErrorSpy).toBeCalled()
|
||||
editDialog.succeeded.emit(mailAccounts[0])
|
||||
expect(toastInfoSpy).toHaveBeenCalledWith(
|
||||
`Saved account "${mailAccounts[0].name}".`
|
||||
)
|
||||
editDialog.cancel()
|
||||
component.editMailAccount()
|
||||
})
|
||||
|
||||
it('should support delete mail account, show error if needed', () => {
|
||||
completeSetup()
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((refs) => (modal = refs[0]))
|
||||
component.deleteMailAccount(mailAccounts[0] as PaperlessMailAccount)
|
||||
const deleteDialog = modal.componentInstance as ConfirmDialogComponent
|
||||
const deleteSpy = jest.spyOn(mailAccountService, 'delete')
|
||||
const toastErrorSpy = jest.spyOn(toastService, 'showError')
|
||||
const toastInfoSpy = jest.spyOn(toastService, 'showInfo')
|
||||
const listAllSpy = jest.spyOn(mailAccountService, 'listAll')
|
||||
deleteSpy.mockReturnValueOnce(
|
||||
throwError(() => new Error('error deleting mail account'))
|
||||
)
|
||||
deleteDialog.confirm()
|
||||
expect(toastErrorSpy).toBeCalled()
|
||||
deleteSpy.mockReturnValueOnce(of(true))
|
||||
deleteDialog.confirm()
|
||||
expect(listAllSpy).toHaveBeenCalled()
|
||||
expect(toastInfoSpy).toHaveBeenCalledWith('Deleted mail account')
|
||||
})
|
||||
|
||||
it('should support edit / create mail rule, show error if needed', () => {
|
||||
completeSetup()
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((refs) => (modal = refs[0]))
|
||||
component.editMailRule(mailRules[0] as PaperlessMailRule)
|
||||
const editDialog = modal.componentInstance as MailRuleEditDialogComponent
|
||||
const toastErrorSpy = jest.spyOn(toastService, 'showError')
|
||||
const toastInfoSpy = jest.spyOn(toastService, 'showInfo')
|
||||
editDialog.failed.emit()
|
||||
expect(toastErrorSpy).toBeCalled()
|
||||
editDialog.succeeded.emit(mailRules[0])
|
||||
expect(toastInfoSpy).toHaveBeenCalledWith(
|
||||
`Saved rule "${mailRules[0].name}".`
|
||||
)
|
||||
editDialog.cancel()
|
||||
component.editMailRule()
|
||||
})
|
||||
|
||||
it('should support delete mail rule, show error if needed', () => {
|
||||
completeSetup()
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((refs) => (modal = refs[0]))
|
||||
component.deleteMailRule(mailRules[0] as PaperlessMailRule)
|
||||
const deleteDialog = modal.componentInstance as ConfirmDialogComponent
|
||||
const deleteSpy = jest.spyOn(mailRuleService, 'delete')
|
||||
const toastErrorSpy = jest.spyOn(toastService, 'showError')
|
||||
const toastInfoSpy = jest.spyOn(toastService, 'showInfo')
|
||||
const listAllSpy = jest.spyOn(mailRuleService, 'listAll')
|
||||
deleteSpy.mockReturnValueOnce(
|
||||
throwError(() => new Error('error deleting mail rule'))
|
||||
)
|
||||
deleteDialog.confirm()
|
||||
expect(toastErrorSpy).toBeCalled()
|
||||
deleteSpy.mockReturnValueOnce(of(true))
|
||||
deleteDialog.confirm()
|
||||
expect(listAllSpy).toHaveBeenCalled()
|
||||
expect(toastInfoSpy).toHaveBeenCalledWith('Deleted mail rule')
|
||||
})
|
||||
|
||||
it('should support edit permissions on mail rule objects', () => {
|
||||
completeSetup()
|
||||
const perms = {
|
||||
owner: 99,
|
||||
set_permissions: {
|
||||
view: {
|
||||
users: [1],
|
||||
groups: [2],
|
||||
},
|
||||
change: {
|
||||
users: [3],
|
||||
groups: [4],
|
||||
},
|
||||
},
|
||||
}
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((refs) => (modal = refs[0]))
|
||||
const toastErrorSpy = jest.spyOn(toastService, 'showError')
|
||||
const toastInfoSpy = jest.spyOn(toastService, 'showInfo')
|
||||
const rulePatchSpy = jest.spyOn(mailRuleService, 'patch')
|
||||
component.editPermissions(mailRules[0] as PaperlessMailRule)
|
||||
expect(modal).not.toBeUndefined()
|
||||
let dialog = modal.componentInstance as PermissionsDialogComponent
|
||||
expect(dialog.object).toEqual(mailRules[0])
|
||||
|
||||
rulePatchSpy.mockReturnValueOnce(
|
||||
throwError(() => new Error('error saving perms'))
|
||||
)
|
||||
dialog.confirmClicked.emit(perms)
|
||||
expect(rulePatchSpy).toHaveBeenCalled()
|
||||
expect(toastErrorSpy).toHaveBeenCalled()
|
||||
rulePatchSpy.mockReturnValueOnce(of(mailRules[0] as PaperlessMailRule))
|
||||
dialog.confirmClicked.emit(perms)
|
||||
expect(toastInfoSpy).toHaveBeenCalledWith('Permissions updated')
|
||||
|
||||
modalService.dismissAll()
|
||||
})
|
||||
|
||||
it('should support edit permissions on mail account objects', () => {
|
||||
completeSetup()
|
||||
const perms = {
|
||||
owner: 99,
|
||||
set_permissions: {
|
||||
view: {
|
||||
users: [1],
|
||||
groups: [2],
|
||||
},
|
||||
change: {
|
||||
users: [3],
|
||||
groups: [4],
|
||||
},
|
||||
},
|
||||
}
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((refs) => (modal = refs[0]))
|
||||
const accountPatchSpy = jest.spyOn(mailAccountService, 'patch')
|
||||
component.editPermissions(mailAccounts[0] as PaperlessMailAccount)
|
||||
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)
|
||||
expect(accountPatchSpy).toHaveBeenCalled()
|
||||
})
|
||||
})
|
232
src-ui/src/app/components/manage/mail/mail.component.ts
Normal file
232
src-ui/src/app/components/manage/mail/mail.component.ts
Normal file
@@ -0,0 +1,232 @@
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { Subject, first, takeUntil } from 'rxjs'
|
||||
import { ObjectWithPermissions } from 'src/app/data/object-with-permissions'
|
||||
import { PaperlessMailAccount } from 'src/app/data/paperless-mail-account'
|
||||
import { PaperlessMailRule } from 'src/app/data/paperless-mail-rule'
|
||||
import {
|
||||
PermissionsService,
|
||||
PermissionAction,
|
||||
} from 'src/app/services/permissions.service'
|
||||
import { AbstractPaperlessService } from 'src/app/services/rest/abstract-paperless-service'
|
||||
import { MailAccountService } from 'src/app/services/rest/mail-account.service'
|
||||
import { MailRuleService } from 'src/app/services/rest/mail-rule.service'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
|
||||
import { EditDialogMode } from '../../common/edit-dialog/edit-dialog.component'
|
||||
import { MailAccountEditDialogComponent } from '../../common/edit-dialog/mail-account-edit-dialog/mail-account-edit-dialog.component'
|
||||
import { MailRuleEditDialogComponent } from '../../common/edit-dialog/mail-rule-edit-dialog/mail-rule-edit-dialog.component'
|
||||
import { PermissionsDialogComponent } from '../../common/permissions-dialog/permissions-dialog.component'
|
||||
import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-mail',
|
||||
templateUrl: './mail.component.html',
|
||||
styleUrls: ['./mail.component.scss'],
|
||||
})
|
||||
export class MailComponent
|
||||
extends ComponentWithPermissions
|
||||
implements OnInit, OnDestroy
|
||||
{
|
||||
mailAccounts: PaperlessMailAccount[] = []
|
||||
mailRules: PaperlessMailRule[] = []
|
||||
|
||||
unsubscribeNotifier: Subject<any> = new Subject()
|
||||
|
||||
constructor(
|
||||
public mailAccountService: MailAccountService,
|
||||
public mailRuleService: MailRuleService,
|
||||
private toastService: ToastService,
|
||||
private modalService: NgbModal,
|
||||
public permissionsService: PermissionsService
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.mailAccountService
|
||||
.listAll(null, null, { full_perms: true })
|
||||
.pipe(first(), takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe({
|
||||
next: (r) => {
|
||||
this.mailAccounts = r.results
|
||||
},
|
||||
error: (e) => {
|
||||
this.toastService.showError(
|
||||
$localize`Error retrieving mail accounts`,
|
||||
e
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
this.mailRuleService
|
||||
.listAll(null, null, { full_perms: true })
|
||||
.pipe(first(), takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe({
|
||||
next: (r) => {
|
||||
this.mailRules = r.results
|
||||
},
|
||||
error: (e) => {
|
||||
this.toastService.showError($localize`Error retrieving mail rules`, e)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unsubscribeNotifier.next(true)
|
||||
}
|
||||
|
||||
editMailAccount(account: PaperlessMailAccount = null) {
|
||||
const modal = this.modalService.open(MailAccountEditDialogComponent, {
|
||||
backdrop: 'static',
|
||||
size: 'xl',
|
||||
})
|
||||
modal.componentInstance.dialogMode = account
|
||||
? EditDialogMode.EDIT
|
||||
: EditDialogMode.CREATE
|
||||
modal.componentInstance.object = account
|
||||
modal.componentInstance.succeeded
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe((newMailAccount) => {
|
||||
this.toastService.showInfo(
|
||||
$localize`Saved account "${newMailAccount.name}".`
|
||||
)
|
||||
this.mailAccountService.clearCache()
|
||||
this.mailAccountService
|
||||
.listAll(null, null, { full_perms: true })
|
||||
.subscribe((r) => {
|
||||
this.mailAccounts = r.results
|
||||
})
|
||||
})
|
||||
modal.componentInstance.failed
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe((e) => {
|
||||
this.toastService.showError($localize`Error saving account.`, e)
|
||||
})
|
||||
}
|
||||
|
||||
deleteMailAccount(account: PaperlessMailAccount) {
|
||||
const modal = this.modalService.open(ConfirmDialogComponent, {
|
||||
backdrop: 'static',
|
||||
})
|
||||
modal.componentInstance.title = $localize`Confirm delete mail account`
|
||||
modal.componentInstance.messageBold = $localize`This operation will permanently delete this mail account.`
|
||||
modal.componentInstance.message = $localize`This operation cannot be undone.`
|
||||
modal.componentInstance.btnClass = 'btn-danger'
|
||||
modal.componentInstance.btnCaption = $localize`Proceed`
|
||||
modal.componentInstance.confirmClicked.subscribe(() => {
|
||||
modal.componentInstance.buttonsEnabled = false
|
||||
this.mailAccountService.delete(account).subscribe({
|
||||
next: () => {
|
||||
modal.close()
|
||||
this.toastService.showInfo($localize`Deleted mail account`)
|
||||
this.mailAccountService.clearCache()
|
||||
this.mailAccountService
|
||||
.listAll(null, null, { full_perms: true })
|
||||
.subscribe((r) => {
|
||||
this.mailAccounts = r.results
|
||||
})
|
||||
},
|
||||
error: (e) => {
|
||||
this.toastService.showError(
|
||||
$localize`Error deleting mail account.`,
|
||||
e
|
||||
)
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
editMailRule(rule: PaperlessMailRule = null) {
|
||||
const modal = this.modalService.open(MailRuleEditDialogComponent, {
|
||||
backdrop: 'static',
|
||||
size: 'xl',
|
||||
})
|
||||
modal.componentInstance.dialogMode = rule
|
||||
? EditDialogMode.EDIT
|
||||
: EditDialogMode.CREATE
|
||||
modal.componentInstance.object = rule
|
||||
modal.componentInstance.succeeded
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe((newMailRule) => {
|
||||
this.toastService.showInfo($localize`Saved rule "${newMailRule.name}".`)
|
||||
this.mailRuleService.clearCache()
|
||||
this.mailRuleService
|
||||
.listAll(null, null, { full_perms: true })
|
||||
.subscribe((r) => {
|
||||
this.mailRules = r.results
|
||||
})
|
||||
})
|
||||
modal.componentInstance.failed
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe((e) => {
|
||||
this.toastService.showError($localize`Error saving rule.`, e)
|
||||
})
|
||||
}
|
||||
|
||||
deleteMailRule(rule: PaperlessMailRule) {
|
||||
const modal = this.modalService.open(ConfirmDialogComponent, {
|
||||
backdrop: 'static',
|
||||
})
|
||||
modal.componentInstance.title = $localize`Confirm delete mail rule`
|
||||
modal.componentInstance.messageBold = $localize`This operation will permanently delete this mail rule.`
|
||||
modal.componentInstance.message = $localize`This operation cannot be undone.`
|
||||
modal.componentInstance.btnClass = 'btn-danger'
|
||||
modal.componentInstance.btnCaption = $localize`Proceed`
|
||||
modal.componentInstance.confirmClicked.subscribe(() => {
|
||||
modal.componentInstance.buttonsEnabled = false
|
||||
this.mailRuleService.delete(rule).subscribe({
|
||||
next: () => {
|
||||
modal.close()
|
||||
this.toastService.showInfo($localize`Deleted mail rule`)
|
||||
this.mailRuleService.clearCache()
|
||||
this.mailRuleService
|
||||
.listAll(null, null, { full_perms: true })
|
||||
.subscribe((r) => {
|
||||
this.mailRules = r.results
|
||||
})
|
||||
},
|
||||
error: (e) => {
|
||||
this.toastService.showError($localize`Error deleting mail rule.`, e)
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
editPermissions(object: PaperlessMailRule | PaperlessMailAccount) {
|
||||
const modal = this.modalService.open(PermissionsDialogComponent, {
|
||||
backdrop: 'static',
|
||||
})
|
||||
const dialog: PermissionsDialogComponent =
|
||||
modal.componentInstance as PermissionsDialogComponent
|
||||
dialog.object = object
|
||||
modal.componentInstance.confirmClicked.subscribe((permissions) => {
|
||||
modal.componentInstance.buttonsEnabled = false
|
||||
const service: AbstractPaperlessService<
|
||||
PaperlessMailRule | PaperlessMailAccount
|
||||
> = '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 {
|
||||
return this.permissionsService.currentUserHasObjectPermissions(
|
||||
PermissionAction.Change,
|
||||
obj
|
||||
)
|
||||
}
|
||||
|
||||
userIsOwner(obj: ObjectWithPermissions): boolean {
|
||||
return this.permissionsService.currentUserOwnsObject(obj)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user