Blank out display fields for better backwards compatibility

This commit is contained in:
shamoon 2024-04-19 00:57:37 -07:00
parent 9a2d30cb33
commit 0e1ab79773
9 changed files with 110 additions and 57 deletions

View File

@ -1,6 +1,6 @@
<div class="d-flex flex-row mt-2 align-items-center">
{{title}}:
<div class="ms-2 d-flex flex-row gap-2 w-100"
<span class="me-2">{{title}}:</span>
<div class="d-flex flex-row gap-2 w-100 mh-1" style="min-height: 1em;"
cdkDropList #selectedList="cdkDropList"
cdkDropListOrientation="horizontal"
(cdkDropListDropped)="drop($event)"
@ -11,7 +11,7 @@
</div>
</div>
<div class="d-flex flex-row mt-2 align-items-center bg-light p-2">
<div class="d-flex flex-row gap-2 w-100"
<div class="d-flex flex-row gap-2 w-100 mh-1" style="min-height: 1em;"
cdkDropList #unselectedList="cdkDropList"
cdkDropListOrientation="horizontal"
(cdkDropListDropped)="drop($event)"

View File

@ -32,6 +32,9 @@ describe('DragDropSelectComponent', () => {
{ id: '2', name: 'Item 2' },
{ id: '3', name: 'Item 3' },
])
component.writeValue(null)
expect(component.selectedItems).toEqual([])
})
it('should update selectedItems when an item is dropped within selectedList', () => {

View File

@ -34,9 +34,8 @@ export class DragDropSelectComponent extends AbstractInputComponent<string[]> {
writeValue(newValue: string[]): void {
super.writeValue(newValue)
this.selectedItems = newValue.map((id) =>
this.items.find((i) => i.id === id)
)
this.selectedItems =
newValue?.map((id) => this.items.find((i) => i.id === id)) ?? []
}
public drop(event: CdkDragDrop<string[]>) {

View File

@ -9,19 +9,19 @@
<a class="btn-link text-decoration-none" header-buttons [routerLink]="[]" (click)="showAll()" i18n>Show all</a>
}
@if (documents.length && (!savedView.display_mode || savedView.display_mode === DashboardViewMode.TABLE)) {
@if (documents.length && displayMode === DisplayMode.TABLE) {
<table content class="table table-hover mb-0 mt-n2 align-middle">
<thead>
<tr>
@for (column of savedView.display_fields; track column; let i = $index) {
@if (activeDisplayFields.includes(column)) {
@for (field of displayFields; track field; let i = $index) {
@if (displayFields.includes(field)) {
<th
scope="col"
[ngClass]="{
'd-none d-md-table-cell': i > 1,
'w-25': column === DashboardViewTableColumn.CREATED || column === DashboardViewTableColumn.ADDED
'w-25': field === DisplayField.CREATED || field === DisplayField.ADDED
}">
{{ getColumnTitle(column) }}
{{ getColumnTitle(field) }}
</th>
}
}
@ -30,44 +30,44 @@
<tbody>
@for (doc of documents; track doc.id) {
<tr>
@for (column of savedView.display_fields; track column; let i = $index) {
@if (activeDisplayFields.includes(column)) {
@for (field of displayFields; track field; let i = $index) {
@if (displayFields.includes(field)) {
<td class="py-2 py-md-3 position-relative" [ngClass]="{ 'd-none d-md-table-cell': i > 1 }">
@switch (column) {
@case (DashboardViewTableColumn.ADDED) {
@switch (field) {
@case (DisplayField.ADDED) {
<a routerLink="/documents/{{doc.id}}" class="btn-link text-dark text-decoration-none py-2 py-md-3">{{doc.added | customDate}}</a>
}
@case (DashboardViewTableColumn.CREATED) {
@case (DisplayField.CREATED) {
<a routerLink="/documents/{{doc.id}}" class="btn-link text-dark text-decoration-none py-2 py-md-3">{{doc.created_date | customDate}}</a>
}
@case (DashboardViewTableColumn.TITLE) {
@case (DisplayField.TITLE) {
<a routerLink="/documents/{{doc.id}}" title="Edit" i18n-title class="btn-link text-dark text-decoration-none py-2 py-md-3">{{doc.title | documentTitle}}</a>
}
@case (DashboardViewTableColumn.CORRESPONDENT) {
@case (DisplayField.CORRESPONDENT) {
@if (doc.correspondent) {
<a class="btn-link text-dark text-decoration-none" type="button" (click)="clickCorrespondent(doc.correspondent, $event)">{{(doc.correspondent$ | async)?.name}}</a>
}
}
@case (DashboardViewTableColumn.TAGS) {
@case (DisplayField.TAGS) {
@for (t of doc.tags$ | async; track t) {
<pngx-tag [tag]="t" class="ms-1" (click)="clickTag(t.id, $event)"></pngx-tag>
}
}
@case (DashboardViewTableColumn.DOCUMENT_TYPE) {
@case (DisplayField.DOCUMENT_TYPE) {
@if (doc.document_type) {
<a class="btn-link text-dark text-decoration-none" type="button" (click)="clickDocType(doc.document_type, $event)">{{(doc.document_type$ | async)?.name}}</a>
}
}
@case (DashboardViewTableColumn.STORAGE_PATH) {
@case (DisplayField.STORAGE_PATH) {
@if (doc.storage_path) {
<a class="btn-link text-dark text-decoration-none" type="button" (click)="clickStoragePath(doc.storage_path, $event)">{{(doc.storage_path$ | async)?.name}}</a>
}
}
}
@if (column.startsWith(DashboardViewTableColumn.CUSTOM_FIELD)) {
<pngx-custom-field-display [document]="doc" [fieldDisplayKey]="column"></pngx-custom-field-display>
@if (field.startsWith(DisplayField.CUSTOM_FIELD)) {
<pngx-custom-field-display [document]="doc" [fieldDisplayKey]="field"></pngx-custom-field-display>
}
@if (i === savedView.display_fields.length - 1) {
@if (i === displayFields.length - 1) {
<div class="btn-group position-absolute top-50 end-0 translate-middle-y">
<a [href]="getPreviewUrl(doc)" title="View Preview" i18n-title target="_blank" class="btn px-4 btn-dark border-dark-subtle"
[ngbPopover]="previewContent" [popoverTitle]="doc.title | documentTitle"
@ -89,14 +89,14 @@
}
</tbody>
</table>
} @else if (documents.length && savedView.display_mode === DashboardViewMode.SMALL_CARDS) {
} @else if (documents.length && displayMode === DisplayMode.SMALL_CARDS) {
<div class="row row-cols-paperless-cards my-n2">
@for (d of documents; track d.id) {
<pngx-document-card-small
class="p-0"
(dblClickDocument)="openDocumentDetail(d)"
[document]="d"
[displayFields]="activeDisplayFields"
[displayFields]="displayFields"
(clickTag)="clickTag($event)"
(clickCorrespondent)="clickCorrespondent($event)"
(clickStoragePath)="clickStoragePath($event)"
@ -104,13 +104,13 @@
</pngx-document-card-small>
}
</div>
} @else if (documents.length && savedView.display_mode === DashboardViewMode.LARGE_CARDS) {
} @else if (documents.length && displayMode === DisplayMode.LARGE_CARDS) {
<div class="row my-n2">
@for (d of documents; track d.id) {
<pngx-document-card-large
(dblClickDocument)="openDocumentDetail(d)"
[document]="d"
[displayFields]="activeDisplayFields"
[displayFields]="displayFields"
(clickTag)="clickTag($event)"
(clickCorrespondent)="clickCorrespondent($event)"
(clickStoragePath)="clickStoragePath($event)"

View File

@ -342,4 +342,39 @@ describe('SavedViewWidgetComponent', () => {
'Storage path'
)
})
it('should hide fields if no perms', () => {
fixture = TestBed.createComponent(SavedViewWidgetComponent)
component = fixture.componentInstance
component.savedView = {
sort_field: 'added',
sort_reverse: true,
show_in_sidebar: true,
show_on_dashboard: true,
filter_rules: [],
display_fields: [DisplayField.TITLE, 'foo' as any, 'bar' as any],
}
component.ngOnInit()
expect(component.displayFields).toEqual([DisplayField.TITLE])
})
it('should use fallback display settings', () => {
fixture = TestBed.createComponent(SavedViewWidgetComponent)
component = fixture.componentInstance
component.savedView = {
sort_field: 'added',
sort_reverse: true,
show_in_sidebar: true,
show_on_dashboard: true,
filter_rules: [],
}
component.ngOnInit()
expect(component.displayMode).toEqual(DisplayMode.TABLE)
expect(component.displayFields).toEqual([
DisplayField.CREATED,
DisplayField.TITLE,
DisplayField.TAGS,
DisplayField.CORRESPONDENT,
])
})
})

View File

@ -46,8 +46,8 @@ export class SavedViewWidgetComponent
extends ComponentWithPermissions
implements OnInit, OnDestroy
{
public DashboardViewMode = DisplayMode
public DashboardViewTableColumn = DisplayField
public DisplayMode = DisplayMode
public DisplayField = DisplayField
public CustomFieldDataType = CustomFieldDataType
loading: boolean = true
@ -80,14 +80,18 @@ export class SavedViewWidgetComponent
mouseOnPreview = false
popoverHidden = true
activeDisplayFields: DisplayField[] = [
DisplayField.TITLE,
displayMode: DisplayMode
displayFields: DisplayField[] = [
DisplayField.CREATED,
DisplayField.ADDED,
DisplayField.TITLE,
DisplayField.TAGS,
DisplayField.CORRESPONDENT,
]
ngOnInit(): void {
this.reload()
this.displayMode = this.savedView.display_mode ?? DisplayMode.TABLE
this.consumerStatusService
.onDocumentConsumptionFinished()
.pipe(takeUntil(this.unsubscribeNotifier))
@ -109,19 +113,32 @@ export class SavedViewWidgetComponent
})
}
this.savedView.display_fields?.forEach((column) => {
let type: PermissionType = Object.values(PermissionType).find((t) =>
t.includes(column)
)
if (column.startsWith(DisplayField.CUSTOM_FIELD)) {
type = PermissionType.CustomField
}
if (
type &&
this.permissionsService.currentUserCan(PermissionAction.View, type)
)
this.activeDisplayFields.push(column)
})
if (this.savedView.display_fields) {
this.displayFields = this.savedView.display_fields
?.map((field) => {
if (
[
DisplayField.TITLE,
DisplayField.CREATED,
DisplayField.ADDED,
].includes(field)
) {
return field
}
let type: PermissionType = Object.values(PermissionType).find((t) =>
t.includes(field)
)
if (field.startsWith(DisplayField.CUSTOM_FIELD)) {
type = PermissionType.CustomField
}
return type &&
this.permissionsService.currentUserCan(PermissionAction.View, type)
? field
: null
})
.filter((f) => f)
}
}
ngOnDestroy(): void {

View File

@ -102,9 +102,11 @@ export class DocumentListComponent
this.unmodifiedSavedView.sort_reverse !== this.list.sortReverse ||
(this.unmodifiedSavedView.page_size &&
this.unmodifiedSavedView.page_size !== this.list.pageSize) ||
this.unmodifiedSavedView.display_mode !== this.list.displayMode ||
this.unmodifiedSavedView.display_fields.join(',') !==
this.activeDisplayFields.join(',') ||
(this.unmodifiedSavedView.display_mode &&
this.unmodifiedSavedView.display_mode !== this.list.displayMode) ||
(this.unmodifiedSavedView.display_fields &&
this.unmodifiedSavedView.display_fields.join(',') !==
this.activeDisplayFields.join(',')) ||
filterRulesDiffer(
this.unmodifiedSavedView.filter_rules,
this.list.filterRules
@ -190,12 +192,6 @@ export class DocumentListComponent
})
return
}
if (!view.display_mode) {
view.display_mode = this.list.displayMode
}
if (!view.display_fields) {
view.display_fields = this.list.displayFields
}
this.unmodifiedSavedView = view
this.list.activateSavedViewWithQueryParams(
view,

View File

@ -42,6 +42,7 @@ class Migration(migrations.Migration):
model_name="savedview",
name="display_fields",
field=multiselectfield.db.fields.MultiSelectField(
blank=True,
choices=[
("title", "Title"),
("created", "Created"),
@ -51,8 +52,9 @@ class Migration(migrations.Migration):
("correspondent", "Correspondent"),
("storagepath", "Storage Path"),
],
default="created,title,tag,correspondent",
max_length=128,
null=True,
verbose_name="Document display fields",
),
),
]

View File

@ -606,7 +606,8 @@ class SavedView(ModelWithOwner):
verbose_name=_("Document display fields"),
choices=DisplayFields.choices,
dyanmic_choices=[DynamicDisplayFields.CUSTOM_FIELD],
default=f"{DisplayFields.CREATED},{DisplayFields.TITLE},{DisplayFields.TAGS},{DisplayFields.CORRESPONDENT}",
null=True,
blank=True,
)
class Meta: