From b3106e408c203a7ef5e4bfe32907897b9ecf5298 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Tue, 20 Oct 2026 09:44:37 -0700 Subject: [PATCH] Lots of enum cleanup --- ...emplate-editor-zone-list.component.spec.ts | 12 ++- ...ocr-template-editor-zone-list.component.ts | 18 ++-- .../ocr-template-editor.component.html | 2 +- .../ocr-template-editor.component.spec.ts | 17 ++-- .../ocr-template-editor.component.ts | 28 +++--- .../ocr-template-editor/zone-geometry.spec.ts | 10 ++- src-ui/src/app/data/ocr-template.ts | 89 +++++++------------ 7 files changed, 79 insertions(+), 97 deletions(-) diff --git a/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor-zone-list/ocr-template-editor-zone-list.component.spec.ts b/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor-zone-list/ocr-template-editor-zone-list.component.spec.ts index b3bec5999..32a21b0c8 100644 --- a/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor-zone-list/ocr-template-editor-zone-list.component.spec.ts +++ b/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor-zone-list/ocr-template-editor-zone-list.component.spec.ts @@ -1,13 +1,17 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons' import { CustomField } from 'src/app/data/custom-field' -import { OcrTemplateZone } from 'src/app/data/ocr-template' +import { + OcrTemplateZone, + OcrZoneTarget, + OcrZoneTransform, +} from 'src/app/data/ocr-template' import { OcrTemplateEditorZoneListComponent } from './ocr-template-editor-zone-list.component' function zone(overrides: Partial = {}): OcrTemplateZone { return { name: 'Zone 1', - target: 'custom_field', + target: OcrZoneTarget.CustomField, custom_field: 7, x: 10, y: 20, @@ -15,7 +19,7 @@ function zone(overrides: Partial = {}): OcrTemplateZone { height: 40, page: 1, ocr_language: 'eng', - transform: 'strip', + transform: OcrZoneTransform.Strip, validation_regex: '', order: 0, ...overrides, @@ -76,7 +80,7 @@ describe('OcrTemplateEditorZoneListComponent', () => { it('warns only for zones without a field and clears the warning when assigned', () => { component.zones = [ zone({ custom_field: null }), - zone({ target: 'title', custom_field: null }), + zone({ target: OcrZoneTarget.Title, custom_field: null }), zone(), ] fixture.detectChanges() diff --git a/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor-zone-list/ocr-template-editor-zone-list.component.ts b/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor-zone-list/ocr-template-editor-zone-list.component.ts index 82ce69bf2..c94bf0968 100644 --- a/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor-zone-list/ocr-template-editor-zone-list.component.ts +++ b/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor-zone-list/ocr-template-editor-zone-list.component.ts @@ -5,6 +5,7 @@ import { getZoneFieldKey, OCR_BUILTIN_TARGETS, OcrTemplateZone, + OcrZoneTarget, } from 'src/app/data/ocr-template' import { getZoneColor } from '../zone-geometry' @@ -35,18 +36,15 @@ export class OcrTemplateEditorZoneListComponent { } getZoneTargetName(zone: OcrTemplateZone): string { - const target = zone.target || 'custom_field' - if (target === 'custom_field') { - return zone.custom_field - ? this.getCustomFieldName(zone.custom_field) - : $localize`(no field)` + if (zone.target === OcrZoneTarget.CustomField) { + return ( + this.customFields.find((field) => field.id === zone.custom_field) + ?.name ?? '' + ) } - return OCR_BUILTIN_TARGETS.find((t) => t.id === target)?.name ?? target - } - - private getCustomFieldName(id: number): string { return ( - this.customFields.find((field) => field.id === id)?.name ?? `Field #${id}` + OCR_BUILTIN_TARGETS.find((target) => target.id === zone.target)?.name ?? + '' ) } } diff --git a/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor.component.html b/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor.component.html index 9f31477ba..24652fc99 100644 --- a/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor.component.html +++ b/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor.component.html @@ -129,7 +129,7 @@ - @if (zone.transform === dateTransform) { + @if (zone.transform === OcrZoneTransform.Date) { { succeeded.next(created) expect(component.template.zones[0]).toMatchObject({ - target: 'custom_field', + target: OcrZoneTarget.CustomField, custom_field: 5, }) expect(component.fieldItems().map((item) => item.id)).toEqual([ - 'title', - 'asn', - 'created', + OcrZoneTarget.Title, + OcrZoneTarget.Asn, + OcrZoneTarget.Created, 5, ]) }) @@ -470,7 +473,7 @@ describe('OcrTemplateEditorComponent', () => { const titleZone = { ...zone(), name: 'First', - target: 'title' as const, + target: OcrZoneTarget.Title, custom_field: null, } component.template.combine_formats = { title: '{First} / {Second}' } @@ -579,7 +582,7 @@ describe('OcrTemplateEditorComponent', () => { component.testZone() expect(component.zoneTestResult?.value).toBe('123') - selected.transform = 'numeric' + selected.transform = OcrZoneTransform.Numeric expect(component.zoneTestResult).toBeNull() component.testZone() selected.width++ diff --git a/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor.component.ts b/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor.component.ts index d66e54270..a59ced798 100644 --- a/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor.component.ts +++ b/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor.component.ts @@ -48,18 +48,14 @@ import { DocumentType } from 'src/app/data/document-type' import { DATE_FORMAT_OPTIONS, DEFAULT_OCR_ZONE_LANGUAGE, - DEFAULT_OCR_ZONE_TARGET, - DEFAULT_OCR_ZONE_TRANSFORM, getZoneFieldKey, - isOcrBuiltinTarget, OCR_BUILTIN_TARGETS, OCR_LANGUAGE_OPTIONS, OCR_SUPPORTED_FIELD_TYPES, - OCR_ZONE_TARGET, - OCR_ZONE_TRANSFORM, - OcrBuiltinTarget, OcrTemplate, OcrTemplateZone, + OcrZoneTarget, + OcrZoneTransform, OcrZoneTestResult, TRANSFORM_OPTIONS, ZoneTestRequest, @@ -91,7 +87,7 @@ import { } from './zone-geometry' type ActiveTab = 'settings' | 'zones' -type ZoneFieldSelection = OcrBuiltinTarget | number | null +type ZoneFieldSelection = OcrZoneTarget | number | null type OverlayInteraction = | { kind: 'idle' } | { kind: 'drawing'; pointerId: number; rect: DrawingRect } @@ -201,7 +197,7 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy { readonly documentTypes = signal([]) transformOptions = TRANSFORM_OPTIONS ocrLanguageOptions = OCR_LANGUAGE_OPTIONS - dateTransform = OCR_ZONE_TRANSFORM.Date + readonly OcrZoneTransform = OcrZoneTransform noSampleDocumentTitle = $localize`Select a sample document to test this zone` dateFormatItems = [ ...DATE_FORMAT_OPTIONS, @@ -610,7 +606,7 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy { const imageSize = this.imageNaturalSize() return { name: `Zone ${this.template.zones.length + 1}`, - target: DEFAULT_OCR_ZONE_TARGET, + target: OcrZoneTarget.CustomField, custom_field: null, x: rect.x, y: rect.y, @@ -618,7 +614,7 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy { height: rect.h, page: this.previewPageDisplay, ocr_language: DEFAULT_OCR_ZONE_LANGUAGE, - transform: DEFAULT_OCR_ZONE_TRANSFORM, + transform: OcrZoneTransform.Strip, date_format: '', validation_regex: '', order: this.template.zones.length, @@ -889,18 +885,20 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy { zone.ocr_language = (langs ?? []).join('+') } + /** The field select's value: a built-in target, or a custom field id. */ zoneFieldValue(zone: OcrTemplateZone): ZoneFieldSelection { - const target = zone.target || DEFAULT_OCR_ZONE_TARGET - return target === OCR_ZONE_TARGET.CustomField ? zone.custom_field : target + return zone.target === OcrZoneTarget.CustomField + ? zone.custom_field + : zone.target } setZoneField(zone: OcrTemplateZone, value: ZoneFieldSelection) { - if (isOcrBuiltinTarget(value)) { + if (typeof value === 'string') { zone.target = value zone.custom_field = null } else { - zone.target = OCR_ZONE_TARGET.CustomField - zone.custom_field = typeof value === 'number' ? value : null + zone.target = OcrZoneTarget.CustomField + zone.custom_field = value } } diff --git a/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/zone-geometry.spec.ts b/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/zone-geometry.spec.ts index 161416b94..573e426e4 100644 --- a/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/zone-geometry.spec.ts +++ b/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/zone-geometry.spec.ts @@ -1,4 +1,8 @@ -import { OcrTemplateZone } from 'src/app/data/ocr-template' +import { + OcrTemplateZone, + OcrZoneTarget, + OcrZoneTransform, +} from 'src/app/data/ocr-template' import { findHandleAt, findZoneAt, @@ -13,7 +17,7 @@ import { function zone(overrides: Partial = {}): OcrTemplateZone { return { name: 'Zone', - target: 'custom_field', + target: OcrZoneTarget.CustomField, custom_field: 1, x: 100, y: 200, @@ -21,7 +25,7 @@ function zone(overrides: Partial = {}): OcrTemplateZone { height: 400, page: 1, ocr_language: 'eng', - transform: 'strip', + transform: OcrZoneTransform.Strip, validation_regex: '', order: 0, ...overrides, diff --git a/src-ui/src/app/data/ocr-template.ts b/src-ui/src/app/data/ocr-template.ts index 778755e07..453dd262d 100644 --- a/src-ui/src/app/data/ocr-template.ts +++ b/src-ui/src/app/data/ocr-template.ts @@ -1,55 +1,30 @@ import { CustomFieldDataType } from './custom-field' import { ObjectWithId } from './object-with-id' -export type OcrZoneTarget = 'custom_field' | 'title' | 'asn' | 'created' -export type OcrBuiltinTarget = Exclude -export type OcrZoneTransform = - | 'none' - | 'strip' - | 'uppercase' - | 'lowercase' - | 'numeric' - | 'strip_punctuation' - | 'date' - | 'qr_code' - -export const OCR_ZONE_TARGET = { - CustomField: 'custom_field', - Title: 'title', - Asn: 'asn', - Created: 'created', -} as const satisfies Record - -export const OCR_ZONE_TRANSFORM = { - None: 'none', - Strip: 'strip', - Uppercase: 'uppercase', - Lowercase: 'lowercase', - Numeric: 'numeric', - StripPunctuation: 'strip_punctuation', - Date: 'date', - QrCode: 'qr_code', -} as const satisfies Record - -export const DEFAULT_OCR_ZONE_TARGET = OCR_ZONE_TARGET.CustomField -export const DEFAULT_OCR_ZONE_TRANSFORM = OCR_ZONE_TRANSFORM.Strip -export const DEFAULT_OCR_ZONE_LANGUAGE = 'deu+eng' - -export function isOcrBuiltinTarget(value: unknown): value is OcrBuiltinTarget { - return ( - value === OCR_ZONE_TARGET.Title || - value === OCR_ZONE_TARGET.Asn || - value === OCR_ZONE_TARGET.Created - ) +export enum OcrZoneTarget { + CustomField = 'custom_field', + Title = 'title', + Asn = 'asn', + Created = 'created', } +export enum OcrZoneTransform { + None = 'none', + Strip = 'strip', + Uppercase = 'uppercase', + Lowercase = 'lowercase', + Numeric = 'numeric', + StripPunctuation = 'strip_punctuation', + Date = 'date', + QrCode = 'qr_code', +} + +export const DEFAULT_OCR_ZONE_LANGUAGE = 'deu+eng' + /** The field a zone writes to, keyed by OcrTemplate.combine_formats. */ export function getZoneFieldKey(zone: OcrTemplateZone): string | null { - const target = zone.target || DEFAULT_OCR_ZONE_TARGET - if (target !== OCR_ZONE_TARGET.CustomField) return target - return zone.custom_field === null || zone.custom_field === undefined - ? null - : String(zone.custom_field) + if (zone.target !== OcrZoneTarget.CustomField) return zone.target + return zone.custom_field === null ? null : String(zone.custom_field) } /** Custom field types zone OCR can write to. See models.py OCR_SUPPORTED_FIELD_TYPES. */ @@ -65,15 +40,15 @@ export const OCR_SUPPORTED_FIELD_TYPES: CustomFieldDataType[] = [ ] export const OCR_BUILTIN_TARGETS = [ - { id: OCR_ZONE_TARGET.Title, name: $localize`Title` }, - { id: OCR_ZONE_TARGET.Asn, name: $localize`Archive serial number` }, - { id: OCR_ZONE_TARGET.Created, name: $localize`Date created` }, + { id: OcrZoneTarget.Title, name: $localize`Title` }, + { id: OcrZoneTarget.Asn, name: $localize`Archive serial number` }, + { id: OcrZoneTarget.Created, name: $localize`Date created` }, ] export interface OcrTemplateZone { id?: number name: string - target?: OcrZoneTarget + target: OcrZoneTarget custom_field: number | null page?: number x: number @@ -90,17 +65,17 @@ export interface OcrTemplateZone { } export const TRANSFORM_OPTIONS = [ - { id: OCR_ZONE_TRANSFORM.None, name: $localize`None` }, - { id: OCR_ZONE_TRANSFORM.Strip, name: $localize`Strip whitespace` }, - { id: OCR_ZONE_TRANSFORM.Uppercase, name: $localize`Uppercase` }, - { id: OCR_ZONE_TRANSFORM.Lowercase, name: $localize`Lowercase` }, - { id: OCR_ZONE_TRANSFORM.Numeric, name: $localize`Numeric only` }, + { id: OcrZoneTransform.None, name: $localize`None` }, + { id: OcrZoneTransform.Strip, name: $localize`Strip whitespace` }, + { id: OcrZoneTransform.Uppercase, name: $localize`Uppercase` }, + { id: OcrZoneTransform.Lowercase, name: $localize`Lowercase` }, + { id: OcrZoneTransform.Numeric, name: $localize`Numeric only` }, { - id: OCR_ZONE_TRANSFORM.StripPunctuation, + id: OcrZoneTransform.StripPunctuation, name: $localize`Remove leading/trailing punctuation`, }, - { id: OCR_ZONE_TRANSFORM.Date, name: $localize`Parse date` }, - { id: OCR_ZONE_TRANSFORM.QrCode, name: $localize`Read QR/barcode` }, + { id: OcrZoneTransform.Date, name: $localize`Parse date` }, + { id: OcrZoneTransform.QrCode, name: $localize`Read QR/barcode` }, ] export const OCR_LANGUAGE_OPTIONS = [