Frontend version info updates, checksum

This commit is contained in:
shamoon
2026-02-10 09:43:15 -08:00
parent 224a873de2
commit 9ca80af42f
4 changed files with 67 additions and 28 deletions

View File

@@ -1,25 +1,46 @@
<pngx-page-header [(title)]="title" [id]="documentId"> <pngx-page-header [(title)]="title" [id]="documentId">
@if (document?.versions?.length > 0) { @if (document?.versions?.length > 0) {
<div class="btn-group" ngbDropdown role="group"> <div class="btn-group" ngbDropdown role="group" autoClose="outside">
<div class="btn-group" ngbDropdown role="group"> <button class="btn btn-sm btn-outline-secondary dropdown-toggle" ngbDropdownToggle>
<button class="btn btn-sm btn-outline-secondary dropdown-toggle" ngbDropdownToggle [disabled]="!hasVersions"> <i-bs name="layers"></i-bs>
<i-bs name="layers"></i-bs> <span class="d-none d-lg-inline ps-1" i18n>Version</span>
<span class="d-none d-lg-inline ps-1" i18n>Version</span>
</button>
<div class="dropdown-menu shadow" ngbDropdownMenu>
@for (vid of document.versions; track vid) {
<button ngbDropdownItem (click)="selectVersion(vid)">
<span i18n>Version</span> {{vid}}
@if (selectedVersionId === vid) { <span>&nbsp;</span> }
</button>
}
</div>
</div>
<input #versionFileInput type="file" class="visually-hidden" (change)="onVersionFileSelected($event)" />
<button class="btn btn-sm btn-outline-secondary" title="Upload new version" i18n-title (click)="versionFileInput.click()" [disabled]="!userIsOwner || !userCanEdit">
<i-bs name="file-earmark-plus"></i-bs><span class="visually-hidden" i18n>Upload new version</span>
</button> </button>
<div class="dropdown-menu shadow" ngbDropdownMenu>
<div class="px-3 py-2">
<div class="input-group input-group-sm mb-2">
<span class="input-group-text" i18n>Label</span>
<input class="form-control" type="text" [(ngModel)]="newVersionLabel" i18n-placeholder placeholder="Optional" [disabled]="!userIsOwner || !userCanEdit" />
</div>
<input #versionFileInput type="file" class="visually-hidden" (change)="onVersionFileSelected($event)" />
<button class="btn btn-sm btn-outline-secondary w-100" (click)="versionFileInput.click()" [disabled]="!userIsOwner || !userCanEdit">
<i-bs name="file-earmark-plus"></i-bs><span class="ps-1" i18n>Add new version</span>
</button>
</div>
<div class="dropdown-divider"></div>
@for (version of document.versions; track version.id) {
<button ngbDropdownItem (click)="selectVersion(version.id)">
<div class="d-flex align-items-center w-100 version-item">
<span class="badge bg-light text-lowercase text-muted">
{{ version.checksum | slice:0:8 }}
</span>
<div class="flex-grow-1 ms-3 small">
<div class="small">
@if (version.label) {
{{ version.label }}
} @else {
<span i18n>ID</span> #{{version.id}}
}
</div>
<div class="version-subtitle text-muted">
{{ version.added | customDate:'short' }}
</div>
</div>
@if (selectedVersionId === version.id) { <span class="ms-2"></span> }
</div>
</button>
}
</div>
</div> </div>
} }
@if (archiveContentRenderType === ContentRenderType.PDF && !useNativePdfViewer) { @if (archiveContentRenderType === ContentRenderType.PDF && !useNativePdfViewer) {

View File

@@ -1,4 +1,4 @@
import { AsyncPipe, NgTemplateOutlet } from '@angular/common' import { AsyncPipe, NgTemplateOutlet, SlicePipe } from '@angular/common'
import { HttpClient, HttpResponse } from '@angular/common/http' import { HttpClient, HttpResponse } from '@angular/common/http'
import { Component, inject, OnDestroy, OnInit, ViewChild } from '@angular/core' import { Component, inject, OnDestroy, OnInit, ViewChild } from '@angular/core'
import { import {
@@ -36,7 +36,7 @@ import { Correspondent } from 'src/app/data/correspondent'
import { CustomField, CustomFieldDataType } from 'src/app/data/custom-field' import { CustomField, CustomFieldDataType } from 'src/app/data/custom-field'
import { CustomFieldInstance } from 'src/app/data/custom-field-instance' import { CustomFieldInstance } from 'src/app/data/custom-field-instance'
import { DataType } from 'src/app/data/datatype' import { DataType } from 'src/app/data/datatype'
import { Document } from 'src/app/data/document' import { Document, DocumentVersionInfo } from 'src/app/data/document'
import { DocumentMetadata } from 'src/app/data/document-metadata' import { DocumentMetadata } from 'src/app/data/document-metadata'
import { DocumentNote } from 'src/app/data/document-note' import { DocumentNote } from 'src/app/data/document-note'
import { DocumentSuggestions } from 'src/app/data/document-suggestions' import { DocumentSuggestions } from 'src/app/data/document-suggestions'
@@ -176,6 +176,7 @@ enum ContentRenderType {
TextAreaComponent, TextAreaComponent,
RouterModule, RouterModule,
PngxPdfViewerComponent, PngxPdfViewerComponent,
SlicePipe,
], ],
}) })
export class DocumentDetailComponent export class DocumentDetailComponent
@@ -230,6 +231,7 @@ export class DocumentDetailComponent
thumbUrl: string thumbUrl: string
// Versioning: which document ID to use for file preview/download // Versioning: which document ID to use for file preview/download
selectedVersionId: number selectedVersionId: number
newVersionLabel: string = ''
previewText: string previewText: string
previewLoaded: boolean = false previewLoaded: boolean = false
tiffURL: string tiffURL: string
@@ -673,8 +675,9 @@ export class DocumentDetailComponent
updateComponent(doc: Document) { updateComponent(doc: Document) {
this.document = doc this.document = doc
// Default selected version is the newest version // Default selected version is the newest version
this.selectedVersionId = doc.versions?.length const versions = doc.versions ?? []
? Math.max(...doc.versions) this.selectedVersionId = versions.length
? Math.max(...versions.map((version) => version.id))
: doc.id : doc.id
this.requiresPassword = false this.requiresPassword = false
this.updateFormForCustomFields() this.updateFormForCustomFields()
@@ -734,8 +737,12 @@ export class DocumentDetailComponent
} }
} }
get hasVersions(): boolean { getVersionBadge(version: DocumentVersionInfo): string {
return this.document?.versions?.length > 1 console.log(version)
const checksum = version?.checksum ?? ''
if (!checksum) return '----'
return checksum.slice(0, 4).toUpperCase()
} }
// Update file preview and download target to a specific version (by document id) // Update file preview and download target to a specific version (by document id)
@@ -1186,14 +1193,16 @@ export class DocumentDetailComponent
const file = input.files[0] const file = input.files[0]
// Reset input to allow re-selection of the same file later // Reset input to allow re-selection of the same file later
input.value = '' input.value = ''
const label = this.newVersionLabel?.trim()
this.documentsService this.documentsService
.uploadVersion(this.documentId, file) .uploadVersion(this.documentId, file, label)
.pipe(first()) .pipe(first())
.subscribe({ .subscribe({
next: () => { next: () => {
this.toastService.showInfo( this.toastService.showInfo(
$localize`Uploading new version. Processing will happen in the background.` $localize`Uploading new version. Processing will happen in the background.`
) )
this.newVersionLabel = ''
// Refresh metadata to reflect that versions changed (when ready) // Refresh metadata to reflect that versions changed (when ready)
this.openDocumentService.refreshDocument(this.documentId) this.openDocumentService.refreshDocument(this.documentId)
}, },

View File

@@ -159,12 +159,19 @@ export interface Document extends ObjectWithPermissions {
page_count?: number page_count?: number
duplicate_documents?: Document[]
// Versioning // Versioning
head_version?: number head_version?: number
versions?: number[] versions?: DocumentVersionInfo[]
duplicate_documents?: Document[]
// Frontend only // Frontend only
__changedFields?: string[] __changedFields?: string[]
} }
export interface DocumentVersionInfo {
id: number
added?: Date
label?: string
checksum?: string
}

View File

@@ -1066,6 +1066,7 @@ class DocumentVersionInfoSerializer(serializers.Serializer):
id = serializers.IntegerField() id = serializers.IntegerField()
added = serializers.DateTimeField() added = serializers.DateTimeField()
label = serializers.CharField(required=False, allow_null=True) label = serializers.CharField(required=False, allow_null=True)
checksum = serializers.CharField(required=False, allow_null=True)
@extend_schema_serializer( @extend_schema_serializer(
@@ -1139,6 +1140,7 @@ class DocumentSerializer(
"id": doc.id, "id": doc.id,
"added": doc.added, "added": doc.added,
"label": doc.version_label, "label": doc.version_label,
"checksum": doc.checksum,
} }
info = [build_info(doc) for doc in versions] info = [build_info(doc) for doc in versions]