fix:create-document

This commit is contained in:
hungdztrau123
2024-05-31 09:08:28 +07:00
parent 0d76578906
commit 640d8b1c28
43 changed files with 470 additions and 208 deletions

View File

@@ -1,8 +0,0 @@
@if (tag === undefined) {
@if (!clickable) {
<span class="badge private" i18n>Private</span>
}
@if (clickable) {
<a [title]="linkTitle" class="badge private" i18n>Private</a>
}
}

View File

@@ -1,13 +0,0 @@
a {
cursor: pointer;
white-space: normal;
word-break: break-word;
text-align: end;
}
.private {
background-color: #000000;
color: #ffffff;
opacity: .5;
font-style: italic;
}

View File

@@ -1,45 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { WarehouseComponent } from './warehouse.component'
import { Warehouse } from 'src/app/data/warehouse'
import { By } from '@angular/platform-browser'
const warehouse: Warehouse = {
id: 1,
type: 'Warehouse',
name: 'Warehouse1',
parent_warehouse: null,
}
describe('WarehouseComponent', () => {
let component: WarehouseComponent
let fixture: ComponentFixture<WarehouseComponent>
beforeEach(async () => {
TestBed.configureTestingModule({
declarations: [WarehouseComponent],
providers: [],
imports: [],
}).compileComponents()
fixture = TestBed.createComponent(WarehouseComponent)
component = fixture.componentInstance
fixture.detectChanges()
})
it('should handle private warehouses', () => {
expect(
fixture.debugElement.query(By.css('span')).nativeElement.textContent
).toEqual('Private')
})
it('should support clickable option', () => {
component.warehouse = warehouse
fixture.detectChanges()
expect(fixture.debugElement.query(By.css('a.badge'))).toBeNull()
component.clickable = true
fixture.detectChanges()
expect(fixture.debugElement.query(By.css('a.badge'))).not.toBeNull()
})
})

View File

@@ -1,20 +0,0 @@
import { Component, Input } from '@angular/core'
import { Warehouse } from 'src/app/data/warehouse'
@Component({
selector: 'pngx-warehouse',
templateUrl: './warehouse.component.html',
styleUrls: ['./warehouse.component.scss'],
})
export class WarehouseComponent {
constructor() {}
@Input()
warehouse: Warehouse
@Input()
linkTitle: string = ''
@Input()
clickable: boolean = false
}

View File

