diff --git a/src-ui/e2e/src/app.e2e-spec.ts b/src-ui/e2e/src/app.e2e-spec.ts index f2348e0c4..760871864 100644 --- a/src-ui/e2e/src/app.e2e-spec.ts +++ b/src-ui/e2e/src/app.e2e-spec.ts @@ -1,23 +1,25 @@ -import { AppPage } from './app.po'; -import { browser, logging } from 'protractor'; +import { AppPage } from './app.po' +import { browser, logging } from 'protractor' describe('workspace-project App', () => { - let page: AppPage; + let page: AppPage beforeEach(() => { - page = new AppPage(); - }); + page = new AppPage() + }) it('should display welcome message', () => { - page.navigateTo(); - expect(page.getTitleText()).toEqual('paperless-ui app is running!'); - }); + page.navigateTo() + expect(page.getTitleText()).toEqual('paperless-ui app is running!') + }) afterEach(async () => { // Assert that there are no errors emitted from the browser - const logs = await browser.manage().logs().get(logging.Type.BROWSER); - expect(logs).not.toContain(jasmine.objectContaining({ - level: logging.Level.SEVERE, - } as logging.Entry)); - }); -}); + const logs = await browser.manage().logs().get(logging.Type.BROWSER) + expect(logs).not.toContain( + jasmine.objectContaining({ + level: logging.Level.SEVERE, + } as logging.Entry) + ) + }) +}) diff --git a/src-ui/e2e/src/app.po.ts b/src-ui/e2e/src/app.po.ts index b68475e0f..7a2f42e17 100644 --- a/src-ui/e2e/src/app.po.ts +++ b/src-ui/e2e/src/app.po.ts @@ -1,11 +1,13 @@ -import { browser, by, element } from 'protractor'; +import { browser, by, element } from 'protractor' export class AppPage { navigateTo(): Promise { - return browser.get(browser.baseUrl) as Promise; + return browser.get(browser.baseUrl) as Promise } getTitleText(): Promise { - return element(by.css('app-root .content span')).getText() as Promise; + return element( + by.css('app-root .content span') + ).getText() as Promise } } diff --git a/src-ui/src/app/app-routing.module.ts b/src-ui/src/app/app-routing.module.ts index c2ea53bb7..436d2fad4 100644 --- a/src-ui/src/app/app-routing.module.ts +++ b/src-ui/src/app/app-routing.module.ts @@ -1,39 +1,47 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; -import { AppFrameComponent } from './components/app-frame/app-frame.component'; -import { DashboardComponent } from './components/dashboard/dashboard.component'; -import { DocumentDetailComponent } from './components/document-detail/document-detail.component'; -import { DocumentListComponent } from './components/document-list/document-list.component'; -import { CorrespondentListComponent } from './components/manage/correspondent-list/correspondent-list.component'; -import { DocumentTypeListComponent } from './components/manage/document-type-list/document-type-list.component'; -import { LogsComponent } from './components/manage/logs/logs.component'; -import { SettingsComponent } from './components/manage/settings/settings.component'; -import { TagListComponent } from './components/manage/tag-list/tag-list.component'; -import { NotFoundComponent } from './components/not-found/not-found.component'; -import {DocumentAsnComponent} from "./components/document-asn/document-asn.component"; -import { DirtyFormGuard } from './guards/dirty-form.guard'; +import { NgModule } from '@angular/core' +import { Routes, RouterModule } from '@angular/router' +import { AppFrameComponent } from './components/app-frame/app-frame.component' +import { DashboardComponent } from './components/dashboard/dashboard.component' +import { DocumentDetailComponent } from './components/document-detail/document-detail.component' +import { DocumentListComponent } from './components/document-list/document-list.component' +import { CorrespondentListComponent } from './components/manage/correspondent-list/correspondent-list.component' +import { DocumentTypeListComponent } from './components/manage/document-type-list/document-type-list.component' +import { LogsComponent } from './components/manage/logs/logs.component' +import { SettingsComponent } from './components/manage/settings/settings.component' +import { TagListComponent } from './components/manage/tag-list/tag-list.component' +import { NotFoundComponent } from './components/not-found/not-found.component' +import { DocumentAsnComponent } from './components/document-asn/document-asn.component' +import { DirtyFormGuard } from './guards/dirty-form.guard' const routes: Routes = [ - {path: '', redirectTo: 'dashboard', pathMatch: 'full'}, - {path: '', component: AppFrameComponent, children: [ - {path: 'dashboard', component: DashboardComponent }, - {path: 'documents', component: DocumentListComponent }, - {path: 'view/:id', component: DocumentListComponent }, - {path: 'documents/:id', component: DocumentDetailComponent }, - {path: 'asn/:id', component: DocumentAsnComponent }, - {path: 'tags', component: TagListComponent }, - {path: 'documenttypes', component: DocumentTypeListComponent }, - {path: 'correspondents', component: CorrespondentListComponent }, - {path: 'logs', component: LogsComponent }, - {path: 'settings', component: SettingsComponent, canDeactivate: [DirtyFormGuard] }, - ]}, + { path: '', redirectTo: 'dashboard', pathMatch: 'full' }, + { + path: '', + component: AppFrameComponent, + children: [ + { path: 'dashboard', component: DashboardComponent }, + { path: 'documents', component: DocumentListComponent }, + { path: 'view/:id', component: DocumentListComponent }, + { path: 'documents/:id', component: DocumentDetailComponent }, + { path: 'asn/:id', component: DocumentAsnComponent }, + { path: 'tags', component: TagListComponent }, + { path: 'documenttypes', component: DocumentTypeListComponent }, + { path: 'correspondents', component: CorrespondentListComponent }, + { path: 'logs', component: LogsComponent }, + { + path: 'settings', + component: SettingsComponent, + canDeactivate: [DirtyFormGuard], + }, + ], + }, - {path: '404', component: NotFoundComponent}, - {path: '**', redirectTo: '/404', pathMatch: 'full'} -]; + { path: '404', component: NotFoundComponent }, + { path: '**', redirectTo: '/404', pathMatch: 'full' }, +] @NgModule({ imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })], - exports: [RouterModule] + exports: [RouterModule], }) -export class AppRoutingModule { } +export class AppRoutingModule {} diff --git a/src-ui/src/app/app.component.spec.ts b/src-ui/src/app/app.component.spec.ts index 969a50dd9..f3ce2b3c2 100644 --- a/src-ui/src/app/app.component.spec.ts +++ b/src-ui/src/app/app.component.spec.ts @@ -1,35 +1,33 @@ -import { TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { AppComponent } from './app.component'; +import { TestBed } from '@angular/core/testing' +import { RouterTestingModule } from '@angular/router/testing' +import { AppComponent } from './app.component' describe('AppComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [ - RouterTestingModule - ], - declarations: [ - AppComponent - ], - }).compileComponents(); - }); + imports: [RouterTestingModule], + declarations: [AppComponent], + }).compileComponents() + }) it('should create the app', () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - }); + const fixture = TestBed.createComponent(AppComponent) + const app = fixture.componentInstance + expect(app).toBeTruthy() + }) it(`should have as title 'paperless-ui'`, () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('paperless-ui'); - }); + const fixture = TestBed.createComponent(AppComponent) + const app = fixture.componentInstance + expect(app.title).toEqual('paperless-ui') + }) it('should render title', () => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.nativeElement; - expect(compiled.querySelector('.content span').textContent).toContain('paperless-ui app is running!'); - }); -}); + const fixture = TestBed.createComponent(AppComponent) + fixture.detectChanges() + const compiled = fixture.nativeElement + expect(compiled.querySelector('.content span').textContent).toContain( + 'paperless-ui app is running!' + ) + }) +}) diff --git a/src-ui/src/app/app.component.ts b/src-ui/src/app/app.component.ts index 2f7de03b5..b21c771ae 100644 --- a/src-ui/src/app/app.component.ts +++ b/src-ui/src/app/app.component.ts @@ -1,24 +1,28 @@ -import { SettingsService, SETTINGS_KEYS } from './services/settings.service'; -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; -import { Subscription } from 'rxjs'; -import { ConsumerStatusService } from './services/consumer-status.service'; -import { ToastService } from './services/toast.service'; +import { SettingsService, SETTINGS_KEYS } from './services/settings.service' +import { Component, OnDestroy, OnInit } from '@angular/core' +import { Router } from '@angular/router' +import { Subscription } from 'rxjs' +import { ConsumerStatusService } from './services/consumer-status.service' +import { ToastService } from './services/toast.service' @Component({ selector: 'app-root', templateUrl: './app.component.html', - styleUrls: ['./app.component.scss'] + styleUrls: ['./app.component.scss'], }) export class AppComponent implements OnInit, OnDestroy { + newDocumentSubscription: Subscription + successSubscription: Subscription + failedSubscription: Subscription - newDocumentSubscription: Subscription; - successSubscription: Subscription; - failedSubscription: Subscription; - - constructor (private settings: SettingsService, private consumerStatusService: ConsumerStatusService, private toastService: ToastService, private router: Router) { - let anyWindow = (window as any) - anyWindow.pdfWorkerSrc = 'assets/js/pdf.worker.min.js'; + constructor( + private settings: SettingsService, + private consumerStatusService: ConsumerStatusService, + private toastService: ToastService, + private router: Router + ) { + let anyWindow = window as any + anyWindow.pdfWorkerSrc = 'assets/js/pdf.worker.min.js' this.settings.updateAppearanceSettings() } @@ -36,7 +40,12 @@ export class AppComponent implements OnInit, OnDestroy { } private showNotification(key) { - if (this.router.url == '/dashboard' && this.settings.get(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD)) { + if ( + this.router.url == '/dashboard' && + this.settings.get( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD + ) + ) { return false } return this.settings.get(key) @@ -45,26 +54,50 @@ export class AppComponent implements OnInit, OnDestroy { ngOnInit(): void { this.consumerStatusService.connect() + this.successSubscription = this.consumerStatusService + .onDocumentConsumptionFinished() + .subscribe((status) => { + if ( + this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS) + ) { + this.toastService.show({ + title: $localize`Document added`, + delay: 10000, + content: $localize`Document ${status.filename} was added to paperless.`, + actionName: $localize`Open document`, + action: () => { + this.router.navigate(['documents', status.documentId]) + }, + }) + } + }) - this.successSubscription = this.consumerStatusService.onDocumentConsumptionFinished().subscribe(status => { - if (this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS)) { - this.toastService.show({title: $localize`Document added`, delay: 10000, content: $localize`Document ${status.filename} was added to paperless.`, actionName: $localize`Open document`, action: () => { - this.router.navigate(['documents', status.documentId]) - }}) - } - }) + this.failedSubscription = this.consumerStatusService + .onDocumentConsumptionFailed() + .subscribe((status) => { + if ( + this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED) + ) { + this.toastService.showError( + $localize`Could not add ${status.filename}\: ${status.message}` + ) + } + }) - this.failedSubscription = this.consumerStatusService.onDocumentConsumptionFailed().subscribe(status => { - if (this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED)) { - this.toastService.showError($localize`Could not add ${status.filename}\: ${status.message}`) - } - }) - - this.newDocumentSubscription = this.consumerStatusService.onDocumentDetected().subscribe(status => { - if (this.showNotification(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT)) { - this.toastService.show({title: $localize`New document detected`, delay: 5000, content: $localize`Document ${status.filename} is being processed by paperless.`}) - } - }) + this.newDocumentSubscription = this.consumerStatusService + .onDocumentDetected() + .subscribe((status) => { + if ( + this.showNotification( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT + ) + ) { + this.toastService.show({ + title: $localize`New document detected`, + delay: 5000, + content: $localize`Document ${status.filename} is being processed by paperless.`, + }) + } + }) } - } diff --git a/src-ui/src/app/app.module.ts b/src-ui/src/app/app.module.ts index be6f6543b..0d8ead9d3 100644 --- a/src-ui/src/app/app.module.ts +++ b/src-ui/src/app/app.module.ts @@ -1,85 +1,88 @@ -import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser' +import { NgModule } from '@angular/core' -import { AppRoutingModule } from './app-routing.module'; -import { AppComponent } from './app.component'; -import { NgbDateAdapter, NgbDateParserFormatter, NgbModule } from '@ng-bootstrap/ng-bootstrap'; -import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; -import { DocumentListComponent } from './components/document-list/document-list.component'; -import { DocumentDetailComponent } from './components/document-detail/document-detail.component'; -import { DashboardComponent } from './components/dashboard/dashboard.component'; -import { TagListComponent } from './components/manage/tag-list/tag-list.component'; -import { DocumentTypeListComponent } from './components/manage/document-type-list/document-type-list.component'; -import { LogsComponent } from './components/manage/logs/logs.component'; -import { SettingsComponent } from './components/manage/settings/settings.component'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { DatePipe, registerLocaleData } from '@angular/common'; -import { NotFoundComponent } from './components/not-found/not-found.component'; -import { CorrespondentListComponent } from './components/manage/correspondent-list/correspondent-list.component'; -import { ConfirmDialogComponent } from './components/common/confirm-dialog/confirm-dialog.component'; -import { CorrespondentEditDialogComponent } from './components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component'; -import { TagEditDialogComponent } from './components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component'; -import { DocumentTypeEditDialogComponent } from './components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component'; -import { TagComponent } from './components/common/tag/tag.component'; -import { PageHeaderComponent } from './components/common/page-header/page-header.component'; -import { AppFrameComponent } from './components/app-frame/app-frame.component'; -import { ToastsComponent } from './components/common/toasts/toasts.component'; -import { FilterEditorComponent } from './components/document-list/filter-editor/filter-editor.component'; -import { FilterableDropdownComponent } from './components/common/filterable-dropdown/filterable-dropdown.component'; -import { ToggleableDropdownButtonComponent } from './components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component'; -import { DateDropdownComponent } from './components/common/date-dropdown/date-dropdown.component'; -import { DocumentCardLargeComponent } from './components/document-list/document-card-large/document-card-large.component'; -import { DocumentCardSmallComponent } from './components/document-list/document-card-small/document-card-small.component'; -import { BulkEditorComponent } from './components/document-list/bulk-editor/bulk-editor.component'; -import { NgxFileDropModule } from 'ngx-file-drop'; -import { TextComponent } from './components/common/input/text/text.component'; -import { SelectComponent } from './components/common/input/select/select.component'; -import { CheckComponent } from './components/common/input/check/check.component'; -import { SaveViewConfigDialogComponent } from './components/document-list/save-view-config-dialog/save-view-config-dialog.component'; -import { InfiniteScrollModule } from 'ngx-infinite-scroll'; -import { TagsComponent } from './components/common/input/tags/tags.component'; -import { SortableDirective } from './directives/sortable.directive'; -import { CookieService } from 'ngx-cookie-service'; -import { CsrfInterceptor } from './interceptors/csrf.interceptor'; -import { SavedViewWidgetComponent } from './components/dashboard/widgets/saved-view-widget/saved-view-widget.component'; -import { StatisticsWidgetComponent } from './components/dashboard/widgets/statistics-widget/statistics-widget.component'; -import { UploadFileWidgetComponent } from './components/dashboard/widgets/upload-file-widget/upload-file-widget.component'; -import { WidgetFrameComponent } from './components/dashboard/widgets/widget-frame/widget-frame.component'; -import { PdfViewerModule } from 'ng2-pdf-viewer'; -import { WelcomeWidgetComponent } from './components/dashboard/widgets/welcome-widget/welcome-widget.component'; -import { YesNoPipe } from './pipes/yes-no.pipe'; -import { FileSizePipe } from './pipes/file-size.pipe'; -import { FilterPipe } from './pipes/filter.pipe'; -import { DocumentTitlePipe } from './pipes/document-title.pipe'; -import { MetadataCollapseComponent } from './components/document-detail/metadata-collapse/metadata-collapse.component'; -import { SelectDialogComponent } from './components/common/select-dialog/select-dialog.component'; -import { NgSelectModule } from '@ng-select/ng-select'; -import { NumberComponent } from './components/common/input/number/number.component'; -import { SafePipe } from './pipes/safe.pipe'; -import { CustomDatePipe } from './pipes/custom-date.pipe'; -import { DateComponent } from './components/common/input/date/date.component'; -import { ISODateTimeAdapter } from './utils/ngb-iso-date-time-adapter'; -import { LocalizedDateParserFormatter } from './utils/ngb-date-parser-formatter'; -import { ApiVersionInterceptor } from './interceptors/api-version.interceptor'; -import { ColorSliderModule } from 'ngx-color/slider'; -import { ColorComponent } from './components/common/input/color/color.component'; -import { DocumentAsnComponent } from './components/document-asn/document-asn.component'; - -import localeCs from '@angular/common/locales/cs'; -import localeDa from '@angular/common/locales/da'; -import localeDe from '@angular/common/locales/de'; -import localeEnGb from '@angular/common/locales/en-GB'; -import localeEs from '@angular/common/locales/es'; -import localeFr from '@angular/common/locales/fr'; -import localeIt from '@angular/common/locales/it'; -import localeLb from '@angular/common/locales/lb'; -import localeNl from '@angular/common/locales/nl'; -import localePl from '@angular/common/locales/pl'; -import localePt from '@angular/common/locales/pt'; -import localeSv from '@angular/common/locales/sv'; -import localeRo from '@angular/common/locales/ro'; -import localeRu from '@angular/common/locales/ru'; +import { AppRoutingModule } from './app-routing.module' +import { AppComponent } from './app.component' +import { + NgbDateAdapter, + NgbDateParserFormatter, + NgbModule, +} from '@ng-bootstrap/ng-bootstrap' +import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http' +import { DocumentListComponent } from './components/document-list/document-list.component' +import { DocumentDetailComponent } from './components/document-detail/document-detail.component' +import { DashboardComponent } from './components/dashboard/dashboard.component' +import { TagListComponent } from './components/manage/tag-list/tag-list.component' +import { DocumentTypeListComponent } from './components/manage/document-type-list/document-type-list.component' +import { LogsComponent } from './components/manage/logs/logs.component' +import { SettingsComponent } from './components/manage/settings/settings.component' +import { FormsModule, ReactiveFormsModule } from '@angular/forms' +import { DatePipe, registerLocaleData } from '@angular/common' +import { NotFoundComponent } from './components/not-found/not-found.component' +import { CorrespondentListComponent } from './components/manage/correspondent-list/correspondent-list.component' +import { ConfirmDialogComponent } from './components/common/confirm-dialog/confirm-dialog.component' +import { CorrespondentEditDialogComponent } from './components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component' +import { TagEditDialogComponent } from './components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component' +import { DocumentTypeEditDialogComponent } from './components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component' +import { TagComponent } from './components/common/tag/tag.component' +import { PageHeaderComponent } from './components/common/page-header/page-header.component' +import { AppFrameComponent } from './components/app-frame/app-frame.component' +import { ToastsComponent } from './components/common/toasts/toasts.component' +import { FilterEditorComponent } from './components/document-list/filter-editor/filter-editor.component' +import { FilterableDropdownComponent } from './components/common/filterable-dropdown/filterable-dropdown.component' +import { ToggleableDropdownButtonComponent } from './components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component' +import { DateDropdownComponent } from './components/common/date-dropdown/date-dropdown.component' +import { DocumentCardLargeComponent } from './components/document-list/document-card-large/document-card-large.component' +import { DocumentCardSmallComponent } from './components/document-list/document-card-small/document-card-small.component' +import { BulkEditorComponent } from './components/document-list/bulk-editor/bulk-editor.component' +import { NgxFileDropModule } from 'ngx-file-drop' +import { TextComponent } from './components/common/input/text/text.component' +import { SelectComponent } from './components/common/input/select/select.component' +import { CheckComponent } from './components/common/input/check/check.component' +import { SaveViewConfigDialogComponent } from './components/document-list/save-view-config-dialog/save-view-config-dialog.component' +import { InfiniteScrollModule } from 'ngx-infinite-scroll' +import { TagsComponent } from './components/common/input/tags/tags.component' +import { SortableDirective } from './directives/sortable.directive' +import { CookieService } from 'ngx-cookie-service' +import { CsrfInterceptor } from './interceptors/csrf.interceptor' +import { SavedViewWidgetComponent } from './components/dashboard/widgets/saved-view-widget/saved-view-widget.component' +import { StatisticsWidgetComponent } from './components/dashboard/widgets/statistics-widget/statistics-widget.component' +import { UploadFileWidgetComponent } from './components/dashboard/widgets/upload-file-widget/upload-file-widget.component' +import { WidgetFrameComponent } from './components/dashboard/widgets/widget-frame/widget-frame.component' +import { PdfViewerModule } from 'ng2-pdf-viewer' +import { WelcomeWidgetComponent } from './components/dashboard/widgets/welcome-widget/welcome-widget.component' +import { YesNoPipe } from './pipes/yes-no.pipe' +import { FileSizePipe } from './pipes/file-size.pipe' +import { FilterPipe } from './pipes/filter.pipe' +import { DocumentTitlePipe } from './pipes/document-title.pipe' +import { MetadataCollapseComponent } from './components/document-detail/metadata-collapse/metadata-collapse.component' +import { SelectDialogComponent } from './components/common/select-dialog/select-dialog.component' +import { NgSelectModule } from '@ng-select/ng-select' +import { NumberComponent } from './components/common/input/number/number.component' +import { SafePipe } from './pipes/safe.pipe' +import { CustomDatePipe } from './pipes/custom-date.pipe' +import { DateComponent } from './components/common/input/date/date.component' +import { ISODateTimeAdapter } from './utils/ngb-iso-date-time-adapter' +import { LocalizedDateParserFormatter } from './utils/ngb-date-parser-formatter' +import { ApiVersionInterceptor } from './interceptors/api-version.interceptor' +import { ColorSliderModule } from 'ngx-color/slider' +import { ColorComponent } from './components/common/input/color/color.component' +import { DocumentAsnComponent } from './components/document-asn/document-asn.component' +import localeCs from '@angular/common/locales/cs' +import localeDa from '@angular/common/locales/da' +import localeDe from '@angular/common/locales/de' +import localeEnGb from '@angular/common/locales/en-GB' +import localeEs from '@angular/common/locales/es' +import localeFr from '@angular/common/locales/fr' +import localeIt from '@angular/common/locales/it' +import localeLb from '@angular/common/locales/lb' +import localeNl from '@angular/common/locales/nl' +import localePl from '@angular/common/locales/pl' +import localePt from '@angular/common/locales/pt' +import localeSv from '@angular/common/locales/sv' +import localeRo from '@angular/common/locales/ro' +import localeRu from '@angular/common/locales/ru' registerLocaleData(localeCs) registerLocaleData(localeDa) @@ -91,8 +94,8 @@ registerLocaleData(localeIt) registerLocaleData(localeLb) registerLocaleData(localeNl) registerLocaleData(localePl) -registerLocaleData(localePt, "pt-BR") -registerLocaleData(localePt, "pt-PT") +registerLocaleData(localePt, 'pt-BR') +registerLocaleData(localePt, 'pt-PT') registerLocaleData(localeRo) registerLocaleData(localeRu) registerLocaleData(localeSv) @@ -146,7 +149,7 @@ registerLocaleData(localeSv) CustomDatePipe, DateComponent, ColorComponent, - DocumentAsnComponent + DocumentAsnComponent, ], imports: [ BrowserModule, @@ -159,24 +162,26 @@ registerLocaleData(localeSv) InfiniteScrollModule, PdfViewerModule, NgSelectModule, - ColorSliderModule + ColorSliderModule, ], providers: [ DatePipe, - CookieService, { + CookieService, + { provide: HTTP_INTERCEPTORS, useClass: CsrfInterceptor, - multi: true - },{ + multi: true, + }, + { provide: HTTP_INTERCEPTORS, useClass: ApiVersionInterceptor, - multi: true + multi: true, }, FilterPipe, DocumentTitlePipe, - {provide: NgbDateAdapter, useClass: ISODateTimeAdapter}, - {provide: NgbDateParserFormatter, useClass: LocalizedDateParserFormatter} + { provide: NgbDateAdapter, useClass: ISODateTimeAdapter }, + { provide: NgbDateParserFormatter, useClass: LocalizedDateParserFormatter }, ], - bootstrap: [AppComponent] + bootstrap: [AppComponent], }) -export class AppModule { } +export class AppModule {} diff --git a/src-ui/src/app/components/app-frame/app-frame.component.spec.ts b/src-ui/src/app/components/app-frame/app-frame.component.spec.ts index 2d0df437c..ae32cc1f7 100644 --- a/src-ui/src/app/components/app-frame/app-frame.component.spec.ts +++ b/src-ui/src/app/components/app-frame/app-frame.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { AppFrameComponent } from './app-frame.component'; +import { AppFrameComponent } from './app-frame.component' describe('AppFrameComponent', () => { - let component: AppFrameComponent; - let fixture: ComponentFixture; + let component: AppFrameComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ AppFrameComponent ] - }) - .compileComponents(); - }); + declarations: [AppFrameComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(AppFrameComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(AppFrameComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/app-frame/app-frame.component.ts b/src-ui/src/app/components/app-frame/app-frame.component.ts index 74f3cd5b5..5a4521e12 100644 --- a/src-ui/src/app/components/app-frame/app-frame.component.ts +++ b/src-ui/src/app/components/app-frame/app-frame.component.ts @@ -1,26 +1,31 @@ -import { Component } from '@angular/core'; -import { FormControl } from '@angular/forms'; -import { ActivatedRoute, Router, Params } from '@angular/router'; -import { from, Observable, Subscription, BehaviorSubject } from 'rxjs'; -import { debounceTime, distinctUntilChanged, map, switchMap, first } from 'rxjs/operators'; -import { PaperlessDocument } from 'src/app/data/paperless-document'; -import { OpenDocumentsService } from 'src/app/services/open-documents.service'; -import { SavedViewService } from 'src/app/services/rest/saved-view.service'; -import { SearchService } from 'src/app/services/rest/search.service'; -import { environment } from 'src/environments/environment'; -import { DocumentDetailComponent } from '../document-detail/document-detail.component'; -import { Meta } from '@angular/platform-browser'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { FILTER_FULLTEXT_QUERY } from 'src/app/data/filter-rule-type'; +import { Component } from '@angular/core' +import { FormControl } from '@angular/forms' +import { ActivatedRoute, Router, Params } from '@angular/router' +import { from, Observable, Subscription, BehaviorSubject } from 'rxjs' +import { + debounceTime, + distinctUntilChanged, + map, + switchMap, + first, +} from 'rxjs/operators' +import { PaperlessDocument } from 'src/app/data/paperless-document' +import { OpenDocumentsService } from 'src/app/services/open-documents.service' +import { SavedViewService } from 'src/app/services/rest/saved-view.service' +import { SearchService } from 'src/app/services/rest/search.service' +import { environment } from 'src/environments/environment' +import { DocumentDetailComponent } from '../document-detail/document-detail.component' +import { Meta } from '@angular/platform-browser' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { FILTER_FULLTEXT_QUERY } from 'src/app/data/filter-rule-type' @Component({ selector: 'app-app-frame', templateUrl: './app-frame.component.html', - styleUrls: ['./app-frame.component.scss'] + styleUrls: ['./app-frame.component.scss'], }) export class AppFrameComponent { - - constructor ( + constructor( public router: Router, private activatedRoute: ActivatedRoute, private openDocumentsService: OpenDocumentsService, @@ -28,7 +33,7 @@ export class AppFrameComponent { public savedViewService: SavedViewService, private list: DocumentListViewService, private meta: Meta - ) { } + ) {} versionString = `${environment.appTitle} ${environment.version}` @@ -48,14 +53,14 @@ export class AppFrameComponent { text$.pipe( debounceTime(200), distinctUntilChanged(), - map(term => { + map((term) => { if (term.lastIndexOf(' ') != -1) { return term.substring(term.lastIndexOf(' ') + 1) } else { return term } }), - switchMap(term => + switchMap((term) => term.length < 2 ? from([[]]) : this.searchService.autocomplete(term) ) ) @@ -66,49 +71,60 @@ export class AppFrameComponent { let lastSpaceIndex = currentSearch.lastIndexOf(' ') if (lastSpaceIndex != -1) { currentSearch = currentSearch.substring(0, lastSpaceIndex + 1) - currentSearch += event.item + " " + currentSearch += event.item + ' ' } else { - currentSearch = event.item + " " + currentSearch = event.item + ' ' } this.searchField.patchValue(currentSearch) } search() { this.closeMenu() - this.list.quickFilter([{rule_type: FILTER_FULLTEXT_QUERY, value: this.searchField.value}]) + this.list.quickFilter([ + { rule_type: FILTER_FULLTEXT_QUERY, value: this.searchField.value }, + ]) } closeDocument(d: PaperlessDocument) { - this.openDocumentsService.closeDocument(d).pipe(first()).subscribe(confirmed => { - if (confirmed) { - this.closeMenu() - let route = this.activatedRoute.snapshot - while (route.firstChild) { - route = route.firstChild + this.openDocumentsService + .closeDocument(d) + .pipe(first()) + .subscribe((confirmed) => { + if (confirmed) { + this.closeMenu() + let route = this.activatedRoute.snapshot + while (route.firstChild) { + route = route.firstChild + } + if ( + route.component == DocumentDetailComponent && + route.params['id'] == d.id + ) { + this.router.navigate(['']) + } } - if (route.component == DocumentDetailComponent && route.params['id'] == d.id) { - this.router.navigate([""]) - } - } - }) + }) } closeAll() { // user may need to confirm losing unsaved changes - this.openDocumentsService.closeAll().pipe(first()).subscribe(confirmed => { - if (confirmed) { - this.closeMenu() + this.openDocumentsService + .closeAll() + .pipe(first()) + .subscribe((confirmed) => { + if (confirmed) { + this.closeMenu() - // TODO: is there a better way to do this? - let route = this.activatedRoute - while (route.firstChild) { - route = route.firstChild + // TODO: is there a better way to do this? + let route = this.activatedRoute + while (route.firstChild) { + route = route.firstChild + } + if (route.component === DocumentDetailComponent) { + this.router.navigate(['']) + } } - if (route.component === DocumentDetailComponent) { - this.router.navigate([""]) - } - } - }) + }) } get displayName() { @@ -123,5 +139,4 @@ export class AppFrameComponent { return null } } - } diff --git a/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.spec.ts b/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.spec.ts index fe08dc57a..7d92d78e5 100644 --- a/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.spec.ts +++ b/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { ConfirmDialogComponent } from './confirm-dialog.component'; +import { ConfirmDialogComponent } from './confirm-dialog.component' describe('ConfirmDialogComponent', () => { - let component: ConfirmDialogComponent; - let fixture: ComponentFixture; + let component: ConfirmDialogComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ ConfirmDialogComponent ] - }) - .compileComponents(); - }); + declarations: [ConfirmDialogComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(ConfirmDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(ConfirmDialogComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.ts b/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.ts index 5e198992e..10d32db43 100644 --- a/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.ts +++ b/src-ui/src/app/components/common/confirm-dialog/confirm-dialog.component.ts @@ -1,15 +1,14 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; -import { Subject } from 'rxjs'; +import { Component, EventEmitter, Input, Output } from '@angular/core' +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' +import { Subject } from 'rxjs' @Component({ selector: 'app-confirm-dialog', templateUrl: './confirm-dialog.component.html', - styleUrls: ['./confirm-dialog.component.scss'] + styleUrls: ['./confirm-dialog.component.scss'], }) export class ConfirmDialogComponent { - - constructor(public activeModal: NgbActiveModal) { } + constructor(public activeModal: NgbActiveModal) {} @Output() public confirmClicked = new EventEmitter() @@ -24,7 +23,7 @@ export class ConfirmDialogComponent { message @Input() - btnClass = "btn-primary" + btnClass = 'btn-primary' @Input() btnCaption = $localize`Confirm` diff --git a/src-ui/src/app/components/common/date-dropdown/date-dropdown.component.spec.ts b/src-ui/src/app/components/common/date-dropdown/date-dropdown.component.spec.ts index 8355db1c4..b689078e1 100644 --- a/src-ui/src/app/components/common/date-dropdown/date-dropdown.component.spec.ts +++ b/src-ui/src/app/components/common/date-dropdown/date-dropdown.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { DateDropdownComponent } from './date-dropdown.component'; +import { DateDropdownComponent } from './date-dropdown.component' describe('DateDropdownComponent', () => { - let component: DateDropdownComponent; - let fixture: ComponentFixture; + let component: DateDropdownComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ DateDropdownComponent ] - }) - .compileComponents(); - }); + declarations: [DateDropdownComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(DateDropdownComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(DateDropdownComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/common/date-dropdown/date-dropdown.component.ts b/src-ui/src/app/components/common/date-dropdown/date-dropdown.component.ts index 70d02540c..f9d90ae7a 100644 --- a/src-ui/src/app/components/common/date-dropdown/date-dropdown.component.ts +++ b/src-ui/src/app/components/common/date-dropdown/date-dropdown.component.ts @@ -1,10 +1,17 @@ -import { formatDate } from '@angular/common'; -import { Component, EventEmitter, Input, Output, OnInit, OnDestroy } from '@angular/core'; -import { NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap'; -import { Subject, Subscription } from 'rxjs'; -import { debounceTime } from 'rxjs/operators'; -import { SettingsService } from 'src/app/services/settings.service'; -import { ISODateAdapter } from 'src/app/utils/ngb-iso-date-adapter'; +import { formatDate } from '@angular/common' +import { + Component, + EventEmitter, + Input, + Output, + OnInit, + OnDestroy, +} from '@angular/core' +import { NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap' +import { Subject, Subscription } from 'rxjs' +import { debounceTime } from 'rxjs/operators' +import { SettingsService } from 'src/app/services/settings.service' +import { ISODateAdapter } from 'src/app/utils/ngb-iso-date-adapter' export interface DateSelection { before?: string @@ -20,21 +27,18 @@ const LAST_YEAR = 3 selector: 'app-date-dropdown', templateUrl: './date-dropdown.component.html', styleUrls: ['./date-dropdown.component.scss'], - providers: [ - {provide: NgbDateAdapter, useClass: ISODateAdapter}, - ] + providers: [{ provide: NgbDateAdapter, useClass: ISODateAdapter }], }) export class DateDropdownComponent implements OnInit, OnDestroy { - constructor(settings: SettingsService) { this.datePlaceHolder = settings.getLocalizedDateInputFormat() } quickFilters = [ - {id: LAST_7_DAYS, name: $localize`Last 7 days`}, - {id: LAST_MONTH, name: $localize`Last month`}, - {id: LAST_3_MONTHS, name: $localize`Last 3 months`}, - {id: LAST_YEAR, name: $localize`Last year`} + { id: LAST_7_DAYS, name: $localize`Last 7 days` }, + { id: LAST_MONTH, name: $localize`Last month` }, + { id: LAST_3_MONTHS, name: $localize`Last 3 months` }, + { id: LAST_YEAR, name: $localize`Last year` }, ] datePlaceHolder: string @@ -62,9 +66,7 @@ export class DateDropdownComponent implements OnInit, OnDestroy { private sub: Subscription ngOnInit() { - this.sub = this.datesSetDebounce$.pipe( - debounceTime(400) - ).subscribe(() => { + this.sub = this.datesSetDebounce$.pipe(debounceTime(400)).subscribe(() => { this.onChange() }) } @@ -81,11 +83,11 @@ export class DateDropdownComponent implements OnInit, OnDestroy { switch (qf) { case LAST_7_DAYS: date.setDate(date.getDate() - 7) - break; + break case LAST_MONTH: date.setMonth(date.getMonth() - 1) - break; + break case LAST_3_MONTHS: date.setMonth(date.getMonth() - 3) @@ -94,20 +96,22 @@ export class DateDropdownComponent implements OnInit, OnDestroy { case LAST_YEAR: date.setFullYear(date.getFullYear() - 1) break - - } - this.dateAfter = formatDate(date, 'yyyy-MM-dd', "en-us", "UTC") + } + this.dateAfter = formatDate(date, 'yyyy-MM-dd', 'en-us', 'UTC') this.onChange() } onChange() { this.dateAfterChange.emit(this.dateAfter) this.dateBeforeChange.emit(this.dateBefore) - this.datesSet.emit({after: this.dateAfter, before: this.dateBefore}) + this.datesSet.emit({ after: this.dateAfter, before: this.dateBefore }) } onChangeDebounce() { - this.datesSetDebounce$.next({after: this.dateAfter, before: this.dateBefore}) + this.datesSetDebounce$.next({ + after: this.dateAfter, + before: this.dateBefore, + }) } clearBefore() { diff --git a/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.spec.ts b/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.spec.ts index 597599604..2f258b4d1 100644 --- a/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.spec.ts +++ b/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { EditDialogComponent } from './edit-dialog.component'; +import { EditDialogComponent } from './edit-dialog.component' describe('EditDialogComponent', () => { - let component: EditDialogComponent; - let fixture: ComponentFixture; + let component: EditDialogComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ EditDialogComponent ] - }) - .compileComponents(); - }); + declarations: [EditDialogComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(EditDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(EditDialogComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.ts b/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.ts index 3faf18dbb..92b16a93d 100644 --- a/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.ts +++ b/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.ts @@ -1,20 +1,22 @@ -import { Directive, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { FormGroup } from '@angular/forms'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; -import { MATCHING_ALGORITHMS, MATCH_AUTO } from 'src/app/data/matching-model'; -import { ObjectWithId } from 'src/app/data/object-with-id'; -import { AbstractPaperlessService } from 'src/app/services/rest/abstract-paperless-service'; -import { ToastService } from 'src/app/services/toast.service'; +import { Directive, EventEmitter, Input, OnInit, Output } from '@angular/core' +import { FormGroup } from '@angular/forms' +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' +import { Observable } from 'rxjs' +import { map } from 'rxjs/operators' +import { MATCHING_ALGORITHMS, MATCH_AUTO } from 'src/app/data/matching-model' +import { ObjectWithId } from 'src/app/data/object-with-id' +import { AbstractPaperlessService } from 'src/app/services/rest/abstract-paperless-service' +import { ToastService } from 'src/app/services/toast.service' @Directive() -export abstract class EditDialogComponent implements OnInit { - +export abstract class EditDialogComponent + implements OnInit +{ constructor( private service: AbstractPaperlessService, private activeModal: NgbActiveModal, - private toastService: ToastService) { } + private toastService: ToastService + ) {} @Input() dialogMode: string = 'create' @@ -43,7 +45,7 @@ export abstract class EditDialogComponent implements OnI // wait to enable close button so it doesnt steal focus from input since its the first clickable element in the DOM setTimeout(() => { this.closeEnabled = true - }); + }) } getCreateTitle() { @@ -65,7 +67,7 @@ export abstract class EditDialogComponent implements OnI case 'edit': return this.getEditTitle() default: - break; + break } } @@ -78,25 +80,31 @@ export abstract class EditDialogComponent implements OnI } save() { - var newObject = Object.assign(Object.assign({}, this.object), this.objectForm.value) + var newObject = Object.assign( + Object.assign({}, this.object), + this.objectForm.value + ) var serverResponse: Observable switch (this.dialogMode) { case 'create': serverResponse = this.service.create(newObject) - break; + break case 'edit': serverResponse = this.service.update(newObject) default: - break; + break } this.networkActive = true - serverResponse.subscribe(result => { - this.activeModal.close() - this.success.emit(result) - }, error => { - this.error = error.error - this.networkActive = false - }) + serverResponse.subscribe( + (result) => { + this.activeModal.close() + this.success.emit(result) + }, + (error) => { + this.error = error.error + this.networkActive = false + } + ) } cancel() { diff --git a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.spec.ts b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.spec.ts index 3eef95c16..30b00adff 100644 --- a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.spec.ts +++ b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { FilterableDropodownComponent } from './filterable-dropdown.component'; +import { FilterableDropodownComponent } from './filterable-dropdown.component' describe('FilterableDropodownComponent', () => { - let component: FilterableDropodownComponent; - let fixture: ComponentFixture; + let component: FilterableDropodownComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ FilterableDropodownComponent ] - }) - .compileComponents(); - }); + declarations: [FilterableDropodownComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(FilterableDropodownComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(FilterableDropodownComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts index 27b04d08b..0f7218f06 100644 --- a/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts +++ b/src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts @@ -1,17 +1,23 @@ -import { Component, EventEmitter, Input, Output, ElementRef, ViewChild } from '@angular/core'; -import { FilterPipe } from 'src/app/pipes/filter.pipe'; +import { + Component, + EventEmitter, + Input, + Output, + ElementRef, + ViewChild, +} from '@angular/core' +import { FilterPipe } from 'src/app/pipes/filter.pipe' import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap' -import { ToggleableItemState } from './toggleable-dropdown-button/toggleable-dropdown-button.component'; -import { MatchingModel } from 'src/app/data/matching-model'; -import { Subject } from 'rxjs'; +import { ToggleableItemState } from './toggleable-dropdown-button/toggleable-dropdown-button.component' +import { MatchingModel } from 'src/app/data/matching-model' +import { Subject } from 'rxjs' export interface ChangedItems { - itemsToAdd: MatchingModel[], + itemsToAdd: MatchingModel[] itemsToRemove: MatchingModel[] } export class FilterableDropdownSelectionModel { - changed = new Subject() multiple = false @@ -22,14 +28,20 @@ export class FilterableDropdownSelectionModel { get itemsSorted(): MatchingModel[] { // TODO: this is getting called very often - return this.items.sort((a,b) => { + return this.items.sort((a, b) => { if (a.id == null && b.id != null) { return -1 } else if (a.id != null && b.id == null) { return 1 - } else if (this.getNonTemporary(a.id) == ToggleableItemState.NotSelected && this.getNonTemporary(b.id) != ToggleableItemState.NotSelected) { + } else if ( + this.getNonTemporary(a.id) == ToggleableItemState.NotSelected && + this.getNonTemporary(b.id) != ToggleableItemState.NotSelected + ) { return 1 - } else if (this.getNonTemporary(a.id) != ToggleableItemState.NotSelected && this.getNonTemporary(b.id) == ToggleableItemState.NotSelected) { + } else if ( + this.getNonTemporary(a.id) != ToggleableItemState.NotSelected && + this.getNonTemporary(b.id) == ToggleableItemState.NotSelected + ) { return -1 } else { return a.name.localeCompare(b.name) @@ -42,11 +54,17 @@ export class FilterableDropdownSelectionModel { private temporarySelectionStates = new Map() getSelectedItems() { - return this.items.filter(i => this.temporarySelectionStates.get(i.id) == ToggleableItemState.Selected) + return this.items.filter( + (i) => + this.temporarySelectionStates.get(i.id) == ToggleableItemState.Selected + ) } getExcludedItems() { - return this.items.filter(i => this.temporarySelectionStates.get(i.id) == ToggleableItemState.Excluded) + return this.items.filter( + (i) => + this.temporarySelectionStates.get(i.id) == ToggleableItemState.Excluded + ) } set(id: number, state: ToggleableItemState, fireEvent = true) { @@ -62,9 +80,16 @@ export class FilterableDropdownSelectionModel { toggle(id: number, fireEvent = true) { let state = this.temporarySelectionStates.get(id) - if (state == null || (state != ToggleableItemState.Selected && state != ToggleableItemState.Excluded)) { + if ( + state == null || + (state != ToggleableItemState.Selected && + state != ToggleableItemState.Excluded) + ) { this.temporarySelectionStates.set(id, ToggleableItemState.Selected) - } else if (state == ToggleableItemState.Selected || state == ToggleableItemState.Excluded) { + } else if ( + state == ToggleableItemState.Selected || + state == ToggleableItemState.Excluded + ) { this.temporarySelectionStates.delete(id) } @@ -91,7 +116,7 @@ export class FilterableDropdownSelectionModel { } } - exclude(id: number, fireEvent:boolean = true) { + exclude(id: number, fireEvent: boolean = true) { let state = this.temporarySelectionStates.get(id) if (state == null || state != ToggleableItemState.Excluded) { this.temporarySelectionStates.set(id, ToggleableItemState.Excluded) @@ -130,7 +155,9 @@ export class FilterableDropdownSelectionModel { } get(id: number) { - return this.temporarySelectionStates.get(id) || ToggleableItemState.NotSelected + return ( + this.temporarySelectionStates.get(id) || ToggleableItemState.NotSelected + ) } selectionSize() { @@ -150,9 +177,19 @@ export class FilterableDropdownSelectionModel { } isDirty() { - if (!Array.from(this.temporarySelectionStates.keys()).every(id => this.temporarySelectionStates.get(id) == this.selectionStates.get(id))) { + if ( + !Array.from(this.temporarySelectionStates.keys()).every( + (id) => + this.temporarySelectionStates.get(id) == this.selectionStates.get(id) + ) + ) { return true - } else if (!Array.from(this.selectionStates.keys()).every(id => this.selectionStates.get(id) == this.temporarySelectionStates.get(id))) { + } else if ( + !Array.from(this.selectionStates.keys()).every( + (id) => + this.selectionStates.get(id) == this.temporarySelectionStates.get(id) + ) + ) { return true } else if (this.temporaryLogicalOperator !== this._logicalOperator) { return true @@ -162,7 +199,10 @@ export class FilterableDropdownSelectionModel { } isNoneSelected() { - return this.selectionSize() == 1 && this.get(null) == ToggleableItemState.Selected + return ( + this.selectionSize() == 1 && + this.get(null) == ToggleableItemState.Selected + ) } init(map) { @@ -187,8 +227,17 @@ export class FilterableDropdownSelectionModel { diff(): ChangedItems { return { - itemsToAdd: this.items.filter(item => this.temporarySelectionStates.get(item.id) == ToggleableItemState.Selected && this.selectionStates.get(item.id) != ToggleableItemState.Selected), - itemsToRemove: this.items.filter(item => !this.temporarySelectionStates.has(item.id) && this.selectionStates.has(item.id)), + itemsToAdd: this.items.filter( + (item) => + this.temporarySelectionStates.get(item.id) == + ToggleableItemState.Selected && + this.selectionStates.get(item.id) != ToggleableItemState.Selected + ), + itemsToRemove: this.items.filter( + (item) => + !this.temporarySelectionStates.has(item.id) && + this.selectionStates.has(item.id) + ), } } } @@ -196,10 +245,9 @@ export class FilterableDropdownSelectionModel { @Component({ selector: 'app-filterable-dropdown', templateUrl: './filterable-dropdown.component.html', - styleUrls: ['./filterable-dropdown.component.scss'] + styleUrls: ['./filterable-dropdown.component.scss'], }) export class FilterableDropdownComponent { - @ViewChild('listFilterTextInput') listFilterTextInput: ElementRef @ViewChild('dropdown') dropdown: NgbDropdown @@ -211,7 +259,7 @@ export class FilterableDropdownComponent { this._selectionModel.items = Array.from(items) this._selectionModel.items.unshift({ name: $localize`:Filter drop down element to filter for documents with no correspondent/type/tag assigned:Not assigned`, - id: null + id: null, }) } } @@ -229,7 +277,7 @@ export class FilterableDropdownComponent { model.items = this.selectionModel.items model.multiple = this.selectionModel.multiple } - model.changed.subscribe(updatedModel => { + model.changed.subscribe((updatedModel) => { this.selectionModelChange.next(updatedModel) }) this._selectionModel = model @@ -255,7 +303,7 @@ export class FilterableDropdownComponent { title: string @Input() - filterPlaceholder: string = "" + filterPlaceholder: string = '' @Input() icon: string @@ -276,14 +324,17 @@ export class FilterableDropdownComponent { open = new EventEmitter() get operatorToggleEnabled(): boolean { - return this.selectionModel.selectionSize() > 1 && this.selectionModel.getExcludedItems().length == 0 + return ( + this.selectionModel.selectionSize() > 1 && + this.selectionModel.getExcludedItems().length == 0 + ) } modelIsDirty: boolean = false constructor(private filterPipe: FilterPipe) { this.selectionModel = new FilterableDropdownSelectionModel() - this.selectionModelChange.subscribe(updatedModel => { + this.selectionModelChange.subscribe((updatedModel) => { this.modelIsDirty = updatedModel.isDirty() }) } @@ -300,7 +351,7 @@ export class FilterableDropdownComponent { dropdownOpenChange(open: boolean): void { if (open) { setTimeout(() => { - this.listFilterTextInput.nativeElement.focus(); + this.listFilterTextInput.nativeElement.focus() }, 0) if (this.editing) { this.selectionModel.reset() diff --git a/src-ui/src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component.spec.ts b/src-ui/src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component.spec.ts index ec2868d7c..4c9d79396 100644 --- a/src-ui/src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component.spec.ts +++ b/src-ui/src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { ToggleableDropdownButtonComponent } from './toggleable-dropdown-button.component'; +import { ToggleableDropdownButtonComponent } from './toggleable-dropdown-button.component' describe('ToggleableDropdownButtonComponent', () => { - let component: ToggleableDropdownButtonComponent; - let fixture: ComponentFixture; + let component: ToggleableDropdownButtonComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ ToggleableDropdownButtonComponent ] - }) - .compileComponents(); - }); + declarations: [ToggleableDropdownButtonComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(ToggleableDropdownButtonComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(ToggleableDropdownButtonComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component.ts b/src-ui/src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component.ts index a30f1863d..610824527 100644 --- a/src-ui/src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component.ts +++ b/src-ui/src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component.ts @@ -1,20 +1,19 @@ -import { Component, EventEmitter, Input, Output, OnInit } from '@angular/core'; -import { MatchingModel } from 'src/app/data/matching-model'; +import { Component, EventEmitter, Input, Output, OnInit } from '@angular/core' +import { MatchingModel } from 'src/app/data/matching-model' export enum ToggleableItemState { NotSelected = 0, Selected = 1, PartiallySelected = 2, - Excluded = 3 + Excluded = 3, } @Component({ selector: 'app-toggleable-dropdown-button', templateUrl: './toggleable-dropdown-button.component.html', - styleUrls: ['./toggleable-dropdown-button.component.scss'] + styleUrls: ['./toggleable-dropdown-button.component.scss'], }) export class ToggleableDropdownButtonComponent { - @Input() item: MatchingModel diff --git a/src-ui/src/app/components/common/input/abstract-input.ts b/src-ui/src/app/components/common/input/abstract-input.ts index 5165edc3b..113945749 100644 --- a/src-ui/src/app/components/common/input/abstract-input.ts +++ b/src-ui/src/app/components/common/input/abstract-input.ts @@ -1,30 +1,29 @@ -import { Directive, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; -import { ControlValueAccessor } from '@angular/forms'; -import { v4 as uuidv4 } from 'uuid'; +import { Directive, ElementRef, Input, OnInit, ViewChild } from '@angular/core' +import { ControlValueAccessor } from '@angular/forms' +import { v4 as uuidv4 } from 'uuid' @Directive() export class AbstractInputComponent implements OnInit, ControlValueAccessor { - - @ViewChild("inputField") + @ViewChild('inputField') inputField: ElementRef - constructor() { } + constructor() {} - onChange = (newValue: T) => {}; + onChange = (newValue: T) => {} - onTouched = () => {}; + onTouched = () => {} writeValue(newValue: any): void { this.value = newValue } registerOnChange(fn: any): void { - this.onChange = fn; + this.onChange = fn } registerOnTouched(fn: any): void { - this.onTouched = fn; + this.onTouched = fn } setDisabledState?(isDisabled: boolean): void { - this.disabled = isDisabled; + this.disabled = isDisabled } focus() { @@ -37,7 +36,7 @@ export class AbstractInputComponent implements OnInit, ControlValueAccessor { title: string @Input() - disabled = false; + disabled = false @Input() error: string diff --git a/src-ui/src/app/components/common/input/check/check.component.spec.ts b/src-ui/src/app/components/common/input/check/check.component.spec.ts index 9649ed157..0ac6271a4 100644 --- a/src-ui/src/app/components/common/input/check/check.component.spec.ts +++ b/src-ui/src/app/components/common/input/check/check.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { CheckComponent } from './check.component'; +import { CheckComponent } from './check.component' describe('CheckComponent', () => { - let component: CheckComponent; - let fixture: ComponentFixture; + let component: CheckComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ CheckComponent ] - }) - .compileComponents(); - }); + declarations: [CheckComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(CheckComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(CheckComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/common/input/check/check.component.ts b/src-ui/src/app/components/common/input/check/check.component.ts index d452aad87..f4a6e527e 100644 --- a/src-ui/src/app/components/common/input/check/check.component.ts +++ b/src-ui/src/app/components/common/input/check/check.component.ts @@ -1,22 +1,22 @@ -import { Component, forwardRef, Input, OnInit } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { v4 as uuidv4 } from 'uuid'; -import { AbstractInputComponent } from '../abstract-input'; +import { Component, forwardRef, Input, OnInit } from '@angular/core' +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' +import { v4 as uuidv4 } from 'uuid' +import { AbstractInputComponent } from '../abstract-input' @Component({ - providers: [{ - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => CheckComponent), - multi: true - }], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => CheckComponent), + multi: true, + }, + ], selector: 'app-input-check', templateUrl: './check.component.html', - styleUrls: ['./check.component.scss'] + styleUrls: ['./check.component.scss'], }) export class CheckComponent extends AbstractInputComponent { - constructor() { super() } - } diff --git a/src-ui/src/app/components/common/input/color/color.component.spec.ts b/src-ui/src/app/components/common/input/color/color.component.spec.ts index 7c5d0d270..f431ebe73 100644 --- a/src-ui/src/app/components/common/input/color/color.component.spec.ts +++ b/src-ui/src/app/components/common/input/color/color.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { ColorComponent } from './color.component'; +import { ColorComponent } from './color.component' describe('ColorComponent', () => { - let component: ColorComponent; - let fixture: ComponentFixture; + let component: ColorComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ ColorComponent ] - }) - .compileComponents(); - }); + declarations: [ColorComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(ColorComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(ColorComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/common/input/color/color.component.ts b/src-ui/src/app/components/common/input/color/color.component.ts index a7f3452f2..3efdda8c8 100644 --- a/src-ui/src/app/components/common/input/color/color.component.ts +++ b/src-ui/src/app/components/common/input/color/color.component.ts @@ -1,20 +1,21 @@ -import { Component, forwardRef } from '@angular/core'; -import { NG_VALUE_ACCESSOR } from '@angular/forms'; -import { randomColor } from 'src/app/utils/color'; -import { AbstractInputComponent } from '../abstract-input'; +import { Component, forwardRef } from '@angular/core' +import { NG_VALUE_ACCESSOR } from '@angular/forms' +import { randomColor } from 'src/app/utils/color' +import { AbstractInputComponent } from '../abstract-input' @Component({ - providers: [{ - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => ColorComponent), - multi: true - }], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ColorComponent), + multi: true, + }, + ], selector: 'app-input-color', templateUrl: './color.component.html', - styleUrls: ['./color.component.scss'] + styleUrls: ['./color.component.scss'], }) export class ColorComponent extends AbstractInputComponent { - constructor() { super() } diff --git a/src-ui/src/app/components/common/input/date/date.component.spec.ts b/src-ui/src/app/components/common/input/date/date.component.spec.ts index ea92c7b30..e2f0f1014 100644 --- a/src-ui/src/app/components/common/input/date/date.component.spec.ts +++ b/src-ui/src/app/components/common/input/date/date.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { DateComponent } from './date.component'; +import { DateComponent } from './date.component' describe('DateComponent', () => { - let component: DateComponent; - let fixture: ComponentFixture; + let component: DateComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ DateComponent ] - }) - .compileComponents(); - }); + declarations: [DateComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(DateComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(DateComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/common/input/date/date.component.ts b/src-ui/src/app/components/common/input/date/date.component.ts index 251ba9c98..a6d39321b 100644 --- a/src-ui/src/app/components/common/input/date/date.component.ts +++ b/src-ui/src/app/components/common/input/date/date.component.ts @@ -1,21 +1,24 @@ -import { Component, forwardRef, OnInit } from '@angular/core'; -import { NG_VALUE_ACCESSOR } from '@angular/forms'; -import { SettingsService } from 'src/app/services/settings.service'; -import { AbstractInputComponent } from '../abstract-input'; - +import { Component, forwardRef, OnInit } from '@angular/core' +import { NG_VALUE_ACCESSOR } from '@angular/forms' +import { SettingsService } from 'src/app/services/settings.service' +import { AbstractInputComponent } from '../abstract-input' @Component({ - providers: [{ - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => DateComponent), - multi: true - }], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => DateComponent), + multi: true, + }, + ], selector: 'app-input-date', templateUrl: './date.component.html', - styleUrls: ['./date.component.scss'] + styleUrls: ['./date.component.scss'], }) -export class DateComponent extends AbstractInputComponent implements OnInit { - +export class DateComponent + extends AbstractInputComponent + implements OnInit +{ constructor(private settings: SettingsService) { super() } diff --git a/src-ui/src/app/components/common/input/number/number.component.spec.ts b/src-ui/src/app/components/common/input/number/number.component.spec.ts index 3476cbc22..f513af1d5 100644 --- a/src-ui/src/app/components/common/input/number/number.component.spec.ts +++ b/src-ui/src/app/components/common/input/number/number.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { NumberComponent } from './number.component'; +import { NumberComponent } from './number.component' describe('NumberComponent', () => { - let component: NumberComponent; - let fixture: ComponentFixture; + let component: NumberComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ NumberComponent ] - }) - .compileComponents(); - }); + declarations: [NumberComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(NumberComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(NumberComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/common/input/number/number.component.ts b/src-ui/src/app/components/common/input/number/number.component.ts index 2d28a7801..cb29ff5e5 100644 --- a/src-ui/src/app/components/common/input/number/number.component.ts +++ b/src-ui/src/app/components/common/input/number/number.component.ts @@ -1,21 +1,22 @@ -import { Component, forwardRef } from '@angular/core'; -import { NG_VALUE_ACCESSOR } from '@angular/forms'; -import { FILTER_ASN_ISNULL } from 'src/app/data/filter-rule-type'; -import { DocumentService } from 'src/app/services/rest/document.service'; -import { AbstractInputComponent } from '../abstract-input'; +import { Component, forwardRef } from '@angular/core' +import { NG_VALUE_ACCESSOR } from '@angular/forms' +import { FILTER_ASN_ISNULL } from 'src/app/data/filter-rule-type' +import { DocumentService } from 'src/app/services/rest/document.service' +import { AbstractInputComponent } from '../abstract-input' @Component({ - providers: [{ - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => NumberComponent), - multi: true - }], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => NumberComponent), + multi: true, + }, + ], selector: 'app-input-number', templateUrl: './number.component.html', - styleUrls: ['./number.component.scss'] + styleUrls: ['./number.component.scss'], }) export class NumberComponent extends AbstractInputComponent { - constructor(private documentService: DocumentService) { super() } @@ -24,16 +25,17 @@ export class NumberComponent extends AbstractInputComponent { if (this.value) { return } - this.documentService.listFiltered(1, 1, "archive_serial_number", true, [{rule_type: FILTER_ASN_ISNULL, value: "false"}]).subscribe( - results => { + this.documentService + .listFiltered(1, 1, 'archive_serial_number', true, [ + { rule_type: FILTER_ASN_ISNULL, value: 'false' }, + ]) + .subscribe((results) => { if (results.count > 0) { this.value = results.results[0].archive_serial_number + 1 } else { this.value = 1 } this.onChange(this.value) - } - ) + }) } - } diff --git a/src-ui/src/app/components/common/input/select/select.component.spec.ts b/src-ui/src/app/components/common/input/select/select.component.spec.ts index 2fb4207eb..ddab3ab94 100644 --- a/src-ui/src/app/components/common/input/select/select.component.spec.ts +++ b/src-ui/src/app/components/common/input/select/select.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { SelectComponent } from './select.component'; +import { SelectComponent } from './select.component' describe('SelectComponent', () => { - let component: SelectComponent; - let fixture: ComponentFixture; + let component: SelectComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ SelectComponent ] - }) - .compileComponents(); - }); + declarations: [SelectComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(SelectComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(SelectComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/common/input/select/select.component.ts b/src-ui/src/app/components/common/input/select/select.component.ts index 921e3606c..98aef8d94 100644 --- a/src-ui/src/app/components/common/input/select/select.component.ts +++ b/src-ui/src/app/components/common/input/select/select.component.ts @@ -1,23 +1,30 @@ -import { Component, EventEmitter, forwardRef, Input, Output } from '@angular/core'; -import { NG_VALUE_ACCESSOR } from '@angular/forms'; -import { AbstractInputComponent } from '../abstract-input'; +import { + Component, + EventEmitter, + forwardRef, + Input, + Output, +} from '@angular/core' +import { NG_VALUE_ACCESSOR } from '@angular/forms' +import { AbstractInputComponent } from '../abstract-input' @Component({ - providers: [{ - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => SelectComponent), - multi: true - }], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => SelectComponent), + multi: true, + }, + ], selector: 'app-input-select', templateUrl: './select.component.html', - styleUrls: ['./select.component.scss'] + styleUrls: ['./select.component.scss'], }) export class SelectComponent extends AbstractInputComponent { - constructor() { super() this.addItemRef = this.addItem.bind(this) - } + } @Input() items: any[] @@ -47,7 +54,9 @@ export class SelectComponent extends AbstractInputComponent { getSuggestions() { if (this.suggestions && this.items) { - return this.suggestions.filter(id => id != this.value).map(id => this.items.find(item => item.id == id)) + return this.suggestions + .filter((id) => id != this.value) + .map((id) => this.items.find((item) => item.id == id)) } else { return [] } @@ -75,7 +84,6 @@ export class SelectComponent extends AbstractInputComponent { onBlur() { setTimeout(() => { this.clearLastSearchTerm() - }, 3000); + }, 3000) } - } diff --git a/src-ui/src/app/components/common/input/tags/tags.component.spec.ts b/src-ui/src/app/components/common/input/tags/tags.component.spec.ts index 582775da4..c2e22f806 100644 --- a/src-ui/src/app/components/common/input/tags/tags.component.spec.ts +++ b/src-ui/src/app/components/common/input/tags/tags.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { TagsComponent } from './tags.component'; +import { TagsComponent } from './tags.component' describe('TagsComponent', () => { - let component: TagsComponent; - let fixture: ComponentFixture; + let component: TagsComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ TagsComponent ] - }) - .compileComponents(); - }); + declarations: [TagsComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(TagsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(TagsComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/common/input/tags/tags.component.ts b/src-ui/src/app/components/common/input/tags/tags.component.ts index 8db444ba3..d1dc61544 100644 --- a/src-ui/src/app/components/common/input/tags/tags.component.ts +++ b/src-ui/src/app/components/common/input/tags/tags.component.ts @@ -1,45 +1,46 @@ -import { Component, forwardRef, Input, OnInit } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { TagEditDialogComponent } from 'src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component'; -import { PaperlessTag } from 'src/app/data/paperless-tag'; -import { TagService } from 'src/app/services/rest/tag.service'; +import { Component, forwardRef, Input, OnInit } from '@angular/core' +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' +import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { TagEditDialogComponent } from 'src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component' +import { PaperlessTag } from 'src/app/data/paperless-tag' +import { TagService } from 'src/app/services/rest/tag.service' @Component({ - providers: [{ - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => TagsComponent), - multi: true - }], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => TagsComponent), + multi: true, + }, + ], selector: 'app-input-tags', templateUrl: './tags.component.html', - styleUrls: ['./tags.component.scss'] + styleUrls: ['./tags.component.scss'], }) export class TagsComponent implements OnInit, ControlValueAccessor { - constructor(private tagService: TagService, private modalService: NgbModal) { this.createTagRef = this.createTag.bind(this) } - onChange = (newValue: number[]) => {}; + onChange = (newValue: number[]) => {} - onTouched = () => {}; + onTouched = () => {} writeValue(newValue: number[]): void { this.value = newValue } registerOnChange(fn: any): void { - this.onChange = fn; + this.onChange = fn } registerOnTouched(fn: any): void { - this.onTouched = fn; + this.onTouched = fn } setDisabledState?(isDisabled: boolean): void { - this.disabled = isDisabled; + this.disabled = isDisabled } ngOnInit(): void { - this.tagService.listAll().subscribe(result => { + this.tagService.listAll().subscribe((result) => { this.tags = result.results }) } @@ -63,7 +64,7 @@ export class TagsComponent implements OnInit, ControlValueAccessor { getTag(id) { if (this.tags) { - return this.tags.find(tag => tag.id == id) + return this.tags.find((tag) => tag.id == id) } else { return null } @@ -80,12 +81,15 @@ export class TagsComponent implements OnInit, ControlValueAccessor { } createTag(name: string = null) { - var modal = this.modalService.open(TagEditDialogComponent, {backdrop: 'static'}) + var modal = this.modalService.open(TagEditDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.dialogMode = 'create' if (name) modal.componentInstance.object = { name: name } - else if (this._lastSearchTerm) modal.componentInstance.object = { name: this._lastSearchTerm } - modal.componentInstance.success.subscribe(newTag => { - this.tagService.listAll().subscribe(tags => { + else if (this._lastSearchTerm) + modal.componentInstance.object = { name: this._lastSearchTerm } + modal.componentInstance.success.subscribe((newTag) => { + this.tagService.listAll().subscribe((tags) => { this.tags = tags.results this.value = [...this.value, newTag.id] this.onChange(this.value) @@ -95,7 +99,9 @@ export class TagsComponent implements OnInit, ControlValueAccessor { getSuggestions() { if (this.suggestions && this.tags) { - return this.suggestions.filter(id => !this.value.includes(id)).map(id => this.tags.find(tag => tag.id == id)) + return this.suggestions + .filter((id) => !this.value.includes(id)) + .map((id) => this.tags.find((tag) => tag.id == id)) } else { return [] } @@ -117,7 +123,6 @@ export class TagsComponent implements OnInit, ControlValueAccessor { onBlur() { setTimeout(() => { this.clearLastSearchTerm() - }, 3000); + }, 3000) } - } diff --git a/src-ui/src/app/components/common/input/text/text.component.spec.ts b/src-ui/src/app/components/common/input/text/text.component.spec.ts index 24b1e9e65..509d14ad3 100644 --- a/src-ui/src/app/components/common/input/text/text.component.spec.ts +++ b/src-ui/src/app/components/common/input/text/text.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { TextComponent } from './text.component'; +import { TextComponent } from './text.component' describe('TextComponent', () => { - let component: TextComponent; - let fixture: ComponentFixture; + let component: TextComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ TextComponent ] - }) - .compileComponents(); - }); + declarations: [TextComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(TextComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(TextComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/common/input/text/text.component.ts b/src-ui/src/app/components/common/input/text/text.component.ts index 0a1a05749..d2bac853d 100644 --- a/src-ui/src/app/components/common/input/text/text.component.ts +++ b/src-ui/src/app/components/common/input/text/text.component.ts @@ -1,21 +1,21 @@ -import { Component, forwardRef } from '@angular/core'; -import { NG_VALUE_ACCESSOR } from '@angular/forms'; -import { AbstractInputComponent } from '../abstract-input'; +import { Component, forwardRef } from '@angular/core' +import { NG_VALUE_ACCESSOR } from '@angular/forms' +import { AbstractInputComponent } from '../abstract-input' @Component({ - providers: [{ - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => TextComponent), - multi: true - }], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => TextComponent), + multi: true, + }, + ], selector: 'app-input-text', templateUrl: './text.component.html', - styleUrls: ['./text.component.scss'] + styleUrls: ['./text.component.scss'], }) export class TextComponent extends AbstractInputComponent { - constructor() { super() } - } diff --git a/src-ui/src/app/components/common/page-header/page-header.component.spec.ts b/src-ui/src/app/components/common/page-header/page-header.component.spec.ts index eb863e4f9..711fffbfd 100644 --- a/src-ui/src/app/components/common/page-header/page-header.component.spec.ts +++ b/src-ui/src/app/components/common/page-header/page-header.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { PageHeaderComponent } from './page-header.component'; +import { PageHeaderComponent } from './page-header.component' describe('PageHeaderComponent', () => { - let component: PageHeaderComponent; - let fixture: ComponentFixture; + let component: PageHeaderComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ PageHeaderComponent ] - }) - .compileComponents(); - }); + declarations: [PageHeaderComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(PageHeaderComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(PageHeaderComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/common/page-header/page-header.component.ts b/src-ui/src/app/components/common/page-header/page-header.component.ts index 153e6bea6..5b68e1423 100644 --- a/src-ui/src/app/components/common/page-header/page-header.component.ts +++ b/src-ui/src/app/components/common/page-header/page-header.component.ts @@ -1,17 +1,16 @@ -import { Component, Input } from '@angular/core'; -import { Title } from '@angular/platform-browser'; -import { environment } from 'src/environments/environment'; +import { Component, Input } from '@angular/core' +import { Title } from '@angular/platform-browser' +import { environment } from 'src/environments/environment' @Component({ selector: 'app-page-header', templateUrl: './page-header.component.html', - styleUrls: ['./page-header.component.scss'] + styleUrls: ['./page-header.component.scss'], }) export class PageHeaderComponent { + constructor(private titleService: Title) {} - constructor(private titleService: Title) { } - - _title = "" + _title = '' @Input() set title(title: string) { @@ -24,6 +23,5 @@ export class PageHeaderComponent { } @Input() - subTitle: string = "" - + subTitle: string = '' } diff --git a/src-ui/src/app/components/common/select-dialog/select-dialog.component.spec.ts b/src-ui/src/app/components/common/select-dialog/select-dialog.component.spec.ts index 3810bcbea..06ab79ef8 100644 --- a/src-ui/src/app/components/common/select-dialog/select-dialog.component.spec.ts +++ b/src-ui/src/app/components/common/select-dialog/select-dialog.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { SelectDialogComponent } from './select-dialog.component'; +import { SelectDialogComponent } from './select-dialog.component' describe('SelectDialogComponent', () => { - let component: SelectDialogComponent; - let fixture: ComponentFixture; + let component: SelectDialogComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ SelectDialogComponent ] - }) - .compileComponents(); - }); + declarations: [SelectDialogComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(SelectDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(SelectDialogComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/common/select-dialog/select-dialog.component.ts b/src-ui/src/app/components/common/select-dialog/select-dialog.component.ts index 99bf9b91a..dc0375caf 100644 --- a/src-ui/src/app/components/common/select-dialog/select-dialog.component.ts +++ b/src-ui/src/app/components/common/select-dialog/select-dialog.component.ts @@ -1,15 +1,14 @@ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; -import { ObjectWithId } from 'src/app/data/object-with-id'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core' +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' +import { ObjectWithId } from 'src/app/data/object-with-id' @Component({ selector: 'app-select-dialog', templateUrl: './select-dialog.component.html', - styleUrls: ['./select-dialog.component.scss'] + styleUrls: ['./select-dialog.component.scss'], }) - export class SelectDialogComponent implements OnInit { - constructor(public activeModal: NgbActiveModal) { } + constructor(public activeModal: NgbActiveModal) {} @Output() public selectClicked = new EventEmitter() @@ -25,8 +24,7 @@ export class SelectDialogComponent implements OnInit { selected: number - ngOnInit(): void { - } + ngOnInit(): void {} cancelClicked() { this.activeModal.close() diff --git a/src-ui/src/app/components/common/tag/tag.component.spec.ts b/src-ui/src/app/components/common/tag/tag.component.spec.ts index a2dd3b5a9..0b324ecf0 100644 --- a/src-ui/src/app/components/common/tag/tag.component.spec.ts +++ b/src-ui/src/app/components/common/tag/tag.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { TagComponent } from './tag.component'; +import { TagComponent } from './tag.component' describe('TagComponent', () => { - let component: TagComponent; - let fixture: ComponentFixture; + let component: TagComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ TagComponent ] - }) - .compileComponents(); - }); + declarations: [TagComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(TagComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(TagComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/common/tag/tag.component.ts b/src-ui/src/app/components/common/tag/tag.component.ts index e552ade9c..af2663536 100644 --- a/src-ui/src/app/components/common/tag/tag.component.ts +++ b/src-ui/src/app/components/common/tag/tag.component.ts @@ -1,25 +1,22 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { PaperlessTag } from 'src/app/data/paperless-tag'; +import { Component, Input, OnInit } from '@angular/core' +import { PaperlessTag } from 'src/app/data/paperless-tag' @Component({ selector: 'app-tag', templateUrl: './tag.component.html', - styleUrls: ['./tag.component.scss'] + styleUrls: ['./tag.component.scss'], }) export class TagComponent implements OnInit { - - constructor() { } + constructor() {} @Input() tag: PaperlessTag @Input() - linkTitle: string = "" + linkTitle: string = '' @Input() clickable: boolean = false - ngOnInit(): void { - } - + ngOnInit(): void {} } diff --git a/src-ui/src/app/components/common/toasts/toasts.component.spec.ts b/src-ui/src/app/components/common/toasts/toasts.component.spec.ts index 3486005f1..26c006345 100644 --- a/src-ui/src/app/components/common/toasts/toasts.component.spec.ts +++ b/src-ui/src/app/components/common/toasts/toasts.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { ToastsComponent } from './toasts.component'; +import { ToastsComponent } from './toasts.component' describe('ToastsComponent', () => { - let component: ToastsComponent; - let fixture: ComponentFixture; + let component: ToastsComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ ToastsComponent ] - }) - .compileComponents(); - }); + declarations: [ToastsComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(ToastsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(ToastsComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/common/toasts/toasts.component.ts b/src-ui/src/app/components/common/toasts/toasts.component.ts index 8f142646d..ac7a693d6 100644 --- a/src-ui/src/app/components/common/toasts/toasts.component.ts +++ b/src-ui/src/app/components/common/toasts/toasts.component.ts @@ -1,15 +1,14 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { Subscription } from 'rxjs'; -import { Toast, ToastService } from 'src/app/services/toast.service'; +import { Component, OnDestroy, OnInit } from '@angular/core' +import { Subscription } from 'rxjs' +import { Toast, ToastService } from 'src/app/services/toast.service' @Component({ selector: 'app-toasts', templateUrl: './toasts.component.html', - styleUrls: ['./toasts.component.scss'] + styleUrls: ['./toasts.component.scss'], }) export class ToastsComponent implements OnInit, OnDestroy { - - constructor(private toastService: ToastService) { } + constructor(private toastService: ToastService) {} subscription: Subscription @@ -20,7 +19,8 @@ export class ToastsComponent implements OnInit, OnDestroy { } ngOnInit(): void { - this.subscription = this.toastService.getToasts().subscribe(toasts => this.toasts = toasts) + this.subscription = this.toastService + .getToasts() + .subscribe((toasts) => (this.toasts = toasts)) } - } diff --git a/src-ui/src/app/components/dashboard/dashboard.component.spec.ts b/src-ui/src/app/components/dashboard/dashboard.component.spec.ts index 5ec4ff8fc..623e13628 100644 --- a/src-ui/src/app/components/dashboard/dashboard.component.spec.ts +++ b/src-ui/src/app/components/dashboard/dashboard.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { DashboardComponent } from './dashboard.component'; +import { DashboardComponent } from './dashboard.component' describe('DashboardComponent', () => { - let component: DashboardComponent; - let fixture: ComponentFixture; + let component: DashboardComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ DashboardComponent ] - }) - .compileComponents(); - }); + declarations: [DashboardComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(DashboardComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(DashboardComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/dashboard/dashboard.component.ts b/src-ui/src/app/components/dashboard/dashboard.component.ts index 5dd19006e..3dd648212 100644 --- a/src-ui/src/app/components/dashboard/dashboard.component.ts +++ b/src-ui/src/app/components/dashboard/dashboard.component.ts @@ -1,20 +1,15 @@ -import { Component, OnInit } from '@angular/core'; -import { Meta } from '@angular/platform-browser'; -import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'; -import { SavedViewService } from 'src/app/services/rest/saved-view.service'; - +import { Component, OnInit } from '@angular/core' +import { Meta } from '@angular/platform-browser' +import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' +import { SavedViewService } from 'src/app/services/rest/saved-view.service' @Component({ selector: 'app-dashboard', templateUrl: './dashboard.component.html', - styleUrls: ['./dashboard.component.scss'] + styleUrls: ['./dashboard.component.scss'], }) export class DashboardComponent implements OnInit { - - constructor( - private savedViewService: SavedViewService, - private meta: Meta - ) { } + constructor(private savedViewService: SavedViewService, private meta: Meta) {} get displayName() { let tagFullName = this.meta.getTag('name=full_name') @@ -39,9 +34,10 @@ export class DashboardComponent implements OnInit { savedViews: PaperlessSavedView[] = [] ngOnInit(): void { - this.savedViewService.listAll().subscribe(results => { - this.savedViews = results.results.filter(savedView => savedView.show_on_dashboard) + this.savedViewService.listAll().subscribe((results) => { + this.savedViews = results.results.filter( + (savedView) => savedView.show_on_dashboard + ) }) } - } diff --git a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.spec.ts b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.spec.ts index f0095b618..df26f34c8 100644 --- a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.spec.ts +++ b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { SavedViewWidgetComponent } from './saved-view-widget.component'; +import { SavedViewWidgetComponent } from './saved-view-widget.component' describe('SavedViewWidgetComponent', () => { - let component: SavedViewWidgetComponent; - let fixture: ComponentFixture; + let component: SavedViewWidgetComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ SavedViewWidgetComponent ] - }) - .compileComponents(); - }); + declarations: [SavedViewWidgetComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(SavedViewWidgetComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(SavedViewWidgetComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts index 20bc26cdc..3057452f0 100644 --- a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts +++ b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts @@ -1,24 +1,24 @@ -import { Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; -import { Subscription } from 'rxjs'; -import { PaperlessDocument } from 'src/app/data/paperless-document'; -import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { ConsumerStatusService } from 'src/app/services/consumer-status.service'; -import { DocumentService } from 'src/app/services/rest/document.service'; +import { Component, Input, OnDestroy, OnInit } from '@angular/core' +import { Router } from '@angular/router' +import { Subscription } from 'rxjs' +import { PaperlessDocument } from 'src/app/data/paperless-document' +import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { ConsumerStatusService } from 'src/app/services/consumer-status.service' +import { DocumentService } from 'src/app/services/rest/document.service' @Component({ selector: 'app-saved-view-widget', templateUrl: './saved-view-widget.component.html', - styleUrls: ['./saved-view-widget.component.scss'] + styleUrls: ['./saved-view-widget.component.scss'], }) export class SavedViewWidgetComponent implements OnInit, OnDestroy { - constructor( private documentService: DocumentService, private router: Router, private list: DocumentListViewService, - private consumerStatusService: ConsumerStatusService) { } + private consumerStatusService: ConsumerStatusService + ) {} @Input() savedView: PaperlessSavedView @@ -29,9 +29,11 @@ export class SavedViewWidgetComponent implements OnInit, OnDestroy { ngOnInit(): void { this.reload() - this.subscription = this.consumerStatusService.onDocumentConsumptionFinished().subscribe(status => { - this.reload() - }) + this.subscription = this.consumerStatusService + .onDocumentConsumptionFinished() + .subscribe((status) => { + this.reload() + }) } ngOnDestroy(): void { @@ -39,9 +41,17 @@ export class SavedViewWidgetComponent implements OnInit, OnDestroy { } reload() { - this.documentService.listFiltered(1,10,this.savedView.sort_field, this.savedView.sort_reverse, this.savedView.filter_rules).subscribe(result => { - this.documents = result.results - }) + this.documentService + .listFiltered( + 1, + 10, + this.savedView.sort_field, + this.savedView.sort_reverse, + this.savedView.filter_rules + ) + .subscribe((result) => { + this.documents = result.results + }) } showAll() { @@ -49,8 +59,7 @@ export class SavedViewWidgetComponent implements OnInit, OnDestroy { this.router.navigate(['view', this.savedView.id]) } else { this.list.loadSavedView(this.savedView, true) - this.router.navigate(["documents"]) + this.router.navigate(['documents']) } } - } diff --git a/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.spec.ts b/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.spec.ts index e8e44ca54..ba9523dc6 100644 --- a/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.spec.ts +++ b/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { StatisticsWidgetComponent } from './statistics-widget.component'; +import { StatisticsWidgetComponent } from './statistics-widget.component' describe('StatisticsWidgetComponent', () => { - let component: StatisticsWidgetComponent; - let fixture: ComponentFixture; + let component: StatisticsWidgetComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ StatisticsWidgetComponent ] - }) - .compileComponents(); - }); + declarations: [StatisticsWidgetComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(StatisticsWidgetComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(StatisticsWidgetComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.ts b/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.ts index f1488a66f..a13839f19 100644 --- a/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.ts +++ b/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.ts @@ -1,24 +1,24 @@ -import { HttpClient } from '@angular/common/http'; -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { Observable, Subscription } from 'rxjs'; -import { ConsumerStatusService } from 'src/app/services/consumer-status.service'; -import { environment } from 'src/environments/environment'; +import { HttpClient } from '@angular/common/http' +import { Component, OnDestroy, OnInit } from '@angular/core' +import { Observable, Subscription } from 'rxjs' +import { ConsumerStatusService } from 'src/app/services/consumer-status.service' +import { environment } from 'src/environments/environment' export interface Statistics { documents_total?: number documents_inbox?: number } - @Component({ selector: 'app-statistics-widget', templateUrl: './statistics-widget.component.html', - styleUrls: ['./statistics-widget.component.scss'] + styleUrls: ['./statistics-widget.component.scss'], }) export class StatisticsWidgetComponent implements OnInit, OnDestroy { - - constructor(private http: HttpClient, - private consumerStatusService: ConsumerStatusService) { } + constructor( + private http: HttpClient, + private consumerStatusService: ConsumerStatusService + ) {} statistics: Statistics = {} @@ -29,20 +29,21 @@ export class StatisticsWidgetComponent implements OnInit, OnDestroy { } reload() { - this.getStatistics().subscribe(statistics => { + this.getStatistics().subscribe((statistics) => { this.statistics = statistics }) } ngOnInit(): void { this.reload() - this.subscription = this.consumerStatusService.onDocumentConsumptionFinished().subscribe(status => { - this.reload() - }) + this.subscription = this.consumerStatusService + .onDocumentConsumptionFinished() + .subscribe((status) => { + this.reload() + }) } ngOnDestroy(): void { this.subscription.unsubscribe() } - } diff --git a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.spec.ts b/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.spec.ts index 88e8efa2e..6f05feaec 100644 --- a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.spec.ts +++ b/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { UploadFileWidgetComponent } from './upload-file-widget.component'; +import { UploadFileWidgetComponent } from './upload-file-widget.component' describe('UploadFileWidgetComponent', () => { - let component: UploadFileWidgetComponent; - let fixture: ComponentFixture; + let component: UploadFileWidgetComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ UploadFileWidgetComponent ] - }) - .compileComponents(); - }); + declarations: [UploadFileWidgetComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(UploadFileWidgetComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(UploadFileWidgetComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts b/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts index e74e2bc41..6ba6103d3 100644 --- a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts +++ b/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts @@ -1,15 +1,19 @@ -import { HttpEventType } from '@angular/common/http'; -import { Component, OnInit } from '@angular/core'; -import { FileSystemFileEntry, NgxFileDropEntry } from 'ngx-file-drop'; -import { ConsumerStatusService, FileStatus, FileStatusPhase } from 'src/app/services/consumer-status.service'; -import { DocumentService } from 'src/app/services/rest/document.service'; +import { HttpEventType } from '@angular/common/http' +import { Component, OnInit } from '@angular/core' +import { FileSystemFileEntry, NgxFileDropEntry } from 'ngx-file-drop' +import { + ConsumerStatusService, + FileStatus, + FileStatusPhase, +} from 'src/app/services/consumer-status.service' +import { DocumentService } from 'src/app/services/rest/document.service' const MAX_ALERTS = 5 @Component({ selector: 'app-upload-file-widget', templateUrl: './upload-file-widget.component.html', - styleUrls: ['./upload-file-widget.component.scss'] + styleUrls: ['./upload-file-widget.component.scss'], }) export class UploadFileWidgetComponent implements OnInit { alertsExpanded = false @@ -17,7 +21,7 @@ export class UploadFileWidgetComponent implements OnInit { constructor( private documentService: DocumentService, private consumerStatusService: ConsumerStatusService - ) { } + ) {} getStatus() { return this.consumerStatusService.getConsumerStatus().slice(0, MAX_ALERTS) @@ -25,7 +29,8 @@ export class UploadFileWidgetComponent implements OnInit { getStatusSummary() { let strings = [] - let countUploadingAndProcessing = this.consumerStatusService.getConsumerStatusNotCompleted().length + let countUploadingAndProcessing = + this.consumerStatusService.getConsumerStatusNotCompleted().length let countFailed = this.getStatusFailed().length let countSuccess = this.getStatusSuccess().length if (countUploadingAndProcessing > 0) { @@ -37,16 +42,21 @@ export class UploadFileWidgetComponent implements OnInit { if (countSuccess > 0) { strings.push($localize`Added: ${countSuccess}`) } - return strings.join($localize`:this string is used to separate processing, failed and added on the file upload widget:, `) + return strings.join( + $localize`:this string is used to separate processing, failed and added on the file upload widget:, ` + ) } getStatusHidden() { - if (this.consumerStatusService.getConsumerStatus().length < MAX_ALERTS) return [] + if (this.consumerStatusService.getConsumerStatus().length < MAX_ALERTS) + return [] else return this.consumerStatusService.getConsumerStatus().slice(MAX_ALERTS) } getStatusUploading() { - return this.consumerStatusService.getConsumerStatus(FileStatusPhase.UPLOADING) + return this.consumerStatusService.getConsumerStatus( + FileStatusPhase.UPLOADING + ) } getStatusFailed() { @@ -64,7 +74,7 @@ export class UploadFileWidgetComponent implements OnInit { let current = 0 let max = 0 - this.getStatusUploading().forEach(status => { + this.getStatusUploading().forEach((status) => { current += status.currentPhaseProgress max += status.currentPhaseMaxProgress }) @@ -73,18 +83,21 @@ export class UploadFileWidgetComponent implements OnInit { } isFinished(status: FileStatus) { - return status.phase == FileStatusPhase.FAILED || status.phase == FileStatusPhase.SUCCESS + return ( + status.phase == FileStatusPhase.FAILED || + status.phase == FileStatusPhase.SUCCESS + ) } getStatusColor(status: FileStatus) { switch (status.phase) { case FileStatusPhase.PROCESSING: case FileStatusPhase.UPLOADING: - return "primary" + return 'primary' case FileStatusPhase.FAILED: - return "danger" + return 'danger' case FileStatusPhase.SUCCESS: - return "success" + return 'success' } } @@ -96,20 +109,16 @@ export class UploadFileWidgetComponent implements OnInit { this.consumerStatusService.dismissCompleted() } - ngOnInit(): void { - } + ngOnInit(): void {} - public fileOver(event){ - } + public fileOver(event) {} - public fileLeave(event){ - } + public fileLeave(event) {} public dropped(files: NgxFileDropEntry[]) { for (const droppedFile of files) { if (droppedFile.fileEntry.isFile) { - - const fileEntry = droppedFile.fileEntry as FileSystemFileEntry; + const fileEntry = droppedFile.fileEntry as FileSystemFileEntry fileEntry.file((file: File) => { let formData = new FormData() formData.append('document', file, file.name) @@ -117,29 +126,37 @@ export class UploadFileWidgetComponent implements OnInit { status.message = $localize`Connecting...` - this.documentService.uploadDocument(formData).subscribe(event => { - if (event.type == HttpEventType.UploadProgress) { - status.updateProgress(FileStatusPhase.UPLOADING, event.loaded, event.total) - status.message = $localize`Uploading...` - } else if (event.type == HttpEventType.Response) { - status.taskId = event.body["task_id"] - status.message = $localize`Upload complete, waiting...` - } - - }, error => { - switch (error.status) { - case 400: { - this.consumerStatusService.fail(status, error.error.document) - break; + this.documentService.uploadDocument(formData).subscribe( + (event) => { + if (event.type == HttpEventType.UploadProgress) { + status.updateProgress( + FileStatusPhase.UPLOADING, + event.loaded, + event.total + ) + status.message = $localize`Uploading...` + } else if (event.type == HttpEventType.Response) { + status.taskId = event.body['task_id'] + status.message = $localize`Upload complete, waiting...` } - default: { - this.consumerStatusService.fail(status, $localize`HTTP error: ${error.status} ${error.statusText}`) - break; + }, + (error) => { + switch (error.status) { + case 400: { + this.consumerStatusService.fail(status, error.error.document) + break + } + default: { + this.consumerStatusService.fail( + status, + $localize`HTTP error: ${error.status} ${error.statusText}` + ) + break + } } } - - }) - }); + ) + }) } } } diff --git a/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.spec.ts b/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.spec.ts index 5e8c2494b..7dee2aad1 100644 --- a/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.spec.ts +++ b/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { WelcomeWidgetComponent } from './welcome-widget.component'; +import { WelcomeWidgetComponent } from './welcome-widget.component' describe('WelcomeWidgetComponent', () => { - let component: WelcomeWidgetComponent; - let fixture: ComponentFixture; + let component: WelcomeWidgetComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ WelcomeWidgetComponent ] - }) - .compileComponents(); - }); + declarations: [WelcomeWidgetComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(WelcomeWidgetComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(WelcomeWidgetComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.ts b/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.ts index 71a87189c..9873932ee 100644 --- a/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.ts +++ b/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.ts @@ -1,15 +1,12 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core' @Component({ selector: 'app-welcome-widget', templateUrl: './welcome-widget.component.html', - styleUrls: ['./welcome-widget.component.scss'] + styleUrls: ['./welcome-widget.component.scss'], }) export class WelcomeWidgetComponent implements OnInit { + constructor() {} - constructor() { } - - ngOnInit(): void { - } - + ngOnInit(): void {} } diff --git a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.spec.ts b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.spec.ts index ea1696750..750498f01 100644 --- a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.spec.ts +++ b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { WidgetFrameComponent } from './widget-frame.component'; +import { WidgetFrameComponent } from './widget-frame.component' describe('WidgetFrameComponent', () => { - let component: WidgetFrameComponent; - let fixture: ComponentFixture; + let component: WidgetFrameComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ WidgetFrameComponent ] - }) - .compileComponents(); - }); + declarations: [WidgetFrameComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(WidgetFrameComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(WidgetFrameComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.ts b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.ts index 38d6b0023..f21f6ca35 100644 --- a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.ts +++ b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.ts @@ -1,18 +1,15 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core' @Component({ selector: 'app-widget-frame', templateUrl: './widget-frame.component.html', - styleUrls: ['./widget-frame.component.scss'] + styleUrls: ['./widget-frame.component.scss'], }) export class WidgetFrameComponent implements OnInit { - - constructor() { } + constructor() {} @Input() title: string - ngOnInit(): void { - } - + ngOnInit(): void {} } diff --git a/src-ui/src/app/components/document-asn/document-asn.component.spec.ts b/src-ui/src/app/components/document-asn/document-asn.component.spec.ts index 5a9826f8d..92290955d 100644 --- a/src-ui/src/app/components/document-asn/document-asn.component.spec.ts +++ b/src-ui/src/app/components/document-asn/document-asn.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { DocumentAsnComponent } from './document-asn.component'; +import { DocumentAsnComponent } from './document-asn.component' describe('DocumentASNComponentComponent', () => { - let component: DocumentAsnComponent; - let fixture: ComponentFixture; + let component: DocumentAsnComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ DocumentAsnComponent ] - }) - .compileComponents(); - }); + declarations: [DocumentAsnComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(DocumentAsnComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(DocumentAsnComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/document-asn/document-asn.component.ts b/src-ui/src/app/components/document-asn/document-asn.component.ts index 550c331b9..4fb9f474a 100644 --- a/src-ui/src/app/components/document-asn/document-asn.component.ts +++ b/src-ui/src/app/components/document-asn/document-asn.component.ts @@ -1,34 +1,33 @@ -import { Component, OnInit } from '@angular/core'; -import {DocumentService} from "../../services/rest/document.service"; -import {ActivatedRoute, Router} from "@angular/router"; -import {FILTER_ASN} from "../../data/filter-rule-type"; +import { Component, OnInit } from '@angular/core' +import { DocumentService } from '../../services/rest/document.service' +import { ActivatedRoute, Router } from '@angular/router' +import { FILTER_ASN } from '../../data/filter-rule-type' @Component({ selector: 'app-document-asncomponent', templateUrl: './document-asn.component.html', - styleUrls: ['./document-asn.component.scss'] + styleUrls: ['./document-asn.component.scss'], }) export class DocumentAsnComponent implements OnInit { - asn: string constructor( private documentsService: DocumentService, private route: ActivatedRoute, - private router: Router) { } - + private router: Router + ) {} ngOnInit(): void { - - this.route.paramMap.subscribe(paramMap => { - this.asn = paramMap.get('id'); - this.documentsService.listAllFilteredIds([{rule_type: FILTER_ASN, value: this.asn}]).subscribe(documentId => { - if (documentId.length == 1) { - this.router.navigate(['documents', documentId[0]]) - } else { - this.router.navigate(['404']) - } - }) + this.route.paramMap.subscribe((paramMap) => { + this.asn = paramMap.get('id') + this.documentsService + .listAllFilteredIds([{ rule_type: FILTER_ASN, value: this.asn }]) + .subscribe((documentId) => { + if (documentId.length == 1) { + this.router.navigate(['documents', documentId[0]]) + } else { + this.router.navigate(['404']) + } + }) }) - } } diff --git a/src-ui/src/app/components/document-detail/document-detail.component.spec.ts b/src-ui/src/app/components/document-detail/document-detail.component.spec.ts index 0e4923e2e..bcd7c396f 100644 --- a/src-ui/src/app/components/document-detail/document-detail.component.spec.ts +++ b/src-ui/src/app/components/document-detail/document-detail.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { DocumentDetailComponent } from './document-detail.component'; +import { DocumentDetailComponent } from './document-detail.component' describe('DocumentDetailComponent', () => { - let component: DocumentDetailComponent; - let fixture: ComponentFixture; + let component: DocumentDetailComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ DocumentDetailComponent ] - }) - .compileComponents(); - }); + declarations: [DocumentDetailComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(DocumentDetailComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(DocumentDetailComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/document-detail/document-detail.component.ts b/src-ui/src/app/components/document-detail/document-detail.component.ts index 052e5cb40..dcafa6925 100644 --- a/src-ui/src/app/components/document-detail/document-detail.component.ts +++ b/src-ui/src/app/components/document-detail/document-detail.component.ts @@ -1,38 +1,55 @@ -import { Component, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { ActivatedRoute, Router } from '@angular/router'; -import { NgbModal, NgbNav } from '@ng-bootstrap/ng-bootstrap'; -import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'; -import { PaperlessDocument } from 'src/app/data/paperless-document'; -import { PaperlessDocumentMetadata } from 'src/app/data/paperless-document-metadata'; -import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'; -import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { OpenDocumentsService } from 'src/app/services/open-documents.service'; -import { CorrespondentService } from 'src/app/services/rest/correspondent.service'; -import { DocumentTypeService } from 'src/app/services/rest/document-type.service'; -import { DocumentService } from 'src/app/services/rest/document.service'; -import { ConfirmDialogComponent } from '../common/confirm-dialog/confirm-dialog.component'; -import { CorrespondentEditDialogComponent } from '../manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component'; -import { DocumentTypeEditDialogComponent } from '../manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component'; -import { PDFDocumentProxy } from 'ng2-pdf-viewer'; -import { ToastService } from 'src/app/services/toast.service'; -import { TextComponent } from '../common/input/text/text.component'; -import { SettingsService, SETTINGS_KEYS } from 'src/app/services/settings.service'; -import { dirtyCheck, DirtyComponent } from '@ngneat/dirty-check-forms'; -import { Observable, Subject, BehaviorSubject } from 'rxjs'; -import { first, takeUntil, switchMap, map, debounceTime, distinctUntilChanged } from 'rxjs/operators'; -import { PaperlessDocumentSuggestions } from 'src/app/data/paperless-document-suggestions'; -import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type'; +import { + Component, + OnInit, + OnDestroy, + ViewChild, + ElementRef, +} from '@angular/core' +import { FormControl, FormGroup } from '@angular/forms' +import { ActivatedRoute, Router } from '@angular/router' +import { NgbModal, NgbNav } from '@ng-bootstrap/ng-bootstrap' +import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent' +import { PaperlessDocument } from 'src/app/data/paperless-document' +import { PaperlessDocumentMetadata } from 'src/app/data/paperless-document-metadata' +import { PaperlessDocumentType } from 'src/app/data/paperless-document-type' +import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { OpenDocumentsService } from 'src/app/services/open-documents.service' +import { CorrespondentService } from 'src/app/services/rest/correspondent.service' +import { DocumentTypeService } from 'src/app/services/rest/document-type.service' +import { DocumentService } from 'src/app/services/rest/document.service' +import { ConfirmDialogComponent } from '../common/confirm-dialog/confirm-dialog.component' +import { CorrespondentEditDialogComponent } from '../manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component' +import { DocumentTypeEditDialogComponent } from '../manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component' +import { PDFDocumentProxy } from 'ng2-pdf-viewer' +import { ToastService } from 'src/app/services/toast.service' +import { TextComponent } from '../common/input/text/text.component' +import { + SettingsService, + SETTINGS_KEYS, +} from 'src/app/services/settings.service' +import { dirtyCheck, DirtyComponent } from '@ngneat/dirty-check-forms' +import { Observable, Subject, BehaviorSubject } from 'rxjs' +import { + first, + takeUntil, + switchMap, + map, + debounceTime, + distinctUntilChanged, +} from 'rxjs/operators' +import { PaperlessDocumentSuggestions } from 'src/app/data/paperless-document-suggestions' +import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type' @Component({ selector: 'app-document-detail', templateUrl: './document-detail.component.html', - styleUrls: ['./document-detail.component.scss'] + styleUrls: ['./document-detail.component.scss'], }) -export class DocumentDetailComponent implements OnInit, OnDestroy, DirtyComponent { - - @ViewChild("inputTitle") +export class DocumentDetailComponent + implements OnInit, OnDestroy, DirtyComponent +{ + @ViewChild('inputTitle') titleInput: TextComponent expandOriginalMetadata = false @@ -63,7 +80,7 @@ export class DocumentDetailComponent implements OnInit, OnDestroy, DirtyComponen correspondent: new FormControl(), document_type: new FormControl(), archive_serial_number: new FormControl(), - tags: new FormControl([]) + tags: new FormControl([]), }) previewCurrentPage: number = 1 @@ -76,8 +93,13 @@ export class DocumentDetailComponent implements OnInit, OnDestroy, DirtyComponen @ViewChild('nav') nav: NgbNav @ViewChild('pdfPreview') set pdfPreview(element) { // this gets called when compontent added or removed from DOM - if (element && element.nativeElement.offsetParent !== null && this.nav?.activeId == 4) { // its visible - setTimeout(()=> this.nav?.select(1)); + if ( + element && + element.nativeElement.offsetParent !== null && + this.nav?.activeId == 4 + ) { + // its visible + setTimeout(() => this.nav?.select(1)) } } @@ -92,16 +114,19 @@ export class DocumentDetailComponent implements OnInit, OnDestroy, DirtyComponen private documentListViewService: DocumentListViewService, private documentTitlePipe: DocumentTitlePipe, private toastService: ToastService, - private settings: SettingsService) { - this.titleSubject.pipe( + private settings: SettingsService + ) { + this.titleSubject + .pipe( debounceTime(1000), distinctUntilChanged(), takeUntil(this.unsubscribeNotifier) - ).subscribe(titleValue => { + ) + .subscribe((titleValue) => { this.title = titleValue - this.documentForm.patchValue({'title': titleValue}) + this.documentForm.patchValue({ title: titleValue }) }) - } + } titleKeyUp(event) { this.titleSubject.next(event.target?.value) @@ -112,180 +137,291 @@ export class DocumentDetailComponent implements OnInit, OnDestroy, DirtyComponen } getContentType() { - return this.metadata?.has_archive_version ? 'application/pdf' : this.metadata?.original_mime_type + return this.metadata?.has_archive_version + ? 'application/pdf' + : this.metadata?.original_mime_type } ngOnInit(): void { - this.documentForm.valueChanges.pipe(takeUntil(this.unsubscribeNotifier)).subscribe(wow => { - Object.assign(this.document, this.documentForm.value) - }) - - this.correspondentService.listAll().pipe(first()).subscribe(result => this.correspondents = result.results) - this.documentTypeService.listAll().pipe(first()).subscribe(result => this.documentTypes = result.results) - - this.route.paramMap.pipe(switchMap(paramMap => { - const documentId = +paramMap.get('id') - return this.documentsService.get(documentId) - })).pipe(switchMap((doc) => { - this.documentId = doc.id - this.previewUrl = this.documentsService.getPreviewUrl(this.documentId) - this.downloadUrl = this.documentsService.getDownloadUrl(this.documentId) - this.downloadOriginalUrl = this.documentsService.getDownloadUrl(this.documentId, true) - this.suggestions = null - if (this.openDocumentService.getOpenDocument(this.documentId)) { - this.updateComponent(this.openDocumentService.getOpenDocument(this.documentId)) - } else { - this.openDocumentService.openDocument(doc) - this.updateComponent(doc) - } - - // Initialize dirtyCheck - this.store = new BehaviorSubject({ - title: doc.title, - content: doc.content, - created: doc.created, - correspondent: doc.correspondent, - document_type: doc.document_type, - archive_serial_number: doc.archive_serial_number, - tags: [...doc.tags] + this.documentForm.valueChanges + .pipe(takeUntil(this.unsubscribeNotifier)) + .subscribe((wow) => { + Object.assign(this.document, this.documentForm.value) }) - this.isDirty$ = dirtyCheck(this.documentForm, this.store.asObservable()) + this.correspondentService + .listAll() + .pipe(first()) + .subscribe((result) => (this.correspondents = result.results)) + this.documentTypeService + .listAll() + .pipe(first()) + .subscribe((result) => (this.documentTypes = result.results)) - return this.isDirty$.pipe(map(dirty => ({doc, dirty}))) - })) - .pipe(takeUntil(this.unsubscribeNotifier)) - .subscribe(({doc, dirty}) => { - this.openDocumentService.setDirty(doc.id, dirty) - }, error => {this.router.navigate(['404'])}) + this.route.paramMap + .pipe( + switchMap((paramMap) => { + const documentId = +paramMap.get('id') + return this.documentsService.get(documentId) + }) + ) + .pipe( + switchMap((doc) => { + this.documentId = doc.id + this.previewUrl = this.documentsService.getPreviewUrl(this.documentId) + this.downloadUrl = this.documentsService.getDownloadUrl( + this.documentId + ) + this.downloadOriginalUrl = this.documentsService.getDownloadUrl( + this.documentId, + true + ) + this.suggestions = null + if (this.openDocumentService.getOpenDocument(this.documentId)) { + this.updateComponent( + this.openDocumentService.getOpenDocument(this.documentId) + ) + } else { + this.openDocumentService.openDocument(doc) + this.updateComponent(doc) + } + + // Initialize dirtyCheck + this.store = new BehaviorSubject({ + title: doc.title, + content: doc.content, + created: doc.created, + correspondent: doc.correspondent, + document_type: doc.document_type, + archive_serial_number: doc.archive_serial_number, + tags: [...doc.tags], + }) + + this.isDirty$ = dirtyCheck( + this.documentForm, + this.store.asObservable() + ) + + return this.isDirty$.pipe(map((dirty) => ({ doc, dirty }))) + }) + ) + .pipe(takeUntil(this.unsubscribeNotifier)) + .subscribe( + ({ doc, dirty }) => { + this.openDocumentService.setDirty(doc.id, dirty) + }, + (error) => { + this.router.navigate(['404']) + } + ) } - ngOnDestroy() : void { - this.unsubscribeNotifier.next(); - this.unsubscribeNotifier.complete(); + ngOnDestroy(): void { + this.unsubscribeNotifier.next() + this.unsubscribeNotifier.complete() } updateComponent(doc: PaperlessDocument) { this.document = doc - this.documentsService.getMetadata(doc.id).pipe(first()).subscribe(result => { - this.metadata = result - }, error => { - this.metadata = null - }) - this.documentsService.getSuggestions(doc.id).pipe(first()).subscribe(result => { - this.suggestions = result - }, error => { - this.suggestions = null - }) + this.documentsService + .getMetadata(doc.id) + .pipe(first()) + .subscribe( + (result) => { + this.metadata = result + }, + (error) => { + this.metadata = null + } + ) + this.documentsService + .getSuggestions(doc.id) + .pipe(first()) + .subscribe( + (result) => { + this.suggestions = result + }, + (error) => { + this.suggestions = null + } + ) this.title = this.documentTitlePipe.transform(doc.title) this.documentForm.patchValue(doc) } createDocumentType(newName: string) { - var modal = this.modalService.open(DocumentTypeEditDialogComponent, {backdrop: 'static'}) + var modal = this.modalService.open(DocumentTypeEditDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.dialogMode = 'create' if (newName) modal.componentInstance.object = { name: newName } - modal.componentInstance.success.pipe(switchMap(newDocumentType => { - return this.documentTypeService.listAll().pipe(map(documentTypes => ({newDocumentType, documentTypes}))) - })) - .pipe(takeUntil(this.unsubscribeNotifier)) - .subscribe(({newDocumentType, documentTypes}) => { - this.documentTypes = documentTypes.results - this.documentForm.get('document_type').setValue(newDocumentType.id) - }) + modal.componentInstance.success + .pipe( + switchMap((newDocumentType) => { + return this.documentTypeService + .listAll() + .pipe(map((documentTypes) => ({ newDocumentType, documentTypes }))) + }) + ) + .pipe(takeUntil(this.unsubscribeNotifier)) + .subscribe(({ newDocumentType, documentTypes }) => { + this.documentTypes = documentTypes.results + this.documentForm.get('document_type').setValue(newDocumentType.id) + }) } createCorrespondent(newName: string) { - var modal = this.modalService.open(CorrespondentEditDialogComponent, {backdrop: 'static'}) + var modal = this.modalService.open(CorrespondentEditDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.dialogMode = 'create' if (newName) modal.componentInstance.object = { name: newName } - modal.componentInstance.success.pipe(switchMap(newCorrespondent => { - return this.correspondentService.listAll().pipe(map(correspondents => ({newCorrespondent, correspondents}))) - })) - .pipe(takeUntil(this.unsubscribeNotifier)) - .subscribe(({newCorrespondent, correspondents}) => { - this.correspondents = correspondents.results - this.documentForm.get('correspondent').setValue(newCorrespondent.id) - }) + modal.componentInstance.success + .pipe( + switchMap((newCorrespondent) => { + return this.correspondentService + .listAll() + .pipe( + map((correspondents) => ({ newCorrespondent, correspondents })) + ) + }) + ) + .pipe(takeUntil(this.unsubscribeNotifier)) + .subscribe(({ newCorrespondent, correspondents }) => { + this.correspondents = correspondents.results + this.documentForm.get('correspondent').setValue(newCorrespondent.id) + }) } discard() { - this.documentsService.get(this.documentId).pipe(first()).subscribe(doc => { - Object.assign(this.document, doc) - this.title = doc.title - this.documentForm.patchValue(doc) - }, error => {this.router.navigate(['404'])}) + this.documentsService + .get(this.documentId) + .pipe(first()) + .subscribe( + (doc) => { + Object.assign(this.document, doc) + this.title = doc.title + this.documentForm.patchValue(doc) + }, + (error) => { + this.router.navigate(['404']) + } + ) } save() { this.networkActive = true this.store.next(this.documentForm.value) - this.documentsService.update(this.document).pipe(first()).subscribe(result => { - this.close() - this.networkActive = false - this.error = null - }, error => { - this.networkActive = false - this.error = error.error - }) + this.documentsService + .update(this.document) + .pipe(first()) + .subscribe( + (result) => { + this.close() + this.networkActive = false + this.error = null + }, + (error) => { + this.networkActive = false + this.error = error.error + } + ) } saveEditNext() { this.networkActive = true this.store.next(this.documentForm.value) - this.documentsService.update(this.document).pipe(switchMap(updateResult => { - return this.documentListViewService.getNext(this.documentId).pipe(map(nextDocId => ({nextDocId, updateResult}))) - })).pipe(switchMap(({nextDocId, updateResult}) => { - if (nextDocId && updateResult) return this.openDocumentService.closeDocument(this.document).pipe(map(closeResult => ({updateResult, nextDocId, closeResult}))) - })) - .pipe(first()) - .subscribe(({updateResult, nextDocId, closeResult}) => { - this.error = null - this.networkActive = false - if (closeResult && updateResult && nextDocId) { - this.router.navigate(['documents', nextDocId]) - this.titleInput?.focus() - } - }, error => { - this.networkActive = false - this.error = error.error - }) + this.documentsService + .update(this.document) + .pipe( + switchMap((updateResult) => { + return this.documentListViewService + .getNext(this.documentId) + .pipe(map((nextDocId) => ({ nextDocId, updateResult }))) + }) + ) + .pipe( + switchMap(({ nextDocId, updateResult }) => { + if (nextDocId && updateResult) + return this.openDocumentService + .closeDocument(this.document) + .pipe( + map((closeResult) => ({ updateResult, nextDocId, closeResult })) + ) + }) + ) + .pipe(first()) + .subscribe( + ({ updateResult, nextDocId, closeResult }) => { + this.error = null + this.networkActive = false + if (closeResult && updateResult && nextDocId) { + this.router.navigate(['documents', nextDocId]) + this.titleInput?.focus() + } + }, + (error) => { + this.networkActive = false + this.error = error.error + } + ) } close() { - this.openDocumentService.closeDocument(this.document).pipe(first()).subscribe(closed => { - if (!closed) return; - if (this.documentListViewService.activeSavedViewId) { - this.router.navigate(['view', this.documentListViewService.activeSavedViewId]) - } else { - this.router.navigate(['documents']) - } - }) + this.openDocumentService + .closeDocument(this.document) + .pipe(first()) + .subscribe((closed) => { + if (!closed) return + if (this.documentListViewService.activeSavedViewId) { + this.router.navigate([ + 'view', + this.documentListViewService.activeSavedViewId, + ]) + } else { + this.router.navigate(['documents']) + } + }) } delete() { - let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(ConfirmDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.title = $localize`Confirm delete` modal.componentInstance.messageBold = $localize`Do you really want to delete document "${this.document.title}"?` modal.componentInstance.message = $localize`The files for this document will be deleted permanently. This operation cannot be undone.` - modal.componentInstance.btnClass = "btn-danger" + modal.componentInstance.btnClass = 'btn-danger' modal.componentInstance.btnCaption = $localize`Delete document` - modal.componentInstance.confirmClicked.pipe(switchMap(() => { - modal.componentInstance.buttonsEnabled = false - return this.documentsService.delete(this.document) - })) - .pipe(takeUntil(this.unsubscribeNotifier)) - .subscribe(() => { - modal.close() - this.close() - }, error => { - this.toastService.showError($localize`Error deleting document: ${JSON.stringify(error)}`) - modal.componentInstance.buttonsEnabled = true - }) + modal.componentInstance.confirmClicked + .pipe( + switchMap(() => { + modal.componentInstance.buttonsEnabled = false + return this.documentsService.delete(this.document) + }) + ) + .pipe(takeUntil(this.unsubscribeNotifier)) + .subscribe( + () => { + modal.close() + this.close() + }, + (error) => { + this.toastService.showError( + $localize`Error deleting document: ${JSON.stringify(error)}` + ) + modal.componentInstance.buttonsEnabled = true + } + ) } moreLike() { - this.documentListViewService.quickFilter([{rule_type: FILTER_FULLTEXT_MORELIKE, value: this.documentId.toString()}]) + this.documentListViewService.quickFilter([ + { + rule_type: FILTER_FULLTEXT_MORELIKE, + value: this.documentId.toString(), + }, + ]) } hasNext() { @@ -311,5 +447,4 @@ export class DocumentDetailComponent implements OnInit, OnDestroy, DirtyComponen pdfPreviewLoaded(pdf: PDFDocumentProxy) { this.previewNumPages = pdf.numPages } - } diff --git a/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.spec.ts b/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.spec.ts index 2bd96760b..8e133d52e 100644 --- a/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.spec.ts +++ b/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { MetadataCollapseComponent } from './metadata-collapse.component'; +import { MetadataCollapseComponent } from './metadata-collapse.component' describe('MetadataCollapseComponent', () => { - let component: MetadataCollapseComponent; - let fixture: ComponentFixture; + let component: MetadataCollapseComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ MetadataCollapseComponent ] - }) - .compileComponents(); - }); + declarations: [MetadataCollapseComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(MetadataCollapseComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(MetadataCollapseComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts b/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts index 34bbbd655..efef478b6 100644 --- a/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts +++ b/src-ui/src/app/components/document-detail/metadata-collapse/metadata-collapse.component.ts @@ -1,13 +1,12 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core' @Component({ selector: 'app-metadata-collapse', templateUrl: './metadata-collapse.component.html', - styleUrls: ['./metadata-collapse.component.scss'] + styleUrls: ['./metadata-collapse.component.scss'], }) export class MetadataCollapseComponent implements OnInit { - - constructor() { } + constructor() {} expand = false @@ -17,7 +16,5 @@ export class MetadataCollapseComponent implements OnInit { @Input() title = $localize`Metadata` - ngOnInit(): void { - } - + ngOnInit(): void {} } 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 140d73301..df43a8873 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 @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { BulkEditorComponent } from './bulk-editor.component'; +import { BulkEditorComponent } from './bulk-editor.component' describe('BulkEditorComponent', () => { - let component: BulkEditorComponent; - let fixture: ComponentFixture; + let component: BulkEditorComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ BulkEditorComponent ] - }) - .compileComponents(); - }); + declarations: [BulkEditorComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(BulkEditorComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(BulkEditorComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) 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 310290291..00d6a2273 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 @@ -1,29 +1,37 @@ -import { Component } from '@angular/core'; -import { PaperlessTag } from 'src/app/data/paperless-tag'; -import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'; -import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'; -import { TagService } from 'src/app/services/rest/tag.service'; -import { CorrespondentService } from 'src/app/services/rest/correspondent.service'; -import { DocumentTypeService } from 'src/app/services/rest/document-type.service'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { DocumentService, SelectionDataItem } from 'src/app/services/rest/document.service'; -import { OpenDocumentsService } from 'src/app/services/open-documents.service'; -import { ConfirmDialogComponent } from 'src/app/components/common/confirm-dialog/confirm-dialog.component'; -import { ChangedItems, FilterableDropdownSelectionModel } from '../../common/filterable-dropdown/filterable-dropdown.component'; -import { ToggleableItemState } from '../../common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component'; -import { MatchingModel } from 'src/app/data/matching-model'; -import { SettingsService, SETTINGS_KEYS } from 'src/app/services/settings.service'; -import { ToastService } from 'src/app/services/toast.service'; -import { saveAs } from 'file-saver'; +import { Component } from '@angular/core' +import { PaperlessTag } from 'src/app/data/paperless-tag' +import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent' +import { PaperlessDocumentType } from 'src/app/data/paperless-document-type' +import { TagService } from 'src/app/services/rest/tag.service' +import { CorrespondentService } from 'src/app/services/rest/correspondent.service' +import { DocumentTypeService } from 'src/app/services/rest/document-type.service' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { + DocumentService, + SelectionDataItem, +} from 'src/app/services/rest/document.service' +import { OpenDocumentsService } from 'src/app/services/open-documents.service' +import { ConfirmDialogComponent } from 'src/app/components/common/confirm-dialog/confirm-dialog.component' +import { + ChangedItems, + FilterableDropdownSelectionModel, +} from '../../common/filterable-dropdown/filterable-dropdown.component' +import { ToggleableItemState } from '../../common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component' +import { MatchingModel } from 'src/app/data/matching-model' +import { + SettingsService, + SETTINGS_KEYS, +} from 'src/app/services/settings.service' +import { ToastService } from 'src/app/services/toast.service' +import { saveAs } from 'file-saver' @Component({ selector: 'app-bulk-editor', templateUrl: './bulk-editor.component.html', - styleUrls: ['./bulk-editor.component.scss'] + styleUrls: ['./bulk-editor.component.scss'], }) export class BulkEditorComponent { - tags: PaperlessTag[] correspondents: PaperlessCorrespondent[] documentTypes: PaperlessDocumentType[] @@ -42,43 +50,63 @@ export class BulkEditorComponent { private openDocumentService: OpenDocumentsService, private settings: SettingsService, private toastService: ToastService - ) { } + ) {} - applyOnClose: boolean = this.settings.get(SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE) - showConfirmationDialogs: boolean = this.settings.get(SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS) + applyOnClose: boolean = this.settings.get( + SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE + ) + showConfirmationDialogs: boolean = this.settings.get( + SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS + ) ngOnInit() { - this.tagService.listAll().subscribe(result => this.tags = result.results) - this.correspondentService.listAll().subscribe(result => this.correspondents = result.results) - this.documentTypeService.listAll().subscribe(result => this.documentTypes = result.results) + this.tagService + .listAll() + .subscribe((result) => (this.tags = result.results)) + this.correspondentService + .listAll() + .subscribe((result) => (this.correspondents = result.results)) + this.documentTypeService + .listAll() + .subscribe((result) => (this.documentTypes = result.results)) } private executeBulkOperation(modal, method: string, args) { if (modal) { modal.componentInstance.buttonsEnabled = false } - this.documentService.bulkEdit(Array.from(this.list.selected), method, args).subscribe( - response => { - this.list.reload() - this.list.reduceSelectionToFilter() - this.list.selected.forEach(id => { - this.openDocumentService.refreshDocument(id) - }) - if (modal) { - modal.close() + this.documentService + .bulkEdit(Array.from(this.list.selected), method, args) + .subscribe( + (response) => { + this.list.reload() + this.list.reduceSelectionToFilter() + this.list.selected.forEach((id) => { + this.openDocumentService.refreshDocument(id) + }) + if (modal) { + modal.close() + } + }, + (error) => { + if (modal) { + modal.componentInstance.buttonsEnabled = true + } + this.toastService.showError( + $localize`Error executing bulk operation: ${JSON.stringify( + error.error + )}` + ) } - }, error => { - if (modal) { - modal.componentInstance.buttonsEnabled = true - } - this.toastService.showError($localize`Error executing bulk operation: ${JSON.stringify(error.error)}`) - } - ) + ) } - private applySelectionData(items: SelectionDataItem[], selectionModel: FilterableDropdownSelectionModel) { + private applySelectionData( + items: SelectionDataItem[], + selectionModel: FilterableDropdownSelectionModel + ) { let selectionData = new Map() - items.forEach(i => { + items.forEach((i) => { if (i.document_count == this.list.selected.size) { selectionData.set(i.id, ToggleableItemState.Selected) } else if (i.document_count > 0) { @@ -89,129 +117,210 @@ export class BulkEditorComponent { } openTagsDropdown() { - this.documentService.getSelectionData(Array.from(this.list.selected)).subscribe(s => { - this.applySelectionData(s.selected_tags, this.tagSelectionModel) - }) + this.documentService + .getSelectionData(Array.from(this.list.selected)) + .subscribe((s) => { + this.applySelectionData(s.selected_tags, this.tagSelectionModel) + }) } openDocumentTypeDropdown() { - this.documentService.getSelectionData(Array.from(this.list.selected)).subscribe(s => { - this.applySelectionData(s.selected_document_types, this.documentTypeSelectionModel) - }) + this.documentService + .getSelectionData(Array.from(this.list.selected)) + .subscribe((s) => { + this.applySelectionData( + s.selected_document_types, + this.documentTypeSelectionModel + ) + }) } openCorrespondentDropdown() { - this.documentService.getSelectionData(Array.from(this.list.selected)).subscribe(s => { - this.applySelectionData(s.selected_correspondents, this.correspondentSelectionModel) - }) + this.documentService + .getSelectionData(Array.from(this.list.selected)) + .subscribe((s) => { + this.applySelectionData( + s.selected_correspondents, + this.correspondentSelectionModel + ) + }) } private _localizeList(items: MatchingModel[]) { if (items.length == 0) { - return "" + return '' } else if (items.length == 1) { return $localize`"${items[0].name}"` } else if (items.length == 2) { return $localize`:This is for messages like 'modify "tag1" and "tag2"':"${items[0].name}" and "${items[1].name}"` } else { - let list = items.slice(0, items.length - 1).map(i => $localize`"${i.name}"`).join($localize`:this is used to separate enumerations and should probably be a comma and a whitespace in most languages:, `) - return $localize`:this is for messages like 'modify "tag1", "tag2" and "tag3"':${list} and "${items[items.length - 1].name}"` + let list = items + .slice(0, items.length - 1) + .map((i) => $localize`"${i.name}"`) + .join( + $localize`:this is used to separate enumerations and should probably be a comma and a whitespace in most languages:, ` + ) + return $localize`:this is for messages like 'modify "tag1", "tag2" and "tag3"':${list} and "${ + items[items.length - 1].name + }"` } } setTags(changedTags: ChangedItems) { - if (changedTags.itemsToAdd.length == 0 && changedTags.itemsToRemove.length == 0) return + if ( + changedTags.itemsToAdd.length == 0 && + changedTags.itemsToRemove.length == 0 + ) + return if (this.showConfirmationDialogs) { - let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(ConfirmDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.title = $localize`Confirm tags assignment` - if (changedTags.itemsToAdd.length == 1 && changedTags.itemsToRemove.length == 0) { + if ( + changedTags.itemsToAdd.length == 1 && + changedTags.itemsToRemove.length == 0 + ) { let tag = changedTags.itemsToAdd[0] modal.componentInstance.message = $localize`This operation will add the tag "${tag.name}" to ${this.list.selected.size} selected document(s).` - } else if (changedTags.itemsToAdd.length > 1 && changedTags.itemsToRemove.length == 0) { - modal.componentInstance.message = $localize`This operation will add the tags ${this._localizeList(changedTags.itemsToAdd)} to ${this.list.selected.size} selected document(s).` - } else if (changedTags.itemsToAdd.length == 0 && changedTags.itemsToRemove.length == 1) { + } else if ( + changedTags.itemsToAdd.length > 1 && + changedTags.itemsToRemove.length == 0 + ) { + modal.componentInstance.message = $localize`This operation will add the tags ${this._localizeList( + changedTags.itemsToAdd + )} to ${this.list.selected.size} selected document(s).` + } else if ( + changedTags.itemsToAdd.length == 0 && + changedTags.itemsToRemove.length == 1 + ) { let tag = changedTags.itemsToRemove[0] modal.componentInstance.message = $localize`This operation will remove the tag "${tag.name}" from ${this.list.selected.size} selected document(s).` - } else if (changedTags.itemsToAdd.length == 0 && changedTags.itemsToRemove.length > 1) { - modal.componentInstance.message = $localize`This operation will remove the tags ${this._localizeList(changedTags.itemsToRemove)} from ${this.list.selected.size} selected document(s).` + } else if ( + changedTags.itemsToAdd.length == 0 && + changedTags.itemsToRemove.length > 1 + ) { + modal.componentInstance.message = $localize`This operation will remove the tags ${this._localizeList( + changedTags.itemsToRemove + )} from ${this.list.selected.size} selected document(s).` } else { - modal.componentInstance.message = $localize`This operation will add the tags ${this._localizeList(changedTags.itemsToAdd)} and remove the tags ${this._localizeList(changedTags.itemsToRemove)} on ${this.list.selected.size} selected document(s).` + modal.componentInstance.message = $localize`This operation will add the tags ${this._localizeList( + changedTags.itemsToAdd + )} and remove the tags ${this._localizeList( + changedTags.itemsToRemove + )} on ${this.list.selected.size} selected document(s).` } - modal.componentInstance.btnClass = "btn-warning" + modal.componentInstance.btnClass = 'btn-warning' modal.componentInstance.btnCaption = $localize`Confirm` modal.componentInstance.confirmClicked.subscribe(() => { - this.executeBulkOperation(modal, 'modify_tags', {"add_tags": changedTags.itemsToAdd.map(t => t.id), "remove_tags": changedTags.itemsToRemove.map(t => t.id)}) + this.executeBulkOperation(modal, 'modify_tags', { + add_tags: changedTags.itemsToAdd.map((t) => t.id), + remove_tags: changedTags.itemsToRemove.map((t) => t.id), + }) }) } else { - this.executeBulkOperation(null, 'modify_tags', {"add_tags": changedTags.itemsToAdd.map(t => t.id), "remove_tags": changedTags.itemsToRemove.map(t => t.id)}) + this.executeBulkOperation(null, 'modify_tags', { + add_tags: changedTags.itemsToAdd.map((t) => t.id), + remove_tags: changedTags.itemsToRemove.map((t) => t.id), + }) } } setCorrespondents(changedCorrespondents: ChangedItems) { - if (changedCorrespondents.itemsToAdd.length == 0 && changedCorrespondents.itemsToRemove.length == 0) return + if ( + changedCorrespondents.itemsToAdd.length == 0 && + changedCorrespondents.itemsToRemove.length == 0 + ) + return - let correspondent = changedCorrespondents.itemsToAdd.length > 0 ? changedCorrespondents.itemsToAdd[0] : null + let correspondent = + changedCorrespondents.itemsToAdd.length > 0 + ? changedCorrespondents.itemsToAdd[0] + : null if (this.showConfirmationDialogs) { - let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(ConfirmDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.title = $localize`Confirm correspondent assignment` if (correspondent) { modal.componentInstance.message = $localize`This operation will assign the correspondent "${correspondent.name}" to ${this.list.selected.size} selected document(s).` } else { modal.componentInstance.message = $localize`This operation will remove the correspondent from ${this.list.selected.size} selected document(s).` } - modal.componentInstance.btnClass = "btn-warning" + modal.componentInstance.btnClass = 'btn-warning' modal.componentInstance.btnCaption = $localize`Confirm` modal.componentInstance.confirmClicked.subscribe(() => { - this.executeBulkOperation(modal, 'set_correspondent', {"correspondent": correspondent ? correspondent.id : null}) + this.executeBulkOperation(modal, 'set_correspondent', { + correspondent: correspondent ? correspondent.id : null, + }) }) } else { - this.executeBulkOperation(null, 'set_correspondent', {"correspondent": correspondent ? correspondent.id : null}) + this.executeBulkOperation(null, 'set_correspondent', { + correspondent: correspondent ? correspondent.id : null, + }) } } setDocumentTypes(changedDocumentTypes: ChangedItems) { - if (changedDocumentTypes.itemsToAdd.length == 0 && changedDocumentTypes.itemsToRemove.length == 0) return + if ( + changedDocumentTypes.itemsToAdd.length == 0 && + changedDocumentTypes.itemsToRemove.length == 0 + ) + return - let documentType = changedDocumentTypes.itemsToAdd.length > 0 ? changedDocumentTypes.itemsToAdd[0] : null + let documentType = + changedDocumentTypes.itemsToAdd.length > 0 + ? changedDocumentTypes.itemsToAdd[0] + : null if (this.showConfirmationDialogs) { - let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(ConfirmDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.title = $localize`Confirm document type assignment` if (documentType) { modal.componentInstance.message = $localize`This operation will assign the document type "${documentType.name}" to ${this.list.selected.size} selected document(s).` } else { modal.componentInstance.message = $localize`This operation will remove the document type from ${this.list.selected.size} selected document(s).` } - modal.componentInstance.btnClass = "btn-warning" + modal.componentInstance.btnClass = 'btn-warning' modal.componentInstance.btnCaption = $localize`Confirm` modal.componentInstance.confirmClicked.subscribe(() => { - this.executeBulkOperation(modal, 'set_document_type', {"document_type": documentType ? documentType.id : null}) + this.executeBulkOperation(modal, 'set_document_type', { + document_type: documentType ? documentType.id : null, + }) }) } else { - this.executeBulkOperation(null, 'set_document_type', {"document_type": documentType ? documentType.id : null}) + this.executeBulkOperation(null, 'set_document_type', { + document_type: documentType ? documentType.id : null, + }) } } applyDelete() { - let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(ConfirmDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.delayConfirm(5) modal.componentInstance.title = $localize`Delete confirm` modal.componentInstance.messageBold = $localize`This operation will permanently delete ${this.list.selected.size} selected document(s).` modal.componentInstance.message = $localize`This operation cannot be undone.` - modal.componentInstance.btnClass = "btn-danger" + modal.componentInstance.btnClass = 'btn-danger' modal.componentInstance.btnCaption = $localize`Delete document(s)` modal.componentInstance.confirmClicked.subscribe(() => { modal.componentInstance.buttonsEnabled = false - this.executeBulkOperation(modal, "delete", {}) + this.executeBulkOperation(modal, 'delete', {}) }) } - downloadSelected(content = "archive") { - this.documentService.bulkDownload(Array.from(this.list.selected), content).subscribe((result: any) => { - saveAs(result, 'documents.zip'); - }) + downloadSelected(content = 'archive') { + this.documentService + .bulkDownload(Array.from(this.list.selected), content) + .subscribe((result: any) => { + saveAs(result, 'documents.zip') + }) } } diff --git a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.spec.ts b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.spec.ts index 72b48f139..49a2ff3ab 100644 --- a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.spec.ts +++ b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { DocumentCardLargeComponent } from './document-card-large.component'; +import { DocumentCardLargeComponent } from './document-card-large.component' describe('DocumentCardLargeComponent', () => { - let component: DocumentCardLargeComponent; - let fixture: ComponentFixture; + let component: DocumentCardLargeComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ DocumentCardLargeComponent ] - }) - .compileComponents(); - }); + declarations: [DocumentCardLargeComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(DocumentCardLargeComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(DocumentCardLargeComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.ts b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.ts index d8f29ef5a..1c4e9a7aa 100644 --- a/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.ts +++ b/src-ui/src/app/components/document-list/document-card-large/document-card-large.component.ts @@ -1,20 +1,36 @@ -import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; -import { DomSanitizer } from '@angular/platform-browser'; -import { PaperlessDocument } from 'src/app/data/paperless-document'; -import { DocumentService } from 'src/app/services/rest/document.service'; -import { SettingsService, SETTINGS_KEYS } from 'src/app/services/settings.service'; -import { NgbPopover } from '@ng-bootstrap/ng-bootstrap'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type'; +import { + Component, + EventEmitter, + Input, + OnInit, + Output, + ViewChild, +} from '@angular/core' +import { DomSanitizer } from '@angular/platform-browser' +import { PaperlessDocument } from 'src/app/data/paperless-document' +import { DocumentService } from 'src/app/services/rest/document.service' +import { + SettingsService, + SETTINGS_KEYS, +} from 'src/app/services/settings.service' +import { NgbPopover } from '@ng-bootstrap/ng-bootstrap' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type' @Component({ selector: 'app-document-card-large', templateUrl: './document-card-large.component.html', - styleUrls: ['./document-card-large.component.scss', '../popover-preview/popover-preview.scss'] + styleUrls: [ + './document-card-large.component.scss', + '../popover-preview/popover-preview.scss', + ], }) export class DocumentCardLargeComponent implements OnInit { - - constructor(private documentService: DocumentService, private sanitizer: DomSanitizer, private settingsService: SettingsService) { } + constructor( + private documentService: DocumentService, + private sanitizer: DomSanitizer, + private settingsService: SettingsService + ) {} @Input() selected = false @@ -39,7 +55,7 @@ export class DocumentCardLargeComponent implements OnInit { clickDocumentType = new EventEmitter() @Output() - clickMoreLike= new EventEmitter() + clickMoreLike = new EventEmitter() @ViewChild('popover') popover: NgbPopover @@ -49,17 +65,16 @@ export class DocumentCardLargeComponent implements OnInit { get searchScoreClass() { if (this.document.__search_hit__) { if (this.document.__search_hit__.score > 0.7) { - return "success" + return 'success' } else if (this.document.__search_hit__.score > 0.3) { - return "warning" + return 'warning' } else { - return "danger" + return 'danger' } } } - ngOnInit(): void { - } + ngOnInit(): void {} getIsThumbInverted() { return this.settingsService.get(SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED) @@ -90,7 +105,7 @@ export class DocumentCardLargeComponent implements OnInit { } else { this.popover.close() } - }, 600); + }, 600) } } diff --git a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.spec.ts b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.spec.ts index 4ed43b2e2..ae5a9cc5a 100644 --- a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.spec.ts +++ b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { DocumentCardSmallComponent } from './document-card-small.component'; +import { DocumentCardSmallComponent } from './document-card-small.component' describe('DocumentCardSmallComponent', () => { - let component: DocumentCardSmallComponent; - let fixture: ComponentFixture; + let component: DocumentCardSmallComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ DocumentCardSmallComponent ] - }) - .compileComponents(); - }); + declarations: [DocumentCardSmallComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(DocumentCardSmallComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(DocumentCardSmallComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.ts b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.ts index 10c2c5d23..cbff950a2 100644 --- a/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.ts +++ b/src-ui/src/app/components/document-list/document-card-small/document-card-small.component.ts @@ -1,18 +1,33 @@ -import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; -import { map } from 'rxjs/operators'; -import { PaperlessDocument } from 'src/app/data/paperless-document'; -import { DocumentService } from 'src/app/services/rest/document.service'; -import { SettingsService, SETTINGS_KEYS } from 'src/app/services/settings.service'; -import { NgbPopover } from '@ng-bootstrap/ng-bootstrap'; +import { + Component, + EventEmitter, + Input, + OnInit, + Output, + ViewChild, +} from '@angular/core' +import { map } from 'rxjs/operators' +import { PaperlessDocument } from 'src/app/data/paperless-document' +import { DocumentService } from 'src/app/services/rest/document.service' +import { + SettingsService, + SETTINGS_KEYS, +} from 'src/app/services/settings.service' +import { NgbPopover } from '@ng-bootstrap/ng-bootstrap' @Component({ selector: 'app-document-card-small', templateUrl: './document-card-small.component.html', - styleUrls: ['./document-card-small.component.scss', '../popover-preview/popover-preview.scss'] + styleUrls: [ + './document-card-small.component.scss', + '../popover-preview/popover-preview.scss', + ], }) export class DocumentCardSmallComponent implements OnInit { - - constructor(private documentService: DocumentService, private settingsService: SettingsService) { } + constructor( + private documentService: DocumentService, + private settingsService: SettingsService + ) {} @Input() selected = false @@ -39,8 +54,7 @@ export class DocumentCardSmallComponent implements OnInit { mouseOnPreview = false popoverHidden = true - ngOnInit(): void { - } + ngOnInit(): void {} getIsThumbInverted() { return this.settingsService.get(SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED) @@ -60,7 +74,7 @@ export class DocumentCardSmallComponent implements OnInit { getTagsLimited$() { return this.document.tags$.pipe( - map(tags => { + map((tags) => { if (tags.length > 7) { this.moreTags = tags.length - 6 return tags.slice(0, 6) @@ -84,7 +98,7 @@ export class DocumentCardSmallComponent implements OnInit { } else { this.popover.close() } - }, 600); + }, 600) } } diff --git a/src-ui/src/app/components/document-list/document-list.component.spec.ts b/src-ui/src/app/components/document-list/document-list.component.spec.ts index 9230b4631..dec0355e5 100644 --- a/src-ui/src/app/components/document-list/document-list.component.spec.ts +++ b/src-ui/src/app/components/document-list/document-list.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { DocumentListComponent } from './document-list.component'; +import { DocumentListComponent } from './document-list.component' describe('DocumentListComponent', () => { - let component: DocumentListComponent; - let fixture: ComponentFixture; + let component: DocumentListComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ DocumentListComponent ] - }) - .compileComponents(); - }); + declarations: [DocumentListComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(DocumentListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(DocumentListComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/document-list/document-list.component.ts b/src-ui/src/app/components/document-list/document-list.component.ts index 390da80c6..f79247034 100644 --- a/src-ui/src/app/components/document-list/document-list.component.ts +++ b/src-ui/src/app/components/document-list/document-list.component.ts @@ -1,27 +1,39 @@ -import { Component, OnDestroy, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { Subscription } from 'rxjs'; -import { FilterRule, isFullTextFilterRule } from 'src/app/data/filter-rule'; -import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type'; -import { PaperlessDocument } from 'src/app/data/paperless-document'; -import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'; -import { SortableDirective, SortEvent } from 'src/app/directives/sortable.directive'; -import { ConsumerStatusService } from 'src/app/services/consumer-status.service'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { DOCUMENT_SORT_FIELDS, DOCUMENT_SORT_FIELDS_FULLTEXT } from 'src/app/services/rest/document.service'; -import { SavedViewService } from 'src/app/services/rest/saved-view.service'; -import { ToastService } from 'src/app/services/toast.service'; -import { FilterEditorComponent } from './filter-editor/filter-editor.component'; -import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component'; +import { + Component, + OnDestroy, + OnInit, + QueryList, + ViewChild, + ViewChildren, +} from '@angular/core' +import { ActivatedRoute, Router } from '@angular/router' +import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { Subscription } from 'rxjs' +import { FilterRule, isFullTextFilterRule } from 'src/app/data/filter-rule' +import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type' +import { PaperlessDocument } from 'src/app/data/paperless-document' +import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' +import { + SortableDirective, + SortEvent, +} from 'src/app/directives/sortable.directive' +import { ConsumerStatusService } from 'src/app/services/consumer-status.service' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { + DOCUMENT_SORT_FIELDS, + DOCUMENT_SORT_FIELDS_FULLTEXT, +} from 'src/app/services/rest/document.service' +import { SavedViewService } from 'src/app/services/rest/saved-view.service' +import { ToastService } from 'src/app/services/toast.service' +import { FilterEditorComponent } from './filter-editor/filter-editor.component' +import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component' @Component({ selector: 'app-document-list', templateUrl: './document-list.component.html', - styleUrls: ['./document-list.component.scss'] + styleUrls: ['./document-list.component.scss'], }) export class DocumentListComponent implements OnInit, OnDestroy { - constructor( public list: DocumentListViewService, public savedViewService: SavedViewService, @@ -30,12 +42,12 @@ export class DocumentListComponent implements OnInit, OnDestroy { private toastService: ToastService, private modalService: NgbModal, private consumerStatusService: ConsumerStatusService - ) { } + ) {} - @ViewChild("filterEditor") + @ViewChild('filterEditor') private filterEditor: FilterEditorComponent - @ViewChildren(SortableDirective) headers: QueryList; + @ViewChildren(SortableDirective) headers: QueryList displayMode = 'smallCards' // largeCards, smallCards, details @@ -52,7 +64,9 @@ export class DocumentListComponent implements OnInit, OnDestroy { } getSortFields() { - return isFullTextFilterRule(this.list.filterRules) ? DOCUMENT_SORT_FIELDS_FULLTEXT : DOCUMENT_SORT_FIELDS + return isFullTextFilterRule(this.list.filterRules) + ? DOCUMENT_SORT_FIELDS_FULLTEXT + : DOCUMENT_SORT_FIELDS } onSort(event: SortEvent) { @@ -71,14 +85,16 @@ export class DocumentListComponent implements OnInit, OnDestroy { if (localStorage.getItem('document-list:displayMode') != null) { this.displayMode = localStorage.getItem('document-list:displayMode') } - this.consumptionFinishedSubscription = this.consumerStatusService.onDocumentConsumptionFinished().subscribe(() => { - this.list.reload() - }) - this.route.paramMap.subscribe(params => { + this.consumptionFinishedSubscription = this.consumerStatusService + .onDocumentConsumptionFinished() + .subscribe(() => { + this.list.reload() + }) + this.route.paramMap.subscribe((params) => { if (params.has('id')) { - this.savedViewService.getCached(+params.get('id')).subscribe(view => { + this.savedViewService.getCached(+params.get('id')).subscribe((view) => { if (!view) { - this.router.navigate(["404"]) + this.router.navigate(['404']) return } this.list.activateSavedView(view) @@ -110,19 +126,23 @@ export class DocumentListComponent implements OnInit, OnDestroy { id: this.list.activeSavedViewId, filter_rules: this.list.filterRules, sort_field: this.list.sortField, - sort_reverse: this.list.sortReverse + sort_reverse: this.list.sortReverse, } - this.savedViewService.patch(savedView).subscribe(result => { - this.toastService.showInfo($localize`View "${this.list.activeSavedViewTitle}" saved successfully.`) + this.savedViewService.patch(savedView).subscribe((result) => { + this.toastService.showInfo( + $localize`View "${this.list.activeSavedViewTitle}" saved successfully.` + ) this.unmodifiedFilterRules = this.list.filterRules }) } } saveViewConfigAs() { - let modal = this.modalService.open(SaveViewConfigDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(SaveViewConfigDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.defaultName = this.filterEditor.generateFilterName() - modal.componentInstance.saveClicked.subscribe(formValue => { + modal.componentInstance.saveClicked.subscribe((formValue) => { modal.componentInstance.buttonsEnabled = false let savedView: PaperlessSavedView = { name: formValue.name, @@ -130,16 +150,21 @@ export class DocumentListComponent implements OnInit, OnDestroy { show_in_sidebar: formValue.showInSideBar, filter_rules: this.list.filterRules, sort_reverse: this.list.sortReverse, - sort_field: this.list.sortField + sort_field: this.list.sortField, } - this.savedViewService.create(savedView).subscribe(() => { - modal.close() - this.toastService.showInfo($localize`View "${savedView.name}" created successfully.`) - }, error => { - modal.componentInstance.error = error.error - modal.componentInstance.buttonsEnabled = true - }) + this.savedViewService.create(savedView).subscribe( + () => { + modal.close() + this.toastService.showInfo( + $localize`View "${savedView.name}" created successfully.` + ) + }, + (error) => { + modal.componentInstance.error = error.error + modal.componentInstance.buttonsEnabled = true + } + ) }) } @@ -170,7 +195,9 @@ export class DocumentListComponent implements OnInit, OnDestroy { } clickMoreLike(documentID: number) { - this.list.quickFilter([{rule_type: FILTER_FULLTEXT_MORELIKE, value: documentID.toString()}]) + this.list.quickFilter([ + { rule_type: FILTER_FULLTEXT_MORELIKE, value: documentID.toString() }, + ]) } trackByDocumentId(index, item: PaperlessDocument) { diff --git a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.spec.ts b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.spec.ts index 9aee51435..cec3fed1a 100644 --- a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.spec.ts +++ b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { FilterEditorComponent } from './filter-editor.component'; +import { FilterEditorComponent } from './filter-editor.component' describe('FilterEditorComponent', () => { - let component: FilterEditorComponent; - let fixture: ComponentFixture; + let component: FilterEditorComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ FilterEditorComponent ] - }) - .compileComponents(); - }); + declarations: [FilterEditorComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(FilterEditorComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(FilterEditorComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts index 175e3475f..11ed97ef1 100644 --- a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts +++ b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts @@ -1,56 +1,85 @@ -import { Component, EventEmitter, Input, Output, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/core'; -import { PaperlessTag } from 'src/app/data/paperless-tag'; -import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'; -import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'; -import { Subject, Subscription } from 'rxjs'; -import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; -import { DocumentTypeService } from 'src/app/services/rest/document-type.service'; -import { TagService } from 'src/app/services/rest/tag.service'; -import { CorrespondentService } from 'src/app/services/rest/correspondent.service'; -import { FilterRule } from 'src/app/data/filter-rule'; -import { FILTER_ADDED_AFTER, FILTER_ADDED_BEFORE, FILTER_ASN, FILTER_CORRESPONDENT, FILTER_CREATED_AFTER, FILTER_CREATED_BEFORE, FILTER_DOCUMENT_TYPE, FILTER_FULLTEXT_MORELIKE, FILTER_FULLTEXT_QUERY, FILTER_HAS_ANY_TAG, FILTER_HAS_TAGS_ALL, FILTER_HAS_TAGS_ANY, FILTER_DOES_NOT_HAVE_TAG, FILTER_TITLE, FILTER_TITLE_CONTENT } from 'src/app/data/filter-rule-type'; -import { FilterableDropdownSelectionModel } from '../../common/filterable-dropdown/filterable-dropdown.component'; -import { ToggleableItemState } from '../../common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component'; -import { DocumentService } from 'src/app/services/rest/document.service'; -import { PaperlessDocument } from 'src/app/data/paperless-document'; +import { + Component, + EventEmitter, + Input, + Output, + OnInit, + OnDestroy, + ViewChild, + ElementRef, +} from '@angular/core' +import { PaperlessTag } from 'src/app/data/paperless-tag' +import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent' +import { PaperlessDocumentType } from 'src/app/data/paperless-document-type' +import { Subject, Subscription } from 'rxjs' +import { debounceTime, distinctUntilChanged } from 'rxjs/operators' +import { DocumentTypeService } from 'src/app/services/rest/document-type.service' +import { TagService } from 'src/app/services/rest/tag.service' +import { CorrespondentService } from 'src/app/services/rest/correspondent.service' +import { FilterRule } from 'src/app/data/filter-rule' +import { + FILTER_ADDED_AFTER, + FILTER_ADDED_BEFORE, + FILTER_ASN, + FILTER_CORRESPONDENT, + FILTER_CREATED_AFTER, + FILTER_CREATED_BEFORE, + FILTER_DOCUMENT_TYPE, + FILTER_FULLTEXT_MORELIKE, + FILTER_FULLTEXT_QUERY, + FILTER_HAS_ANY_TAG, + FILTER_HAS_TAGS_ALL, + FILTER_HAS_TAGS_ANY, + FILTER_DOES_NOT_HAVE_TAG, + FILTER_TITLE, + FILTER_TITLE_CONTENT, +} from 'src/app/data/filter-rule-type' +import { FilterableDropdownSelectionModel } from '../../common/filterable-dropdown/filterable-dropdown.component' +import { ToggleableItemState } from '../../common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component' +import { DocumentService } from 'src/app/services/rest/document.service' +import { PaperlessDocument } from 'src/app/data/paperless-document' -const TEXT_FILTER_TARGET_TITLE = "title" -const TEXT_FILTER_TARGET_TITLE_CONTENT = "title-content" -const TEXT_FILTER_TARGET_ASN = "asn" -const TEXT_FILTER_TARGET_FULLTEXT_QUERY = "fulltext-query" -const TEXT_FILTER_TARGET_FULLTEXT_MORELIKE = "fulltext-morelike" +const TEXT_FILTER_TARGET_TITLE = 'title' +const TEXT_FILTER_TARGET_TITLE_CONTENT = 'title-content' +const TEXT_FILTER_TARGET_ASN = 'asn' +const TEXT_FILTER_TARGET_FULLTEXT_QUERY = 'fulltext-query' +const TEXT_FILTER_TARGET_FULLTEXT_MORELIKE = 'fulltext-morelike' @Component({ selector: 'app-filter-editor', templateUrl: './filter-editor.component.html', - styleUrls: ['./filter-editor.component.scss'] + styleUrls: ['./filter-editor.component.scss'], }) export class FilterEditorComponent implements OnInit, OnDestroy { - generateFilterName() { if (this.filterRules.length == 1) { let rule = this.filterRules[0] - switch(this.filterRules[0].rule_type) { - + switch (this.filterRules[0].rule_type) { case FILTER_CORRESPONDENT: if (rule.value) { - return $localize`Correspondent: ${this.correspondents.find(c => c.id == +rule.value)?.name}` + return $localize`Correspondent: ${ + this.correspondents.find((c) => c.id == +rule.value)?.name + }` } else { return $localize`Without correspondent` } case FILTER_DOCUMENT_TYPE: if (rule.value) { - return $localize`Type: ${this.documentTypes.find(dt => dt.id == +rule.value)?.name}` + return $localize`Type: ${ + this.documentTypes.find((dt) => dt.id == +rule.value)?.name + }` } else { return $localize`Without document type` } case FILTER_HAS_TAGS_ALL: - return $localize`Tag: ${this.tags.find(t => t.id == +rule.value)?.name}` + return $localize`Tag: ${ + this.tags.find((t) => t.id == +rule.value)?.name + }` case FILTER_HAS_ANY_TAG: - if (rule.value == "false") { + if (rule.value == 'false') { return $localize`Without any tag` } @@ -62,7 +91,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy { } } - return "" + return '' } constructor( @@ -70,28 +99,37 @@ export class FilterEditorComponent implements OnInit, OnDestroy { private tagService: TagService, private correspondentService: CorrespondentService, private documentService: DocumentService - ) { } + ) {} - @ViewChild("textFilterInput") + @ViewChild('textFilterInput') textFilterInput: ElementRef tags: PaperlessTag[] = [] correspondents: PaperlessCorrespondent[] = [] documentTypes: PaperlessDocumentType[] = [] - _textFilter = "" + _textFilter = '' _moreLikeId: number _moreLikeDoc: PaperlessDocument get textFilterTargets() { let targets = [ - {id: TEXT_FILTER_TARGET_TITLE, name: $localize`Title`}, - {id: TEXT_FILTER_TARGET_TITLE_CONTENT, name: $localize`Title & content`}, - {id: TEXT_FILTER_TARGET_ASN, name: $localize`ASN`}, - {id: TEXT_FILTER_TARGET_FULLTEXT_QUERY, name: $localize`Advanced search`} + { id: TEXT_FILTER_TARGET_TITLE, name: $localize`Title` }, + { + id: TEXT_FILTER_TARGET_TITLE_CONTENT, + name: $localize`Title & content`, + }, + { id: TEXT_FILTER_TARGET_ASN, name: $localize`ASN` }, + { + id: TEXT_FILTER_TARGET_FULLTEXT_QUERY, + name: $localize`Advanced search`, + }, ] if (this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_MORELIKE) { - targets.push({id: TEXT_FILTER_TARGET_FULLTEXT_MORELIKE, name: $localize`More like`}) + targets.push({ + id: TEXT_FILTER_TARGET_FULLTEXT_MORELIKE, + name: $localize`More like`, + }) } return targets } @@ -99,10 +137,10 @@ export class FilterEditorComponent implements OnInit, OnDestroy { textFilterTarget = TEXT_FILTER_TARGET_TITLE_CONTENT get textFilterTargetName() { - return this.textFilterTargets.find(t => t.id == this.textFilterTarget)?.name + return this.textFilterTargets.find((t) => t.id == this.textFilterTarget) + ?.name } - tagSelectionModel = new FilterableDropdownSelectionModel() correspondentSelectionModel = new FilterableDropdownSelectionModel() documentTypeSelectionModel = new FilterableDropdownSelectionModel() @@ -126,7 +164,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy { } @Input() - set filterRules (value: FilterRule[]) { + set filterRules(value: FilterRule[]) { this._filterRules = value this.documentTypeSelectionModel.clear(false) @@ -139,7 +177,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy { this.dateCreatedBefore = null this.dateCreatedAfter = null - value.forEach(rule => { + value.forEach((rule) => { switch (rule.rule_type) { case FILTER_TITLE: this._textFilter = rule.value @@ -160,7 +198,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy { case FILTER_FULLTEXT_MORELIKE: this._moreLikeId = +rule.value this.textFilterTarget = TEXT_FILTER_TARGET_FULLTEXT_MORELIKE - this.documentService.get(this._moreLikeId).subscribe(result => { + this.documentService.get(this._moreLikeId).subscribe((result) => { this._moreLikeDoc = result this._textFilter = result.title }) @@ -178,23 +216,43 @@ export class FilterEditorComponent implements OnInit, OnDestroy { this.dateAddedBefore = rule.value break case FILTER_HAS_TAGS_ALL: - this.tagSelectionModel.set(rule.value ? +rule.value : null, ToggleableItemState.Selected, false) + this.tagSelectionModel.set( + rule.value ? +rule.value : null, + ToggleableItemState.Selected, + false + ) break case FILTER_HAS_TAGS_ANY: this.tagSelectionModel.logicalOperator = 'or' - this.tagSelectionModel.set(rule.value ? +rule.value : null, ToggleableItemState.Selected, false) + this.tagSelectionModel.set( + rule.value ? +rule.value : null, + ToggleableItemState.Selected, + false + ) break case FILTER_HAS_ANY_TAG: this.tagSelectionModel.set(null, ToggleableItemState.Selected, false) break case FILTER_DOES_NOT_HAVE_TAG: - this.tagSelectionModel.set(rule.value ? +rule.value : null, ToggleableItemState.Excluded, false) + this.tagSelectionModel.set( + rule.value ? +rule.value : null, + ToggleableItemState.Excluded, + false + ) break case FILTER_CORRESPONDENT: - this.correspondentSelectionModel.set(rule.value ? +rule.value : null, ToggleableItemState.Selected, false) + this.correspondentSelectionModel.set( + rule.value ? +rule.value : null, + ToggleableItemState.Selected, + false + ) break case FILTER_DOCUMENT_TYPE: - this.documentTypeSelectionModel.set(rule.value ? +rule.value : null, ToggleableItemState.Selected, false) + this.documentTypeSelectionModel.set( + rule.value ? +rule.value : null, + ToggleableItemState.Selected, + false + ) break } }) @@ -203,49 +261,104 @@ export class FilterEditorComponent implements OnInit, OnDestroy { get filterRules(): FilterRule[] { let filterRules: FilterRule[] = [] - if (this._textFilter && this.textFilterTarget == TEXT_FILTER_TARGET_TITLE_CONTENT) { - filterRules.push({rule_type: FILTER_TITLE_CONTENT, value: this._textFilter}) + if ( + this._textFilter && + this.textFilterTarget == TEXT_FILTER_TARGET_TITLE_CONTENT + ) { + filterRules.push({ + rule_type: FILTER_TITLE_CONTENT, + value: this._textFilter, + }) } if (this._textFilter && this.textFilterTarget == TEXT_FILTER_TARGET_TITLE) { - filterRules.push({rule_type: FILTER_TITLE, value: this._textFilter}) + filterRules.push({ rule_type: FILTER_TITLE, value: this._textFilter }) } if (this._textFilter && this.textFilterTarget == TEXT_FILTER_TARGET_ASN) { - filterRules.push({rule_type: FILTER_ASN, value: this._textFilter}) + filterRules.push({ rule_type: FILTER_ASN, value: this._textFilter }) } - if (this._textFilter && this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_QUERY) { - filterRules.push({rule_type: FILTER_FULLTEXT_QUERY, value: this._textFilter}) + if ( + this._textFilter && + this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_QUERY + ) { + filterRules.push({ + rule_type: FILTER_FULLTEXT_QUERY, + value: this._textFilter, + }) } - if (this._moreLikeId && this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_MORELIKE) { - filterRules.push({rule_type: FILTER_FULLTEXT_MORELIKE, value: this._moreLikeId?.toString()}) + if ( + this._moreLikeId && + this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_MORELIKE + ) { + filterRules.push({ + rule_type: FILTER_FULLTEXT_MORELIKE, + value: this._moreLikeId?.toString(), + }) } if (this.tagSelectionModel.isNoneSelected()) { - filterRules.push({rule_type: FILTER_HAS_ANY_TAG, value: "false"}) + filterRules.push({ rule_type: FILTER_HAS_ANY_TAG, value: 'false' }) } else { - const tagFilterType = this.tagSelectionModel.logicalOperator == 'and' ? FILTER_HAS_TAGS_ALL : FILTER_HAS_TAGS_ANY - this.tagSelectionModel.getSelectedItems().filter(tag => tag.id).forEach(tag => { - filterRules.push({rule_type: tagFilterType, value: tag.id?.toString()}) - }) - this.tagSelectionModel.getExcludedItems().filter(tag => tag.id).forEach(tag => { - filterRules.push({rule_type: FILTER_DOES_NOT_HAVE_TAG, value: tag.id?.toString()}) - }) + const tagFilterType = + this.tagSelectionModel.logicalOperator == 'and' + ? FILTER_HAS_TAGS_ALL + : FILTER_HAS_TAGS_ANY + this.tagSelectionModel + .getSelectedItems() + .filter((tag) => tag.id) + .forEach((tag) => { + filterRules.push({ + rule_type: tagFilterType, + value: tag.id?.toString(), + }) + }) + this.tagSelectionModel + .getExcludedItems() + .filter((tag) => tag.id) + .forEach((tag) => { + filterRules.push({ + rule_type: FILTER_DOES_NOT_HAVE_TAG, + value: tag.id?.toString(), + }) + }) } - this.correspondentSelectionModel.getSelectedItems().forEach(correspondent => { - filterRules.push({rule_type: FILTER_CORRESPONDENT, value: correspondent.id?.toString()}) - }) - this.documentTypeSelectionModel.getSelectedItems().forEach(documentType => { - filterRules.push({rule_type: FILTER_DOCUMENT_TYPE, value: documentType.id?.toString()}) - }) + this.correspondentSelectionModel + .getSelectedItems() + .forEach((correspondent) => { + filterRules.push({ + rule_type: FILTER_CORRESPONDENT, + value: correspondent.id?.toString(), + }) + }) + this.documentTypeSelectionModel + .getSelectedItems() + .forEach((documentType) => { + filterRules.push({ + rule_type: FILTER_DOCUMENT_TYPE, + value: documentType.id?.toString(), + }) + }) if (this.dateCreatedBefore) { - filterRules.push({rule_type: FILTER_CREATED_BEFORE, value: this.dateCreatedBefore}) + filterRules.push({ + rule_type: FILTER_CREATED_BEFORE, + value: this.dateCreatedBefore, + }) } if (this.dateCreatedAfter) { - filterRules.push({rule_type: FILTER_CREATED_AFTER, value: this.dateCreatedAfter}) + filterRules.push({ + rule_type: FILTER_CREATED_AFTER, + value: this.dateCreatedAfter, + }) } if (this.dateAddedBefore) { - filterRules.push({rule_type: FILTER_ADDED_BEFORE, value: this.dateAddedBefore}) + filterRules.push({ + rule_type: FILTER_ADDED_BEFORE, + value: this.dateAddedBefore, + }) } if (this.dateAddedAfter) { - filterRules.push({rule_type: FILTER_ADDED_AFTER, value: this.dateAddedAfter}) + filterRules.push({ + rule_type: FILTER_ADDED_AFTER, + value: this.dateAddedAfter, + }) } return filterRules } @@ -260,14 +373,20 @@ export class FilterEditorComponent implements OnInit, OnDestroy { if (this._unmodifiedFilterRules.length != this._filterRules.length) { modified = true } else { - modified = this._unmodifiedFilterRules.some(rule => { - return (this._filterRules.find(fri => fri.rule_type == rule.rule_type && fri.value == rule.value) == undefined) + modified = this._unmodifiedFilterRules.some((rule) => { + return ( + this._filterRules.find( + (fri) => fri.rule_type == rule.rule_type && fri.value == rule.value + ) == undefined + ) }) if (!modified) { // only check other direction if we havent already determined is modified - modified = this._filterRules.some(rule => { - this._unmodifiedFilterRules.find(fr => fr.rule_type == rule.rule_type && fr.value == rule.value) == undefined + modified = this._filterRules.some((rule) => { + this._unmodifiedFilterRules.find( + (fr) => fr.rule_type == rule.rule_type && fr.value == rule.value + ) == undefined }) } } @@ -290,23 +409,27 @@ export class FilterEditorComponent implements OnInit, OnDestroy { subscription: Subscription ngOnInit() { - this.tagService.listAll().subscribe(result => this.tags = result.results) - this.correspondentService.listAll().subscribe(result => this.correspondents = result.results) - this.documentTypeService.listAll().subscribe(result => this.documentTypes = result.results) + this.tagService + .listAll() + .subscribe((result) => (this.tags = result.results)) + this.correspondentService + .listAll() + .subscribe((result) => (this.correspondents = result.results)) + this.documentTypeService + .listAll() + .subscribe((result) => (this.documentTypes = result.results)) this.textFilterDebounce = new Subject() - this.subscription = this.textFilterDebounce.pipe( - debounceTime(400), - distinctUntilChanged() - ).subscribe(text => { - this._textFilter = text - this.documentService.searchQuery = text - this.updateRules() - }) + this.subscription = this.textFilterDebounce + .pipe(debounceTime(400), distinctUntilChanged()) + .subscribe((text) => { + this._textFilter = text + this.documentService.searchQuery = text + this.updateRules() + }) if (this._textFilter) this.documentService.searchQuery = this._textFilter - } ngOnDestroy() { @@ -324,11 +447,17 @@ export class FilterEditorComponent implements OnInit, OnDestroy { } addCorrespondent(correspondentId: number) { - this.correspondentSelectionModel.set(correspondentId, ToggleableItemState.Selected) + this.correspondentSelectionModel.set( + correspondentId, + ToggleableItemState.Selected + ) } addDocumentType(documentTypeId: number) { - this.documentTypeSelectionModel.set(documentTypeId, ToggleableItemState.Selected) + this.documentTypeSelectionModel.set( + documentTypeId, + ToggleableItemState.Selected + ) } onTagsDropdownOpen() { @@ -344,8 +473,11 @@ export class FilterEditorComponent implements OnInit, OnDestroy { } changeTextFilterTarget(target) { - if (this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_MORELIKE && target != TEXT_FILTER_TARGET_FULLTEXT_MORELIKE) { - this._textFilter = "" + if ( + this.textFilterTarget == TEXT_FILTER_TARGET_FULLTEXT_MORELIKE && + target != TEXT_FILTER_TARGET_FULLTEXT_MORELIKE + ) { + this._textFilter = '' } this.textFilterTarget = target this.textFilterInput.nativeElement.focus() diff --git a/src-ui/src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.spec.ts b/src-ui/src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.spec.ts index 11ac77c0b..5087da37a 100644 --- a/src-ui/src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.spec.ts +++ b/src-ui/src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { SaveViewConfigDialogComponent } from './save-view-config-dialog.component'; +import { SaveViewConfigDialogComponent } from './save-view-config-dialog.component' describe('SaveViewConfigDialogComponent', () => { - let component: SaveViewConfigDialogComponent; - let fixture: ComponentFixture; + let component: SaveViewConfigDialogComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ SaveViewConfigDialogComponent ] - }) - .compileComponents(); - }); + declarations: [SaveViewConfigDialogComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(SaveViewConfigDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(SaveViewConfigDialogComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.ts b/src-ui/src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.ts index 4f70941dd..84d4e9b24 100644 --- a/src-ui/src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.ts +++ b/src-ui/src/app/components/document-list/save-view-config-dialog/save-view-config-dialog.component.ts @@ -1,15 +1,14 @@ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core' +import { FormControl, FormGroup } from '@angular/forms' +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' @Component({ selector: 'app-save-view-config-dialog', templateUrl: './save-view-config-dialog.component.html', - styleUrls: ['./save-view-config-dialog.component.scss'] + styleUrls: ['./save-view-config-dialog.component.scss'], }) export class SaveViewConfigDialogComponent implements OnInit { - - constructor(private modal: NgbActiveModal) { } + constructor(private modal: NgbActiveModal) {} @Output() public saveClicked = new EventEmitter() @@ -22,7 +21,7 @@ export class SaveViewConfigDialogComponent implements OnInit { closeEnabled = false - _defaultName = "" + _defaultName = '' get defaultName() { return this._defaultName @@ -31,7 +30,7 @@ export class SaveViewConfigDialogComponent implements OnInit { @Input() set defaultName(value: string) { this._defaultName = value - this.saveViewConfigForm.patchValue({name: value}) + this.saveViewConfigForm.patchValue({ name: value }) } saveViewConfigForm = new FormGroup({ @@ -44,7 +43,7 @@ export class SaveViewConfigDialogComponent implements OnInit { // wait to enable close button so it doesnt steal focus from input since its the first clickable element in the DOM setTimeout(() => { this.closeEnabled = true - }); + }) } save() { diff --git a/src-ui/src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.spec.ts b/src-ui/src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.spec.ts index b400b80fe..1a491b113 100644 --- a/src-ui/src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.spec.ts +++ b/src-ui/src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { CorrespondentEditDialogComponent } from './correspondent-edit-dialog.component'; +import { CorrespondentEditDialogComponent } from './correspondent-edit-dialog.component' describe('CorrespondentEditDialogComponent', () => { - let component: CorrespondentEditDialogComponent; - let fixture: ComponentFixture; + let component: CorrespondentEditDialogComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ CorrespondentEditDialogComponent ] - }) - .compileComponents(); - }); + declarations: [CorrespondentEditDialogComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(CorrespondentEditDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(CorrespondentEditDialogComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts b/src-ui/src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts index b2fe8a929..cba0a922a 100644 --- a/src-ui/src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts +++ b/src-ui/src/app/components/manage/correspondent-list/correspondent-edit-dialog/correspondent-edit-dialog.component.ts @@ -1,19 +1,22 @@ -import { Component } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; -import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'; -import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'; -import { CorrespondentService } from 'src/app/services/rest/correspondent.service'; -import { ToastService } from 'src/app/services/toast.service'; +import { Component } from '@angular/core' +import { FormControl, FormGroup } from '@angular/forms' +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' +import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component' +import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent' +import { CorrespondentService } from 'src/app/services/rest/correspondent.service' +import { ToastService } from 'src/app/services/toast.service' @Component({ selector: 'app-correspondent-edit-dialog', templateUrl: './correspondent-edit-dialog.component.html', - styleUrls: ['./correspondent-edit-dialog.component.scss'] + styleUrls: ['./correspondent-edit-dialog.component.scss'], }) export class CorrespondentEditDialogComponent extends EditDialogComponent { - - constructor(service: CorrespondentService, activeModal: NgbActiveModal, toastService: ToastService) { + constructor( + service: CorrespondentService, + activeModal: NgbActiveModal, + toastService: ToastService + ) { super(service, activeModal, toastService) } @@ -29,9 +32,8 @@ export class CorrespondentEditDialogComponent extends EditDialogComponent { - let component: CorrespondentListComponent; - let fixture: ComponentFixture; + let component: CorrespondentListComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ CorrespondentListComponent ] - }) - .compileComponents(); - }); + declarations: [CorrespondentListComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(CorrespondentListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(CorrespondentListComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/manage/correspondent-list/correspondent-list.component.ts b/src-ui/src/app/components/manage/correspondent-list/correspondent-list.component.ts index fc057e87a..3322d2ff0 100644 --- a/src-ui/src/app/components/manage/correspondent-list/correspondent-list.component.ts +++ b/src-ui/src/app/components/manage/correspondent-list/correspondent-list.component.ts @@ -1,25 +1,31 @@ -import { Component } from '@angular/core'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { FILTER_CORRESPONDENT } from 'src/app/data/filter-rule-type'; -import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { CorrespondentService } from 'src/app/services/rest/correspondent.service'; -import { ToastService } from 'src/app/services/toast.service'; -import { GenericListComponent } from '../generic-list/generic-list.component'; -import { CorrespondentEditDialogComponent } from './correspondent-edit-dialog/correspondent-edit-dialog.component'; +import { Component } from '@angular/core' +import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { FILTER_CORRESPONDENT } from 'src/app/data/filter-rule-type' +import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { CorrespondentService } from 'src/app/services/rest/correspondent.service' +import { ToastService } from 'src/app/services/toast.service' +import { GenericListComponent } from '../generic-list/generic-list.component' +import { CorrespondentEditDialogComponent } from './correspondent-edit-dialog/correspondent-edit-dialog.component' @Component({ selector: 'app-correspondent-list', templateUrl: './correspondent-list.component.html', - styleUrls: ['./correspondent-list.component.scss'] + styleUrls: ['./correspondent-list.component.scss'], }) export class CorrespondentListComponent extends GenericListComponent { - - constructor(correspondentsService: CorrespondentService, modalService: NgbModal, + constructor( + correspondentsService: CorrespondentService, + modalService: NgbModal, private list: DocumentListViewService, toastService: ToastService ) { - super(correspondentsService,modalService,CorrespondentEditDialogComponent, toastService) + super( + correspondentsService, + modalService, + CorrespondentEditDialogComponent, + toastService + ) } getDeleteMessage(object: PaperlessCorrespondent) { @@ -27,6 +33,8 @@ export class CorrespondentListComponent extends GenericListComponent { - let component: DocumentTypeEditDialogComponent; - let fixture: ComponentFixture; + let component: DocumentTypeEditDialogComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ DocumentTypeEditDialogComponent ] - }) - .compileComponents(); - }); + declarations: [DocumentTypeEditDialogComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(DocumentTypeEditDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(DocumentTypeEditDialogComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts b/src-ui/src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts index b4a15d303..05d207f35 100644 --- a/src-ui/src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts +++ b/src-ui/src/app/components/manage/document-type-list/document-type-edit-dialog/document-type-edit-dialog.component.ts @@ -1,19 +1,22 @@ -import { Component } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; -import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'; -import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'; -import { DocumentTypeService } from 'src/app/services/rest/document-type.service'; -import { ToastService } from 'src/app/services/toast.service'; +import { Component } from '@angular/core' +import { FormControl, FormGroup } from '@angular/forms' +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' +import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component' +import { PaperlessDocumentType } from 'src/app/data/paperless-document-type' +import { DocumentTypeService } from 'src/app/services/rest/document-type.service' +import { ToastService } from 'src/app/services/toast.service' @Component({ selector: 'app-document-type-edit-dialog', templateUrl: './document-type-edit-dialog.component.html', - styleUrls: ['./document-type-edit-dialog.component.scss'] + styleUrls: ['./document-type-edit-dialog.component.scss'], }) export class DocumentTypeEditDialogComponent extends EditDialogComponent { - - constructor(service: DocumentTypeService, activeModal: NgbActiveModal, toastService: ToastService) { + constructor( + service: DocumentTypeService, + activeModal: NgbActiveModal, + toastService: ToastService + ) { super(service, activeModal, toastService) } @@ -29,9 +32,8 @@ export class DocumentTypeEditDialogComponent extends EditDialogComponent { - let component: DocumentTypeListComponent; - let fixture: ComponentFixture; + let component: DocumentTypeListComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ DocumentTypeListComponent ] - }) - .compileComponents(); - }); + declarations: [DocumentTypeListComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(DocumentTypeListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(DocumentTypeListComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/manage/document-type-list/document-type-list.component.ts b/src-ui/src/app/components/manage/document-type-list/document-type-list.component.ts index 02b9231ee..6950fb483 100644 --- a/src-ui/src/app/components/manage/document-type-list/document-type-list.component.ts +++ b/src-ui/src/app/components/manage/document-type-list/document-type-list.component.ts @@ -1,21 +1,22 @@ -import { Component } from '@angular/core'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { FILTER_DOCUMENT_TYPE } from 'src/app/data/filter-rule-type'; -import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { DocumentTypeService } from 'src/app/services/rest/document-type.service'; -import { ToastService } from 'src/app/services/toast.service'; -import { GenericListComponent } from '../generic-list/generic-list.component'; -import { DocumentTypeEditDialogComponent } from './document-type-edit-dialog/document-type-edit-dialog.component'; +import { Component } from '@angular/core' +import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { FILTER_DOCUMENT_TYPE } from 'src/app/data/filter-rule-type' +import { PaperlessDocumentType } from 'src/app/data/paperless-document-type' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { DocumentTypeService } from 'src/app/services/rest/document-type.service' +import { ToastService } from 'src/app/services/toast.service' +import { GenericListComponent } from '../generic-list/generic-list.component' +import { DocumentTypeEditDialogComponent } from './document-type-edit-dialog/document-type-edit-dialog.component' @Component({ selector: 'app-document-type-list', templateUrl: './document-type-list.component.html', - styleUrls: ['./document-type-list.component.scss'] + styleUrls: ['./document-type-list.component.scss'], }) export class DocumentTypeListComponent extends GenericListComponent { - - constructor(service: DocumentTypeService, modalService: NgbModal, + constructor( + service: DocumentTypeService, + modalService: NgbModal, private list: DocumentListViewService, toastService: ToastService ) { @@ -26,8 +27,9 @@ export class DocumentTypeListComponent extends GenericListComponent { - let component: GenericListComponent; - let fixture: ComponentFixture; + let component: GenericListComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ GenericListComponent ] - }) - .compileComponents(); - }); + declarations: [GenericListComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(GenericListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(GenericListComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/manage/generic-list/generic-list.component.ts b/src-ui/src/app/components/manage/generic-list/generic-list.component.ts index fdfe699b4..c719a67a1 100644 --- a/src-ui/src/app/components/manage/generic-list/generic-list.component.ts +++ b/src-ui/src/app/components/manage/generic-list/generic-list.component.ts @@ -1,25 +1,39 @@ -import { Directive, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { Subject, Subscription } from 'rxjs'; -import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; -import { MatchingModel, MATCHING_ALGORITHMS, MATCH_AUTO } from 'src/app/data/matching-model'; -import { ObjectWithId } from 'src/app/data/object-with-id'; -import { SortableDirective, SortEvent } from 'src/app/directives/sortable.directive'; -import { AbstractNameFilterService } from 'src/app/services/rest/abstract-name-filter-service'; -import { ToastService } from 'src/app/services/toast.service'; -import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'; +import { + Directive, + OnDestroy, + OnInit, + QueryList, + ViewChildren, +} from '@angular/core' +import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { Subject, Subscription } from 'rxjs' +import { debounceTime, distinctUntilChanged } from 'rxjs/operators' +import { + MatchingModel, + MATCHING_ALGORITHMS, + MATCH_AUTO, +} from 'src/app/data/matching-model' +import { ObjectWithId } from 'src/app/data/object-with-id' +import { + SortableDirective, + SortEvent, +} from 'src/app/directives/sortable.directive' +import { AbstractNameFilterService } from 'src/app/services/rest/abstract-name-filter-service' +import { ToastService } from 'src/app/services/toast.service' +import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component' @Directive() -export abstract class GenericListComponent implements OnInit, OnDestroy { - +export abstract class GenericListComponent + implements OnInit, OnDestroy +{ constructor( private service: AbstractNameFilterService, private modalService: NgbModal, private editDialogComponent: any, - private toastService: ToastService) { - } + private toastService: ToastService + ) {} - @ViewChildren(SortableDirective) headers: QueryList; + @ViewChildren(SortableDirective) headers: QueryList public data: T[] = [] @@ -38,9 +52,11 @@ export abstract class GenericListComponent implements On if (o.matching_algorithm == MATCH_AUTO) { return $localize`Automatic` } else if (o.match && o.match.length > 0) { - return `${MATCHING_ALGORITHMS.find(a => a.id == o.matching_algorithm).shortName}: ${o.match}` + return `${ + MATCHING_ALGORITHMS.find((a) => a.id == o.matching_algorithm).shortName + }: ${o.match}` } else { - return "-" + return '-' } } @@ -50,20 +66,18 @@ export abstract class GenericListComponent implements On this.reloadData() } - ngOnInit(): void { this.reloadData() this.nameFilterDebounce = new Subject() - this.subscription = this.nameFilterDebounce.pipe( - debounceTime(400), - distinctUntilChanged() - ).subscribe(title => { - this._nameFilter = title - this.page = 1 - this.reloadData() - }) + this.subscription = this.nameFilterDebounce + .pipe(debounceTime(400), distinctUntilChanged()) + .subscribe((title) => { + this._nameFilter = title + this.page = 1 + this.reloadData() + }) } ngOnDestroy() { @@ -71,25 +85,37 @@ export abstract class GenericListComponent implements On } reloadData() { - this.service.listFiltered(this.page, null, this.sortField, this.sortReverse, this._nameFilter).subscribe(c => { - this.data = c.results - this.collectionSize = c.count - }); + this.service + .listFiltered( + this.page, + null, + this.sortField, + this.sortReverse, + this._nameFilter + ) + .subscribe((c) => { + this.data = c.results + this.collectionSize = c.count + }) } openCreateDialog() { - var activeModal = this.modalService.open(this.editDialogComponent, {backdrop: 'static'}) + var activeModal = this.modalService.open(this.editDialogComponent, { + backdrop: 'static', + }) activeModal.componentInstance.dialogMode = 'create' - activeModal.componentInstance.success.subscribe(o => { + activeModal.componentInstance.success.subscribe((o) => { this.reloadData() }) } openEditDialog(object: T) { - var activeModal = this.modalService.open(this.editDialogComponent, {backdrop: 'static'}) + var activeModal = this.modalService.open(this.editDialogComponent, { + backdrop: 'static', + }) activeModal.componentInstance.object = object activeModal.componentInstance.dialogMode = 'edit' - activeModal.componentInstance.success.subscribe(o => { + activeModal.componentInstance.success.subscribe((o) => { this.reloadData() }) } @@ -99,23 +125,31 @@ export abstract class GenericListComponent implements On } openDeleteDialog(object: T) { - var activeModal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) + var activeModal = this.modalService.open(ConfirmDialogComponent, { + backdrop: 'static', + }) activeModal.componentInstance.title = $localize`Confirm delete` activeModal.componentInstance.messageBold = this.getDeleteMessage(object) activeModal.componentInstance.message = $localize`Associated documents will not be deleted.` - activeModal.componentInstance.btnClass = "btn-danger" + activeModal.componentInstance.btnClass = 'btn-danger' activeModal.componentInstance.btnCaption = $localize`Delete` activeModal.componentInstance.confirmClicked.subscribe(() => { activeModal.componentInstance.buttonsEnabled = false - this.service.delete(object).subscribe(_ => { - activeModal.close() - this.reloadData() - }, error => { - activeModal.componentInstance.buttonsEnabled = true - this.toastService.showError($localize`Error while deleting element: ${JSON.stringify(error.error)}`) - }) - } - ) + this.service.delete(object).subscribe( + (_) => { + activeModal.close() + this.reloadData() + }, + (error) => { + activeModal.componentInstance.buttonsEnabled = true + this.toastService.showError( + $localize`Error while deleting element: ${JSON.stringify( + error.error + )}` + ) + } + ) + }) } get nameFilter() { @@ -125,7 +159,7 @@ export abstract class GenericListComponent implements On set nameFilter(nameFilter: string) { this.nameFilterDebounce.next(nameFilter) } - + onNameFilterKeyUp(event: KeyboardEvent) { if (event.code == 'Escape') this.nameFilterDebounce.next(null) } diff --git a/src-ui/src/app/components/manage/logs/logs.component.spec.ts b/src-ui/src/app/components/manage/logs/logs.component.spec.ts index 12a4e107b..9a06d413c 100644 --- a/src-ui/src/app/components/manage/logs/logs.component.spec.ts +++ b/src-ui/src/app/components/manage/logs/logs.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { LogsComponent } from './logs.component'; +import { LogsComponent } from './logs.component' describe('LogsComponent', () => { - let component: LogsComponent; - let fixture: ComponentFixture; + let component: LogsComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ LogsComponent ] - }) - .compileComponents(); - }); + declarations: [LogsComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(LogsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(LogsComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/manage/logs/logs.component.ts b/src-ui/src/app/components/manage/logs/logs.component.ts index 26ceb5c57..b2e6af80d 100644 --- a/src-ui/src/app/components/manage/logs/logs.component.ts +++ b/src-ui/src/app/components/manage/logs/logs.component.ts @@ -1,14 +1,19 @@ -import { Component, ElementRef, OnInit, AfterViewChecked, ViewChild } from '@angular/core'; -import { LogService } from 'src/app/services/rest/log.service'; +import { + Component, + ElementRef, + OnInit, + AfterViewChecked, + ViewChild, +} from '@angular/core' +import { LogService } from 'src/app/services/rest/log.service' @Component({ selector: 'app-logs', templateUrl: './logs.component.html', - styleUrls: ['./logs.component.scss'] + styleUrls: ['./logs.component.scss'], }) export class LogsComponent implements OnInit, AfterViewChecked { - - constructor(private logService: LogService) { } + constructor(private logService: LogService) {} logs: string[] = [] @@ -19,7 +24,7 @@ export class LogsComponent implements OnInit, AfterViewChecked { @ViewChild('logContainer') logContainer: ElementRef ngOnInit(): void { - this.logService.list().subscribe(result => { + this.logService.list().subscribe((result) => { this.logFiles = result if (this.logFiles.length > 0) { this.activeLog = this.logFiles[0] @@ -29,25 +34,28 @@ export class LogsComponent implements OnInit, AfterViewChecked { } ngAfterViewChecked() { - this.scrollToBottom(); + this.scrollToBottom() } reloadLogs() { - this.logService.get(this.activeLog).subscribe(result => { - this.logs = result - }, error => { - this.logs = [] - }) + this.logService.get(this.activeLog).subscribe( + (result) => { + this.logs = result + }, + (error) => { + this.logs = [] + } + ) } getLogLevel(log: string) { - if (log.indexOf("[DEBUG]") != -1) { + if (log.indexOf('[DEBUG]') != -1) { return 10 - } else if (log.indexOf("[WARNING]") != -1) { + } else if (log.indexOf('[WARNING]') != -1) { return 30 - } else if (log.indexOf("[ERROR]") != -1) { + } else if (log.indexOf('[ERROR]') != -1) { return 40 - } else if (log.indexOf("[CRITICAL]") != -1) { + } else if (log.indexOf('[CRITICAL]') != -1) { return 50 } else { return 20 @@ -58,8 +66,7 @@ export class LogsComponent implements OnInit, AfterViewChecked { this.logContainer?.nativeElement.scroll({ top: this.logContainer.nativeElement.scrollHeight, left: 0, - behavior: 'auto' - }); + behavior: 'auto', + }) } - } diff --git a/src-ui/src/app/components/manage/settings/settings.component.spec.ts b/src-ui/src/app/components/manage/settings/settings.component.spec.ts index a3a508b0e..0ba0ab117 100644 --- a/src-ui/src/app/components/manage/settings/settings.component.spec.ts +++ b/src-ui/src/app/components/manage/settings/settings.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { SettingsComponent } from './settings.component'; +import { SettingsComponent } from './settings.component' describe('SettingsComponent', () => { - let component: SettingsComponent; - let fixture: ComponentFixture; + let component: SettingsComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ SettingsComponent ] - }) - .compileComponents(); - }); + declarations: [SettingsComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(SettingsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(SettingsComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/manage/settings/settings.component.ts b/src-ui/src/app/components/manage/settings/settings.component.ts index dc785f2c1..45785c709 100644 --- a/src-ui/src/app/components/manage/settings/settings.component.ts +++ b/src-ui/src/app/components/manage/settings/settings.component.ts @@ -1,39 +1,49 @@ -import { Component, Inject, LOCALE_ID, OnInit, OnDestroy, Renderer2 } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { SavedViewService } from 'src/app/services/rest/saved-view.service'; -import { LanguageOption, SettingsService, SETTINGS_KEYS } from 'src/app/services/settings.service'; -import { ToastService } from 'src/app/services/toast.service'; -import { dirtyCheck, DirtyComponent } from '@ngneat/dirty-check-forms'; -import { Observable, Subscription, BehaviorSubject } from 'rxjs'; +import { + Component, + Inject, + LOCALE_ID, + OnInit, + OnDestroy, + Renderer2, +} from '@angular/core' +import { FormControl, FormGroup } from '@angular/forms' +import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { SavedViewService } from 'src/app/services/rest/saved-view.service' +import { + LanguageOption, + SettingsService, + SETTINGS_KEYS, +} from 'src/app/services/settings.service' +import { ToastService } from 'src/app/services/toast.service' +import { dirtyCheck, DirtyComponent } from '@ngneat/dirty-check-forms' +import { Observable, Subscription, BehaviorSubject } from 'rxjs' @Component({ selector: 'app-settings', templateUrl: './settings.component.html', - styleUrls: ['./settings.component.scss'] + styleUrls: ['./settings.component.scss'], }) export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent { - savedViewGroup = new FormGroup({}) settingsForm = new FormGroup({ - 'bulkEditConfirmationDialogs': new FormControl(null), - 'bulkEditApplyOnClose': new FormControl(null), - 'documentListItemPerPage': new FormControl(null), - 'darkModeUseSystem': new FormControl(null), - 'darkModeEnabled': new FormControl(null), - 'darkModeInvertThumbs': new FormControl(null), - 'themeColor': new FormControl(null), - 'useNativePdfViewer': new FormControl(null), - 'savedViews': this.savedViewGroup, - 'displayLanguage': new FormControl(null), - 'dateLocale': new FormControl(null), - 'dateFormat': new FormControl(null), - 'notificationsConsumerNewDocument': new FormControl(null), - 'notificationsConsumerSuccess': new FormControl(null), - 'notificationsConsumerFailed': new FormControl(null), - 'notificationsConsumerSuppressOnDashboard': new FormControl(null), + bulkEditConfirmationDialogs: new FormControl(null), + bulkEditApplyOnClose: new FormControl(null), + documentListItemPerPage: new FormControl(null), + darkModeUseSystem: new FormControl(null), + darkModeEnabled: new FormControl(null), + darkModeInvertThumbs: new FormControl(null), + themeColor: new FormControl(null), + useNativePdfViewer: new FormControl(null), + savedViews: this.savedViewGroup, + displayLanguage: new FormControl(null), + dateLocale: new FormControl(null), + dateFormat: new FormControl(null), + notificationsConsumerNewDocument: new FormControl(null), + notificationsConsumerSuccess: new FormControl(null), + notificationsConsumerFailed: new FormControl(null), + notificationsConsumerSuppressOnDashboard: new FormControl(null), }) savedViews: PaperlessSavedView[] @@ -44,7 +54,11 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent { isDirty: Boolean = false get computedDateLocale(): string { - return this.settingsForm.value.dateLocale || this.settingsForm.value.displayLanguage || this.currentLocale + return ( + this.settingsForm.value.dateLocale || + this.settingsForm.value.displayLanguage || + this.currentLocale + ) } constructor( @@ -53,48 +67,71 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent { private toastService: ToastService, private settings: SettingsService, @Inject(LOCALE_ID) public currentLocale: string - ) { } + ) {} ngOnInit() { - this.savedViewService.listAll().subscribe(r => { + this.savedViewService.listAll().subscribe((r) => { this.savedViews = r.results let storeData = { - 'bulkEditConfirmationDialogs': this.settings.get(SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS), - 'bulkEditApplyOnClose': this.settings.get(SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE), - 'documentListItemPerPage': this.settings.get(SETTINGS_KEYS.DOCUMENT_LIST_SIZE), - 'darkModeUseSystem': this.settings.get(SETTINGS_KEYS.DARK_MODE_USE_SYSTEM), - 'darkModeEnabled': this.settings.get(SETTINGS_KEYS.DARK_MODE_ENABLED), - 'darkModeInvertThumbs': this.settings.get(SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED), - 'themeColor': this.settings.get(SETTINGS_KEYS.THEME_COLOR), - 'useNativePdfViewer': this.settings.get(SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER), - 'savedViews': {}, - 'displayLanguage': this.settings.getLanguage(), - 'dateLocale': this.settings.get(SETTINGS_KEYS.DATE_LOCALE), - 'dateFormat': this.settings.get(SETTINGS_KEYS.DATE_FORMAT), - 'notificationsConsumerNewDocument': this.settings.get(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT), - 'notificationsConsumerSuccess': this.settings.get(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS), - 'notificationsConsumerFailed': this.settings.get(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED), - 'notificationsConsumerSuppressOnDashboard': this.settings.get(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD), + bulkEditConfirmationDialogs: this.settings.get( + SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS + ), + bulkEditApplyOnClose: this.settings.get( + SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE + ), + documentListItemPerPage: this.settings.get( + SETTINGS_KEYS.DOCUMENT_LIST_SIZE + ), + darkModeUseSystem: this.settings.get( + SETTINGS_KEYS.DARK_MODE_USE_SYSTEM + ), + darkModeEnabled: this.settings.get(SETTINGS_KEYS.DARK_MODE_ENABLED), + darkModeInvertThumbs: this.settings.get( + SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED + ), + themeColor: this.settings.get(SETTINGS_KEYS.THEME_COLOR), + useNativePdfViewer: this.settings.get( + SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER + ), + savedViews: {}, + displayLanguage: this.settings.getLanguage(), + dateLocale: this.settings.get(SETTINGS_KEYS.DATE_LOCALE), + dateFormat: this.settings.get(SETTINGS_KEYS.DATE_FORMAT), + notificationsConsumerNewDocument: this.settings.get( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT + ), + notificationsConsumerSuccess: this.settings.get( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS + ), + notificationsConsumerFailed: this.settings.get( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED + ), + notificationsConsumerSuppressOnDashboard: this.settings.get( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD + ), } for (let view of this.savedViews) { storeData.savedViews[view.id.toString()] = { - "id": view.id, - "name": view.name, - "show_on_dashboard": view.show_on_dashboard, - "show_in_sidebar": view.show_in_sidebar + id: view.id, + name: view.name, + show_on_dashboard: view.show_on_dashboard, + show_in_sidebar: view.show_in_sidebar, } - this.savedViewGroup.addControl(view.id.toString(), new FormGroup({ - "id": new FormControl(null), - "name": new FormControl(null), - "show_on_dashboard": new FormControl(null), - "show_in_sidebar": new FormControl(null) - })) + this.savedViewGroup.addControl( + view.id.toString(), + new FormGroup({ + id: new FormControl(null), + name: new FormControl(null), + show_on_dashboard: new FormControl(null), + show_in_sidebar: new FormControl(null), + }) + ) } this.store = new BehaviorSubject(storeData) - this.storeSub = this.store.asObservable().subscribe(state => { + this.storeSub = this.store.asObservable().subscribe((state) => { this.settingsForm.patchValue(state, { emitEvent: false }) }) @@ -102,45 +139,93 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent { this.isDirty$ = dirtyCheck(this.settingsForm, this.store.asObservable()) // Record dirty in case we need to 'undo' appearance settings if not saved on close - this.isDirty$.subscribe(dirty => { + this.isDirty$.subscribe((dirty) => { this.isDirty = dirty }) - + // "Live" visual changes prior to save this.settingsForm.valueChanges.subscribe(() => { - this.settings.updateAppearanceSettings(this.settingsForm.get('darkModeUseSystem').value, this.settingsForm.get('darkModeEnabled').value, this.settingsForm.get('themeColor').value) + this.settings.updateAppearanceSettings( + this.settingsForm.get('darkModeUseSystem').value, + this.settingsForm.get('darkModeEnabled').value, + this.settingsForm.get('themeColor').value + ) }) }) } ngOnDestroy() { if (this.isDirty) this.settings.updateAppearanceSettings() // in case user changed appearance but didnt save - this.storeSub && this.storeSub.unsubscribe(); + this.storeSub && this.storeSub.unsubscribe() } deleteSavedView(savedView: PaperlessSavedView) { this.savedViewService.delete(savedView).subscribe(() => { this.savedViewGroup.removeControl(savedView.id.toString()) this.savedViews.splice(this.savedViews.indexOf(savedView), 1) - this.toastService.showInfo($localize`Saved view "${savedView.name}" deleted.`) + this.toastService.showInfo( + $localize`Saved view "${savedView.name}" deleted.` + ) }) } private saveLocalSettings() { - this.settings.set(SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE, this.settingsForm.value.bulkEditApplyOnClose) - this.settings.set(SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS, this.settingsForm.value.bulkEditConfirmationDialogs) - this.settings.set(SETTINGS_KEYS.DOCUMENT_LIST_SIZE, this.settingsForm.value.documentListItemPerPage) - this.settings.set(SETTINGS_KEYS.DARK_MODE_USE_SYSTEM, this.settingsForm.value.darkModeUseSystem) - this.settings.set(SETTINGS_KEYS.DARK_MODE_ENABLED, (this.settingsForm.value.darkModeEnabled == true).toString()) - this.settings.set(SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED, (this.settingsForm.value.darkModeInvertThumbs == true).toString()) - this.settings.set(SETTINGS_KEYS.THEME_COLOR, (this.settingsForm.value.themeColor).toString()) - this.settings.set(SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER, this.settingsForm.value.useNativePdfViewer) - this.settings.set(SETTINGS_KEYS.DATE_LOCALE, this.settingsForm.value.dateLocale) - this.settings.set(SETTINGS_KEYS.DATE_FORMAT, this.settingsForm.value.dateFormat) - this.settings.set(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT, this.settingsForm.value.notificationsConsumerNewDocument) - this.settings.set(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS, this.settingsForm.value.notificationsConsumerSuccess) - this.settings.set(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED, this.settingsForm.value.notificationsConsumerFailed) - this.settings.set(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD, this.settingsForm.value.notificationsConsumerSuppressOnDashboard) + this.settings.set( + SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE, + this.settingsForm.value.bulkEditApplyOnClose + ) + this.settings.set( + SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS, + this.settingsForm.value.bulkEditConfirmationDialogs + ) + this.settings.set( + SETTINGS_KEYS.DOCUMENT_LIST_SIZE, + this.settingsForm.value.documentListItemPerPage + ) + this.settings.set( + SETTINGS_KEYS.DARK_MODE_USE_SYSTEM, + this.settingsForm.value.darkModeUseSystem + ) + this.settings.set( + SETTINGS_KEYS.DARK_MODE_ENABLED, + (this.settingsForm.value.darkModeEnabled == true).toString() + ) + this.settings.set( + SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED, + (this.settingsForm.value.darkModeInvertThumbs == true).toString() + ) + this.settings.set( + SETTINGS_KEYS.THEME_COLOR, + this.settingsForm.value.themeColor.toString() + ) + this.settings.set( + SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER, + this.settingsForm.value.useNativePdfViewer + ) + this.settings.set( + SETTINGS_KEYS.DATE_LOCALE, + this.settingsForm.value.dateLocale + ) + this.settings.set( + SETTINGS_KEYS.DATE_FORMAT, + this.settingsForm.value.dateFormat + ) + this.settings.set( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT, + this.settingsForm.value.notificationsConsumerNewDocument + ) + this.settings.set( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS, + this.settingsForm.value.notificationsConsumerSuccess + ) + this.settings.set( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED, + this.settingsForm.value.notificationsConsumerFailed + ) + this.settings.set( + SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD, + this.settingsForm.value.notificationsConsumerSuppressOnDashboard + ) this.settings.setLanguage(this.settingsForm.value.displayLanguage) this.store.next(this.settingsForm.value) this.documentListViewService.updatePageSize() @@ -149,14 +234,14 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent { } get displayLanguageOptions(): LanguageOption[] { - return [ - {code: "", name: $localize`Use system language`} - ].concat(this.settings.getLanguageOptions()) + return [{ code: '', name: $localize`Use system language` }].concat( + this.settings.getLanguageOptions() + ) } get dateLocaleOptions(): LanguageOption[] { return [ - {code: "", name: $localize`Use date format of display language`} + { code: '', name: $localize`Use date format of display language` }, ].concat(this.settings.getDateLocaleOptions()) } @@ -170,18 +255,24 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent { x.push(this.savedViewGroup.value[id]) } if (x.length > 0) { - this.savedViewService.patchMany(x).subscribe(s => { - this.saveLocalSettings() - }, error => { - this.toastService.showError($localize`Error while storing settings on server: ${JSON.stringify(error.error)}`) - }) + this.savedViewService.patchMany(x).subscribe( + (s) => { + this.saveLocalSettings() + }, + (error) => { + this.toastService.showError( + $localize`Error while storing settings on server: ${JSON.stringify( + error.error + )}` + ) + } + ) } else { this.saveLocalSettings() } - } clearThemeColor() { - this.settingsForm.get('themeColor').patchValue(''); + this.settingsForm.get('themeColor').patchValue('') } } diff --git a/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.spec.ts b/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.spec.ts index 378cefdab..72cec03c2 100644 --- a/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.spec.ts +++ b/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { TagEditDialogComponent } from './tag-edit-dialog.component'; +import { TagEditDialogComponent } from './tag-edit-dialog.component' describe('TagEditDialogComponent', () => { - let component: TagEditDialogComponent; - let fixture: ComponentFixture; + let component: TagEditDialogComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ TagEditDialogComponent ] - }) - .compileComponents(); - }); + declarations: [TagEditDialogComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(TagEditDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(TagEditDialogComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts b/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts index 623b033ec..7b5b7abf7 100644 --- a/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts +++ b/src-ui/src/app/components/manage/tag-list/tag-edit-dialog/tag-edit-dialog.component.ts @@ -1,20 +1,23 @@ -import { Component } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; -import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; -import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component'; -import { PaperlessTag } from 'src/app/data/paperless-tag'; -import { TagService } from 'src/app/services/rest/tag.service'; -import { ToastService } from 'src/app/services/toast.service'; -import { randomColor } from 'src/app/utils/color'; +import { Component } from '@angular/core' +import { FormControl, FormGroup } from '@angular/forms' +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' +import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component' +import { PaperlessTag } from 'src/app/data/paperless-tag' +import { TagService } from 'src/app/services/rest/tag.service' +import { ToastService } from 'src/app/services/toast.service' +import { randomColor } from 'src/app/utils/color' @Component({ selector: 'app-tag-edit-dialog', templateUrl: './tag-edit-dialog.component.html', - styleUrls: ['./tag-edit-dialog.component.scss'] + styleUrls: ['./tag-edit-dialog.component.scss'], }) export class TagEditDialogComponent extends EditDialogComponent { - - constructor(service: TagService, activeModal: NgbActiveModal, toastService: ToastService) { + constructor( + service: TagService, + activeModal: NgbActiveModal, + toastService: ToastService + ) { super(service, activeModal, toastService) } @@ -32,9 +35,8 @@ export class TagEditDialogComponent extends EditDialogComponent { color: new FormControl(randomColor()), is_inbox_tag: new FormControl(false), matching_algorithm: new FormControl(1), - match: new FormControl(""), - is_insensitive: new FormControl(true) + match: new FormControl(''), + is_insensitive: new FormControl(true), }) } - } diff --git a/src-ui/src/app/components/manage/tag-list/tag-list.component.spec.ts b/src-ui/src/app/components/manage/tag-list/tag-list.component.spec.ts index 0623f541a..75c038d08 100644 --- a/src-ui/src/app/components/manage/tag-list/tag-list.component.spec.ts +++ b/src-ui/src/app/components/manage/tag-list/tag-list.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { TagListComponent } from './tag-list.component'; +import { TagListComponent } from './tag-list.component' describe('TagListComponent', () => { - let component: TagListComponent; - let fixture: ComponentFixture; + let component: TagListComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ TagListComponent ] - }) - .compileComponents(); - }); + declarations: [TagListComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(TagListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(TagListComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/manage/tag-list/tag-list.component.ts b/src-ui/src/app/components/manage/tag-list/tag-list.component.ts index 6d93d7dd4..f29598bfe 100644 --- a/src-ui/src/app/components/manage/tag-list/tag-list.component.ts +++ b/src-ui/src/app/components/manage/tag-list/tag-list.component.ts @@ -1,21 +1,22 @@ -import { Component } from '@angular/core'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { FILTER_HAS_TAGS_ALL } from 'src/app/data/filter-rule-type'; -import { PaperlessTag } from 'src/app/data/paperless-tag'; -import { DocumentListViewService } from 'src/app/services/document-list-view.service'; -import { TagService } from 'src/app/services/rest/tag.service'; -import { ToastService } from 'src/app/services/toast.service'; -import { GenericListComponent } from '../generic-list/generic-list.component'; -import { TagEditDialogComponent } from './tag-edit-dialog/tag-edit-dialog.component'; +import { Component } from '@angular/core' +import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { FILTER_HAS_TAGS_ALL } from 'src/app/data/filter-rule-type' +import { PaperlessTag } from 'src/app/data/paperless-tag' +import { DocumentListViewService } from 'src/app/services/document-list-view.service' +import { TagService } from 'src/app/services/rest/tag.service' +import { ToastService } from 'src/app/services/toast.service' +import { GenericListComponent } from '../generic-list/generic-list.component' +import { TagEditDialogComponent } from './tag-edit-dialog/tag-edit-dialog.component' @Component({ selector: 'app-tag-list', templateUrl: './tag-list.component.html', - styleUrls: ['./tag-list.component.scss'] + styleUrls: ['./tag-list.component.scss'], }) export class TagListComponent extends GenericListComponent { - - constructor(tagService: TagService, modalService: NgbModal, + constructor( + tagService: TagService, + modalService: NgbModal, private list: DocumentListViewService, toastService: ToastService ) { @@ -27,7 +28,8 @@ export class TagListComponent extends GenericListComponent { } filterDocuments(object: PaperlessTag) { - this.list.quickFilter([{rule_type: FILTER_HAS_TAGS_ALL, value: object.id.toString()}]) - + this.list.quickFilter([ + { rule_type: FILTER_HAS_TAGS_ALL, value: object.id.toString() }, + ]) } } diff --git a/src-ui/src/app/components/not-found/not-found.component.spec.ts b/src-ui/src/app/components/not-found/not-found.component.spec.ts index 9d41c99a6..e99177b78 100644 --- a/src-ui/src/app/components/not-found/not-found.component.spec.ts +++ b/src-ui/src/app/components/not-found/not-found.component.spec.ts @@ -1,25 +1,24 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing' -import { NotFoundComponent } from './not-found.component'; +import { NotFoundComponent } from './not-found.component' describe('NotFoundComponent', () => { - let component: NotFoundComponent; - let fixture: ComponentFixture; + let component: NotFoundComponent + let fixture: ComponentFixture beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ NotFoundComponent ] - }) - .compileComponents(); - }); + declarations: [NotFoundComponent], + }).compileComponents() + }) beforeEach(() => { - fixture = TestBed.createComponent(NotFoundComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(NotFoundComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) it('should create', () => { - expect(component).toBeTruthy(); - }); -}); + expect(component).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/components/not-found/not-found.component.ts b/src-ui/src/app/components/not-found/not-found.component.ts index 7cb4124f1..7051da161 100644 --- a/src-ui/src/app/components/not-found/not-found.component.ts +++ b/src-ui/src/app/components/not-found/not-found.component.ts @@ -1,15 +1,12 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core' @Component({ selector: 'app-not-found', templateUrl: './not-found.component.html', - styleUrls: ['./not-found.component.scss'] + styleUrls: ['./not-found.component.scss'], }) export class NotFoundComponent implements OnInit { + constructor() {} - constructor() { } - - ngOnInit(): void { - } - + ngOnInit(): void {} } diff --git a/src-ui/src/app/data/filter-rule-type.ts b/src-ui/src/app/data/filter-rule-type.ts index c72997618..337fee545 100644 --- a/src-ui/src/app/data/filter-rule-type.ts +++ b/src-ui/src/app/data/filter-rule-type.ts @@ -27,40 +27,160 @@ export const FILTER_FULLTEXT_QUERY = 20 export const FILTER_FULLTEXT_MORELIKE = 21 export const FILTER_RULE_TYPES: FilterRuleType[] = [ + { + id: FILTER_TITLE, + filtervar: 'title__icontains', + datatype: 'string', + multi: false, + default: '', + }, + { + id: FILTER_CONTENT, + filtervar: 'content__icontains', + datatype: 'string', + multi: false, + default: '', + }, - {id: FILTER_TITLE, filtervar: "title__icontains", datatype: "string", multi: false, default: ""}, - {id: FILTER_CONTENT, filtervar: "content__icontains", datatype: "string", multi: false, default: ""}, + { + id: FILTER_ASN, + filtervar: 'archive_serial_number', + datatype: 'number', + multi: false, + }, - {id: FILTER_ASN, filtervar: "archive_serial_number", datatype: "number", multi: false}, + { + id: FILTER_CORRESPONDENT, + filtervar: 'correspondent__id', + isnull_filtervar: 'correspondent__isnull', + datatype: 'correspondent', + multi: false, + }, + { + id: FILTER_DOCUMENT_TYPE, + filtervar: 'document_type__id', + isnull_filtervar: 'document_type__isnull', + datatype: 'document_type', + multi: false, + }, - {id: FILTER_CORRESPONDENT, filtervar: "correspondent__id", isnull_filtervar: "correspondent__isnull", datatype: "correspondent", multi: false}, - {id: FILTER_DOCUMENT_TYPE, filtervar: "document_type__id", isnull_filtervar: "document_type__isnull", datatype: "document_type", multi: false}, + { + id: FILTER_IS_IN_INBOX, + filtervar: 'is_in_inbox', + datatype: 'boolean', + multi: false, + default: true, + }, + { + id: FILTER_HAS_TAGS_ALL, + filtervar: 'tags__id__all', + datatype: 'tag', + multi: true, + }, + { + id: FILTER_HAS_TAGS_ANY, + filtervar: 'tags__id__in', + datatype: 'tag', + multi: true, + }, + { + id: FILTER_DOES_NOT_HAVE_TAG, + filtervar: 'tags__id__none', + datatype: 'tag', + multi: true, + }, + { + id: FILTER_HAS_ANY_TAG, + filtervar: 'is_tagged', + datatype: 'boolean', + multi: false, + default: true, + }, - {id: FILTER_IS_IN_INBOX, filtervar: "is_in_inbox", datatype: "boolean", multi: false, default: true}, - {id: FILTER_HAS_TAGS_ALL, filtervar: "tags__id__all", datatype: "tag", multi: true}, - {id: FILTER_HAS_TAGS_ANY, filtervar: "tags__id__in", datatype: "tag", multi: true}, - {id: FILTER_DOES_NOT_HAVE_TAG, filtervar: "tags__id__none", datatype: "tag", multi: true}, - {id: FILTER_HAS_ANY_TAG, filtervar: "is_tagged", datatype: "boolean", multi: false, default: true}, + { + id: FILTER_CREATED_BEFORE, + filtervar: 'created__date__lt', + datatype: 'date', + multi: false, + }, + { + id: FILTER_CREATED_AFTER, + filtervar: 'created__date__gt', + datatype: 'date', + multi: false, + }, - {id: FILTER_CREATED_BEFORE, filtervar: "created__date__lt", datatype: "date", multi: false}, - {id: FILTER_CREATED_AFTER, filtervar: "created__date__gt", datatype: "date", multi: false}, + { + id: FILTER_CREATED_YEAR, + filtervar: 'created__year', + datatype: 'number', + multi: false, + }, + { + id: FILTER_CREATED_MONTH, + filtervar: 'created__month', + datatype: 'number', + multi: false, + }, + { + id: FILTER_CREATED_DAY, + filtervar: 'created__day', + datatype: 'number', + multi: false, + }, - {id: FILTER_CREATED_YEAR, filtervar: "created__year", datatype: "number", multi: false}, - {id: FILTER_CREATED_MONTH, filtervar: "created__month", datatype: "number", multi: false}, - {id: FILTER_CREATED_DAY, filtervar: "created__day", datatype: "number", multi: false}, + { + id: FILTER_ADDED_BEFORE, + filtervar: 'added__date__lt', + datatype: 'date', + multi: false, + }, + { + id: FILTER_ADDED_AFTER, + filtervar: 'added__date__gt', + datatype: 'date', + multi: false, + }, - {id: FILTER_ADDED_BEFORE, filtervar: "added__date__lt", datatype: "date", multi: false}, - {id: FILTER_ADDED_AFTER, filtervar: "added__date__gt", datatype: "date", multi: false}, + { + id: FILTER_MODIFIED_BEFORE, + filtervar: 'modified__date__lt', + datatype: 'date', + multi: false, + }, + { + id: FILTER_MODIFIED_AFTER, + filtervar: 'modified__date__gt', + datatype: 'date', + multi: false, + }, + { + id: FILTER_ASN_ISNULL, + filtervar: 'archive_serial_number__isnull', + datatype: 'boolean', + multi: false, + }, - {id: FILTER_MODIFIED_BEFORE, filtervar: "modified__date__lt", datatype: "date", multi: false}, - {id: FILTER_MODIFIED_AFTER, filtervar: "modified__date__gt", datatype: "date", multi: false}, - {id: FILTER_ASN_ISNULL, filtervar: "archive_serial_number__isnull", datatype: "boolean", multi: false}, + { + id: FILTER_TITLE_CONTENT, + filtervar: 'title_content', + datatype: 'string', + multi: false, + }, - {id: FILTER_TITLE_CONTENT, filtervar: "title_content", datatype: "string", multi: false}, + { + id: FILTER_FULLTEXT_QUERY, + filtervar: 'query', + datatype: 'string', + multi: false, + }, - {id: FILTER_FULLTEXT_QUERY, filtervar: "query", datatype: "string", multi: false}, - - {id: FILTER_FULLTEXT_MORELIKE, filtervar: "more_like_id", datatype: "number", multi: false}, + { + id: FILTER_FULLTEXT_MORELIKE, + filtervar: 'more_like_id', + datatype: 'number', + multi: false, + }, ] export interface FilterRuleType { diff --git a/src-ui/src/app/data/filter-rule.ts b/src-ui/src/app/data/filter-rule.ts index c8b790e21..75819ad52 100644 --- a/src-ui/src/app/data/filter-rule.ts +++ b/src-ui/src/app/data/filter-rule.ts @@ -1,10 +1,13 @@ -import { FILTER_FULLTEXT_MORELIKE, FILTER_FULLTEXT_QUERY } from "./filter-rule-type" +import { + FILTER_FULLTEXT_MORELIKE, + FILTER_FULLTEXT_QUERY, +} from './filter-rule-type' export function cloneFilterRules(filterRules: FilterRule[]): FilterRule[] { if (filterRules) { let newRules: FilterRule[] = [] for (let rule of filterRules) { - newRules.push({rule_type: rule.rule_type, value: rule.value}) + newRules.push({ rule_type: rule.rule_type, value: rule.value }) } return newRules } else { @@ -13,7 +16,13 @@ export function cloneFilterRules(filterRules: FilterRule[]): FilterRule[] { } export function isFullTextFilterRule(filterRules: FilterRule[]): boolean { - return filterRules.find(r => r.rule_type == FILTER_FULLTEXT_QUERY || r.rule_type == FILTER_FULLTEXT_MORELIKE) != null + return ( + filterRules.find( + (r) => + r.rule_type == FILTER_FULLTEXT_QUERY || + r.rule_type == FILTER_FULLTEXT_MORELIKE + ) != null + ) } export interface FilterRule { diff --git a/src-ui/src/app/data/matching-model.ts b/src-ui/src/app/data/matching-model.ts index 49cb5cad4..e228893d6 100644 --- a/src-ui/src/app/data/matching-model.ts +++ b/src-ui/src/app/data/matching-model.ts @@ -1,5 +1,4 @@ -import { ObjectWithId } from './object-with-id'; - +import { ObjectWithId } from './object-with-id' export const MATCH_ANY = 1 export const MATCH_ALL = 2 @@ -9,26 +8,48 @@ export const MATCH_FUZZY = 5 export const MATCH_AUTO = 6 export const MATCHING_ALGORITHMS = [ - {id: MATCH_ANY, shortName: $localize`Any word`, name: $localize`Any: Document contains any of these words (space separated)`}, - {id: MATCH_ALL, shortName: $localize`All words`, name: $localize`All: Document contains all of these words (space separated)`}, - {id: MATCH_LITERAL, shortName: $localize`Exact match`, name: $localize`Exact: Document contains this string`}, - {id: MATCH_REGEX, shortName: $localize`Regular expression`, name: $localize`Regular expression: Document matches this regular expression`}, - {id: MATCH_FUZZY, shortName: $localize`Fuzzy word`, name: $localize`Fuzzy: Document contains a word similar to this word`}, - {id: MATCH_AUTO, shortName: $localize`Automatic`, name: $localize`Auto: Learn matching automatically`}, + { + id: MATCH_ANY, + shortName: $localize`Any word`, + name: $localize`Any: Document contains any of these words (space separated)`, + }, + { + id: MATCH_ALL, + shortName: $localize`All words`, + name: $localize`All: Document contains all of these words (space separated)`, + }, + { + id: MATCH_LITERAL, + shortName: $localize`Exact match`, + name: $localize`Exact: Document contains this string`, + }, + { + id: MATCH_REGEX, + shortName: $localize`Regular expression`, + name: $localize`Regular expression: Document matches this regular expression`, + }, + { + id: MATCH_FUZZY, + shortName: $localize`Fuzzy word`, + name: $localize`Fuzzy: Document contains a word similar to this word`, + }, + { + id: MATCH_AUTO, + shortName: $localize`Automatic`, + name: $localize`Auto: Learn matching automatically`, + }, ] export interface MatchingModel extends ObjectWithId { + name?: string - name?: string + slug?: string - slug?: string + match?: string - match?: string + matching_algorithm?: number - matching_algorithm?: number - - is_insensitive?: boolean - - document_count?: number + is_insensitive?: boolean + document_count?: number } diff --git a/src-ui/src/app/data/object-with-id.ts b/src-ui/src/app/data/object-with-id.ts index e81548f4e..4f5e89c83 100644 --- a/src-ui/src/app/data/object-with-id.ts +++ b/src-ui/src/app/data/object-with-id.ts @@ -1,5 +1,3 @@ export interface ObjectWithId { - - id?: number - + id?: number } diff --git a/src-ui/src/app/data/paperless-correspondent.ts b/src-ui/src/app/data/paperless-correspondent.ts index 3f5bb5719..142efd452 100644 --- a/src-ui/src/app/data/paperless-correspondent.ts +++ b/src-ui/src/app/data/paperless-correspondent.ts @@ -1,7 +1,5 @@ -import { MatchingModel } from './matching-model'; +import { MatchingModel } from './matching-model' export interface PaperlessCorrespondent extends MatchingModel { - last_correspondence?: Date - } diff --git a/src-ui/src/app/data/paperless-document-metadata.ts b/src-ui/src/app/data/paperless-document-metadata.ts index a1063adf9..1f9155b3a 100644 --- a/src-ui/src/app/data/paperless-document-metadata.ts +++ b/src-ui/src/app/data/paperless-document-metadata.ts @@ -1,5 +1,4 @@ export interface PaperlessDocumentMetadata { - original_checksum?: string archived_checksum?: string @@ -9,5 +8,4 @@ export interface PaperlessDocumentMetadata { media_filename?: string has_archive_version?: boolean - } diff --git a/src-ui/src/app/data/paperless-document-suggestions.ts b/src-ui/src/app/data/paperless-document-suggestions.ts index cc68b2b27..0a27df349 100644 --- a/src-ui/src/app/data/paperless-document-suggestions.ts +++ b/src-ui/src/app/data/paperless-document-suggestions.ts @@ -1,9 +1,7 @@ export interface PaperlessDocumentSuggestions { - tags?: number[] correspondents?: number[] document_types?: number[] - } diff --git a/src-ui/src/app/data/paperless-document-type.ts b/src-ui/src/app/data/paperless-document-type.ts index b1d002461..1aec65bc7 100644 --- a/src-ui/src/app/data/paperless-document-type.ts +++ b/src-ui/src/app/data/paperless-document-type.ts @@ -1,5 +1,3 @@ -import { MatchingModel } from './matching-model'; +import { MatchingModel } from './matching-model' -export interface PaperlessDocumentType extends MatchingModel { - -} +export interface PaperlessDocumentType extends MatchingModel {} diff --git a/src-ui/src/app/data/paperless-document.ts b/src-ui/src/app/data/paperless-document.ts index e7412278b..92a5aee45 100644 --- a/src-ui/src/app/data/paperless-document.ts +++ b/src-ui/src/app/data/paperless-document.ts @@ -5,50 +5,46 @@ import { PaperlessDocumentType } from './paperless-document-type' import { Observable } from 'rxjs' export interface SearchHit { - score?: number rank?: number highlights?: string - } export interface PaperlessDocument extends ObjectWithId { + correspondent$?: Observable - correspondent$?: Observable + correspondent?: number - correspondent?: number + document_type$?: Observable - document_type$?: Observable + document_type?: number - document_type?: number + title?: string - title?: string + content?: string - content?: string + file_type?: string - file_type?: string + tags$?: Observable - tags$?: Observable + tags?: number[] - tags?: number[] + checksum?: string - checksum?: string + created?: Date - created?: Date + modified?: Date - modified?: Date + added?: Date - added?: Date + file_name?: string - file_name?: string + download_url?: string - download_url?: string + thumbnail_url?: string - thumbnail_url?: string - - archive_serial_number?: number - - __search_hit__?: SearchHit + archive_serial_number?: number + __search_hit__?: SearchHit } diff --git a/src-ui/src/app/data/paperless-saved-view.ts b/src-ui/src/app/data/paperless-saved-view.ts index 8a4cd58b7..90c07e56a 100644 --- a/src-ui/src/app/data/paperless-saved-view.ts +++ b/src-ui/src/app/data/paperless-saved-view.ts @@ -1,8 +1,7 @@ -import { FilterRule } from './filter-rule'; -import { ObjectWithId } from './object-with-id'; +import { FilterRule } from './filter-rule' +import { ObjectWithId } from './object-with-id' export interface PaperlessSavedView extends ObjectWithId { - name?: string show_on_dashboard?: boolean @@ -14,5 +13,4 @@ export interface PaperlessSavedView extends ObjectWithId { sort_reverse: boolean filter_rules: FilterRule[] - } diff --git a/src-ui/src/app/data/paperless-tag.ts b/src-ui/src/app/data/paperless-tag.ts index a999666c4..7265ae187 100644 --- a/src-ui/src/app/data/paperless-tag.ts +++ b/src-ui/src/app/data/paperless-tag.ts @@ -1,11 +1,9 @@ -import { MatchingModel } from "./matching-model"; +import { MatchingModel } from './matching-model' export interface PaperlessTag extends MatchingModel { + color?: string - color?: string - - text_color?: string - - is_inbox_tag?: boolean + text_color?: string + is_inbox_tag?: boolean } diff --git a/src-ui/src/app/data/results.ts b/src-ui/src/app/data/results.ts index 839c79ed0..dbf99c5a1 100644 --- a/src-ui/src/app/data/results.ts +++ b/src-ui/src/app/data/results.ts @@ -1,7 +1,5 @@ export interface Results { - count: number results: T[] - } diff --git a/src-ui/src/app/data/storage-keys.ts b/src-ui/src/app/data/storage-keys.ts index ec91c06ac..77ee40c32 100644 --- a/src-ui/src/app/data/storage-keys.ts +++ b/src-ui/src/app/data/storage-keys.ts @@ -1,7 +1,7 @@ export const OPEN_DOCUMENT_SERVICE = { - DOCUMENTS: 'open-documents-service:openDocuments' + DOCUMENTS: 'open-documents-service:openDocuments', } export const DOCUMENT_LIST_SERVICE = { - CURRENT_VIEW_CONFIG: 'document-list-service:currentViewConfig' + CURRENT_VIEW_CONFIG: 'document-list-service:currentViewConfig', } diff --git a/src-ui/src/app/data/websocket-consumer-status-message.ts b/src-ui/src/app/data/websocket-consumer-status-message.ts index c20882067..aecdda7c0 100644 --- a/src-ui/src/app/data/websocket-consumer-status-message.ts +++ b/src-ui/src/app/data/websocket-consumer-status-message.ts @@ -1,5 +1,4 @@ export interface WebsocketConsumerStatusMessage { - filename?: string task_id?: string current_progress?: number @@ -7,5 +6,4 @@ export interface WebsocketConsumerStatusMessage { status?: string message?: string document_id: number - } diff --git a/src-ui/src/app/directives/sortable.directive.spec.ts b/src-ui/src/app/directives/sortable.directive.spec.ts index f77b499de..03f6d8c71 100644 --- a/src-ui/src/app/directives/sortable.directive.spec.ts +++ b/src-ui/src/app/directives/sortable.directive.spec.ts @@ -1,8 +1,8 @@ -import { SortableDirective } from './sortable.directive'; +import { SortableDirective } from './sortable.directive' describe('SortableDirective', () => { it('should create an instance', () => { - const directive = new SortableDirective(); - expect(directive).toBeTruthy(); - }); -}); + const directive = new SortableDirective() + expect(directive).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/directives/sortable.directive.ts b/src-ui/src/app/directives/sortable.directive.ts index 22750273d..85d65e398 100644 --- a/src-ui/src/app/directives/sortable.directive.ts +++ b/src-ui/src/app/directives/sortable.directive.ts @@ -1,4 +1,4 @@ -import { Directive, EventEmitter, Input, Output } from '@angular/core'; +import { Directive, EventEmitter, Input, Output } from '@angular/core' export interface SortEvent { column: string @@ -10,15 +10,14 @@ export interface SortEvent { host: { '[class.asc]': 'currentSortField == sortable && !currentSortReverse', '[class.des]': 'currentSortField == sortable && currentSortReverse', - '(click)': 'rotate()' - } + '(click)': 'rotate()', + }, }) export class SortableDirective { - - constructor() { } + constructor() {} @Input() - sortable: string = ''; + sortable: string = '' @Input() currentSortReverse: boolean = false @@ -26,15 +25,18 @@ export class SortableDirective { @Input() currentSortField: string - @Output() sort = new EventEmitter(); + @Output() sort = new EventEmitter() rotate() { if (this.currentSortField != this.sortable) { - this.sort.emit({column: this.sortable, reverse: false}); - } else if (this.currentSortField == this.sortable && !this.currentSortReverse) { - this.sort.emit({column: this.currentSortField, reverse: true}); + this.sort.emit({ column: this.sortable, reverse: false }) + } else if ( + this.currentSortField == this.sortable && + !this.currentSortReverse + ) { + this.sort.emit({ column: this.currentSortField, reverse: true }) } else { - this.sort.emit({column: null, reverse: false}); + this.sort.emit({ column: null, reverse: false }) } } } diff --git a/src-ui/src/app/guards/dirty-form.guard.ts b/src-ui/src/app/guards/dirty-form.guard.ts index 4e7bc39ea..1205f3b0e 100644 --- a/src-ui/src/app/guards/dirty-form.guard.ts +++ b/src-ui/src/app/guards/dirty-form.guard.ts @@ -1,22 +1,24 @@ -import { Injectable } from '@angular/core'; -import { DirtyCheckGuard } from '@ngneat/dirty-check-forms'; -import { Observable, Subject } from 'rxjs'; -import { map } from 'rxjs/operators'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { ConfirmDialogComponent } from 'src/app/components/common/confirm-dialog/confirm-dialog.component'; +import { Injectable } from '@angular/core' +import { DirtyCheckGuard } from '@ngneat/dirty-check-forms' +import { Observable, Subject } from 'rxjs' +import { map } from 'rxjs/operators' +import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { ConfirmDialogComponent } from 'src/app/components/common/confirm-dialog/confirm-dialog.component' @Injectable({ providedIn: 'root' }) export class DirtyFormGuard extends DirtyCheckGuard { constructor(private modalService: NgbModal) { - super(); + super() } confirmChanges(): Observable { - let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(ConfirmDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.title = $localize`Unsaved Changes` modal.componentInstance.messageBold = $localize`You have unsaved changes.` modal.componentInstance.message = $localize`Are you sure you want to leave?` - modal.componentInstance.btnClass = "btn-warning" + modal.componentInstance.btnClass = 'btn-warning' modal.componentInstance.btnCaption = $localize`Leave page` modal.componentInstance.confirmClicked.subscribe(() => { modal.componentInstance.buttonsEnabled = false diff --git a/src-ui/src/app/interceptors/api-version.interceptor.spec.ts b/src-ui/src/app/interceptors/api-version.interceptor.spec.ts index 7ad51f687..b1a2a9e04 100644 --- a/src-ui/src/app/interceptors/api-version.interceptor.spec.ts +++ b/src-ui/src/app/interceptors/api-version.interceptor.spec.ts @@ -1,16 +1,18 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing' -import { ApiVersionInterceptor } from './api-version.interceptor'; +import { ApiVersionInterceptor } from './api-version.interceptor' describe('ApiVersionInterceptor', () => { - beforeEach(() => TestBed.configureTestingModule({ - providers: [ - ApiVersionInterceptor - ] - })); + beforeEach(() => + TestBed.configureTestingModule({ + providers: [ApiVersionInterceptor], + }) + ) it('should be created', () => { - const interceptor: ApiVersionInterceptor = TestBed.inject(ApiVersionInterceptor); - expect(interceptor).toBeTruthy(); - }); -}); + const interceptor: ApiVersionInterceptor = TestBed.inject( + ApiVersionInterceptor + ) + expect(interceptor).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/interceptors/api-version.interceptor.ts b/src-ui/src/app/interceptors/api-version.interceptor.ts index 4df2efba6..eb246c580 100644 --- a/src-ui/src/app/interceptors/api-version.interceptor.ts +++ b/src-ui/src/app/interceptors/api-version.interceptor.ts @@ -1,25 +1,27 @@ -import { Injectable } from '@angular/core'; +import { Injectable } from '@angular/core' import { HttpRequest, HttpHandler, HttpEvent, - HttpInterceptor -} from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { environment } from 'src/environments/environment'; + HttpInterceptor, +} from '@angular/common/http' +import { Observable } from 'rxjs' +import { environment } from 'src/environments/environment' @Injectable() export class ApiVersionInterceptor implements HttpInterceptor { - constructor() {} - intercept(request: HttpRequest, next: HttpHandler): Observable> { + intercept( + request: HttpRequest, + next: HttpHandler + ): Observable> { request = request.clone({ - setHeaders: { - 'Accept': `application/json; version=${environment.apiVersion}` - } - }) + setHeaders: { + Accept: `application/json; version=${environment.apiVersion}`, + }, + }) - return next.handle(request); + return next.handle(request) } } diff --git a/src-ui/src/app/interceptors/csrf.interceptor.spec.ts b/src-ui/src/app/interceptors/csrf.interceptor.spec.ts index 64e20c110..df387acc1 100644 --- a/src-ui/src/app/interceptors/csrf.interceptor.spec.ts +++ b/src-ui/src/app/interceptors/csrf.interceptor.spec.ts @@ -1,16 +1,16 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing' -import { CsrfInterceptor } from './csrf.interceptor'; +import { CsrfInterceptor } from './csrf.interceptor' describe('CsrfInterceptor', () => { - beforeEach(() => TestBed.configureTestingModule({ - providers: [ - CsrfInterceptor - ] - })); + beforeEach(() => + TestBed.configureTestingModule({ + providers: [CsrfInterceptor], + }) + ) it('should be created', () => { - const interceptor: CsrfInterceptor = TestBed.inject(CsrfInterceptor); - expect(interceptor).toBeTruthy(); - }); -}); + const interceptor: CsrfInterceptor = TestBed.inject(CsrfInterceptor) + expect(interceptor).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/interceptors/csrf.interceptor.ts b/src-ui/src/app/interceptors/csrf.interceptor.ts index 1817e3a66..eb136e489 100644 --- a/src-ui/src/app/interceptors/csrf.interceptor.ts +++ b/src-ui/src/app/interceptors/csrf.interceptor.ts @@ -1,35 +1,35 @@ -import { Injectable } from '@angular/core'; +import { Injectable } from '@angular/core' import { HttpRequest, HttpHandler, HttpEvent, - HttpInterceptor -} from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { CookieService } from 'ngx-cookie-service'; -import { Meta } from '@angular/platform-browser'; + HttpInterceptor, +} from '@angular/common/http' +import { Observable } from 'rxjs' +import { CookieService } from 'ngx-cookie-service' +import { Meta } from '@angular/platform-browser' @Injectable() export class CsrfInterceptor implements HttpInterceptor { + constructor(private cookieService: CookieService, private meta: Meta) {} - constructor(private cookieService: CookieService, private meta: Meta) { - - } - - intercept(request: HttpRequest, next: HttpHandler): Observable> { - let prefix = "" + intercept( + request: HttpRequest, + next: HttpHandler + ): Observable> { + let prefix = '' if (this.meta.getTag('name=cookie_prefix')) { prefix = this.meta.getTag('name=cookie_prefix').content } - let csrfToken = this.cookieService.get(`${prefix?prefix:''}csrftoken`) + let csrfToken = this.cookieService.get(`${prefix ? prefix : ''}csrftoken`) if (csrfToken) { - request = request.clone({ + request = request.clone({ setHeaders: { - 'X-CSRFToken': csrfToken - } + 'X-CSRFToken': csrfToken, + }, }) } - return next.handle(request); + return next.handle(request) } } diff --git a/src-ui/src/app/pipes/custom-date.pipe.spec.ts b/src-ui/src/app/pipes/custom-date.pipe.spec.ts index 822966baf..063d80da5 100644 --- a/src-ui/src/app/pipes/custom-date.pipe.spec.ts +++ b/src-ui/src/app/pipes/custom-date.pipe.spec.ts @@ -1,8 +1,8 @@ -import { CustomDatePipe } from './custom-date.pipe'; +import { CustomDatePipe } from './custom-date.pipe' describe('CustomDatePipe', () => { it('create an instance', () => { - const pipe = new CustomDatePipe(); - expect(pipe).toBeTruthy(); - }); -}); + const pipe = new CustomDatePipe() + expect(pipe).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/pipes/custom-date.pipe.ts b/src-ui/src/app/pipes/custom-date.pipe.ts index 71f386b8c..bf5ab1457 100644 --- a/src-ui/src/app/pipes/custom-date.pipe.ts +++ b/src-ui/src/app/pipes/custom-date.pipe.ts @@ -1,32 +1,47 @@ -import { DatePipe } from '@angular/common'; -import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core'; -import { SettingsService, SETTINGS_KEYS } from '../services/settings.service'; +import { DatePipe } from '@angular/common' +import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core' +import { SettingsService, SETTINGS_KEYS } from '../services/settings.service' const FORMAT_TO_ISO_FORMAT = { - "longDate": "y-MM-dd", - "mediumDate": "y-MM-dd", - "shortDate": "y-MM-dd" + longDate: 'y-MM-dd', + mediumDate: 'y-MM-dd', + shortDate: 'y-MM-dd', } @Pipe({ - name: 'customDate' + name: 'customDate', }) export class CustomDatePipe implements PipeTransform { - private defaultLocale: string - constructor(@Inject(LOCALE_ID) locale: string, private datePipe: DatePipe, private settings: SettingsService) { + constructor( + @Inject(LOCALE_ID) locale: string, + private datePipe: DatePipe, + private settings: SettingsService + ) { this.defaultLocale = locale } - transform(value: any, format?: string, timezone?: string, locale?: string): string | null { - let l = locale || this.settings.get(SETTINGS_KEYS.DATE_LOCALE) || this.defaultLocale + transform( + value: any, + format?: string, + timezone?: string, + locale?: string + ): string | null { + let l = + locale || + this.settings.get(SETTINGS_KEYS.DATE_LOCALE) || + this.defaultLocale let f = format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT) - if (l == "iso-8601") { + if (l == 'iso-8601') { return this.datePipe.transform(value, FORMAT_TO_ISO_FORMAT[f], timezone) } else { - return this.datePipe.transform(value, format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT), timezone, l) + return this.datePipe.transform( + value, + format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT), + timezone, + l + ) } } - } diff --git a/src-ui/src/app/pipes/document-title.pipe.spec.ts b/src-ui/src/app/pipes/document-title.pipe.spec.ts index 29835abd6..08afd244e 100644 --- a/src-ui/src/app/pipes/document-title.pipe.spec.ts +++ b/src-ui/src/app/pipes/document-title.pipe.spec.ts @@ -1,8 +1,8 @@ -import { DocumentTitlePipe } from './document-title.pipe'; +import { DocumentTitlePipe } from './document-title.pipe' describe('DocumentTitlePipe', () => { it('create an instance', () => { - const pipe = new DocumentTitlePipe(); - expect(pipe).toBeTruthy(); - }); -}); + const pipe = new DocumentTitlePipe() + expect(pipe).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/pipes/document-title.pipe.ts b/src-ui/src/app/pipes/document-title.pipe.ts index 60a552ca8..e9611a926 100644 --- a/src-ui/src/app/pipes/document-title.pipe.ts +++ b/src-ui/src/app/pipes/document-title.pipe.ts @@ -1,10 +1,9 @@ -import { Pipe, PipeTransform } from '@angular/core'; +import { Pipe, PipeTransform } from '@angular/core' @Pipe({ - name: 'documentTitle' + name: 'documentTitle', }) export class DocumentTitlePipe implements PipeTransform { - transform(value: string): string { if (value) { return value @@ -12,5 +11,4 @@ export class DocumentTitlePipe implements PipeTransform { return $localize`(no title)` } } - } diff --git a/src-ui/src/app/pipes/file-size.pipe.spec.ts b/src-ui/src/app/pipes/file-size.pipe.spec.ts index 8c7a39d22..b84500fad 100644 --- a/src-ui/src/app/pipes/file-size.pipe.spec.ts +++ b/src-ui/src/app/pipes/file-size.pipe.spec.ts @@ -1,8 +1,8 @@ -import { FileSizePipe } from './file-size.pipe'; +import { FileSizePipe } from './file-size.pipe' describe('FileSizePipe', () => { it('create an instance', () => { - const pipe = new FileSizePipe(); - expect(pipe).toBeTruthy(); - }); -}); + const pipe = new FileSizePipe() + expect(pipe).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/pipes/file-size.pipe.ts b/src-ui/src/app/pipes/file-size.pipe.ts index 4ac1e4d61..83f07d837 100644 --- a/src-ui/src/app/pipes/file-size.pipe.ts +++ b/src-ui/src/app/pipes/file-size.pipe.ts @@ -22,12 +22,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -import { Pipe, PipeTransform } from '@angular/core'; +import { Pipe, PipeTransform } from '@angular/core' -type unit = 'bytes' | 'KB' | 'MB' | 'GB' | 'TB' | 'PB'; +type unit = 'bytes' | 'KB' | 'MB' | 'GB' | 'TB' | 'PB' type unitPrecisionMap = { - [u in unit]: number; -}; + [u in unit]: number +} const defaultPrecisionMap: unitPrecisionMap = { bytes: 0, @@ -35,8 +35,8 @@ const defaultPrecisionMap: unitPrecisionMap = { MB: 1, GB: 1, TB: 2, - PB: 2 -}; + PB: 2, +} /* * Convert bytes into largest possible unit. @@ -55,23 +55,26 @@ const defaultPrecisionMap: unitPrecisionMap = { */ @Pipe({ name: 'fileSize' }) export class FileSizePipe implements PipeTransform { - private readonly units: unit[] = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB']; + private readonly units: unit[] = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB'] - transform(bytes: number = 0, precision: number | unitPrecisionMap = defaultPrecisionMap): string { - if (isNaN(parseFloat(String(bytes))) || !isFinite(bytes)) return '?'; + transform( + bytes: number = 0, + precision: number | unitPrecisionMap = defaultPrecisionMap + ): string { + if (isNaN(parseFloat(String(bytes))) || !isFinite(bytes)) return '?' - let unitIndex = 0; + let unitIndex = 0 while (bytes >= 1024) { - bytes /= 1024; - unitIndex++; + bytes /= 1024 + unitIndex++ } - const unit = this.units[unitIndex]; + const unit = this.units[unitIndex] if (typeof precision === 'number') { - return `${bytes.toFixed(+precision)} ${unit}`; + return `${bytes.toFixed(+precision)} ${unit}` } - return `${bytes.toFixed(precision[unit])} ${unit}`; + return `${bytes.toFixed(precision[unit])} ${unit}` } } diff --git a/src-ui/src/app/pipes/filter.pipe.ts b/src-ui/src/app/pipes/filter.pipe.ts index 0be1be507..d48c2ad5d 100644 --- a/src-ui/src/app/pipes/filter.pipe.ts +++ b/src-ui/src/app/pipes/filter.pipe.ts @@ -1,18 +1,20 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { MatchingModel } from '../data/matching-model'; +import { Pipe, PipeTransform } from '@angular/core' +import { MatchingModel } from '../data/matching-model' @Pipe({ - name: 'filter' + name: 'filter', }) export class FilterPipe implements PipeTransform { transform(items: MatchingModel[], searchText: string): MatchingModel[] { - if (!items) return []; - if (!searchText) return items; + if (!items) return [] + if (!searchText) return items - return items.filter(item => { - return Object.keys(item).some(key => { - return String(item[key]).toLowerCase().includes(searchText.toLowerCase()); - }); - }); - } + return items.filter((item) => { + return Object.keys(item).some((key) => { + return String(item[key]) + .toLowerCase() + .includes(searchText.toLowerCase()) + }) + }) + } } diff --git a/src-ui/src/app/pipes/safe.pipe.spec.ts b/src-ui/src/app/pipes/safe.pipe.spec.ts index 49ee0ad14..2fca4cee1 100644 --- a/src-ui/src/app/pipes/safe.pipe.spec.ts +++ b/src-ui/src/app/pipes/safe.pipe.spec.ts @@ -1,8 +1,8 @@ -import { SafePipe } from './safe.pipe'; +import { SafePipe } from './safe.pipe' describe('SafePipe', () => { it('create an instance', () => { - const pipe = new SafePipe(); - expect(pipe).toBeTruthy(); - }); -}); + const pipe = new SafePipe() + expect(pipe).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/pipes/safe.pipe.ts b/src-ui/src/app/pipes/safe.pipe.ts index 3aa987c08..5a3921cbb 100644 --- a/src-ui/src/app/pipes/safe.pipe.ts +++ b/src-ui/src/app/pipes/safe.pipe.ts @@ -1,19 +1,17 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { DomSanitizer } from '@angular/platform-browser'; +import { Pipe, PipeTransform } from '@angular/core' +import { DomSanitizer } from '@angular/platform-browser' @Pipe({ - name: 'safe' + name: 'safe', }) export class SafePipe implements PipeTransform { - - constructor(private sanitizer: DomSanitizer) { } + constructor(private sanitizer: DomSanitizer) {} transform(url) { if (url == null) { - return this.sanitizer.bypassSecurityTrustResourceUrl("") + return this.sanitizer.bypassSecurityTrustResourceUrl('') } else { - return this.sanitizer.bypassSecurityTrustResourceUrl(url); + return this.sanitizer.bypassSecurityTrustResourceUrl(url) } } - } diff --git a/src-ui/src/app/pipes/yes-no.pipe.spec.ts b/src-ui/src/app/pipes/yes-no.pipe.spec.ts index 80acd8acd..3da9518e9 100644 --- a/src-ui/src/app/pipes/yes-no.pipe.spec.ts +++ b/src-ui/src/app/pipes/yes-no.pipe.spec.ts @@ -1,8 +1,8 @@ -import { YesNoPipe } from './yes-no.pipe'; +import { YesNoPipe } from './yes-no.pipe' describe('YesNoPipe', () => { it('create an instance', () => { - const pipe = new YesNoPipe(); - expect(pipe).toBeTruthy(); - }); -}); + const pipe = new YesNoPipe() + expect(pipe).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/pipes/yes-no.pipe.ts b/src-ui/src/app/pipes/yes-no.pipe.ts index f12c844a5..3912e9a92 100644 --- a/src-ui/src/app/pipes/yes-no.pipe.ts +++ b/src-ui/src/app/pipes/yes-no.pipe.ts @@ -1,12 +1,10 @@ -import { Pipe, PipeTransform } from '@angular/core'; +import { Pipe, PipeTransform } from '@angular/core' @Pipe({ - name: 'yesno' + name: 'yesno', }) export class YesNoPipe implements PipeTransform { - transform(value: boolean): unknown { return value ? $localize`Yes` : $localize`No` } - } diff --git a/src-ui/src/app/services/consumer-status.service.spec.ts b/src-ui/src/app/services/consumer-status.service.spec.ts index d19f455e2..03a5b003f 100644 --- a/src-ui/src/app/services/consumer-status.service.spec.ts +++ b/src-ui/src/app/services/consumer-status.service.spec.ts @@ -1,16 +1,16 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing' -import { ConsumerStatusService } from './consumer-status.service'; +import { ConsumerStatusService } from './consumer-status.service' describe('ConsumerStatusService', () => { - let service: ConsumerStatusService; + let service: ConsumerStatusService beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(ConsumerStatusService); - }); + TestBed.configureTestingModule({}) + service = TestBed.inject(ConsumerStatusService) + }) it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); + expect(service).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/services/consumer-status.service.ts b/src-ui/src/app/services/consumer-status.service.ts index 4a729b29d..176227bef 100644 --- a/src-ui/src/app/services/consumer-status.service.ts +++ b/src-ui/src/app/services/consumer-status.service.ts @@ -1,34 +1,33 @@ -import { Injectable } from '@angular/core'; -import { Subject } from 'rxjs'; -import { environment } from 'src/environments/environment'; -import { WebsocketConsumerStatusMessage } from '../data/websocket-consumer-status-message'; +import { Injectable } from '@angular/core' +import { Subject } from 'rxjs' +import { environment } from 'src/environments/environment' +import { WebsocketConsumerStatusMessage } from '../data/websocket-consumer-status-message' export enum FileStatusPhase { STARTED = 0, UPLOADING = 1, PROCESSING = 2, SUCCESS = 3, - FAILED = 4 + FAILED = 4, } export const FILE_STATUS_MESSAGES = { - "document_already_exists": $localize`Document already exists.`, - "file_not_found": $localize`File not found.`, - "pre_consume_script_not_found": $localize`:Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Pre-consume script does not exist.`, - "pre_consume_script_error": $localize`:Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Error while executing pre-consume script.`, - "post_consume_script_not_found": $localize`:Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Post-consume script does not exist.`, - "post_consume_script_error": $localize`:Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Error while executing post-consume script.`, - "new_file": $localize`Received new file.`, - "unsupported_type": $localize`File type not supported.`, - "parsing_document": $localize`Processing document...`, - "generating_thumbnail": $localize`Generating thumbnail...`, - "parse_date": $localize`Retrieving date from document...`, - "save_document": $localize`Saving document...`, - "finished": $localize`Finished.` + document_already_exists: $localize`Document already exists.`, + file_not_found: $localize`File not found.`, + pre_consume_script_not_found: $localize`:Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Pre-consume script does not exist.`, + pre_consume_script_error: $localize`:Pre-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Error while executing pre-consume script.`, + post_consume_script_not_found: $localize`:Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Post-consume script does not exist.`, + post_consume_script_error: $localize`:Post-Consume is a term that appears like that in the documentation as well and does not need a specific translation:Error while executing post-consume script.`, + new_file: $localize`Received new file.`, + unsupported_type: $localize`File type not supported.`, + parsing_document: $localize`Processing document...`, + generating_thumbnail: $localize`Generating thumbnail...`, + parse_date: $localize`Retrieving date from document...`, + save_document: $localize`Saving document...`, + finished: $localize`Finished.`, } export class FileStatus { - filename: string taskId: string @@ -48,16 +47,22 @@ export class FileStatus { case FileStatusPhase.STARTED: return 0.0 case FileStatusPhase.UPLOADING: - return this.currentPhaseProgress / this.currentPhaseMaxProgress * 0.2 + return (this.currentPhaseProgress / this.currentPhaseMaxProgress) * 0.2 case FileStatusPhase.PROCESSING: - return (this.currentPhaseProgress / this.currentPhaseMaxProgress * 0.8) + 0.2 + return ( + (this.currentPhaseProgress / this.currentPhaseMaxProgress) * 0.8 + 0.2 + ) case FileStatusPhase.SUCCESS: case FileStatusPhase.FAILED: return 1.0 } } - updateProgress(status: FileStatusPhase, currentProgress?: number, maxProgress?: number) { + updateProgress( + status: FileStatusPhase, + currentProgress?: number, + maxProgress?: number + ) { if (status >= this.phase) { this.phase = status if (currentProgress != null) { @@ -68,15 +73,13 @@ export class FileStatus { } } } - } @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ConsumerStatusService { - - constructor() { } + constructor() {} private statusWebSocket: WebSocket @@ -87,7 +90,11 @@ export class ConsumerStatusService { private documentConsumptionFailedSubject = new Subject() private get(taskId: string, filename?: string) { - let status = this.consumerStatus.find(e => e.taskId == taskId) || this.consumerStatus.find(e => e.filename == filename && e.taskId == null) + let status = + this.consumerStatus.find((e) => e.taskId == taskId) || + this.consumerStatus.find( + (e) => e.filename == filename && e.taskId == null + ) let created = false if (!status) { status = new FileStatus() @@ -96,7 +103,7 @@ export class ConsumerStatusService { } status.taskId = taskId status.filename = filename - return {'status': status, 'created': created} + return { status: status, created: created } } newFileUpload(filename: string): FileStatus { @@ -108,33 +115,48 @@ export class ConsumerStatusService { getConsumerStatus(phase?: FileStatusPhase) { if (phase != null) { - return this.consumerStatus.filter(s => s.phase == phase) + return this.consumerStatus.filter((s) => s.phase == phase) } else { return this.consumerStatus } } getConsumerStatusNotCompleted() { - return this.consumerStatus.filter(s => s.phase < FileStatusPhase.SUCCESS) + return this.consumerStatus.filter((s) => s.phase < FileStatusPhase.SUCCESS) } getConsumerStatusCompleted() { - return this.consumerStatus.filter(s => s.phase == FileStatusPhase.FAILED || s.phase == FileStatusPhase.SUCCESS) + return this.consumerStatus.filter( + (s) => + s.phase == FileStatusPhase.FAILED || s.phase == FileStatusPhase.SUCCESS + ) } connect() { this.disconnect() - this.statusWebSocket = new WebSocket(`${environment.webSocketProtocol}//${environment.webSocketHost}${environment.webSocketBaseUrl}status/`); + this.statusWebSocket = new WebSocket( + `${environment.webSocketProtocol}//${environment.webSocketHost}${environment.webSocketBaseUrl}status/` + ) this.statusWebSocket.onmessage = (ev) => { let statusMessage: WebsocketConsumerStatusMessage = JSON.parse(ev['data']) - let statusMessageGet = this.get(statusMessage.task_id, statusMessage.filename) + let statusMessageGet = this.get( + statusMessage.task_id, + statusMessage.filename + ) let status = statusMessageGet.status let created = statusMessageGet.created - status.updateProgress(FileStatusPhase.PROCESSING, statusMessage.current_progress, statusMessage.max_progress) - if (statusMessage.message && statusMessage.message in FILE_STATUS_MESSAGES) { + status.updateProgress( + FileStatusPhase.PROCESSING, + statusMessage.current_progress, + statusMessage.max_progress + ) + if ( + statusMessage.message && + statusMessage.message in FILE_STATUS_MESSAGES + ) { status.message = FILE_STATUS_MESSAGES[statusMessage.message] } else if (statusMessage.message) { status.message = statusMessage.message @@ -144,11 +166,11 @@ export class ConsumerStatusService { if (created && statusMessage.status == 'STARTING') { this.documentDetectedSubject.next(status) } - if (statusMessage.status == "SUCCESS") { + if (statusMessage.status == 'SUCCESS') { status.phase = FileStatusPhase.SUCCESS this.documentConsumptionFinishedSubject.next(status) } - if (statusMessage.status == "FAILED") { + if (statusMessage.status == 'FAILED') { status.phase = FileStatusPhase.FAILED this.documentConsumptionFailedSubject.next(status) } @@ -171,9 +193,11 @@ export class ConsumerStatusService { dismiss(status: FileStatus) { let index if (status.taskId != null) { - index = this.consumerStatus.findIndex(s => s.taskId == status.taskId) + index = this.consumerStatus.findIndex((s) => s.taskId == status.taskId) } else { - index = this.consumerStatus.findIndex(s => s.filename == status.filename) + index = this.consumerStatus.findIndex( + (s) => s.filename == status.filename + ) } if (index > -1) { @@ -182,7 +206,9 @@ export class ConsumerStatusService { } dismissCompleted() { - this.consumerStatus = this.consumerStatus.filter(status => status.phase != FileStatusPhase.SUCCESS) + this.consumerStatus = this.consumerStatus.filter( + (status) => status.phase != FileStatusPhase.SUCCESS + ) } onDocumentConsumptionFinished() { @@ -196,5 +222,4 @@ export class ConsumerStatusService { onDocumentDetected() { return this.documentDetectedSubject } - } diff --git a/src-ui/src/app/services/document-list-view.service.spec.ts b/src-ui/src/app/services/document-list-view.service.spec.ts index 92a1177aa..bbb0ed8f2 100644 --- a/src-ui/src/app/services/document-list-view.service.spec.ts +++ b/src-ui/src/app/services/document-list-view.service.spec.ts @@ -1,16 +1,16 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing' -import { DocumentListViewService } from './document-list-view.service'; +import { DocumentListViewService } from './document-list-view.service' describe('DocumentListViewService', () => { - let service: DocumentListViewService; + let service: DocumentListViewService beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(DocumentListViewService); - }); + TestBed.configureTestingModule({}) + service = TestBed.inject(DocumentListViewService) + }) it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); + expect(service).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/services/document-list-view.service.ts b/src-ui/src/app/services/document-list-view.service.ts index 4455520f6..a8b7c3d9e 100644 --- a/src-ui/src/app/services/document-list-view.service.ts +++ b/src-ui/src/app/services/document-list-view.service.ts @@ -1,18 +1,21 @@ -import { Injectable } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { Observable } from 'rxjs'; -import { cloneFilterRules, FilterRule, isFullTextFilterRule } from '../data/filter-rule'; -import { PaperlessDocument } from '../data/paperless-document'; -import { PaperlessSavedView } from '../data/paperless-saved-view'; -import { DOCUMENT_LIST_SERVICE } from '../data/storage-keys'; -import { DocumentService } from './rest/document.service'; -import { SettingsService, SETTINGS_KEYS } from './settings.service'; +import { Injectable } from '@angular/core' +import { ActivatedRoute, Router } from '@angular/router' +import { Observable } from 'rxjs' +import { + cloneFilterRules, + FilterRule, + isFullTextFilterRule, +} from '../data/filter-rule' +import { PaperlessDocument } from '../data/paperless-document' +import { PaperlessSavedView } from '../data/paperless-saved-view' +import { DOCUMENT_LIST_SERVICE } from '../data/storage-keys' +import { DocumentService } from './rest/document.service' +import { SettingsService, SETTINGS_KEYS } from './settings.service' /** * Captures the current state of the list view. */ interface ListViewState { - /** * Title of the document list view. Either "Documents" (localized) or the name of a saved view. */ @@ -49,7 +52,6 @@ interface ListViewState { * Contains the IDs of all selected documents. */ selected?: Set - } /** @@ -59,10 +61,9 @@ interface ListViewState { * and saved views on request. See below. */ @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class DocumentListViewService { - isReloading: boolean = false error: string = null @@ -89,16 +90,19 @@ export class DocumentListViewService { documents: [], currentPage: 1, collectionSize: null, - sortField: "created", + sortField: 'created', sortReverse: true, filterRules: [], - selected: new Set() + selected: new Set(), } } private get activeListViewState() { if (!this.listViewStates.has(this._activeSavedViewId)) { - this.listViewStates.set(this._activeSavedViewId, this.defaultListViewState()) + this.listViewStates.set( + this._activeSavedViewId, + this.defaultListViewState() + ) } return this.listViewStates.get(this._activeSavedViewId) } @@ -131,13 +135,16 @@ export class DocumentListViewService { this.error = null let activeListViewState = this.activeListViewState - this.documentService.listFiltered( - activeListViewState.currentPage, - this.currentPageSize, - activeListViewState.sortField, - activeListViewState.sortReverse, - activeListViewState.filterRules).subscribe( - result => { + this.documentService + .listFiltered( + activeListViewState.currentPage, + this.currentPageSize, + activeListViewState.sortField, + activeListViewState.sortReverse, + activeListViewState.filterRules + ) + .subscribe( + (result) => { this.isReloading = false activeListViewState.collectionSize = result.count activeListViewState.documents = result.results @@ -146,7 +153,7 @@ export class DocumentListViewService { } this.rangeSelectionAnchorIndex = this.lastRangeSelectionToIndex = null }, - error => { + (error) => { this.isReloading = false if (activeListViewState.currentPage != 1 && error.status == 404) { // this happens when applying a filter: the current page might not be available anymore due to the reduced result set. @@ -155,12 +162,16 @@ export class DocumentListViewService { } else { this.error = error.error } - }) + } + ) } set filterRules(filterRules: FilterRule[]) { - if (!isFullTextFilterRule(filterRules) && this.activeListViewState.sortField == "score") { - this.activeListViewState.sortField = "created" + if ( + !isFullTextFilterRule(filterRules) && + this.activeListViewState.sortField == 'score' + ) { + this.activeListViewState.sortField = 'created' } this.activeListViewState.filterRules = filterRules this.reload() @@ -228,9 +239,12 @@ export class DocumentListViewService { currentPage: this.activeListViewState.currentPage, filterRules: this.activeListViewState.filterRules, sortField: this.activeListViewState.sortField, - sortReverse: this.activeListViewState.sortReverse + sortReverse: this.activeListViewState.sortReverse, } - localStorage.setItem(DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG, JSON.stringify(savedState)) + localStorage.setItem( + DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG, + JSON.stringify(savedState) + ) } } @@ -239,15 +253,15 @@ export class DocumentListViewService { this.activeListViewState.filterRules = filterRules this.activeListViewState.currentPage = 1 if (isFullTextFilterRule(filterRules)) { - this.activeListViewState.sortField = "score" + this.activeListViewState.sortField = 'score' this.activeListViewState.sortReverse = false } this.reduceSelectionToFilter() this.saveDocumentListView() - if (this.router.url == "/documents") { + if (this.router.url == '/documents') { this.reload() } else { - this.router.navigate(["documents"]) + this.router.navigate(['documents']) } } @@ -257,8 +271,12 @@ export class DocumentListViewService { hasNext(doc: number) { if (this.documents) { - let index = this.documents.findIndex(d => d.id == doc) - return index != -1 && (this.currentPage < this.getLastPage() || (index + 1) < this.documents.length) + let index = this.documents.findIndex((d) => d.id == doc) + return ( + index != -1 && + (this.currentPage < this.getLastPage() || + index + 1 < this.documents.length) + ) } } @@ -270,13 +288,12 @@ export class DocumentListViewService { } getNext(currentDocId: number): Observable { - return new Observable(nextDocId => { + return new Observable((nextDocId) => { if (this.documents != null) { + let index = this.documents.findIndex((d) => d.id == currentDocId) - let index = this.documents.findIndex(d => d.id == currentDocId) - - if (index != -1 && (index + 1) < this.documents.length) { - nextDocId.next(this.documents[index+1].id) + if (index != -1 && index + 1 < this.documents.length) { + nextDocId.next(this.documents[index + 1].id) nextDocId.complete() } else if (index != -1 && this.currentPage < this.getLastPage()) { this.currentPage += 1 @@ -331,23 +348,27 @@ export class DocumentListViewService { reduceSelectionToFilter() { if (this.selected.size > 0) { - this.documentService.listAllFilteredIds(this.filterRules).subscribe(ids => { - for (let id of this.selected) { - if (!ids.includes(id)) { - this.selected.delete(id) + this.documentService + .listAllFilteredIds(this.filterRules) + .subscribe((ids) => { + for (let id of this.selected) { + if (!ids.includes(id)) { + this.selected.delete(id) + } } - } - }) + }) } } selectAll() { - this.documentService.listAllFilteredIds(this.filterRules).subscribe(ids => ids.forEach(id => this.selected.add(id))) + this.documentService + .listAllFilteredIds(this.filterRules) + .subscribe((ids) => ids.forEach((id) => this.selected.add(id))) } selectPage() { this.selected.clear() - this.documents.forEach(doc => { + this.documents.forEach((doc) => { this.selected.add(doc.id) }) } @@ -366,36 +387,58 @@ export class DocumentListViewService { selectRangeTo(d: PaperlessDocument) { if (this.rangeSelectionAnchorIndex !== null) { const documentToIndex = this.documentIndexInCurrentView(d.id) - const fromIndex = Math.min(this.rangeSelectionAnchorIndex, documentToIndex) + const fromIndex = Math.min( + this.rangeSelectionAnchorIndex, + documentToIndex + ) const toIndex = Math.max(this.rangeSelectionAnchorIndex, documentToIndex) if (this.lastRangeSelectionToIndex !== null) { // revert the old selection - this.documents.slice(Math.min(this.rangeSelectionAnchorIndex, this.lastRangeSelectionToIndex), Math.max(this.rangeSelectionAnchorIndex, this.lastRangeSelectionToIndex) + 1).forEach(d => { - this.selected.delete(d.id) - }) + this.documents + .slice( + Math.min( + this.rangeSelectionAnchorIndex, + this.lastRangeSelectionToIndex + ), + Math.max( + this.rangeSelectionAnchorIndex, + this.lastRangeSelectionToIndex + ) + 1 + ) + .forEach((d) => { + this.selected.delete(d.id) + }) } - this.documents.slice(fromIndex, toIndex + 1).forEach(d => { + this.documents.slice(fromIndex, toIndex + 1).forEach((d) => { this.selected.add(d.id) }) this.lastRangeSelectionToIndex = documentToIndex - } else { // e.g. shift key but was first click + } else { + // e.g. shift key but was first click this.toggleSelected(d) } } documentIndexInCurrentView(documentID: number): number { - return this.documents.map(d => d.id).indexOf(documentID) + return this.documents.map((d) => d.id).indexOf(documentID) } - constructor(private documentService: DocumentService, private settings: SettingsService, private router: Router, private route: ActivatedRoute) { - let documentListViewConfigJson = localStorage.getItem(DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG) + constructor( + private documentService: DocumentService, + private settings: SettingsService, + private router: Router, + private route: ActivatedRoute + ) { + let documentListViewConfigJson = localStorage.getItem( + DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG + ) if (documentListViewConfigJson) { try { let savedState: ListViewState = JSON.parse(documentListViewConfigJson) // Remove null elements from the restored state - Object.keys(savedState).forEach(k => { + Object.keys(savedState).forEach((k) => { if (savedState[k] == null) { delete savedState[k] } diff --git a/src-ui/src/app/services/open-documents.service.spec.ts b/src-ui/src/app/services/open-documents.service.spec.ts index c0d0c7a4b..dcc18b05b 100644 --- a/src-ui/src/app/services/open-documents.service.spec.ts +++ b/src-ui/src/app/services/open-documents.service.spec.ts @@ -1,16 +1,16 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing' -import { OpenDocumentsService } from './open-documents.service'; +import { OpenDocumentsService } from './open-documents.service' describe('OpenDocumentsService', () => { - let service: OpenDocumentsService; + let service: OpenDocumentsService beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(OpenDocumentsService); - }); + TestBed.configureTestingModule({}) + service = TestBed.inject(OpenDocumentsService) + }) it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); + expect(service).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/services/open-documents.service.ts b/src-ui/src/app/services/open-documents.service.ts index 92802c765..5297a38bf 100644 --- a/src-ui/src/app/services/open-documents.service.ts +++ b/src-ui/src/app/services/open-documents.service.ts @@ -1,23 +1,27 @@ -import { Injectable } from '@angular/core'; -import { PaperlessDocument } from '../data/paperless-document'; -import { OPEN_DOCUMENT_SERVICE } from '../data/storage-keys'; -import { DocumentService } from './rest/document.service'; -import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; -import { ConfirmDialogComponent } from 'src/app/components/common/confirm-dialog/confirm-dialog.component'; -import { Observable, Subject, of } from 'rxjs'; -import { first } from 'rxjs/operators'; +import { Injectable } from '@angular/core' +import { PaperlessDocument } from '../data/paperless-document' +import { OPEN_DOCUMENT_SERVICE } from '../data/storage-keys' +import { DocumentService } from './rest/document.service' +import { NgbModal } from '@ng-bootstrap/ng-bootstrap' +import { ConfirmDialogComponent } from 'src/app/components/common/confirm-dialog/confirm-dialog.component' +import { Observable, Subject, of } from 'rxjs' +import { first } from 'rxjs/operators' @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class OpenDocumentsService { - private MAX_OPEN_DOCUMENTS = 5 - constructor(private documentService: DocumentService, private modalService: NgbModal) { + constructor( + private documentService: DocumentService, + private modalService: NgbModal + ) { if (sessionStorage.getItem(OPEN_DOCUMENT_SERVICE.DOCUMENTS)) { try { - this.openDocuments = JSON.parse(sessionStorage.getItem(OPEN_DOCUMENT_SERVICE.DOCUMENTS)) + this.openDocuments = JSON.parse( + sessionStorage.getItem(OPEN_DOCUMENT_SERVICE.DOCUMENTS) + ) } catch (e) { sessionStorage.removeItem(OPEN_DOCUMENT_SERVICE.DOCUMENTS) this.openDocuments = [] @@ -29,14 +33,17 @@ export class OpenDocumentsService { private dirtyDocuments: Set = new Set() refreshDocument(id: number) { - let index = this.openDocuments.findIndex(doc => doc.id == id) + let index = this.openDocuments.findIndex((doc) => doc.id == id) if (index > -1) { - this.documentService.get(id).subscribe(doc => { - this.openDocuments[index] = doc - }, error => { - this.openDocuments.splice(index, 1) - this.save() - }) + this.documentService.get(id).subscribe( + (doc) => { + this.openDocuments[index] = doc + }, + (error) => { + this.openDocuments.splice(index, 1) + this.save() + } + ) } } @@ -45,11 +52,11 @@ export class OpenDocumentsService { } getOpenDocument(id: number): PaperlessDocument { - return this.openDocuments.find(d => d.id == id) + return this.openDocuments.find((d) => d.id == id) } openDocument(doc: PaperlessDocument) { - if (this.openDocuments.find(d => d.id == doc.id) == null) { + if (this.openDocuments.find((d) => d.id == doc.id) == null) { this.openDocuments.unshift(doc) if (this.openDocuments.length > this.MAX_OPEN_DOCUMENTS) { this.openDocuments.pop() @@ -64,18 +71,20 @@ export class OpenDocumentsService { } closeDocument(doc: PaperlessDocument): Observable { - let index = this.openDocuments.findIndex(d => d.id == doc.id) - if (index == -1) return of(true); + let index = this.openDocuments.findIndex((d) => d.id == doc.id) + if (index == -1) return of(true) if (!this.dirtyDocuments.has(doc.id)) { this.openDocuments.splice(index, 1) this.save() return of(true) } else { - let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(ConfirmDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.title = $localize`Unsaved Changes` modal.componentInstance.messageBold = $localize`You have unsaved changes.` modal.componentInstance.message = $localize`Are you sure you want to close this document?` - modal.componentInstance.btnClass = "btn-warning" + modal.componentInstance.btnClass = 'btn-warning' modal.componentInstance.btnCaption = $localize`Close document` modal.componentInstance.confirmClicked.pipe(first()).subscribe(() => { modal.componentInstance.buttonsEnabled = false @@ -92,11 +101,13 @@ export class OpenDocumentsService { closeAll(): Observable { if (this.dirtyDocuments.size) { - let modal = this.modalService.open(ConfirmDialogComponent, {backdrop: 'static'}) + let modal = this.modalService.open(ConfirmDialogComponent, { + backdrop: 'static', + }) modal.componentInstance.title = $localize`Unsaved Changes` modal.componentInstance.messageBold = $localize`You have unsaved changes.` modal.componentInstance.message = $localize`Are you sure you want to close all documents?` - modal.componentInstance.btnClass = "btn-warning" + modal.componentInstance.btnClass = 'btn-warning' modal.componentInstance.btnCaption = $localize`Close documents` modal.componentInstance.confirmClicked.pipe(first()).subscribe(() => { modal.componentInstance.buttonsEnabled = false @@ -117,7 +128,9 @@ export class OpenDocumentsService { } save() { - sessionStorage.setItem(OPEN_DOCUMENT_SERVICE.DOCUMENTS, JSON.stringify(this.openDocuments)) + sessionStorage.setItem( + OPEN_DOCUMENT_SERVICE.DOCUMENTS, + JSON.stringify(this.openDocuments) + ) } - } 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 d605fef49..568803fb8 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 @@ -1,14 +1,20 @@ import { ObjectWithId } from 'src/app/data/object-with-id' import { AbstractPaperlessService } from './abstract-paperless-service' -export abstract class AbstractNameFilterService extends AbstractPaperlessService { - - listFiltered(page?: number, pageSize?: number, sortField?: string, sortReverse?: boolean, nameFilter?: string) { +export abstract class AbstractNameFilterService< + T extends ObjectWithId +> extends AbstractPaperlessService { + listFiltered( + page?: number, + pageSize?: number, + sortField?: string, + sortReverse?: boolean, + nameFilter?: string + ) { let params = {} if (nameFilter) { - params = {'name__icontains': nameFilter} + params = { name__icontains: nameFilter } } return this.list(page, pageSize, sortField, sortReverse, params) } - } diff --git a/src-ui/src/app/services/rest/abstract-paperless-service.spec.ts b/src-ui/src/app/services/rest/abstract-paperless-service.spec.ts index f95a9cb39..99207410d 100644 --- a/src-ui/src/app/services/rest/abstract-paperless-service.spec.ts +++ b/src-ui/src/app/services/rest/abstract-paperless-service.spec.ts @@ -1,7 +1,7 @@ -import { AbstractPaperlessService } from './abstract-paperless-service'; +import { AbstractPaperlessService } from './abstract-paperless-service' describe('AbstractPaperlessService', () => { it('should create an instance', () => { - expect(new AbstractPaperlessService()).toBeTruthy(); - }); -}); + expect(new AbstractPaperlessService()).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/services/rest/abstract-paperless-service.ts b/src-ui/src/app/services/rest/abstract-paperless-service.ts index 8ad1a2141..9a5664c9d 100644 --- a/src-ui/src/app/services/rest/abstract-paperless-service.ts +++ b/src-ui/src/app/services/rest/abstract-paperless-service.ts @@ -6,10 +6,9 @@ import { Results } from 'src/app/data/results' import { environment } from 'src/environments/environment' export abstract class AbstractPaperlessService { - protected baseUrl: string = environment.apiBaseUrl - constructor(protected http: HttpClient, private resourceName: string) { } + constructor(protected http: HttpClient, private resourceName: string) {} protected getResourceUrl(id?: number, action?: string): string { let url = `${this.baseUrl}${this.resourceName}/` @@ -30,7 +29,13 @@ export abstract class AbstractPaperlessService { } } - list(page?: number, pageSize?: number, sortField?: string, sortReverse?: boolean, extraParams?): Observable> { + list( + page?: number, + pageSize?: number, + sortField?: string, + sortReverse?: boolean, + extraParams? + ): Observable> { let httpParams = new HttpParams() if (page) { httpParams = httpParams.set('page', page.toString()) @@ -47,30 +52,39 @@ export abstract class AbstractPaperlessService { httpParams = httpParams.set(extraParamKey, extraParams[extraParamKey]) } } - return this.http.get>(this.getResourceUrl(), {params: httpParams}) + return this.http.get>(this.getResourceUrl(), { + params: httpParams, + }) } private _listAll: Observable> - listAll(sortField?: string, sortReverse?: boolean, extraParams?): Observable> { + listAll( + sortField?: string, + sortReverse?: boolean, + extraParams? + ): Observable> { if (!this._listAll) { - this._listAll = this.list(1, 100000, sortField, sortReverse, extraParams).pipe( - publishReplay(1), - refCount() - ) + this._listAll = this.list( + 1, + 100000, + sortField, + sortReverse, + extraParams + ).pipe(publishReplay(1), refCount()) } return this._listAll } getCached(id: number): Observable { return this.listAll().pipe( - map(list => list.results.find(o => o.id == id)) + map((list) => list.results.find((o) => o.id == id)) ) } getCachedMany(ids: number[]): Observable { return this.listAll().pipe( - map(list => ids.map(id => list.results.find(o => o.id == id))) + map((list) => ids.map((id) => list.results.find((o) => o.id == id))) ) } @@ -101,5 +115,4 @@ export abstract class AbstractPaperlessService { this.clearCache() return this.http.patch(this.getResourceUrl(o.id), o) } - } diff --git a/src-ui/src/app/services/rest/correspondent.service.spec.ts b/src-ui/src/app/services/rest/correspondent.service.spec.ts index a3377fded..56ad7cc2d 100644 --- a/src-ui/src/app/services/rest/correspondent.service.spec.ts +++ b/src-ui/src/app/services/rest/correspondent.service.spec.ts @@ -1,16 +1,16 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing' -import { CorrespondentService } from './correspondent.service'; +import { CorrespondentService } from './correspondent.service' describe('CorrespondentService', () => { - let service: CorrespondentService; + let service: CorrespondentService beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(CorrespondentService); - }); + TestBed.configureTestingModule({}) + service = TestBed.inject(CorrespondentService) + }) it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); + expect(service).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/services/rest/correspondent.service.ts b/src-ui/src/app/services/rest/correspondent.service.ts index 7eac24971..c56dcce5a 100644 --- a/src-ui/src/app/services/rest/correspondent.service.ts +++ b/src-ui/src/app/services/rest/correspondent.service.ts @@ -1,15 +1,13 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'; -import { AbstractNameFilterService } from './abstract-name-filter-service'; +import { HttpClient } from '@angular/common/http' +import { Injectable } from '@angular/core' +import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent' +import { AbstractNameFilterService } from './abstract-name-filter-service' @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class CorrespondentService extends AbstractNameFilterService { - constructor(http: HttpClient) { super(http, 'correspondents') } - } diff --git a/src-ui/src/app/services/rest/document-type.service.spec.ts b/src-ui/src/app/services/rest/document-type.service.spec.ts index adcca11ef..58ff37ce0 100644 --- a/src-ui/src/app/services/rest/document-type.service.spec.ts +++ b/src-ui/src/app/services/rest/document-type.service.spec.ts @@ -1,16 +1,16 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing' -import { DocumentTypeService } from './document-type.service'; +import { DocumentTypeService } from './document-type.service' describe('DocumentTypeService', () => { - let service: DocumentTypeService; + let service: DocumentTypeService beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(DocumentTypeService); - }); + TestBed.configureTestingModule({}) + service = TestBed.inject(DocumentTypeService) + }) it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); + expect(service).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/services/rest/document-type.service.ts b/src-ui/src/app/services/rest/document-type.service.ts index 4f5b7d0ce..e2d96cb3a 100644 --- a/src-ui/src/app/services/rest/document-type.service.ts +++ b/src-ui/src/app/services/rest/document-type.service.ts @@ -1,13 +1,12 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'; -import { AbstractNameFilterService } from './abstract-name-filter-service'; +import { HttpClient } from '@angular/common/http' +import { Injectable } from '@angular/core' +import { PaperlessDocumentType } from 'src/app/data/paperless-document-type' +import { AbstractNameFilterService } from './abstract-name-filter-service' @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class DocumentTypeService extends AbstractNameFilterService { - constructor(http: HttpClient) { super(http, 'document_types') } diff --git a/src-ui/src/app/services/rest/document.service.spec.ts b/src-ui/src/app/services/rest/document.service.spec.ts index 49475199d..933a0f92c 100644 --- a/src-ui/src/app/services/rest/document.service.spec.ts +++ b/src-ui/src/app/services/rest/document.service.spec.ts @@ -1,16 +1,16 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing' -import { DocumentService } from './document.service'; +import { DocumentService } from './document.service' describe('DocumentService', () => { - let service: DocumentService; + let service: DocumentService beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(DocumentService); - }); + TestBed.configureTestingModule({}) + service = TestBed.inject(DocumentService) + }) it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); + expect(service).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/services/rest/document.service.ts b/src-ui/src/app/services/rest/document.service.ts index c6bc61dc8..e22e17ea8 100644 --- a/src-ui/src/app/services/rest/document.service.ts +++ b/src-ui/src/app/services/rest/document.service.ts @@ -1,31 +1,34 @@ -import { Injectable } from '@angular/core'; -import { PaperlessDocument } from 'src/app/data/paperless-document'; -import { PaperlessDocumentMetadata } from 'src/app/data/paperless-document-metadata'; -import { AbstractPaperlessService } from './abstract-paperless-service'; -import { HttpClient, HttpParams } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { Results } from 'src/app/data/results'; -import { FilterRule } from 'src/app/data/filter-rule'; -import { map } from 'rxjs/operators'; -import { CorrespondentService } from './correspondent.service'; -import { DocumentTypeService } from './document-type.service'; -import { TagService } from './tag.service'; -import { FILTER_RULE_TYPES } from 'src/app/data/filter-rule-type'; -import { PaperlessDocumentSuggestions } from 'src/app/data/paperless-document-suggestions'; +import { Injectable } from '@angular/core' +import { PaperlessDocument } from 'src/app/data/paperless-document' +import { PaperlessDocumentMetadata } from 'src/app/data/paperless-document-metadata' +import { AbstractPaperlessService } from './abstract-paperless-service' +import { HttpClient, HttpParams } from '@angular/common/http' +import { Observable } from 'rxjs' +import { Results } from 'src/app/data/results' +import { FilterRule } from 'src/app/data/filter-rule' +import { map } from 'rxjs/operators' +import { CorrespondentService } from './correspondent.service' +import { DocumentTypeService } from './document-type.service' +import { TagService } from './tag.service' +import { FILTER_RULE_TYPES } from 'src/app/data/filter-rule-type' +import { PaperlessDocumentSuggestions } from 'src/app/data/paperless-document-suggestions' export const DOCUMENT_SORT_FIELDS = [ { field: 'archive_serial_number', name: $localize`ASN` }, - { field: "correspondent__name", name: $localize`Correspondent` }, + { field: 'correspondent__name', name: $localize`Correspondent` }, { field: 'title', name: $localize`Title` }, - { field: "document_type__name", name: $localize`Document type` }, + { field: 'document_type__name', name: $localize`Document type` }, { field: 'created', name: $localize`Created` }, { field: 'added', name: $localize`Added` }, - { field: 'modified', name: $localize`Modified` } + { field: 'modified', name: $localize`Modified` }, ] export const DOCUMENT_SORT_FIELDS_FULLTEXT = [ ...DOCUMENT_SORT_FIELDS, - { field: 'score', name: $localize`:Score is a value returned by the full text search engine and specifies how well a result matches the given query:Search score` } + { + field: 'score', + name: $localize`:Score is a value returned by the full text search engine and specifies how well a result matches the given query:Search score`, + }, ] export interface SelectionDataItem { @@ -40,13 +43,17 @@ export interface SelectionData { } @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class DocumentService extends AbstractPaperlessService { - private _searchQuery: string - constructor(http: HttpClient, private correspondentService: CorrespondentService, private documentTypeService: DocumentTypeService, private tagService: TagService) { + constructor( + http: HttpClient, + private correspondentService: CorrespondentService, + private documentTypeService: DocumentTypeService, + private tagService: TagService + ) { super(http, 'documents') } @@ -54,9 +61,11 @@ export class DocumentService extends AbstractPaperlessService if (filterRules) { let params = {} for (let rule of filterRules) { - let ruleType = FILTER_RULE_TYPES.find(t => t.id == rule.rule_type) + let ruleType = FILTER_RULE_TYPES.find((t) => t.id == rule.rule_type) if (ruleType.multi) { - params[ruleType.filtervar] = params[ruleType.filtervar] ? params[ruleType.filtervar] + "," + rule.value : rule.value + params[ruleType.filtervar] = params[ruleType.filtervar] + ? params[ruleType.filtervar] + ',' + rule.value + : rule.value } else if (ruleType.isnull_filtervar && rule.value == null) { params[ruleType.isnull_filtervar] = true } else { @@ -71,7 +80,9 @@ export class DocumentService extends AbstractPaperlessService addObservablesToDocument(doc: PaperlessDocument) { if (doc.correspondent) { - doc.correspondent$ = this.correspondentService.getCached(doc.correspondent) + doc.correspondent$ = this.correspondentService.getCached( + doc.correspondent + ) } if (doc.document_type) { doc.document_type$ = this.documentTypeService.getCached(doc.document_type) @@ -82,26 +93,39 @@ export class DocumentService extends AbstractPaperlessService return doc } - listFiltered(page?: number, pageSize?: number, sortField?: string, sortReverse?: boolean, filterRules?: FilterRule[], extraParams = {}): Observable> { - return this.list(page, pageSize, sortField, sortReverse, Object.assign(extraParams, this.filterRulesToQueryParams(filterRules))).pipe( - map(results => { - results.results.forEach(doc => this.addObservablesToDocument(doc)) + listFiltered( + page?: number, + pageSize?: number, + sortField?: string, + sortReverse?: boolean, + filterRules?: FilterRule[], + extraParams = {} + ): Observable> { + return this.list( + page, + pageSize, + sortField, + sortReverse, + Object.assign(extraParams, this.filterRulesToQueryParams(filterRules)) + ).pipe( + map((results) => { + results.results.forEach((doc) => this.addObservablesToDocument(doc)) return results }) ) } listAllFilteredIds(filterRules?: FilterRule[]): Observable { - return this.listFiltered(1, 100000, null, null, filterRules, {"fields": "id"}).pipe( - map(response => response.results.map(doc => doc.id)) - ) + return this.listFiltered(1, 100000, null, null, filterRules, { + fields: 'id', + }).pipe(map((response) => response.results.map((doc) => doc.id))) } getPreviewUrl(id: number, original: boolean = false): string { let url = this.getResourceUrl(id, 'preview') if (this._searchQuery) url += `#search="${this._searchQuery}"` if (original) { - url += "?original=true" + url += '?original=true' } return url } @@ -113,41 +137,55 @@ export class DocumentService extends AbstractPaperlessService getDownloadUrl(id: number, original: boolean = false): string { let url = this.getResourceUrl(id, 'download') if (original) { - url += "?original=true" + url += '?original=true' } return url } uploadDocument(formData) { - return this.http.post(this.getResourceUrl(null, 'post_document'), formData, {reportProgress: true, observe: "events"}) + return this.http.post( + this.getResourceUrl(null, 'post_document'), + formData, + { reportProgress: true, observe: 'events' } + ) } getMetadata(id: number): Observable { - return this.http.get(this.getResourceUrl(id, 'metadata')) + return this.http.get( + this.getResourceUrl(id, 'metadata') + ) } bulkEdit(ids: number[], method: string, args: any) { return this.http.post(this.getResourceUrl(null, 'bulk_edit'), { - 'documents': ids, - 'method': method, - 'parameters': args + documents: ids, + method: method, + parameters: args, }) } getSelectionData(ids: number[]): Observable { - return this.http.post(this.getResourceUrl(null, 'selection_data'), {"documents": ids}) + return this.http.post( + this.getResourceUrl(null, 'selection_data'), + { documents: ids } + ) } getSuggestions(id: number): Observable { - return this.http.get(this.getResourceUrl(id, 'suggestions')) + return this.http.get( + this.getResourceUrl(id, 'suggestions') + ) } - bulkDownload(ids: number[], content="both") { - return this.http.post(this.getResourceUrl(null, 'bulk_download'), {"documents": ids, "content": content}, { responseType: 'blob' }) + bulkDownload(ids: number[], content = 'both') { + return this.http.post( + this.getResourceUrl(null, 'bulk_download'), + { documents: ids, content: content }, + { responseType: 'blob' } + ) } public set searchQuery(query: string) { this._searchQuery = query } - } diff --git a/src-ui/src/app/services/rest/log.service.spec.ts b/src-ui/src/app/services/rest/log.service.spec.ts index 4a99f7727..625a8fffe 100644 --- a/src-ui/src/app/services/rest/log.service.spec.ts +++ b/src-ui/src/app/services/rest/log.service.spec.ts @@ -1,16 +1,16 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing' -import { LogService } from './log.service'; +import { LogService } from './log.service' describe('LogService', () => { - let service: LogService; + let service: LogService beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(LogService); - }); + TestBed.configureTestingModule({}) + service = TestBed.inject(LogService) + }) it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); + expect(service).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/services/rest/log.service.ts b/src-ui/src/app/services/rest/log.service.ts index 3abf2fb6f..d1a797eeb 100644 --- a/src-ui/src/app/services/rest/log.service.ts +++ b/src-ui/src/app/services/rest/log.service.ts @@ -1,15 +1,13 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { environment } from 'src/environments/environment'; +import { HttpClient } from '@angular/common/http' +import { Injectable } from '@angular/core' +import { Observable } from 'rxjs' +import { environment } from 'src/environments/environment' @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class LogService { - - constructor(private http: HttpClient) { - } + constructor(private http: HttpClient) {} list(): Observable { return this.http.get(`${environment.apiBaseUrl}logs/`) diff --git a/src-ui/src/app/services/rest/saved-view.service.spec.ts b/src-ui/src/app/services/rest/saved-view.service.spec.ts index 588cf6347..59b979a63 100644 --- a/src-ui/src/app/services/rest/saved-view.service.spec.ts +++ b/src-ui/src/app/services/rest/saved-view.service.spec.ts @@ -1,16 +1,16 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing' -import { SavedViewService } from './saved-view.service'; +import { SavedViewService } from './saved-view.service' describe('SavedViewService', () => { - let service: SavedViewService; + let service: SavedViewService beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(SavedViewService); - }); + TestBed.configureTestingModule({}) + service = TestBed.inject(SavedViewService) + }) it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); + expect(service).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/services/rest/saved-view.service.ts b/src-ui/src/app/services/rest/saved-view.service.ts index c765de7f4..dae205cb3 100644 --- a/src-ui/src/app/services/rest/saved-view.service.ts +++ b/src-ui/src/app/services/rest/saved-view.service.ts @@ -1,22 +1,21 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { combineLatest, Observable } from 'rxjs'; -import { tap } from 'rxjs/operators'; -import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'; -import { AbstractPaperlessService } from './abstract-paperless-service'; +import { HttpClient } from '@angular/common/http' +import { Injectable } from '@angular/core' +import { combineLatest, Observable } from 'rxjs' +import { tap } from 'rxjs/operators' +import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' +import { AbstractPaperlessService } from './abstract-paperless-service' @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class SavedViewService extends AbstractPaperlessService { - constructor(http: HttpClient) { super(http, 'saved_views') this.reload() } private reload() { - this.listAll().subscribe(r => this.savedViews = r.results) + this.listAll().subscribe((r) => (this.savedViews = r.results)) } private savedViews: PaperlessSavedView[] = [] @@ -26,34 +25,28 @@ export class SavedViewService extends AbstractPaperlessService v.show_in_sidebar) + return this.savedViews.filter((v) => v.show_in_sidebar) } get dashboardViews() { - return this.savedViews.filter(v => v.show_on_dashboard) + return this.savedViews.filter((v) => v.show_on_dashboard) } create(o: PaperlessSavedView) { - return super.create(o).pipe( - tap(() => this.reload()) - ) + return super.create(o).pipe(tap(() => this.reload())) } update(o: PaperlessSavedView) { - return super.update(o).pipe( - tap(() => this.reload()) - ) + return super.update(o).pipe(tap(() => this.reload())) } patchMany(objects: PaperlessSavedView[]): Observable { - return combineLatest(objects.map(o => super.patch(o))).pipe( + return combineLatest(objects.map((o) => super.patch(o))).pipe( tap(() => this.reload()) ) } delete(o: PaperlessSavedView) { - return super.delete(o).pipe( - tap(() => this.reload()) - ) + return super.delete(o).pipe(tap(() => this.reload())) } } diff --git a/src-ui/src/app/services/rest/search.service.spec.ts b/src-ui/src/app/services/rest/search.service.spec.ts index 23c42c7bb..3bb880213 100644 --- a/src-ui/src/app/services/rest/search.service.spec.ts +++ b/src-ui/src/app/services/rest/search.service.spec.ts @@ -1,16 +1,16 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing' -import { SearchService } from './search.service'; +import { SearchService } from './search.service' describe('SearchService', () => { - let service: SearchService; + let service: SearchService beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(SearchService); - }); + TestBed.configureTestingModule({}) + service = TestBed.inject(SearchService) + }) it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); + expect(service).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/services/rest/search.service.ts b/src-ui/src/app/services/rest/search.service.ts index c14a5c58f..4a75230d9 100644 --- a/src-ui/src/app/services/rest/search.service.ts +++ b/src-ui/src/app/services/rest/search.service.ts @@ -1,19 +1,20 @@ -import { HttpClient, HttpParams } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; -import { environment } from 'src/environments/environment'; -import { DocumentService } from './document.service'; - +import { HttpClient, HttpParams } from '@angular/common/http' +import { Injectable } from '@angular/core' +import { Observable } from 'rxjs' +import { map } from 'rxjs/operators' +import { environment } from 'src/environments/environment' +import { DocumentService } from './document.service' @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class SearchService { - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient) {} autocomplete(term: string): Observable { - return this.http.get(`${environment.apiBaseUrl}search/autocomplete/`, {params: new HttpParams().set('term', term)}) + return this.http.get( + `${environment.apiBaseUrl}search/autocomplete/`, + { params: new HttpParams().set('term', term) } + ) } } diff --git a/src-ui/src/app/services/rest/tag.service.spec.ts b/src-ui/src/app/services/rest/tag.service.spec.ts index f091e933f..279d44acb 100644 --- a/src-ui/src/app/services/rest/tag.service.spec.ts +++ b/src-ui/src/app/services/rest/tag.service.spec.ts @@ -1,16 +1,16 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing' -import { TagService } from './tag.service'; +import { TagService } from './tag.service' describe('TagService', () => { - let service: TagService; + let service: TagService beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(TagService); - }); + TestBed.configureTestingModule({}) + service = TestBed.inject(TagService) + }) it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); + expect(service).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/services/rest/tag.service.ts b/src-ui/src/app/services/rest/tag.service.ts index 7bc55b0c9..f15369c62 100644 --- a/src-ui/src/app/services/rest/tag.service.ts +++ b/src-ui/src/app/services/rest/tag.service.ts @@ -1,13 +1,12 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { PaperlessTag } from 'src/app/data/paperless-tag'; -import { AbstractNameFilterService } from './abstract-name-filter-service'; +import { HttpClient } from '@angular/common/http' +import { Injectable } from '@angular/core' +import { PaperlessTag } from 'src/app/data/paperless-tag' +import { AbstractNameFilterService } from './abstract-name-filter-service' @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class TagService extends AbstractNameFilterService { - constructor(http: HttpClient) { super(http, 'tags') } diff --git a/src-ui/src/app/services/settings.service.spec.ts b/src-ui/src/app/services/settings.service.spec.ts index 359cb6b7a..cd22f5571 100644 --- a/src-ui/src/app/services/settings.service.spec.ts +++ b/src-ui/src/app/services/settings.service.spec.ts @@ -1,16 +1,16 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing' -import { SettingsService } from './settings.service'; +import { SettingsService } from './settings.service' describe('SettingsService', () => { - let service: SettingsService; + let service: SettingsService beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(SettingsService); - }); + TestBed.configureTestingModule({}) + service = TestBed.inject(SettingsService) + }) it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); + expect(service).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/services/settings.service.ts b/src-ui/src/app/services/settings.service.ts index b3a745b69..d78340a6c 100644 --- a/src-ui/src/app/services/settings.service.ts +++ b/src-ui/src/app/services/settings.service.ts @@ -1,8 +1,15 @@ -import { DOCUMENT } from '@angular/common'; -import { Inject, Injectable, LOCALE_ID, Renderer2, RendererFactory2, RendererStyleFlags2 } from '@angular/core'; -import { Meta } from '@angular/platform-browser'; -import { CookieService } from 'ngx-cookie-service'; -import { hexToHsl } from 'src/app/utils/color'; +import { DOCUMENT } from '@angular/common' +import { + Inject, + Injectable, + LOCALE_ID, + Renderer2, + RendererFactory2, + RendererStyleFlags2, +} from '@angular/core' +import { Meta } from '@angular/platform-browser' +import { CookieService } from 'ngx-cookie-service' +import { hexToHsl } from 'src/app/utils/color' export interface PaperlessSettings { key: string @@ -22,7 +29,8 @@ export interface LanguageOption { } export const SETTINGS_KEYS = { - BULK_EDIT_CONFIRMATION_DIALOGS: 'general-settings:bulk-edit:confirmation-dialogs', + BULK_EDIT_CONFIRMATION_DIALOGS: + 'general-settings:bulk-edit:confirmation-dialogs', BULK_EDIT_APPLY_ON_CLOSE: 'general-settings:bulk-edit:apply-on-close', DOCUMENT_LIST_SIZE: 'general-settings:documentListSize', DARK_MODE_USE_SYSTEM: 'general-settings:dark-mode:use-system', @@ -32,35 +40,66 @@ export const SETTINGS_KEYS = { USE_NATIVE_PDF_VIEWER: 'general-settings:document-details:native-pdf-viewer', DATE_LOCALE: 'general-settings:date-display:date-locale', DATE_FORMAT: 'general-settings:date-display:date-format', - NOTIFICATIONS_CONSUMER_NEW_DOCUMENT: 'general-settings:notifications:consumer-new-documents', - NOTIFICATIONS_CONSUMER_SUCCESS: 'general-settings:notifications:consumer-success', - NOTIFICATIONS_CONSUMER_FAILED: 'general-settings:notifications:consumer-failed', - NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD: 'general-settings:notifications:consumer-suppress-on-dashboard', + NOTIFICATIONS_CONSUMER_NEW_DOCUMENT: + 'general-settings:notifications:consumer-new-documents', + NOTIFICATIONS_CONSUMER_SUCCESS: + 'general-settings:notifications:consumer-success', + NOTIFICATIONS_CONSUMER_FAILED: + 'general-settings:notifications:consumer-failed', + NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD: + 'general-settings:notifications:consumer-suppress-on-dashboard', } const SETTINGS: PaperlessSettings[] = [ - {key: SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS, type: "boolean", default: true}, - {key: SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE, type: "boolean", default: false}, - {key: SETTINGS_KEYS.DOCUMENT_LIST_SIZE, type: "number", default: 50}, - {key: SETTINGS_KEYS.DARK_MODE_USE_SYSTEM, type: "boolean", default: true}, - {key: SETTINGS_KEYS.DARK_MODE_ENABLED, type: "boolean", default: false}, - {key: SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED, type: "boolean", default: true}, - {key: SETTINGS_KEYS.THEME_COLOR, type: "string", default: ""}, - {key: SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER, type: "boolean", default: false}, - {key: SETTINGS_KEYS.DATE_LOCALE, type: "string", default: ""}, - {key: SETTINGS_KEYS.DATE_FORMAT, type: "string", default: "mediumDate"}, - {key: SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT, type: "boolean", default: true}, - {key: SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS, type: "boolean", default: true}, - {key: SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED, type: "boolean", default: true}, - {key: SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD, type: "boolean", default: true}, + { + key: SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS, + type: 'boolean', + default: true, + }, + { + key: SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE, + type: 'boolean', + default: false, + }, + { key: SETTINGS_KEYS.DOCUMENT_LIST_SIZE, type: 'number', default: 50 }, + { key: SETTINGS_KEYS.DARK_MODE_USE_SYSTEM, type: 'boolean', default: true }, + { key: SETTINGS_KEYS.DARK_MODE_ENABLED, type: 'boolean', default: false }, + { + key: SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED, + type: 'boolean', + default: true, + }, + { key: SETTINGS_KEYS.THEME_COLOR, type: 'string', default: '' }, + { key: SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER, type: 'boolean', default: false }, + { key: SETTINGS_KEYS.DATE_LOCALE, type: 'string', default: '' }, + { key: SETTINGS_KEYS.DATE_FORMAT, type: 'string', default: 'mediumDate' }, + { + key: SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT, + type: 'boolean', + default: true, + }, + { + key: SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS, + type: 'boolean', + default: true, + }, + { + key: SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED, + type: 'boolean', + default: true, + }, + { + key: SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD, + type: 'boolean', + default: true, + }, ] @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class SettingsService { - - private renderer: Renderer2; + private renderer: Renderer2 constructor( private rendererFactory: RendererFactory2, @@ -69,67 +108,177 @@ export class SettingsService { private meta: Meta, @Inject(LOCALE_ID) private localeId: string ) { - this.renderer = rendererFactory.createRenderer(null, null); + this.renderer = rendererFactory.createRenderer(null, null) this.updateAppearanceSettings() } - public updateAppearanceSettings(darkModeUseSystem = null, darkModeEnabled = null, themeColor = null): void { + public updateAppearanceSettings( + darkModeUseSystem = null, + darkModeEnabled = null, + themeColor = null + ): void { darkModeUseSystem ??= this.get(SETTINGS_KEYS.DARK_MODE_USE_SYSTEM) darkModeEnabled ??= this.get(SETTINGS_KEYS.DARK_MODE_ENABLED) - themeColor ??= this.get(SETTINGS_KEYS.THEME_COLOR); + themeColor ??= this.get(SETTINGS_KEYS.THEME_COLOR) if (darkModeUseSystem) { this.renderer.addClass(this.document.body, 'color-scheme-system') this.renderer.removeClass(this.document.body, 'color-scheme-dark') } else { this.renderer.removeClass(this.document.body, 'color-scheme-system') - darkModeEnabled ? this.renderer.addClass(this.document.body, 'color-scheme-dark') : this.renderer.removeClass(this.document.body, 'color-scheme-dark') + darkModeEnabled + ? this.renderer.addClass(this.document.body, 'color-scheme-dark') + : this.renderer.removeClass(this.document.body, 'color-scheme-dark') } if (themeColor) { const hsl = hexToHsl(themeColor) - this.renderer.setStyle(document.documentElement, '--pngx-primary',`${+hsl.h * 360},${hsl.s * 100}%`, RendererStyleFlags2.DashCase) - this.renderer.setStyle(document.documentElement, '--pngx-primary-lightness',`${hsl.l * 100}%`, RendererStyleFlags2.DashCase) + this.renderer.setStyle( + document.documentElement, + '--pngx-primary', + `${+hsl.h * 360},${hsl.s * 100}%`, + RendererStyleFlags2.DashCase + ) + this.renderer.setStyle( + document.documentElement, + '--pngx-primary-lightness', + `${hsl.l * 100}%`, + RendererStyleFlags2.DashCase + ) } else { - this.renderer.removeStyle(document.documentElement, '--pngx-primary', RendererStyleFlags2.DashCase) - this.renderer.removeStyle(document.documentElement, '--pngx-primary-lightness', RendererStyleFlags2.DashCase) + this.renderer.removeStyle( + document.documentElement, + '--pngx-primary', + RendererStyleFlags2.DashCase + ) + this.renderer.removeStyle( + document.documentElement, + '--pngx-primary-lightness', + RendererStyleFlags2.DashCase + ) } } getLanguageOptions(): LanguageOption[] { const languages = [ - {code: "en-us", name: $localize`English (US)`, englishName: "English (US)", dateInputFormat: "mm/dd/yyyy"}, - {code: "cs-cz", name: $localize`Czech`, englishName: "Czech", dateInputFormat: "dd.mm.yyyy"}, - {code: "da-dk", name: $localize`Danish`, englishName: "Danish", dateInputFormat: "dd.mm.yyyy"}, - {code: "de-de", name: $localize`German`, englishName: "German", dateInputFormat: "dd.mm.yyyy"}, - {code: "en-gb", name: $localize`English (GB)`, englishName: "English (GB)", dateInputFormat: "dd/mm/yyyy"}, - {code: "es-es", name: $localize`Spanish`, englishName: "Spanish", dateInputFormat: "dd/mm/yyyy"}, - {code: "fr-fr", name: $localize`French`, englishName: "French", dateInputFormat: "dd/mm/yyyy"}, - {code: "it-it", name: $localize`Italian`, englishName: "Italian", dateInputFormat: "dd/mm/yyyy"}, - {code: "lb-lu", name: $localize`Luxembourgish`, englishName: "Luxembourgish", dateInputFormat: "dd.mm.yyyy"}, - {code: "nl-nl", name: $localize`Dutch`, englishName: "Dutch", dateInputFormat: "dd-mm-yyyy"}, - {code: "pl-pl", name: $localize`Polish`, englishName: "Polish", dateInputFormat: "dd.mm.yyyy"}, - {code: "pt-br", name: $localize`Portuguese (Brazil)`, englishName: "Portuguese (Brazil)", dateInputFormat: "dd/mm/yyyy"}, - {code: "pt-pt", name: $localize`Portuguese`, englishName: "Portuguese", dateInputFormat: "dd/mm/yyyy"}, - {code: "ro-ro", name: $localize`Romanian`, englishName: "Romanian", dateInputFormat: "dd.mm.yyyy"}, - {code: "ru-ru", name: $localize`Russian`, englishName: "Russian", dateInputFormat: "dd.mm.yyyy"}, - {code: "sv-se", name: $localize`Swedish`, englishName: "Swedish", dateInputFormat: "yyyy-mm-dd"} + { + code: 'en-us', + name: $localize`English (US)`, + englishName: 'English (US)', + dateInputFormat: 'mm/dd/yyyy', + }, + { + code: 'cs-cz', + name: $localize`Czech`, + englishName: 'Czech', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'da-dk', + name: $localize`Danish`, + englishName: 'Danish', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'de-de', + name: $localize`German`, + englishName: 'German', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'en-gb', + name: $localize`English (GB)`, + englishName: 'English (GB)', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'es-es', + name: $localize`Spanish`, + englishName: 'Spanish', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'fr-fr', + name: $localize`French`, + englishName: 'French', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'it-it', + name: $localize`Italian`, + englishName: 'Italian', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'lb-lu', + name: $localize`Luxembourgish`, + englishName: 'Luxembourgish', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'nl-nl', + name: $localize`Dutch`, + englishName: 'Dutch', + dateInputFormat: 'dd-mm-yyyy', + }, + { + code: 'pl-pl', + name: $localize`Polish`, + englishName: 'Polish', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'pt-br', + name: $localize`Portuguese (Brazil)`, + englishName: 'Portuguese (Brazil)', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'pt-pt', + name: $localize`Portuguese`, + englishName: 'Portuguese', + dateInputFormat: 'dd/mm/yyyy', + }, + { + code: 'ro-ro', + name: $localize`Romanian`, + englishName: 'Romanian', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'ru-ru', + name: $localize`Russian`, + englishName: 'Russian', + dateInputFormat: 'dd.mm.yyyy', + }, + { + code: 'sv-se', + name: $localize`Swedish`, + englishName: 'Swedish', + dateInputFormat: 'yyyy-mm-dd', + }, ] // Sort languages by localized name at runtime - languages.sort((a, b) => { return a.name < b.name ? -1 : 1 }) + languages.sort((a, b) => { + return a.name < b.name ? -1 : 1 + }) return languages } getDateLocaleOptions(): LanguageOption[] { - let isoOption: LanguageOption = {code: "iso-8601", name: $localize`ISO 8601`, dateInputFormat: "yyyy-mm-dd"} + let isoOption: LanguageOption = { + code: 'iso-8601', + name: $localize`ISO 8601`, + dateInputFormat: 'yyyy-mm-dd', + } return [isoOption].concat(this.getLanguageOptions()) } private getLanguageCookieName() { - let prefix = "" + let prefix = '' if (this.meta.getTag('name=cookie_prefix')) { prefix = this.meta.getTag('name=cookie_prefix').content } @@ -149,12 +298,18 @@ export class SettingsService { } getLocalizedDateInputFormat(): string { - let dateLocale = this.get(SETTINGS_KEYS.DATE_LOCALE) || this.getLanguage() || this.localeId.toLowerCase() - return this.getDateLocaleOptions().find(o => o.code == dateLocale)?.dateInputFormat || "yyyy-mm-dd" + let dateLocale = + this.get(SETTINGS_KEYS.DATE_LOCALE) || + this.getLanguage() || + this.localeId.toLowerCase() + return ( + this.getDateLocaleOptions().find((o) => o.code == dateLocale) + ?.dateInputFormat || 'yyyy-mm-dd' + ) } get(key: string): any { - let setting = SETTINGS.find(s => s.key == key) + let setting = SETTINGS.find((s) => s.key == key) if (!setting) { return null @@ -164,11 +319,11 @@ export class SettingsService { if (value != null) { switch (setting.type) { - case "boolean": + case 'boolean': return JSON.parse(value) - case "number": + case 'number': return +value - case "string": + case 'string': return value default: return value diff --git a/src-ui/src/app/services/toast.service.spec.ts b/src-ui/src/app/services/toast.service.spec.ts index e0413db84..c6c382013 100644 --- a/src-ui/src/app/services/toast.service.spec.ts +++ b/src-ui/src/app/services/toast.service.spec.ts @@ -1,16 +1,16 @@ -import { TestBed } from '@angular/core/testing'; +import { TestBed } from '@angular/core/testing' -import { ToastService } from './toast.service'; +import { ToastService } from './toast.service' describe('ToastService', () => { - let service: ToastService; + let service: ToastService beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(ToastService); - }); + TestBed.configureTestingModule({}) + service = TestBed.inject(ToastService) + }) it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); + expect(service).toBeTruthy() + }) +}) diff --git a/src-ui/src/app/services/toast.service.ts b/src-ui/src/app/services/toast.service.ts index fc522e2df..7c35b624c 100644 --- a/src-ui/src/app/services/toast.service.ts +++ b/src-ui/src/app/services/toast.service.ts @@ -1,8 +1,7 @@ -import { Injectable } from '@angular/core'; -import { Subject, zip } from 'rxjs'; +import { Injectable } from '@angular/core' +import { Subject, zip } from 'rxjs' export interface Toast { - title: string content: string @@ -12,15 +11,13 @@ export interface Toast { action?: any actionName?: string - } @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ToastService { - - constructor() { } + constructor() {} private toasts: Toast[] = [] @@ -32,15 +29,15 @@ export class ToastService { } showError(content: string, delay: number = 10000) { - this.show({title: $localize`Error`, content: content, delay: delay}) + this.show({ title: $localize`Error`, content: content, delay: delay }) } showInfo(content: string, delay: number = 5000) { - this.show({title: $localize`Information`, content: content, delay: delay}) + this.show({ title: $localize`Information`, content: content, delay: delay }) } closeToast(toast: Toast) { - let index = this.toasts.findIndex(t => t == toast) + let index = this.toasts.findIndex((t) => t == toast) if (index > -1) { this.toasts.splice(index, 1) this.toastsSubject.next(this.toasts) @@ -50,5 +47,4 @@ export class ToastService { getToasts() { return this.toastsSubject } - } diff --git a/src-ui/src/app/utils/color.ts b/src-ui/src/app/utils/color.ts index 068851209..79d237f27 100644 --- a/src-ui/src/app/utils/color.ts +++ b/src-ui/src/app/utils/color.ts @@ -1,8 +1,8 @@ -import { HSL } from "ngx-color" +import { HSL } from 'ngx-color' function componentToHex(c) { var hex = Math.floor(c).toString(16) - return hex.length == 1 ? "0" + hex : hex + return hex.length == 1 ? '0' + hex : hex } /** @@ -18,26 +18,26 @@ function componentToHex(c) { * @param Number l The lightness * @return Array The RGB representation */ -function hslToRgb(h, s, l){ +function hslToRgb(h, s, l) { var r, g, b - if(s == 0){ - r = g = b = l // achromatic - }else{ - function hue2rgb(p, q, t){ - if(t < 0) t += 1 - if(t > 1) t -= 1 - if(t < 1/6) return p + (q - p) * 6 * t - if(t < 1/2) return q - if(t < 2/3) return p + (q - p) * (2/3 - t) * 6 - return p - } + if (s == 0) { + r = g = b = l // achromatic + } else { + function hue2rgb(p, q, t) { + if (t < 0) t += 1 + if (t > 1) t -= 1 + if (t < 1 / 6) return p + (q - p) * 6 * t + if (t < 1 / 2) return q + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6 + return p + } - var q = l < 0.5 ? l * (1 + s) : l + s - l * s - var p = 2 * l - q - r = hue2rgb(p, q, h + 1/3) - g = hue2rgb(p, q, h) - b = hue2rgb(p, q, h - 1/3) + var q = l < 0.5 ? l * (1 + s) : l + s - l * s + var p = 2 * l - q + r = hue2rgb(p, q, h + 1 / 3) + g = hue2rgb(p, q, h) + b = hue2rgb(p, q, h - 1 / 3) } return [r * 255, g * 255, b * 255] @@ -55,35 +55,50 @@ function hslToRgb(h, s, l){ * @param Number b The blue color value * @return Array The HSL representation */ - export function rgbToHsl(r, g, b){ - r /= 255, g /= 255, b /= 255; - var max = Math.max(r, g, b), min = Math.min(r, g, b); - var h, s, l = (max + min) / 2; +export function rgbToHsl(r, g, b) { + ;(r /= 255), (g /= 255), (b /= 255) + var max = Math.max(r, g, b), + min = Math.min(r, g, b) + var h, + s, + l = (max + min) / 2 - if(max == min){ - h = s = 0; // achromatic - }else{ - var d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch(max){ - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - h /= 6; + if (max == min) { + h = s = 0 // achromatic + } else { + var d = max - min + s = l > 0.5 ? d / (2 - max - min) : d / (max + min) + switch (max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0) + break + case g: + h = (b - r) / d + 2 + break + case b: + h = (r - g) / d + 4 + break + } + h /= 6 } - return [h, s, l]; + return [h, s, l] } export function hexToHsl(hex: string): HSL { hex = hex.replace('#', '') let aRgbHex = hex.match(/.{1,2}/g) - const hsl = rgbToHsl(parseInt(aRgbHex[0], 16), parseInt(aRgbHex[1], 16), parseInt(aRgbHex[2], 16)) + const hsl = rgbToHsl( + parseInt(aRgbHex[0], 16), + parseInt(aRgbHex[1], 16), + parseInt(aRgbHex[2], 16) + ) return { h: hsl[0], s: hsl[1], l: hsl[2] } } export function randomColor() { let rgb = hslToRgb(Math.random(), 0.6, Math.random() * 0.4 + 0.4) - return `#${componentToHex(rgb[0])}${componentToHex(rgb[1])}${componentToHex(rgb[2])}` + return `#${componentToHex(rgb[0])}${componentToHex(rgb[1])}${componentToHex( + rgb[2] + )}` } diff --git a/src-ui/src/app/utils/ngb-date-parser-formatter.ts b/src-ui/src/app/utils/ngb-date-parser-formatter.ts index e2a79fd0c..ff7706819 100644 --- a/src-ui/src/app/utils/ngb-date-parser-formatter.ts +++ b/src-ui/src/app/utils/ngb-date-parser-formatter.ts @@ -1,6 +1,9 @@ -import { Injectable } from "@angular/core" -import { NgbDateParserFormatter, NgbDateStruct } from "@ng-bootstrap/ng-bootstrap" -import { SettingsService } from "../services/settings.service" +import { Injectable } from '@angular/core' +import { + NgbDateParserFormatter, + NgbDateStruct, +} from '@ng-bootstrap/ng-bootstrap' +import { SettingsService } from '../services/settings.service' @Injectable() export class LocalizedDateParserFormatter extends NgbDateParserFormatter { @@ -20,45 +23,71 @@ export class LocalizedDateParserFormatter extends NgbDateParserFormatter { */ private getDateParseRegex() { return new RegExp( - "^" + this.getDateInputFormat() - .replace('dd', '(?[0-9]+)') - .replace('mm', '(?[0-9]+)') - .replace('yyyy', '(?[0-9]+)') - .split('.').join('\\.\\s*') + "$" // allow whitespace(s) after dot (specific for German) - ) + '^' + + this.getDateInputFormat() + .replace('dd', '(?[0-9]+)') + .replace('mm', '(?[0-9]+)') + .replace('yyyy', '(?[0-9]+)') + .split('.') + .join('\\.\\s*') + + '$' // allow whitespace(s) after dot (specific for German) + ) } /** - * This adds date separators if none are entered. - * It also adds the current year if it wasn't entered. - * - * This allows users to just enter 1003, 100322, 10032022 and + * This adds date separators if none are entered. + * It also adds the current year if it wasn't entered. + * + * This allows users to just enter 1003, 100322, 10032022 and * have it expanded to 10.03.2022, in the case of the German format. * (All other formats are also supported) - * + * * It also strips any separators before running formatting and pads * any parts of the string, e.g. allowing for 1/2/22, - * which allows quick entry of the date on the numpad. + * which allows quick entry of the date on the numpad. */ private preformatDateInput(value: string): string { const inputFormat = this.getDateInputFormat() const dateSeparator = inputFormat.replace(/[dmy]/gi, '').charAt(0) - + if (this.separatorRegExp.test(value)) { // split on separator, pad & re-join without separator - value = value.split(this.separatorRegExp).map(segment => segment.padStart(2,'0')).join('') - } + value = value + .split(this.separatorRegExp) + .map((segment) => segment.padStart(2, '0')) + .join('') + } if (value.length == 4 && inputFormat.substring(0, 4) != 'yyyy') { - return [value.substring(0, 2), value.substring(2, 4), new Date().getFullYear()].join(dateSeparator) + return [ + value.substring(0, 2), + value.substring(2, 4), + new Date().getFullYear(), + ].join(dateSeparator) } else if (value.length == 4 && inputFormat.substring(0, 4) == 'yyyy') { - return [new Date().getFullYear(), value.substring(0, 2), value.substring(2, 4)].join(dateSeparator) + return [ + new Date().getFullYear(), + value.substring(0, 2), + value.substring(2, 4), + ].join(dateSeparator) } else if (value.length == 6) { - return [value.substring(0, 2), value.substring(2, 4), value.substring(4, 6)].join(dateSeparator) + return [ + value.substring(0, 2), + value.substring(2, 4), + value.substring(4, 6), + ].join(dateSeparator) } else if (value.length == 8 && inputFormat.substring(0, 4) != 'yyyy') { - return [value.substring(0, 2), value.substring(2, 4), value.substring(4, 8)].join(dateSeparator) + return [ + value.substring(0, 2), + value.substring(2, 4), + value.substring(4, 8), + ].join(dateSeparator) } else if (value.length == 8 && inputFormat.substring(0, 4) == 'yyyy') { - return [value.substring(0, 4), value.substring(4, 6), value.substring(6, 8)].join(dateSeparator) + return [ + value.substring(0, 4), + value.substring(4, 6), + value.substring(6, 8), + ].join(dateSeparator) } else { return value } @@ -71,9 +100,9 @@ export class LocalizedDateParserFormatter extends NgbDateParserFormatter { let dateStruct = { day: +match.groups.day, month: +match.groups.month, - year: +match.groups.year + year: +match.groups.year, } - if (dateStruct.year <= (new Date().getFullYear() - 2000)) { + if (dateStruct.year <= new Date().getFullYear() - 2000) { dateStruct.year += 2000 } else if (dateStruct.year < 100) { dateStruct.year += 1900 @@ -87,9 +116,9 @@ export class LocalizedDateParserFormatter extends NgbDateParserFormatter { format(date: NgbDateStruct | null): string { if (date) { return this.getDateInputFormat() - .replace('dd', date.day.toString().padStart(2, '0')) - .replace('mm', date.month.toString().padStart(2, '0')) - .replace('yyyy', date.year.toString().padStart(4, '0')) + .replace('dd', date.day.toString().padStart(2, '0')) + .replace('mm', date.month.toString().padStart(2, '0')) + .replace('yyyy', date.year.toString().padStart(4, '0')) } else { return null } diff --git a/src-ui/src/app/utils/ngb-iso-date-adapter.ts b/src-ui/src/app/utils/ngb-iso-date-adapter.ts index e43602a16..7aa2214b5 100644 --- a/src-ui/src/app/utils/ngb-iso-date-adapter.ts +++ b/src-ui/src/app/utils/ngb-iso-date-adapter.ts @@ -1,16 +1,15 @@ -import { Injectable } from "@angular/core"; -import { NgbDateAdapter, NgbDateStruct } from "@ng-bootstrap/ng-bootstrap"; +import { Injectable } from '@angular/core' +import { NgbDateAdapter, NgbDateStruct } from '@ng-bootstrap/ng-bootstrap' @Injectable() export class ISODateAdapter extends NgbDateAdapter { - fromModel(value: string | null): NgbDateStruct | null { if (value) { let date = new Date(value) return { - day : date.getDate(), - month : date.getMonth() + 1, - year : date.getFullYear() + day: date.getDate(), + month: date.getMonth() + 1, + year: date.getFullYear(), } } else { return null @@ -19,7 +18,13 @@ export class ISODateAdapter extends NgbDateAdapter { toModel(date: NgbDateStruct | null): string | null { if (date) { - return date.year.toString().padStart(4, '0') + "-" + date.month.toString().padStart(2, '0') + "-" + date.day.toString().padStart(2, '0') + return ( + date.year.toString().padStart(4, '0') + + '-' + + date.month.toString().padStart(2, '0') + + '-' + + date.day.toString().padStart(2, '0') + ) } else { return null } diff --git a/src-ui/src/app/utils/ngb-iso-date-time-adapter.ts b/src-ui/src/app/utils/ngb-iso-date-time-adapter.ts index 21a97a19a..b9acc38ec 100644 --- a/src-ui/src/app/utils/ngb-iso-date-time-adapter.ts +++ b/src-ui/src/app/utils/ngb-iso-date-time-adapter.ts @@ -1,16 +1,15 @@ -import { Injectable } from "@angular/core"; -import { NgbDateAdapter, NgbDateStruct } from "@ng-bootstrap/ng-bootstrap"; +import { Injectable } from '@angular/core' +import { NgbDateAdapter, NgbDateStruct } from '@ng-bootstrap/ng-bootstrap' @Injectable() export class ISODateTimeAdapter extends NgbDateAdapter { - fromModel(value: string | null): NgbDateStruct | null { if (value) { let date = new Date(value) return { - day : date.getDate(), - month : date.getMonth() + 1, - year : date.getFullYear() + day: date.getDate(), + month: date.getMonth() + 1, + year: date.getFullYear(), } } else { return null @@ -18,6 +17,8 @@ export class ISODateTimeAdapter extends NgbDateAdapter { } toModel(date: NgbDateStruct | null): string | null { - return date ? new Date(date.year, date.month - 1, date.day).toISOString() : null + return date + ? new Date(date.year, date.month - 1, date.day).toISOString() + : null } } diff --git a/src-ui/src/environments/environment.prod.ts b/src-ui/src/environments/environment.prod.ts index 36ad4ef2a..0f1e41c97 100644 --- a/src-ui/src/environments/environment.prod.ts +++ b/src-ui/src/environments/environment.prod.ts @@ -2,11 +2,11 @@ const base_url = new URL(document.baseURI) export const environment = { production: true, - apiBaseUrl: document.baseURI + "api/", - apiVersion: "2", - appTitle: "Paperless-ngx", - version: "1.6.0", + apiBaseUrl: document.baseURI + 'api/', + apiVersion: '2', + appTitle: 'Paperless-ngx', + version: '1.6.0', webSocketHost: window.location.host, - webSocketProtocol: (window.location.protocol == "https:" ? "wss:" : "ws:"), - webSocketBaseUrl: base_url.pathname + "ws/", -}; + webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:', + webSocketBaseUrl: base_url.pathname + 'ws/', +} diff --git a/src-ui/src/environments/environment.ts b/src-ui/src/environments/environment.ts index 9841a51c5..4386bef1e 100644 --- a/src-ui/src/environments/environment.ts +++ b/src-ui/src/environments/environment.ts @@ -4,14 +4,14 @@ export const environment = { production: false, - apiBaseUrl: "http://localhost:8000/api/", - apiVersion: "2", - appTitle: "Paperless-ngx", - version: "DEVELOPMENT", - webSocketHost: "localhost:8000", - webSocketProtocol: "ws:", - webSocketBaseUrl: "/ws/", -}; + apiBaseUrl: 'http://localhost:8000/api/', + apiVersion: '2', + appTitle: 'Paperless-ngx', + version: 'DEVELOPMENT', + webSocketHost: 'localhost:8000', + webSocketProtocol: 'ws:', + webSocketBaseUrl: '/ws/', +} /* * For easier debugging in development mode, you can import the following file diff --git a/src-ui/src/main.ts b/src-ui/src/main.ts index c7b673cf4..274537fe8 100644 --- a/src-ui/src/main.ts +++ b/src-ui/src/main.ts @@ -1,12 +1,13 @@ -import { enableProdMode } from '@angular/core'; -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { enableProdMode } from '@angular/core' +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' -import { AppModule } from './app/app.module'; -import { environment } from './environments/environment'; +import { AppModule } from './app/app.module' +import { environment } from './environments/environment' if (environment.production) { - enableProdMode(); + enableProdMode() } -platformBrowserDynamic().bootstrapModule(AppModule) - .catch(err => console.error(err)); +platformBrowserDynamic() + .bootstrapModule(AppModule) + .catch((err) => console.error(err)) diff --git a/src-ui/src/polyfills.ts b/src-ui/src/polyfills.ts index 4eef33bb7..ac9c93e4a 100644 --- a/src-ui/src/polyfills.ts +++ b/src-ui/src/polyfills.ts @@ -1,7 +1,7 @@ /*************************************************************************************************** * Load `$localize` onto the global scope - used if i18n tags appear in Angular templates. */ -import '@angular/localize/init'; +import '@angular/localize/init' /** * This file includes polyfills needed by Angular and is loaded before the app. * You can add your own extra polyfills to this file. @@ -49,8 +49,7 @@ import '@angular/localize/init'; /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ -import 'zone.js'; // Included with Angular CLI. - +import 'zone.js' // Included with Angular CLI. /*************************************************************************************************** * APPLICATION IMPORTS diff --git a/src-ui/src/test.ts b/src-ui/src/test.ts index 4bf4afba6..7b78038bb 100644 --- a/src-ui/src/test.ts +++ b/src-ui/src/test.ts @@ -1,27 +1,32 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'zone.js/testing'; -import { getTestBed } from '@angular/core/testing'; +import 'zone.js/testing' +import { getTestBed } from '@angular/core/testing' import { BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; + platformBrowserDynamicTesting, +} from '@angular/platform-browser-dynamic/testing' declare const require: { - context(path: string, deep?: boolean, filter?: RegExp): { - keys(): string[]; - (id: string): T; - }; -}; + context( + path: string, + deep?: boolean, + filter?: RegExp + ): { + keys(): string[] + (id: string): T + } +} // First, initialize the Angular testing environment. getTestBed().initTestEnvironment( BrowserDynamicTestingModule, - platformBrowserDynamicTesting(), { - teardown: { destroyAfterEach: false } -} -); + platformBrowserDynamicTesting(), + { + teardown: { destroyAfterEach: false }, + } +) // Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); +const context = require.context('./', true, /\.spec\.ts$/) // And load the modules. -context.keys().map(context); +context.keys().map(context)