Custom Fields dropdown, skeleton of posting custom fields
This commit is contained in:
parent
548ffd46b0
commit
877b9325c4
@ -103,6 +103,7 @@ import { DragDropModule } from '@angular/cdk/drag-drop'
|
||||
import { FileDropComponent } from './components/file-drop/file-drop.component'
|
||||
import { CustomFieldsComponent } from './components/manage/custom-fields/custom-fields.component'
|
||||
import { CustomFieldEditDialogComponent } from './components/common/edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component'
|
||||
import { CustomFieldsDropdownComponent } from './components/common/custom-fields-dropdown/custom-fields-dropdown.component'
|
||||
|
||||
import localeAf from '@angular/common/locales/af'
|
||||
import localeAr from '@angular/common/locales/ar'
|
||||
@ -250,6 +251,7 @@ function initializeApp(settings: SettingsService) {
|
||||
FileDropComponent,
|
||||
CustomFieldsComponent,
|
||||
CustomFieldEditDialogComponent,
|
||||
CustomFieldsDropdownComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
@ -159,21 +159,21 @@
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.DocumentType }">
|
||||
<a class="nav-link" routerLink="documenttypes" routerLinkActive="active" (click)="closeMenu()" ngbPopover="Document types" i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end" container="body" triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
||||
<a class="nav-link" routerLink="documenttypes" routerLinkActive="active" (click)="closeMenu()" ngbPopover="Document Types" i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end" container="body" triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
||||
<svg class="sidebaricon" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#hash"/>
|
||||
</svg><span> <ng-container i18n>Document types</ng-container></span>
|
||||
</svg><span> <ng-container i18n>Document Types</ng-container></span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.StoragePath }">
|
||||
<a class="nav-link" routerLink="storagepaths" routerLinkActive="active" (click)="closeMenu()" ngbPopover="Storage paths" i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end" container="body" triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
||||
<a class="nav-link" routerLink="storagepaths" routerLinkActive="active" (click)="closeMenu()" ngbPopover="Storage Paths" i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end" container="body" triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
||||
<svg class="sidebaricon" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#folder"/>
|
||||
</svg><span> <ng-container i18n>Storage paths</ng-container></span>
|
||||
</svg><span> <ng-container i18n>Storage Paths</ng-container></span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.CustomField }">
|
||||
<a class="nav-link" routerLink="customfields" routerLinkActive="active" (click)="closeMenu()" ngbPopover="Custom fields" i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end" container="body" triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
||||
<a class="nav-link" routerLink="customfields" routerLinkActive="active" (click)="closeMenu()" ngbPopover="Custom Fields" i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end" container="body" triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
||||
<svg class="sidebaricon" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#ui-radios"/>
|
||||
</svg><span> <ng-container i18n>Custom Fields</ng-container></span>
|
||||
|
@ -0,0 +1,33 @@
|
||||
<div ngbDropdown #fieldDropdown="ngbDropdown" (openChange)="onOpenClose()">
|
||||
<button class="btn btn-sm btn-outline-primary me-2" id="customFieldsDropdown" [disabled]="disabled" ngbDropdownToggle>
|
||||
<svg class="toolbaricon" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#ui-radios" />
|
||||
</svg>
|
||||
<div class="d-none d-sm-inline"> <ng-container i18n>Custom Fields</ng-container></div>
|
||||
</button>
|
||||
<div ngbDropdownMenu aria-labelledby="customFieldsDropdown" class="shadow custom-fields-dropdown">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item">
|
||||
<pngx-input-select class="mb-3"
|
||||
[items]="unusedFields"
|
||||
bindLabel="name"
|
||||
[(ngModel)]="field"
|
||||
[placeholder]="placeholderText"
|
||||
bindValue="id">
|
||||
</pngx-input-select>
|
||||
<div class="btn-toolbar" role="toolbar">
|
||||
<button class="btn btn-sm btn-outline-secondary me-auto" type="button" (click)="createField()">
|
||||
<svg fill="currentColor" class="buttonicon-sm me-1 mb-1">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#asterisk"/>
|
||||
</svg><ng-container i18n>Create New Field</ng-container>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-primary me-1" type="button" (click)="addField(); fieldDropdown.close()" [disabled]="field === undefined">
|
||||
<svg fill="currentColor" class="buttonicon me-1">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#plus-circle"/>
|
||||
</svg><ng-container i18n>Add</ng-container>
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,24 @@
|
||||
.custom-fields-dropdown {
|
||||
min-width: 350px;
|
||||
|
||||
// correct position on mobile
|
||||
@media (max-width: 575.98px) {
|
||||
&.show {
|
||||
margin-left: -175px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .ng-select .ng-select-container .ng-value-container .ng-placeholder,
|
||||
::ng-deep .ng-select .ng-option,
|
||||
::ng-deep .ng-select .ng-select-container .ng-value-container .ng-value {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
::ng-deep .paperless-input-select .ng-select {
|
||||
min-height: calc(1em + 0.75rem + 5px);
|
||||
}
|
||||
|
||||
::ng-deep .paperless-input-select .ng-select .ng-select-container .ng-value-container .ng-input {
|
||||
top: 4px;
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
||||
|
||||
import { CustomFieldsDropdownComponent } from './custom-fields-dropdown.component'
|
||||
import {
|
||||
HttpClientTestingModule,
|
||||
HttpTestingController,
|
||||
} from '@angular/common/http/testing'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
|
||||
import { of } from 'rxjs'
|
||||
import {
|
||||
PaperlessCustomField,
|
||||
PaperlessCustomFieldDataType,
|
||||
} from 'src/app/data/paperless-custom-field'
|
||||
import { SelectComponent } from '../input/select/select.component'
|
||||
import { NgSelectModule } from '@ng-select/ng-select'
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
||||
import {
|
||||
NgbModal,
|
||||
NgbModalModule,
|
||||
NgbModalRef,
|
||||
} from '@ng-bootstrap/ng-bootstrap'
|
||||
import { CustomFieldEditDialogComponent } from '../edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component'
|
||||
import { By } from '@angular/platform-browser'
|
||||
|
||||
const fields: PaperlessCustomField[] = [
|
||||
{
|
||||
id: 0,
|
||||
name: 'Field 1',
|
||||
data_type: PaperlessCustomFieldDataType.Integer,
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
name: 'Field 2',
|
||||
data_type: PaperlessCustomFieldDataType.String,
|
||||
},
|
||||
]
|
||||
|
||||
describe('CustomFieldsDropdownComponent', () => {
|
||||
let component: CustomFieldsDropdownComponent
|
||||
let fixture: ComponentFixture<CustomFieldsDropdownComponent>
|
||||
let customFieldService: CustomFieldsService
|
||||
let toastService: ToastService
|
||||
let modalService: NgbModal
|
||||
let httpController: HttpTestingController
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [CustomFieldsDropdownComponent, SelectComponent],
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
NgSelectModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
NgbModalModule,
|
||||
],
|
||||
})
|
||||
customFieldService = TestBed.inject(CustomFieldsService)
|
||||
httpController = TestBed.inject(HttpTestingController)
|
||||
toastService = TestBed.inject(ToastService)
|
||||
modalService = TestBed.inject(NgbModal)
|
||||
jest.spyOn(customFieldService, 'listAll').mockReturnValue(
|
||||
of({
|
||||
all: fields.map((f) => f.id),
|
||||
count: fields.length,
|
||||
results: fields.concat([]),
|
||||
})
|
||||
)
|
||||
fixture = TestBed.createComponent(CustomFieldsDropdownComponent)
|
||||
component = fixture.componentInstance
|
||||
fixture.detectChanges()
|
||||
})
|
||||
|
||||
it('should support add field', () => {
|
||||
let addedField
|
||||
component.added.subscribe((f) => (addedField = f))
|
||||
component.documentId = 11
|
||||
component.field = fields[0].id
|
||||
component.addField()
|
||||
expect(addedField).not.toBeUndefined()
|
||||
})
|
||||
|
||||
it('should clear field on open / close, updated unused fields', () => {
|
||||
component.field = fields[1].id
|
||||
component.onOpenClose()
|
||||
expect(component.field).toBeUndefined()
|
||||
|
||||
expect(component.unusedFields).toEqual(fields)
|
||||
const updateSpy = jest.spyOn(
|
||||
CustomFieldsDropdownComponent.prototype as any,
|
||||
'updateUnusedFields'
|
||||
)
|
||||
component.existingFields = [fields[1]]
|
||||
component.onOpenClose()
|
||||
expect(updateSpy).toHaveBeenCalled()
|
||||
expect(component.unusedFields).toEqual([fields[0]])
|
||||
})
|
||||
|
||||
it('should support creating field, show error if necessary', () => {
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((m) => (modal = m[m.length - 1]))
|
||||
const toastErrorSpy = jest.spyOn(toastService, 'showError')
|
||||
const toastInfoSpy = jest.spyOn(toastService, 'showInfo')
|
||||
const getFieldsSpy = jest.spyOn(
|
||||
CustomFieldsDropdownComponent.prototype as any,
|
||||
'getFields'
|
||||
)
|
||||
|
||||
const createButton = fixture.debugElement.queryAll(By.css('button'))[1]
|
||||
createButton.triggerEventHandler('click')
|
||||
|
||||
expect(modal).not.toBeUndefined()
|
||||
const editDialog = modal.componentInstance as CustomFieldEditDialogComponent
|
||||
|
||||
// fail first
|
||||
editDialog.failed.emit({ error: 'error creating field' })
|
||||
expect(toastErrorSpy).toHaveBeenCalled()
|
||||
expect(getFieldsSpy).not.toHaveBeenCalled()
|
||||
|
||||
// succeed
|
||||
editDialog.succeeded.emit(fields[0])
|
||||
expect(toastInfoSpy).toHaveBeenCalled()
|
||||
expect(getFieldsSpy).toHaveBeenCalled()
|
||||
})
|
||||
})
|
@ -0,0 +1,100 @@
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnDestroy,
|
||||
Output,
|
||||
SimpleChanges,
|
||||
} from '@angular/core'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { Subject, first, takeUntil } from 'rxjs'
|
||||
import { PaperlessCustomField } from 'src/app/data/paperless-custom-field'
|
||||
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
import { CustomFieldEditDialogComponent } from '../edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-custom-fields-dropdown',
|
||||
templateUrl: './custom-fields-dropdown.component.html',
|
||||
styleUrls: ['./custom-fields-dropdown.component.scss'],
|
||||
})
|
||||
export class CustomFieldsDropdownComponent implements OnDestroy {
|
||||
@Input()
|
||||
documentId: number
|
||||
|
||||
@Input()
|
||||
disabled: boolean = false
|
||||
|
||||
@Input()
|
||||
existingFields: PaperlessCustomField[] = []
|
||||
|
||||
@Output()
|
||||
added = new EventEmitter()
|
||||
|
||||
private customFields: PaperlessCustomField[] = []
|
||||
public unusedFields: PaperlessCustomField[]
|
||||
|
||||
public name: string
|
||||
|
||||
public field: number
|
||||
|
||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||
|
||||
get placeholderText(): string {
|
||||
return $localize`Choose field`
|
||||
}
|
||||
|
||||
constructor(
|
||||
private customFieldsService: CustomFieldsService,
|
||||
private modalService: NgbModal,
|
||||
private toastService: ToastService
|
||||
) {
|
||||
this.getFields()
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.unsubscribeNotifier.next(this)
|
||||
this.unsubscribeNotifier.complete()
|
||||
}
|
||||
|
||||
private getFields() {
|
||||
this.customFieldsService
|
||||
.listAll()
|
||||
.pipe(first(), takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe((result) => {
|
||||
this.customFields = result.results
|
||||
this.updateUnusedFields()
|
||||
})
|
||||
}
|
||||
|
||||
private updateUnusedFields() {
|
||||
this.unusedFields = this.customFields.filter(
|
||||
(f) => !this.existingFields.find((e) => e.id === f.id)
|
||||
)
|
||||
}
|
||||
|
||||
onOpenClose() {
|
||||
this.field = undefined
|
||||
this.updateUnusedFields()
|
||||
}
|
||||
|
||||
addField() {
|
||||
this.added.emit(this.customFields.find((f) => f.id === this.field))
|
||||
}
|
||||
|
||||
createField() {
|
||||
const modal = this.modalService.open(CustomFieldEditDialogComponent)
|
||||
modal.componentInstance.succeeded
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe((newField) => {
|
||||
this.toastService.showInfo($localize`Saved field "${newField.name}".`)
|
||||
this.customFieldsService.clearCache()
|
||||
this.getFields()
|
||||
})
|
||||
modal.componentInstance.failed
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe((e) => {
|
||||
this.toastService.showError($localize`Error saving field.`, e)
|
||||
})
|
||||
}
|
||||
}
|
@ -48,6 +48,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<pngx-custom-fields-dropdown
|
||||
[documentId]="documentId"
|
||||
[disabled]="!userIsOwner"
|
||||
[existingFields]="customFields"
|
||||
(added)="addField($event)">
|
||||
</pngx-custom-fields-dropdown>
|
||||
|
||||
<pngx-share-links-dropdown [documentId]="documentId" [disabled]="!userIsOwner" *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.ShareLink }"></pngx-share-links-dropdown>
|
||||
|
||||
<button type="button" class="btn btn-sm btn-outline-primary me-2" i18n-title title="Close" (click)="close()">
|
||||
@ -93,9 +100,12 @@
|
||||
<pngx-input-select [items]="storagePaths" i18n-title title="Storage path" formControlName="storage_path" [allowNull]="true" [showFilter]="true" [horizontal]="true" (filterDocuments)="filterDocuments($event)"
|
||||
(createNew)="createStoragePath($event)" [suggestions]="suggestions?.storage_paths" i18n-placeholder placeholder="Default" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.StoragePath }"></pngx-input-select>
|
||||
<pngx-input-tags formControlName="tags" [suggestions]="suggestions?.tags" [showFilter]="true" [horizontal]="true" (filterDocuments)="filterDocuments($event)" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.Tag }"></pngx-input-tags>
|
||||
<ng-container *ngFor="let field of customFields">
|
||||
<pngx-input-text [formControlName]="'custom-field-' + field.id" *ngIf="field.type === PaperlessCustomFieldDataType.String" [title]="field.name" [horizontal]="true"></pngx-input-text>
|
||||
<pngx-input-date [formControlName]="'custom-field-' + field.id" *ngIf="field.type === PaperlessCustomFieldDataType.Date" [title]="field.name" [horizontal]="true"></pngx-input-date>
|
||||
<ng-container *ngFor="let field of customFields; let i = index">
|
||||
<div [formGroup]="customFieldFormFields.controls[i]">
|
||||
<pngx-input-text formControlName="value" *ngIf="field.data_type === PaperlessCustomFieldDataType.String" [title]="field.name" [horizontal]="true"></pngx-input-text>
|
||||
<pngx-input-date formControlName="value" *ngIf="field.data_type === PaperlessCustomFieldDataType.Date" [title]="field.name" [horizontal]="true"></pngx-input-date>
|
||||
<pngx-input-number formControlName="value" *ngIf="field.data_type === PaperlessCustomFieldDataType.Integer" [title]="field.name" [horizontal]="true" [showAdd]="false"></pngx-input-number>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'
|
||||
import { FormControl, FormGroup } from '@angular/forms'
|
||||
import { FormArray, FormControl, FormGroup } from '@angular/forms'
|
||||
import { ActivatedRoute, Router } from '@angular/router'
|
||||
import {
|
||||
NgbDateStruct,
|
||||
@ -124,6 +124,7 @@ export class DocumentDetailComponent
|
||||
archive_serial_number: new FormControl(),
|
||||
tags: new FormControl([]),
|
||||
permissions_form: new FormControl(null),
|
||||
custom_fields: new FormArray([]),
|
||||
})
|
||||
|
||||
previewCurrentPage: number = 1
|
||||
@ -140,7 +141,7 @@ export class DocumentDetailComponent
|
||||
ogDate: Date
|
||||
|
||||
public readonly PaperlessCustomFieldDataType = PaperlessCustomFieldDataType
|
||||
customFields: PaperlessCustomField[]
|
||||
customFields: PaperlessCustomField[] = []
|
||||
|
||||
@ViewChild('nav') nav: NgbNav
|
||||
@ViewChild('pdfPreview') set pdfPreview(element) {
|
||||
@ -173,8 +174,7 @@ export class DocumentDetailComponent
|
||||
private storagePathService: StoragePathService,
|
||||
private permissionsService: PermissionsService,
|
||||
private userService: UserService,
|
||||
private http: HttpClient,
|
||||
private customFieldsService: CustomFieldsService
|
||||
private http: HttpClient
|
||||
) {
|
||||
super()
|
||||
}
|
||||
@ -332,6 +332,7 @@ export class DocumentDetailComponent
|
||||
owner: doc.owner,
|
||||
set_permissions: doc.permissions,
|
||||
},
|
||||
custom_fields: doc.custom_fields,
|
||||
})
|
||||
|
||||
this.isDirty$ = dirtyCheck(
|
||||
@ -393,29 +394,7 @@ export class DocumentDetailComponent
|
||||
updateComponent(doc: PaperlessDocument) {
|
||||
this.document = doc
|
||||
this.requiresPassword = false
|
||||
// TODO: Custom fields
|
||||
// this.customFieldsService
|
||||
// .getFields(doc.id)
|
||||
// .pipe(first())
|
||||
// .subscribe({
|
||||
// next: (fields) => {
|
||||
// this.customFields = fields
|
||||
// this.customFields.forEach((field) => {
|
||||
// this.documentForm.addControl(
|
||||
// `custom-field-${field.id}`,
|
||||
// new FormControl(field.data)
|
||||
// )
|
||||
// })
|
||||
// this.store.next(this.documentForm.value)
|
||||
// console.log(fields)
|
||||
// },
|
||||
// error: (error) => {
|
||||
// this.toastService.showError(
|
||||
// $localize`Error retrieving custom fields`,
|
||||
// error
|
||||
// )
|
||||
// },
|
||||
// })
|
||||
this.updateFormForCustomFields()
|
||||
this.documentsService
|
||||
.getMetadata(doc.id)
|
||||
.pipe(first())
|
||||
@ -464,6 +443,22 @@ export class DocumentDetailComponent
|
||||
if (!this.userCanEdit) this.documentForm.disable()
|
||||
}
|
||||
|
||||
get customFieldFormFields(): FormArray {
|
||||
return this.documentForm.get('custom_fields') as FormArray
|
||||
}
|
||||
|
||||
updateFormForCustomFields() {
|
||||
this.customFieldFormFields.clear()
|
||||
this.customFields.forEach((field) => {
|
||||
this.customFieldFormFields.push(
|
||||
new FormGroup({
|
||||
parent: new FormControl(field.id),
|
||||
value: new FormControl(null),
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
createDocumentType(newName: string) {
|
||||
var modal = this.modalService.open(DocumentTypeEditDialogComponent, {
|
||||
backdrop: 'static',
|
||||
@ -543,11 +538,8 @@ export class DocumentDetailComponent
|
||||
this.title = doc.title
|
||||
this.documentForm.patchValue(doc)
|
||||
// TODO: custom field reset
|
||||
// this.customFields.forEach((field) => {
|
||||
// this.documentForm
|
||||
// .get(`custom-field-${field.id}`)
|
||||
// .patchValue(field.data)
|
||||
// })
|
||||
this.customFields = doc.custom_fields
|
||||
this.updateFormForCustomFields()
|
||||
this.openDocumentService.setDirty(doc, false)
|
||||
},
|
||||
error: () => {
|
||||
@ -856,4 +848,9 @@ export class DocumentDetailComponent
|
||||
|
||||
this.documentListViewService.quickFilter(filterRules)
|
||||
}
|
||||
|
||||
addField(field: PaperlessCustomField) {
|
||||
this.customFields.push(field)
|
||||
this.updateFormForCustomFields()
|
||||
}
|
||||
}
|
||||
|
7
src-ui/src/app/data/paperless-custom-field-instance.ts
Normal file
7
src-ui/src/app/data/paperless-custom-field-instance.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { ObjectWithId } from './object-with-id'
|
||||
|
||||
export interface PaperlessCustomFieldInstance extends ObjectWithId {
|
||||
document: number // PaperlessDocument
|
||||
field: number // PaperlessCustomField
|
||||
created: Date
|
||||
}
|
@ -5,6 +5,7 @@ import { Observable } from 'rxjs'
|
||||
import { PaperlessStoragePath } from './paperless-storage-path'
|
||||
import { ObjectWithPermissions } from './object-with-permissions'
|
||||
import { PaperlessDocumentNote } from './paperless-document-note'
|
||||
import { PaperlessCustomField } from './paperless-custom-field'
|
||||
|
||||
export interface SearchHit {
|
||||
score?: number
|
||||
@ -58,4 +59,6 @@ export interface PaperlessDocument extends ObjectWithPermissions {
|
||||
notes?: PaperlessDocumentNote[]
|
||||
|
||||
__search_hit__?: SearchHit
|
||||
|
||||
custom_fields?: PaperlessCustomField[]
|
||||
}
|
||||
|
@ -256,6 +256,10 @@ describe('PermissionsService', () => {
|
||||
'view_consumptiontemplate',
|
||||
'change_consumptiontemplate',
|
||||
'delete_consumptiontemplate',
|
||||
'add_customfield',
|
||||
'view_customfield',
|
||||
'change_customfield',
|
||||
'delete_customfield',
|
||||
],
|
||||
{
|
||||
username: 'testuser',
|
||||
|
14
src-ui/src/app/services/rest/custom-fields.service.spec.ts
Normal file
14
src-ui/src/app/services/rest/custom-fields.service.spec.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { HttpTestingController } from '@angular/common/http/testing'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { commonAbstractPaperlessServiceTests } from './abstract-paperless-service.spec'
|
||||
import { CustomFieldsService } from './custom-fields.service'
|
||||
|
||||
let httpTestingController: HttpTestingController
|
||||
let service: CustomFieldsService
|
||||
let subscription: Subscription
|
||||
const endpoint = 'custom_fields'
|
||||
|
||||
// run common tests
|
||||
commonAbstractPaperlessServiceTests(endpoint, CustomFieldsService)
|
@ -3,6 +3,7 @@ import { HttpClient, HttpParams } from '@angular/common/http'
|
||||
import { AbstractPaperlessService } from './abstract-paperless-service'
|
||||
import { Observable } from 'rxjs'
|
||||
import { PaperlessCustomField } from 'src/app/data/paperless-custom-field'
|
||||
import { PaperlessCustomFieldInstance } from 'src/app/data/paperless-custom-field-instance'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@ -11,30 +12,4 @@ export class CustomFieldsService extends AbstractPaperlessService<PaperlessCusto
|
||||
constructor(http: HttpClient) {
|
||||
super(http, 'custom_fields')
|
||||
}
|
||||
|
||||
// getFields(documentId: number): Observable<PaperlessCustomField[]> {
|
||||
// return this.http.get<PaperlessCustomField[]>(
|
||||
// this.getResourceUrl(documentId, 'custom_fields')
|
||||
// )
|
||||
// }
|
||||
|
||||
// addField(
|
||||
// documentId: number,
|
||||
// field: PaperlessCustomField
|
||||
// ): Observable<PaperlessCustomField[]> {
|
||||
// return this.http.post<PaperlessCustomField[]>(
|
||||
// this.getResourceUrl(documentId, 'custom_fields'),
|
||||
// field
|
||||
// )
|
||||
// }
|
||||
|
||||
// deleteField(
|
||||
// documentId: number,
|
||||
// fieldId: number
|
||||
// ): Observable<PaperlessCustomField[]> {
|
||||
// return this.http.delete<PaperlessCustomField[]>(
|
||||
// this.getResourceUrl(documentId, 'custom_metadata'),
|
||||
// { params: new HttpParams({ fromString: `id=${fieldId}` }) }
|
||||
// )
|
||||
// }
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user