@@ -111,7 +111,7 @@
(createNew)="createDocumentType($event)" [suggestions]="suggestions?.document_types" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.DocumentType }"></pngx-input-select>
<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-select [items]="warehouses" i18n-title title="Warehouse" formControlName="warehouses" [allowNull]="true" [showFilter]="true" [horizontal]="true" (filterDocuments)="filterDocuments($event)"
<pngx-input-select [items]="warehouses" i18n-title title="Warehouse" formControlName="warehouse" [allowNull]="true" [showFilter]="true" [horizontal]="true" (filterDocuments)="filterDocuments($event)"
(createNew)="createWarehouse($event)" [suggestions]="suggestions?.warehouses" i18n-placeholder placeholder="Default" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.Warehouse }"></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>
@for (fieldInstance of document?.custom_fields; track fieldInstance; let i = $index) {

View File

@@ -148,7 +148,7 @@ export class DocumentDetailComponent
correspondent: new FormControl(),
document_type: new FormControl(),
storage_path: new FormControl(),
warehouses: new FormControl(),
warehouse: new FormControl(),
archive_serial_number: new FormControl(),
tags: new FormControl([]),
permissions_form: new FormControl(null),
@@ -271,6 +271,17 @@ export class DocumentDetailComponent
.pipe(first(), takeUntil(this.unsubscribeNotifier))
.subscribe((result) => (this.correspondents = result.results))
}
if (
this.permissionsService.currentUserCan(
PermissionAction.View,
PermissionType.Warehouse
)
) {
this.warehouseService
.listAll()
.pipe(first(), takeUntil(this.unsubscribeNotifier))
.subscribe((result) => (this.warehouses = result.results))
}
if (
this.permissionsService.currentUserCan(
PermissionAction.View,
@@ -293,17 +304,6 @@ export class DocumentDetailComponent
.pipe(first(), takeUntil(this.unsubscribeNotifier))
.subscribe((result) => (this.storagePaths = result.results))
}
if (
this.permissionsService.currentUserCan(
PermissionAction.View,
PermissionType.Warehouse
)
) {
this.warehouseService
.listAll()
.pipe(first(), takeUntil(this.unsubscribeNotifier))
.subscribe((result) => (this.warehouses = result.results))
}
if (
this.permissionsService.currentUserCan(
PermissionAction.View,
@@ -427,7 +427,7 @@ export class DocumentDetailComponent
correspondent: doc.correspondent,
document_type: doc.document_type,
storage_path: doc.storage_path,
warehouses: doc.warehouses,
warehouse: doc.warehouse,
archive_serial_number: doc.archive_serial_number,
tags: [...doc.tags],
permissions_form: {
@@ -639,7 +639,7 @@ export class DocumentDetailComponent
.pipe(takeUntil(this.unsubscribeNotifier))
.subscribe(({ newWarehouse, warehouses }) => {
this.warehouses = warehouses.results
this.documentForm.get('warehouses').setValue(newWarehouse.id)
this.documentForm.get('warehouse').setValue(newWarehouse.id)
})
}

View File

@@ -75,7 +75,7 @@
</pngx-filterable-dropdown>
}
@if (permissionService.currentUserCan(PermissionAction.View, PermissionType.Warehouse)) {
<pngx-filterable-dropdown title="Warehouses" icon="warehouse-fill" i18n-title
<pngx-filterable-dropdown title="Warehouse" icon="warehouse-fill" i18n-title
filterPlaceholder="Filter warehouses" i18n-filterPlaceholder
[items]="warehouses"
[disabled]="!userCanEditAll"
@@ -83,7 +83,7 @@
[manyToOne]="true"
[applyOnClose]="applyOnClose"
[createRef]="createWarehouse.bind(this)"
(opened)="openWarehousesDropdown()"
(opened)="openWarehouseDropdown()"
[(selectionModel)]="warehouseSelectionModel"
[documentCounts]="warehouseDocumentCounts"
(apply)="setWarehouses($event)">

View File

@@ -65,7 +65,7 @@ export class BulkEditorComponent
correspondentSelectionModel = new FilterableDropdownSelectionModel()
documentTypeSelectionModel = new FilterableDropdownSelectionModel()
storagePathsSelectionModel = new FilterableDropdownSelectionModel()
warehousesSelectionModel = new FilterableDropdownSelectionModel()
warehouseSelectionModel = new FilterableDropdownSelectionModel()
tagDocumentCounts: SelectionDataItem[]
correspondentDocumentCounts: SelectionDataItem[]
documentTypeDocumentCounts: SelectionDataItem[]
@@ -324,7 +324,7 @@ export class BulkEditorComponent
this.warehouseDocumentCounts = s.selected_warehouses
this.applySelectionData(
s.selected_warehouses,
this.warehousesSelectionModel
this.warehouseSelectionModel
)
})
}
@@ -609,6 +609,27 @@ export class BulkEditorComponent
})
}
createWarehouse(name: string) {
let modal = this.modalService.open(WarehouseEditDialogComponent, {
backdrop: 'static',
})
modal.componentInstance.dialogMode = EditDialogMode.CREATE
modal.componentInstance.object = { name }
modal.componentInstance.succeeded
.pipe(
switchMap((newWarehouse) => {
return this.warehouseService
.listAll()
.pipe(map((warehouses) => ({ newWarehouse, warehouses })))
})
)
.pipe(takeUntil(this.unsubscribeNotifier))
.subscribe(({ newWarehouse, warehouses }) => {
this.warehouses = warehouses.results
this.warehouseSelectionModel.toggle(newWarehouse.id)
})
}
createDocumentType(name: string) {
let modal = this.modalService.open(DocumentTypeEditDialogComponent, {
backdrop: 'static',
@@ -651,26 +672,6 @@ export class BulkEditorComponent
})
}
createWarehouse(name: string) {
let modal = this.modalService.open(WarehouseEditDialogComponent, {
backdrop: 'static',
})
modal.componentInstance.dialogMode = EditDialogMode.CREATE
modal.componentInstance.object = { name }
modal.componentInstance.succeeded
.pipe(
switchMap((newWarehouse) => {
return this.warehouseService
.listAll()
.pipe(map((warehouses) => ({ newWarehouse, warehouses })))
})
)
.pipe(takeUntil(this.unsubscribeNotifier))
.subscribe(({ newWarehouse, warehouses }) => {
this.warehouses = warehouses.results
this.warehousesSelectionModel.toggle(newWarehouse.id)
})
}
applyDelete() {
let modal = this.modalService.open(ConfirmDialogComponent, {

View File

@@ -83,10 +83,10 @@
<i-bs width=".9em" height=".9em" class="me-2 text-muted" name="archive"></i-bs><small>{{(document.storage_path$ | async)?.name}}</small>
</button>
}
@if (document.warehouses) {
@if (document.warehouse) {
<button type="button" class="list-group-item btn btn-sm bg-light text-dark p-1 border-0 me-2 d-flex align-items-center" title="Filter by warehouse" i18n-title
(click)="clickWarehouse.emit(document.warehouses);$event.stopPropagation()">
<i-bs width=".9em" height=".9em" class="me-2 text-muted" name="archive"></i-bs><small>{{(document.warehouses$ | async)?.name}}</small>
(click)="clickWarehouse.emit(document.warehouse);$event.stopPropagation()">
<i-bs width=".9em" height=".9em" class="me-2 text-muted" name="archive"></i-bs><small>{{(document.warehouse$ | async)?.name}}</small>
</button>
}
@if (document.archive_serial_number | isNumber) {

View File

@@ -47,15 +47,15 @@ export class DocumentCardLargeComponent extends ComponentWithPermissions {
@Output()
clickCorrespondent = new EventEmitter<number>()
@Output()
clickWarehouse = new EventEmitter<number>()
@Output()
clickDocumentType = new EventEmitter<number>()
@Output()
clickStoragePath = new EventEmitter<number>()
@Output()
clickWarehouse = new EventEmitter<number>()
@Output()
clickMoreLike = new EventEmitter()

View File

@@ -54,11 +54,11 @@
<small>{{(document.storage_path$ | async)?.name ?? privateName}}</small>
</button>
}
@if (document.warehouses) {
@if (document.warehouse) {
<button type="button" class="list-group-item list-group-item-action bg-transparent ps-0 p-1 border-0" title="Toggle warehouse filter" i18n-title
(click)="clickWarehouse.emit(document.warehouses);$event.stopPropagation()">
(click)="clickWarehouse.emit(document.warehouse);$event.stopPropagation()">
<i-bs width="1em" height="1em" class="me-2 text-muted" name="folder"></i-bs>
<small>{{(document.warehouses$ | async)?.name ?? privateName}}</small>
<small>{{(document.warehouse$ | async)?.name ?? privateName}}</small>
</button>
}
<div class="list-group-item bg-transparent p-0 border-0 d-flex flex-wrap-reverse justify-content-between">

View File

@@ -125,7 +125,7 @@
@if (displayMode === 'largeCards') {
<div>
@for (d of list.documents; track trackByDocumentId($index, d)) {
<pngx-document-card-large [selected]="list.isSelected(d)" (toggleSelected)="toggleSelected(d, $event)" (dblClickDocument)="openDocumentDetail(d)" [document]="d" (clickTag)="clickTag($event)" (clickCorrespondent)="clickCorrespondent($event)" (clickDocumentType)="clickDocumentType($event)" (clickStoragePath)="clickStoragePath($event)" (clickMoreLike)="clickMoreLike(d.id)">
<pngx-document-card-large [selected]="list.isSelected(d)" (toggleSelected)="toggleSelected(d, $event)" (dblClickDocument)="openDocumentDetail(d)" [document]="d" (clickTag)="clickTag($event)" (clickCorrespondent)="clickCorrespondent($event)" (clickDocumentType)="clickDocumentType($event)" (clickStoragePath)="clickStoragePath($event)" (clickWarehouse)="clickWarehouse($event)" (clickMoreLike)="clickMoreLike(d.id)">
</pngx-document-card-large>
}
</div>
@@ -271,8 +271,8 @@
}
@if (permissionService.currentUserCan(PermissionAction.View, PermissionType.Warehouse)) {
<td class="d-none d-xl-table-cell">
@if (d.warehouses) {
<a (click)="clickWarehouse(d.warehouses);$event.stopPropagation()" title="Filter by warehouse" i18n-title>{{(d.warehouses$ | async)?.name}}</a>
@if (d.warehouse) {
<a (click)="clickWarehouse(d.warehouse);$event.stopPropagation()" title="Filter by warehouse" i18n-title>{{(d.warehouse$ | async)?.name}}</a>
}
</td>
}

View File

@@ -263,6 +263,9 @@ describe('FilterEditorComponent', () => {
httpTestingController.expectNone(
`${environment.apiBaseUrl}documents/storage_paths/`
)
httpTestingController.expectNone(
`${environment.apiBaseUrl}documents/warehouses/`
)
})
// SET filterRules
@@ -1807,6 +1810,10 @@ describe('FilterEditorComponent', () => {
{ id: 32, document_count: 1 },
{ id: 33, document_count: 0 },
],
selected_warehouses: [
{ id: 42, document_count: 1 },
{ id: 43, document_count: 0 },
],
}
})
@@ -1865,6 +1872,24 @@ describe('FilterEditorComponent', () => {
]
expect(component.generateFilterName()).toEqual('Without storage path')
component.filterRules = [
{
rule_type: FILTER_HAS_WAREHOUSE_ANY,
value: '42',
},
]
expect(component.generateFilterName()).toEqual(
`Warehouse path: ${warehouses[0].name}`
)
component.filterRules = [
{
rule_type: FILTER_WAREHOUSE,
value: null,
},
]
expect(component.generateFilterName()).toEqual('Without warehouse')
component.filterRules = [
{
rule_type: FILTER_HAS_TAGS_ALL,

View File

@@ -1,6 +1,6 @@
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 { FILTER_HAS_WAREHOUSE_ANY } from 'src/app/data/filter-rule-type'
import { Warehouse } from 'src/app/data/warehouse'
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
import {
@@ -32,7 +32,7 @@ export class WarehouseListComponent extends ManagementListComponent<Warehouse> {
toastService,
documentListViewService,
permissionsService,
FILTER_HAS_TAGS_ALL,
FILTER_HAS_WAREHOUSE_ANY,
$localize`warehouse`,
$localize`warehouses`,
PermissionType.Warehouse,

View File

@@ -29,9 +29,9 @@ export interface Document extends ObjectWithPermissions {
storage_path?: number
warehouses$?: Observable<Warehouse>
warehouse$?: Observable<Warehouse>
warehouses?: number
warehouse?: number
title?: string

View File

@@ -114,20 +114,20 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [
},
{
id: FILTER_WAREHOUSE,
filtervar: 'warehouses__id',
isnull_filtervar: 'warehouses__isnull',
filtervar: 'warehouse__id',
isnull_filtervar: 'warehouse__isnull',
datatype: 'warehouse',
multi: false,
},
{
id: FILTER_HAS_WAREHOUSE_ANY,
filtervar: 'warehouses__id__in',
filtervar: 'warehouse__id__in',
datatype: 'warehouse',
multi: true,
},
{
id: FILTER_DOES_NOT_HAVE_WAREHOUSE,
filtervar: 'warehouses__id__none',
filtervar: 'warehouse__id__none',
datatype: 'warehouse',
multi: true,
},

View File

@@ -67,6 +67,8 @@ export interface MailRule extends ObjectWithPermissions {
assign_document_type?: number // PaperlessDocumentType.id
assign_warehouse?: number // PaperlessWarehouse.id
assign_correspondent_from?: MailMetadataCorrespondentOption
assign_correspondent?: number // PaperlessCorrespondent.id

View File

@@ -5,4 +5,6 @@ export interface Warehouse extends MatchingModel {
type?: string
parent_warehouse?: number
path?: string
}

View File

@@ -17,7 +17,7 @@ export interface WorkflowAction extends ObjectWithId {
assign_storage_path?: number // StoragePath.id
assign_warehouses?: number // Warehouse.id
assign_warehouse?: number // Warehouse.id
assign_owner?: number // User.id

View File

@@ -34,4 +34,7 @@ export interface WorkflowTrigger extends ObjectWithId {
filter_has_correspondent?: number // Correspondent.id
filter_has_document_type?: number // DocumentType.id
filter_has_warehouse?: number // Warehouse.id
}

View File

@@ -29,6 +29,7 @@ const documents = [
correspondent: 11,
document_type: 3,
storage_path: 8,
warehouse: 14,
},
{
id: 2,

View File

@@ -20,6 +20,7 @@ const documents = [
correspondent: 11,
document_type: 3,
storage_path: 8,
warehouse: 14,
},
{
id: 2,

View File

@@ -138,6 +138,7 @@ describe('PermissionsService', () => {
'view_savedview',
'view_uisettings',
'delete_storagepath',
'delete_warehouse',
'delete_frontendsettings',
'change_paperlesstask',
'view_taskresult',
@@ -185,6 +186,7 @@ describe('PermissionsService', () => {
'delete_document',
'change_uisettings',
'change_storagepath',
'change_warehouse',
'change_document',
'delete_tokenproxy',
'change_note',
@@ -210,6 +212,7 @@ describe('PermissionsService', () => {
'change_tag',
'change_chordcounter',
'add_storagepath',
'add_warehouse',
'delete_group',
'add_taskattributes',
'delete_mailaccount',
@@ -240,6 +243,7 @@ describe('PermissionsService', () => {
'delete_taskresult',
'view_contenttype',
'view_storagepath',
'view_warehouse',
'add_permission',
'change_userobjectpermission',
'delete_savedviewfilterrule',

View File

@@ -24,6 +24,7 @@ const documents = [
correspondent: 11,
document_type: 3,
storage_path: 8,
warehouse: 14,
},
{
id: 2,
@@ -225,6 +226,7 @@ describe(`DocumentService`, () => {
expect(doc.document_type$).not.toBeNull()
expect(doc.tags$).not.toBeNull()
expect(doc.storage_path$).not.toBeNull()
expect(doc.warehouse$).not.toBeNull()
})
httpTestingController
.expectOne(

View File

@@ -28,7 +28,7 @@ export const DOCUMENT_SORT_FIELDS = [
{ field: 'correspondent__name', name: $localize`Correspondent` },
{ field: 'title', name: $localize`Title` },
{ field: 'document_type__name', name: $localize`Document type` },
{ field: 'warehouses__name', name: $localize`Warehouse` },
{ field: 'warehouse__name', name: $localize`Warehouse` },
{ field: 'created', name: $localize`Created` },
{ field: 'added', name: $localize`Added` },
{ field: 'modified', name: $localize`Modified` },
@@ -123,13 +123,13 @@ export class DocumentService extends AbstractPaperlessService<Document> {
doc.storage_path$ = this.storagePathService.getCached(doc.storage_path)
}
if (
doc.warehouses &&
doc.warehouse &&
this.permissionsService.currentUserCan(
PermissionAction.View,
PermissionType.Warehouse
)
) {
doc.warehouses$ = this.warehouseService.getCached(doc.warehouses)
doc.warehouse$ = this.warehouseService.getCached(doc.warehouse)
}
return doc
}

View File

@@ -44,6 +44,7 @@ const group = {
'view_savedview',
'view_uisettings',
'delete_storagepath',
'delete_warehouse',
'delete_frontendsettings',
'change_paperlesstask',
'view_taskresult',
@@ -91,6 +92,7 @@ const group = {
'delete_document',
'change_uisettings',
'change_storagepath',
'change_warehouse',
'change_document',
'delete_tokenproxy',
'change_note',
@@ -116,6 +118,7 @@ const group = {
'change_tag',
'change_chordcounter',
'add_storagepath',
'add_warehouse',
'delete_group',
'add_taskattributes',
'delete_mailaccount',
@@ -146,6 +149,7 @@ const group = {
'delete_taskresult',
'view_contenttype',
'view_storagepath',
'view_warehouse',
'add_permission',
'change_userobjectpermission',
'delete_savedviewfilterrule',