mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
Refactor: loading component
This commit is contained in:
@@ -17,9 +17,9 @@ import {
|
||||
} from 'src/app/data/paperless-config'
|
||||
import { ConfigService } from 'src/app/services/config.service'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component'
|
||||
import { DirtyComponent, dirtyCheck } from '@ngneat/dirty-check-forms'
|
||||
import { SettingsService } from 'src/app/services/settings.service'
|
||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-config',
|
||||
@@ -27,7 +27,7 @@ import { SettingsService } from 'src/app/services/settings.service'
|
||||
styleUrl: './config.component.scss',
|
||||
})
|
||||
export class ConfigComponent
|
||||
extends ComponentWithPermissions
|
||||
extends LoadingComponentWithPermissions
|
||||
implements OnInit, OnDestroy, DirtyComponent
|
||||
{
|
||||
public readonly ConfigOptionType = ConfigOptionType
|
||||
@@ -45,15 +45,11 @@ export class ConfigComponent
|
||||
return PaperlessConfigOptions.filter((o) => o.category === category)
|
||||
}
|
||||
|
||||
public loading: boolean = false
|
||||
|
||||
initialConfig: PaperlessConfig
|
||||
store: BehaviorSubject<any>
|
||||
storeSub: Subscription
|
||||
isDirty$: Observable<boolean>
|
||||
|
||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||
|
||||
constructor(
|
||||
private configService: ConfigService,
|
||||
private toastService: ToastService,
|
||||
@@ -67,7 +63,6 @@ export class ConfigComponent
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loading = true
|
||||
this.configService
|
||||
.getConfig()
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
|
@@ -17,7 +17,7 @@
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
@if (isLoading || !logFiles.length) {
|
||||
@if (loading || !logFiles.length) {
|
||||
<div class="ps-2 d-flex align-items-center">
|
||||
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
|
||||
@if (!logFiles.length) {
|
||||
@@ -30,7 +30,7 @@
|
||||
<div [ngbNavOutlet]="nav" class="mt-2"></div>
|
||||
|
||||
<div class="bg-dark p-3 text-light font-monospace log-container" #logContainer>
|
||||
@if (isLoading && logFiles.length) {
|
||||
@if (loading && logFiles.length) {
|
||||
<div>
|
||||
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
|
||||
<ng-container i18n>Loading...</ng-container>
|
||||
|
@@ -3,22 +3,28 @@ import {
|
||||
ElementRef,
|
||||
OnInit,
|
||||
ViewChild,
|
||||
OnDestroy,
|
||||
ChangeDetectorRef,
|
||||
OnDestroy,
|
||||
} from '@angular/core'
|
||||
import { Subject, takeUntil } from 'rxjs'
|
||||
import { takeUntil } from 'rxjs'
|
||||
import { LogService } from 'src/app/services/rest/log.service'
|
||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-logs',
|
||||
templateUrl: './logs.component.html',
|
||||
styleUrls: ['./logs.component.scss'],
|
||||
})
|
||||
export class LogsComponent implements OnInit, OnDestroy {
|
||||
export class LogsComponent
|
||||
extends LoadingComponentWithPermissions
|
||||
implements OnInit, OnDestroy
|
||||
{
|
||||
constructor(
|
||||
private logService: LogService,
|
||||
private changedetectorRef: ChangeDetectorRef
|
||||
) {}
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
public logs: string[] = []
|
||||
|
||||
@@ -26,22 +32,17 @@ export class LogsComponent implements OnInit, OnDestroy {
|
||||
|
||||
public activeLog: string
|
||||
|
||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||
|
||||
public isLoading: boolean = false
|
||||
|
||||
public autoRefreshInterval: any
|
||||
|
||||
@ViewChild('logContainer') logContainer: ElementRef
|
||||
|
||||
ngOnInit(): void {
|
||||
this.isLoading = true
|
||||
this.logService
|
||||
.list()
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe((result) => {
|
||||
this.logFiles = result
|
||||
this.isLoading = false
|
||||
this.loading = false
|
||||
if (this.logFiles.length > 0) {
|
||||
this.activeLog = this.logFiles[0]
|
||||
this.reloadLogs()
|
||||
@@ -51,25 +52,24 @@ export class LogsComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.unsubscribeNotifier.next(true)
|
||||
this.unsubscribeNotifier.complete()
|
||||
super.ngOnDestroy()
|
||||
clearInterval(this.autoRefreshInterval)
|
||||
}
|
||||
|
||||
reloadLogs() {
|
||||
this.isLoading = true
|
||||
this.loading = true
|
||||
this.logService
|
||||
.get(this.activeLog)
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe({
|
||||
next: (result) => {
|
||||
this.logs = result
|
||||
this.isLoading = false
|
||||
this.loading = false
|
||||
this.scrollToBottom()
|
||||
},
|
||||
error: () => {
|
||||
this.logs = []
|
||||
this.isLoading = false
|
||||
this.loading = false
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@ import {
|
||||
import { PaperlessTask } from 'src/app/data/paperless-task'
|
||||
import { TasksService } from 'src/app/services/tasks.service'
|
||||
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
|
||||
import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component'
|
||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
||||
|
||||
export enum TaskTab {
|
||||
Queued = 'queued',
|
||||
@@ -37,7 +37,7 @@ const FILTER_TARGETS = [
|
||||
styleUrls: ['./tasks.component.scss'],
|
||||
})
|
||||
export class TasksComponent
|
||||
extends ComponentWithPermissions
|
||||
extends LoadingComponentWithPermissions
|
||||
implements OnInit, OnDestroy
|
||||
{
|
||||
public activeTab: TaskTab
|
||||
@@ -70,8 +70,6 @@ export class TasksComponent
|
||||
: FILTER_TARGETS.slice(0, 1)
|
||||
}
|
||||
|
||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||
|
||||
get dismissButtonText(): string {
|
||||
return this.selectedTasks.size > 0
|
||||
? $localize`Dismiss selected`
|
||||
@@ -101,9 +99,9 @@ export class TasksComponent
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
super.ngOnDestroy()
|
||||
this.tasksService.cancelPending()
|
||||
clearInterval(this.autoRefreshInterval)
|
||||
this.unsubscribeNotifier.next(this)
|
||||
}
|
||||
|
||||
dismissTask(task: PaperlessTask) {
|
||||
|
@@ -38,7 +38,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if (isLoading) {
|
||||
@if (loading) {
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
|
||||
@@ -88,7 +88,7 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@if (!isLoading) {
|
||||
@if (!loading) {
|
||||
<div class="d-flex mb-2">
|
||||
<div>
|
||||
<ng-container i18n>{totalDocuments, plural, =1 {One document in trash} other {{{totalDocuments || 0}} total documents in trash}}</ng-container>
|
||||
|
@@ -4,25 +4,26 @@ import { Document } from 'src/app/data/document'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
import { TrashService } from 'src/app/services/trash.service'
|
||||
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
|
||||
import { delay, Subject, takeUntil, tap } from 'rxjs'
|
||||
import { delay, takeUntil, tap } from 'rxjs'
|
||||
import { SettingsService } from 'src/app/services/settings.service'
|
||||
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
|
||||
import { Router } from '@angular/router'
|
||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-trash',
|
||||
templateUrl: './trash.component.html',
|
||||
styleUrl: './trash.component.scss',
|
||||
})
|
||||
export class TrashComponent implements OnDestroy {
|
||||
export class TrashComponent
|
||||
extends LoadingComponentWithPermissions
|
||||
implements OnDestroy
|
||||
{
|
||||
public documentsInTrash: Document[] = []
|
||||
public selectedDocuments: Set<number> = new Set()
|
||||
public allToggled: boolean = false
|
||||
public page: number = 1
|
||||
public totalDocuments: number
|
||||
public isLoading: boolean = false
|
||||
public reveal: boolean = false
|
||||
unsubscribeNotifier: Subject<void> = new Subject()
|
||||
|
||||
constructor(
|
||||
private trashService: TrashService,
|
||||
@@ -31,16 +32,12 @@ export class TrashComponent implements OnDestroy {
|
||||
private settingsService: SettingsService,
|
||||
private router: Router
|
||||
) {
|
||||
super()
|
||||
this.reload()
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unsubscribeNotifier.next()
|
||||
this.unsubscribeNotifier.complete()
|
||||
}
|
||||
|
||||
reload() {
|
||||
this.isLoading = true
|
||||
this.loading = true
|
||||
this.trashService
|
||||
.getTrash(this.page)
|
||||
.pipe(
|
||||
@@ -48,12 +45,12 @@ export class TrashComponent implements OnDestroy {
|
||||
this.documentsInTrash = r.results
|
||||
this.totalDocuments = r.count
|
||||
this.selectedDocuments.clear()
|
||||
this.loading = false
|
||||
}),
|
||||
delay(100)
|
||||
)
|
||||
.subscribe(() => {
|
||||
this.reveal = true
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -1,14 +1,17 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core'
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { interval, Subject, take } from 'rxjs'
|
||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-confirm-dialog',
|
||||
templateUrl: './confirm-dialog.component.html',
|
||||
styleUrls: ['./confirm-dialog.component.scss'],
|
||||
})
|
||||
export class ConfirmDialogComponent {
|
||||
constructor(public activeModal: NgbActiveModal) {}
|
||||
export class ConfirmDialogComponent extends LoadingComponentWithPermissions {
|
||||
constructor(public activeModal: NgbActiveModal) {
|
||||
super()
|
||||
}
|
||||
|
||||
@Output()
|
||||
public confirmClicked = new EventEmitter()
|
||||
|
@@ -25,8 +25,6 @@ export class MergeConfirmDialogComponent
|
||||
|
||||
public metadataDocumentID: number = -1
|
||||
|
||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||
|
||||
constructor(
|
||||
activeModal: NgbActiveModal,
|
||||
private documentService: DocumentService,
|
||||
|
@@ -1,25 +1,22 @@
|
||||
import { getLocaleCurrencyCode } from '@angular/common'
|
||||
import {
|
||||
Component,
|
||||
Inject,
|
||||
Input,
|
||||
LOCALE_ID,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
} from '@angular/core'
|
||||
import { Subject, takeUntil } from 'rxjs'
|
||||
import { Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core'
|
||||
import { takeUntil } from 'rxjs'
|
||||
import { CustomField, CustomFieldDataType } from 'src/app/data/custom-field'
|
||||
import { DisplayField, Document } from 'src/app/data/document'
|
||||
import { Results } from 'src/app/data/results'
|
||||
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
|
||||
import { DocumentService } from 'src/app/services/rest/document.service'
|
||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-custom-field-display',
|
||||
templateUrl: './custom-field-display.component.html',
|
||||
styleUrl: './custom-field-display.component.scss',
|
||||
})
|
||||
export class CustomFieldDisplayComponent implements OnInit, OnDestroy {
|
||||
export class CustomFieldDisplayComponent
|
||||
extends LoadingComponentWithPermissions
|
||||
implements OnInit
|
||||
{
|
||||
CustomFieldDataType = CustomFieldDataType
|
||||
|
||||
private _document: Document
|
||||
@@ -61,7 +58,6 @@ export class CustomFieldDisplayComponent implements OnInit, OnDestroy {
|
||||
|
||||
private docLinkDocuments: Document[] = []
|
||||
|
||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||
private defaultCurrencyCode: any
|
||||
|
||||
constructor(
|
||||
@@ -69,6 +65,7 @@ export class CustomFieldDisplayComponent implements OnInit, OnDestroy {
|
||||
private documentService: DocumentService,
|
||||
@Inject(LOCALE_ID) currentLocale: string
|
||||
) {
|
||||
super()
|
||||
this.defaultCurrencyCode = getLocaleCurrencyCode(currentLocale)
|
||||
this.customFieldService.listAll().subscribe((r) => {
|
||||
this.customFields = r.results
|
||||
@@ -120,9 +117,4 @@ export class CustomFieldDisplayComponent implements OnInit, OnDestroy {
|
||||
public getSelectValue(field: CustomField, id: string): string {
|
||||
return field.extra_data.select_options?.find((o) => o.id === id)?.label
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.unsubscribeNotifier.next(true)
|
||||
this.unsubscribeNotifier.complete()
|
||||
}
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@ import {
|
||||
ViewChildren,
|
||||
} from '@angular/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { Subject, first, takeUntil } from 'rxjs'
|
||||
import { first, takeUntil } from 'rxjs'
|
||||
import { CustomField, DATA_TYPE_LABELS } from 'src/app/data/custom-field'
|
||||
import { CustomFieldInstance } from 'src/app/data/custom-field-instance'
|
||||
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
|
||||
@@ -21,13 +21,14 @@ import {
|
||||
PermissionType,
|
||||
PermissionsService,
|
||||
} from 'src/app/services/permissions.service'
|
||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-custom-fields-dropdown',
|
||||
templateUrl: './custom-fields-dropdown.component.html',
|
||||
styleUrls: ['./custom-fields-dropdown.component.scss'],
|
||||
})
|
||||
export class CustomFieldsDropdownComponent implements OnDestroy {
|
||||
export class CustomFieldsDropdownComponent extends LoadingComponentWithPermissions {
|
||||
@Input()
|
||||
documentId: number
|
||||
|
||||
@@ -60,8 +61,6 @@ export class CustomFieldsDropdownComponent implements OnDestroy {
|
||||
|
||||
public filterText: string
|
||||
|
||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||
|
||||
get canCreateFields(): boolean {
|
||||
return this.permissionsService.currentUserCan(
|
||||
PermissionAction.Add,
|
||||
@@ -75,14 +74,10 @@ export class CustomFieldsDropdownComponent implements OnDestroy {
|
||||
private toastService: ToastService,
|
||||
private permissionsService: PermissionsService
|
||||
) {
|
||||
super()
|
||||
this.getFields()
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.unsubscribeNotifier.next(this)
|
||||
this.unsubscribeNotifier.complete()
|
||||
}
|
||||
|
||||
private getFields() {
|
||||
this.customFieldsService
|
||||
.listAll()
|
||||
|
@@ -2,7 +2,6 @@ import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnDestroy,
|
||||
Output,
|
||||
QueryList,
|
||||
ViewChild,
|
||||
@@ -29,6 +28,7 @@ import {
|
||||
CustomFieldQueryAtom,
|
||||
} from 'src/app/utils/custom-field-query-element'
|
||||
import { popperOptionsReenablePreventOverflow } from 'src/app/utils/popper-options'
|
||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
||||
|
||||
export class CustomFieldQueriesModel {
|
||||
public queries: CustomFieldQueryElement[] = []
|
||||
@@ -157,7 +157,7 @@ export class CustomFieldQueriesModel {
|
||||
templateUrl: './custom-fields-query-dropdown.component.html',
|
||||
styleUrls: ['./custom-fields-query-dropdown.component.scss'],
|
||||
})
|
||||
export class CustomFieldsQueryDropdownComponent implements OnDestroy {
|
||||
export class CustomFieldsQueryDropdownComponent extends LoadingComponentWithPermissions {
|
||||
public CustomFieldQueryComponentType = CustomFieldQueryElementType
|
||||
public CustomFieldQueryOperator = CustomFieldQueryOperator
|
||||
public CustomFieldDataType = CustomFieldDataType
|
||||
@@ -223,19 +223,13 @@ export class CustomFieldsQueryDropdownComponent implements OnDestroy {
|
||||
|
||||
customFields: CustomField[] = []
|
||||
|
||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||
|
||||
constructor(protected customFieldsService: CustomFieldsService) {
|
||||
super()
|
||||
this.selectionModel = new CustomFieldQueriesModel()
|
||||
this.getFields()
|
||||
this.reset()
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.unsubscribeNotifier.next(this)
|
||||
this.unsubscribeNotifier.complete()
|
||||
}
|
||||
|
||||
public onOpenChange(open: boolean) {
|
||||
if (open) {
|
||||
if (this.selectionModel.queries.length === 0) {
|
||||
|
@@ -2,7 +2,6 @@ import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
ElementRef,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
QueryList,
|
||||
ViewChildren,
|
||||
@@ -18,7 +17,7 @@ import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service
|
||||
import { UserService } from 'src/app/services/rest/user.service'
|
||||
import { SettingsService } from 'src/app/services/settings.service'
|
||||
import { EditDialogComponent, EditDialogMode } from '../edit-dialog.component'
|
||||
import { Subject, takeUntil } from 'rxjs'
|
||||
import { takeUntil } from 'rxjs'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-custom-field-edit-dialog',
|
||||
@@ -27,15 +26,13 @@ import { Subject, takeUntil } from 'rxjs'
|
||||
})
|
||||
export class CustomFieldEditDialogComponent
|
||||
extends EditDialogComponent<CustomField>
|
||||
implements OnInit, AfterViewInit, OnDestroy
|
||||
implements OnInit, AfterViewInit
|
||||
{
|
||||
CustomFieldDataType = CustomFieldDataType
|
||||
|
||||
@ViewChildren('selectOption')
|
||||
private selectOptionInputs: QueryList<ElementRef>
|
||||
|
||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||
|
||||
private get selectOptions(): FormArray {
|
||||
return (this.objectForm.controls.extra_data as FormGroup).controls
|
||||
.select_options as FormArray
|
||||
@@ -78,11 +75,6 @@ export class CustomFieldEditDialogComponent
|
||||
})
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.unsubscribeNotifier.next(true)
|
||||
this.unsubscribeNotifier.complete()
|
||||
}
|
||||
|
||||
getCreateTitle() {
|
||||
return $localize`Create new custom field`
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@ import { UserService } from 'src/app/services/rest/user.service'
|
||||
import { PermissionsFormObject } from '../input/permissions/permissions-form/permissions-form.component'
|
||||
import { SettingsService } from 'src/app/services/settings.service'
|
||||
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
|
||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
||||
|
||||
export enum EditDialogMode {
|
||||
CREATE = 0,
|
||||
@@ -23,15 +24,19 @@ export enum EditDialogMode {
|
||||
|
||||
@Directive()
|
||||
export abstract class EditDialogComponent<
|
||||
T extends ObjectWithPermissions | ObjectWithId,
|
||||
> implements OnInit
|
||||
T extends ObjectWithPermissions | ObjectWithId,
|
||||
>
|
||||
extends LoadingComponentWithPermissions
|
||||
implements OnInit
|
||||
{
|
||||
constructor(
|
||||
protected service: AbstractPaperlessService<T>,
|
||||
private activeModal: NgbActiveModal,
|
||||
private userService: UserService,
|
||||
private settingsService: SettingsService
|
||||
) {}
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
users: User[]
|
||||
|
||||
|
@@ -41,8 +41,6 @@ export class StoragePathEditDialogComponent
|
||||
public loading = false
|
||||
public testLoading = false
|
||||
|
||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||
|
||||
constructor(
|
||||
service: StoragePathService,
|
||||
activeModal: NgbActiveModal,
|
||||
@@ -54,11 +52,6 @@ export class StoragePathEditDialogComponent
|
||||
this.initPathObservables()
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.unsubscribeNotifier.next(this)
|
||||
this.unsubscribeNotifier.complete()
|
||||
}
|
||||
|
||||
getCreateTitle() {
|
||||
return $localize`Create new storage path`
|
||||
}
|
||||
|
@@ -6,7 +6,6 @@ import {
|
||||
ElementRef,
|
||||
ViewChild,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
} from '@angular/core'
|
||||
import { FilterPipe } from 'src/app/pipes/filter.pipe'
|
||||
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
|
||||
@@ -17,6 +16,7 @@ import { SelectionDataItem } from 'src/app/services/rest/document.service'
|
||||
import { ObjectWithPermissions } from 'src/app/data/object-with-permissions'
|
||||
import { HotKeyService } from 'src/app/services/hot-key.service'
|
||||
import { popperOptionsReenablePreventOverflow } from 'src/app/utils/popper-options'
|
||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
||||
|
||||
export interface ChangedItems {
|
||||
itemsToAdd: MatchingModel[]
|
||||
@@ -353,7 +353,10 @@ export class FilterableDropdownSelectionModel {
|
||||
templateUrl: './filterable-dropdown.component.html',
|
||||
styleUrls: ['./filterable-dropdown.component.scss'],
|
||||
})
|
||||
export class FilterableDropdownComponent implements OnDestroy, OnInit {
|
||||
export class FilterableDropdownComponent
|
||||
extends LoadingComponentWithPermissions
|
||||
implements OnInit
|
||||
{
|
||||
@ViewChild('listFilterTextInput') listFilterTextInput: ElementRef
|
||||
@ViewChild('dropdown') dropdown: NgbDropdown
|
||||
@ViewChild('buttonItems') buttonItems: ElementRef
|
||||
@@ -467,12 +470,11 @@ export class FilterableDropdownComponent implements OnDestroy, OnInit {
|
||||
|
||||
private keyboardIndex: number
|
||||
|
||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||
|
||||
constructor(
|
||||
private filterPipe: FilterPipe,
|
||||
private hotkeyService: HotKeyService
|
||||
) {
|
||||
super()
|
||||
this.selectionModelChange.subscribe((updatedModel) => {
|
||||
this.modelIsDirty = updatedModel.isDirty()
|
||||
})
|
||||
@@ -495,11 +497,6 @@ export class FilterableDropdownComponent implements OnDestroy, OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.unsubscribeNotifier.next(true)
|
||||
this.unsubscribeNotifier.complete()
|
||||
}
|
||||
|
||||
applyClicked() {
|
||||
if (this.selectionModel.isDirty()) {
|
||||
this.dropdown.close()
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core'
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
import { FormControl, FormGroup } from '@angular/forms'
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { ProfileService } from 'src/app/services/profile.service'
|
||||
@@ -8,18 +8,21 @@ import {
|
||||
SocialAccountProvider,
|
||||
} from 'src/app/data/user-profile'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
import { Subject, takeUntil } from 'rxjs'
|
||||
import { takeUntil } from 'rxjs'
|
||||
import { Clipboard } from '@angular/cdk/clipboard'
|
||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-profile-edit-dialog',
|
||||
templateUrl: './profile-edit-dialog.component.html',
|
||||
styleUrls: ['./profile-edit-dialog.component.scss'],
|
||||
})
|
||||
export class ProfileEditDialogComponent implements OnInit, OnDestroy {
|
||||
export class ProfileEditDialogComponent
|
||||
extends LoadingComponentWithPermissions
|
||||
implements OnInit
|
||||
{
|
||||
public networkActive: boolean = false
|
||||
public error: any
|
||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||
|
||||
public form = new FormGroup({
|
||||
email: new FormControl(''),
|
||||
@@ -60,7 +63,9 @@ export class ProfileEditDialogComponent implements OnInit, OnDestroy {
|
||||
public activeModal: NgbActiveModal,
|
||||
private toastService: ToastService,
|
||||
private clipboard: Clipboard
|
||||
) {}
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.networkActive = true
|
||||
@@ -93,11 +98,6 @@ export class ProfileEditDialogComponent implements OnInit, OnDestroy {
|
||||
})
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.unsubscribeNotifier.next(true)
|
||||
this.unsubscribeNotifier.complete()
|
||||
}
|
||||
|
||||
get saveDisabled(): boolean {
|
||||
return this.error?.password_confirm || this.error?.email_confirm
|
||||
}
|
||||
|
@@ -28,7 +28,6 @@ import {
|
||||
} from 'src/app/data/filter-rule-type'
|
||||
import { OpenDocumentsService } from 'src/app/services/open-documents.service'
|
||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
|
||||
import { ComponentWithPermissions } from 'src/app/components/with-permissions/with-permissions.component'
|
||||
import { NgbPopover } from '@ng-bootstrap/ng-bootstrap'
|
||||
import {
|
||||
PermissionAction,
|
||||
@@ -38,6 +37,7 @@ import {
|
||||
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
|
||||
import { CustomField, CustomFieldDataType } from 'src/app/data/custom-field'
|
||||
import { SettingsService } from 'src/app/services/settings.service'
|
||||
import { LoadingComponentWithPermissions } from 'src/app/components/loading-component/loading.component'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-saved-view-widget',
|
||||
@@ -45,16 +45,13 @@ import { SettingsService } from 'src/app/services/settings.service'
|
||||
styleUrls: ['./saved-view-widget.component.scss'],
|
||||
})
|
||||
export class SavedViewWidgetComponent
|
||||
extends ComponentWithPermissions
|
||||
extends LoadingComponentWithPermissions
|
||||
implements OnInit, OnDestroy
|
||||
{
|
||||
public DisplayMode = DisplayMode
|
||||
public DisplayField = DisplayField
|
||||
public CustomFieldDataType = CustomFieldDataType
|
||||
|
||||
public loading: boolean = true
|
||||
public reveal: boolean = false
|
||||
|
||||
private customFields: CustomField[] = []
|
||||
|
||||
constructor(
|
||||
|
@@ -1,12 +1,18 @@
|
||||
import { AfterViewInit, Component, Input } from '@angular/core'
|
||||
import { LoadingComponentWithPermissions } from 'src/app/components/loading-component/loading.component'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-widget-frame',
|
||||
templateUrl: './widget-frame.component.html',
|
||||
styleUrls: ['./widget-frame.component.scss'],
|
||||
})
|
||||
export class WidgetFrameComponent implements AfterViewInit {
|
||||
constructor() {}
|
||||
export class WidgetFrameComponent
|
||||
extends LoadingComponentWithPermissions
|
||||
implements AfterViewInit
|
||||
{
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
@Input()
|
||||
title: string
|
||||
@@ -17,8 +23,6 @@ export class WidgetFrameComponent implements AfterViewInit {
|
||||
@Input()
|
||||
draggable: any
|
||||
|
||||
public reveal: boolean = false
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
setTimeout(() => {
|
||||
this.reveal = true
|
||||
|
@@ -0,0 +1,43 @@
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { Subject } from 'rxjs'
|
||||
import { LoadingComponentWithPermissions } from './loading.component'
|
||||
import { ComponentWithPermissions } from '../with-permissions/with-permissions.component'
|
||||
import { Component } from '@angular/core'
|
||||
|
||||
class MockComponentWithPermissions extends ComponentWithPermissions {}
|
||||
|
||||
@Component({
|
||||
template: '',
|
||||
})
|
||||
class MockLoadingComponent extends LoadingComponentWithPermissions {}
|
||||
|
||||
describe('LoadingComponentWithPermissions', () => {
|
||||
let component: LoadingComponentWithPermissions
|
||||
|
||||
beforeEach(async () => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [LoadingComponentWithPermissions],
|
||||
})
|
||||
component = new MockLoadingComponent()
|
||||
})
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should have loading set to true by default', () => {
|
||||
expect(component.loading).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should have reveal set to false by default', () => {
|
||||
expect(component.reveal).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should call next and complete on unsubscribeNotifier with itself on destroy', () => {
|
||||
const nextSpy = jest.spyOn(component['unsubscribeNotifier'], 'next')
|
||||
const completeSpy = jest.spyOn(component['unsubscribeNotifier'], 'complete')
|
||||
component.ngOnDestroy()
|
||||
expect(nextSpy).toHaveBeenCalledWith(component)
|
||||
expect(completeSpy).toHaveBeenCalled()
|
||||
})
|
||||
})
|
@@ -0,0 +1,23 @@
|
||||
import { Subject } from 'rxjs'
|
||||
import { ComponentWithPermissions } from '../with-permissions/with-permissions.component'
|
||||
import { Directive, OnDestroy } from '@angular/core'
|
||||
|
||||
@Directive()
|
||||
export abstract class LoadingComponentWithPermissions
|
||||
extends ComponentWithPermissions
|
||||
implements OnDestroy
|
||||
{
|
||||
public loading: boolean = true
|
||||
public reveal: boolean = false
|
||||
|
||||
protected unsubscribeNotifier: Subject<any> = new Subject()
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.unsubscribeNotifier.next(this)
|
||||
this.unsubscribeNotifier.complete()
|
||||
}
|
||||
}
|
@@ -28,6 +28,7 @@ import {
|
||||
CustomFieldQueryLogicalOperator,
|
||||
CustomFieldQueryOperator,
|
||||
} from 'src/app/data/custom-field-query'
|
||||
import { SettingsService } from 'src/app/services/settings.service'
|
||||
|
||||
const fields: CustomField[] = [
|
||||
{
|
||||
@@ -49,6 +50,7 @@ describe('CustomFieldsComponent', () => {
|
||||
let modalService: NgbModal
|
||||
let toastService: ToastService
|
||||
let listViewService: DocumentListViewService
|
||||
let settingsService: SettingsService
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -91,6 +93,8 @@ describe('CustomFieldsComponent', () => {
|
||||
modalService = TestBed.inject(NgbModal)
|
||||
toastService = TestBed.inject(ToastService)
|
||||
listViewService = TestBed.inject(DocumentListViewService)
|
||||
settingsService = TestBed.inject(SettingsService)
|
||||
settingsService.currentUser = { id: 0, username: 'test' }
|
||||
|
||||
fixture = TestBed.createComponent(CustomFieldsComponent)
|
||||
component = fixture.componentInstance
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { delay, Subject, takeUntil, tap } from 'rxjs'
|
||||
import { delay, takeUntil, tap } from 'rxjs'
|
||||
import { DATA_TYPE_LABELS, CustomField } from 'src/app/data/custom-field'
|
||||
import { PermissionsService } from 'src/app/services/permissions.service'
|
||||
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
|
||||
@@ -8,7 +8,6 @@ import { ToastService } from 'src/app/services/toast.service'
|
||||
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
|
||||
import { CustomFieldEditDialogComponent } from '../../common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component'
|
||||
import { EditDialogMode } from '../../common/edit-dialog/edit-dialog.component'
|
||||
import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component'
|
||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
|
||||
import { FILTER_CUSTOM_FIELDS_QUERY } from 'src/app/data/filter-rule-type'
|
||||
import {
|
||||
@@ -16,6 +15,7 @@ import {
|
||||
CustomFieldQueryOperator,
|
||||
} from 'src/app/data/custom-field-query'
|
||||
import { SettingsService } from 'src/app/services/settings.service'
|
||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-custom-fields',
|
||||
@@ -23,15 +23,11 @@ import { SettingsService } from 'src/app/services/settings.service'
|
||||
styleUrls: ['./custom-fields.component.scss'],
|
||||
})
|
||||
export class CustomFieldsComponent
|
||||
extends ComponentWithPermissions
|
||||
extends LoadingComponentWithPermissions
|
||||
implements OnInit
|
||||
{
|
||||
public fields: CustomField[] = []
|
||||
|
||||
public loading: boolean = true
|
||||
public reveal: boolean = false
|
||||
|
||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||
constructor(
|
||||
private customFieldsService: CustomFieldsService,
|
||||
public permissionsService: PermissionsService,
|
||||
|
@@ -44,7 +44,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if (isLoading) {
|
||||
@if (loading) {
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
|
||||
@@ -109,7 +109,7 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@if (!isLoading) {
|
||||
@if (!loading) {
|
||||
<div class="d-flex mb-2">
|
||||
@if (collectionSize > 0) {
|
||||
<div>
|
||||
|
@@ -39,8 +39,8 @@ import {
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
|
||||
import { EditDialogMode } from '../../common/edit-dialog/edit-dialog.component'
|
||||
import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component'
|
||||
import { PermissionsDialogComponent } from '../../common/permissions-dialog/permissions-dialog.component'
|
||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
||||
|
||||
export interface ManagementListColumn {
|
||||
key: string
|
||||
@@ -56,7 +56,7 @@ export interface ManagementListColumn {
|
||||
|
||||
@Directive()
|
||||
export abstract class ManagementListComponent<T extends ObjectWithId>
|
||||
extends ComponentWithPermissions
|
||||
extends LoadingComponentWithPermissions
|
||||
implements OnInit, OnDestroy
|
||||
{
|
||||
constructor(
|
||||
@@ -86,8 +86,6 @@ export abstract class ManagementListComponent<T extends ObjectWithId>
|
||||
public sortField: string
|
||||
public sortReverse: boolean
|
||||
|
||||
public isLoading: boolean = false
|
||||
|
||||
private nameFilterDebounce: Subject<string>
|
||||
protected unsubscribeNotifier: Subject<any> = new Subject()
|
||||
protected _nameFilter: string
|
||||
@@ -95,8 +93,6 @@ export abstract class ManagementListComponent<T extends ObjectWithId>
|
||||
public selectedObjects: Set<number> = new Set()
|
||||
public togggleAll: boolean = false
|
||||
|
||||
public reveal: boolean = false
|
||||
|
||||
ngOnInit(): void {
|
||||
this.reloadData()
|
||||
|
||||
@@ -115,11 +111,6 @@ export abstract class ManagementListComponent<T extends ObjectWithId>
|
||||
})
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unsubscribeNotifier.next(true)
|
||||
this.unsubscribeNotifier.complete()
|
||||
}
|
||||
|
||||
getMatching(o: MatchingModel) {
|
||||
if (o.matching_algorithm == MATCH_AUTO) {
|
||||
return $localize`Automatic`
|
||||
@@ -141,7 +132,7 @@ export abstract class ManagementListComponent<T extends ObjectWithId>
|
||||
}
|
||||
|
||||
reloadData(extraParams: { [key: string]: any } = null) {
|
||||
this.isLoading = true
|
||||
this.loading = true
|
||||
this.clearSelection()
|
||||
this.service
|
||||
.listFiltered(
|
||||
@@ -163,7 +154,7 @@ export abstract class ManagementListComponent<T extends ObjectWithId>
|
||||
)
|
||||
.subscribe(() => {
|
||||
this.reveal = true
|
||||
this.isLoading = false
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -3,11 +3,11 @@ import { FormControl, FormGroup } from '@angular/forms'
|
||||
import { SavedView } from 'src/app/data/saved-view'
|
||||
import { SavedViewService } from 'src/app/services/rest/saved-view.service'
|
||||
import { SettingsService } from 'src/app/services/settings.service'
|
||||
import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component'
|
||||
import { DisplayMode } from 'src/app/data/document'
|
||||
import { BehaviorSubject, Observable, Subject, Subscription } from 'rxjs'
|
||||
import { BehaviorSubject, Observable, takeUntil } from 'rxjs'
|
||||
import { dirtyCheck } from '@ngneat/dirty-check-forms'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-saved-views',
|
||||
@@ -15,7 +15,7 @@ import { ToastService } from 'src/app/services/toast.service'
|
||||
styleUrl: './saved-views.component.scss',
|
||||
})
|
||||
export class SavedViewsComponent
|
||||
extends ComponentWithPermissions
|
||||
extends LoadingComponentWithPermissions
|
||||
implements OnInit, OnDestroy
|
||||
{
|
||||
DisplayMode = DisplayMode
|
||||
@@ -27,11 +27,7 @@ export class SavedViewsComponent
|
||||
})
|
||||
|
||||
private store: BehaviorSubject<any>
|
||||
private storeSub: Subscription
|
||||
public isDirty$: Observable<boolean>
|
||||
private isDirty: boolean = false
|
||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||
private savePending: boolean = false
|
||||
|
||||
get displayFields() {
|
||||
return this.settings.allDisplayFields
|
||||
@@ -56,9 +52,7 @@ export class SavedViewsComponent
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.settings.organizingSidebarSavedViews = false
|
||||
this.unsubscribeNotifier.next(this)
|
||||
this.unsubscribeNotifier.complete()
|
||||
this.storeSub.unsubscribe()
|
||||
super.ngOnDestroy()
|
||||
}
|
||||
|
||||
private initialize() {
|
||||
@@ -93,9 +87,12 @@ export class SavedViewsComponent
|
||||
}
|
||||
|
||||
this.store = new BehaviorSubject(storeData)
|
||||
this.storeSub = this.store.asObservable().subscribe((state) => {
|
||||
this.savedViewsForm.patchValue(state, { emitEvent: false })
|
||||
})
|
||||
this.store
|
||||
.asObservable()
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe((state) => {
|
||||
this.savedViewsForm.patchValue(state, { emitEvent: false })
|
||||
})
|
||||
|
||||
// Initialize dirtyCheck
|
||||
this.isDirty$ = dirtyCheck(this.savedViewsForm, this.store.asObservable())
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
import { WorkflowService } from 'src/app/services/rest/workflow.service'
|
||||
import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component'
|
||||
import { delay, Subject, takeUntil, tap } from 'rxjs'
|
||||
import { delay, takeUntil, tap } from 'rxjs'
|
||||
import { Workflow } from 'src/app/data/workflow'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
@@ -12,6 +11,7 @@ import {
|
||||
} from '../../common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component'
|
||||
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
|
||||
import { EditDialogMode } from '../../common/edit-dialog/edit-dialog.component'
|
||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-workflows',
|
||||
@@ -19,16 +19,11 @@ import { EditDialogMode } from '../../common/edit-dialog/edit-dialog.component'
|
||||
styleUrls: ['./workflows.component.scss'],
|
||||
})
|
||||
export class WorkflowsComponent
|
||||
extends ComponentWithPermissions
|
||||
extends LoadingComponentWithPermissions
|
||||
implements OnInit
|
||||
{
|
||||
public workflows: Workflow[] = []
|
||||
|
||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||
|
||||
public loading: boolean = false
|
||||
public reveal: boolean = false
|
||||
|
||||
constructor(
|
||||
private workflowService: WorkflowService,
|
||||
public permissionsService: PermissionsService,
|
||||
|
Reference in New Issue
Block a user