From 1d75c0c99bc414c18a2038f0f21caceced5862a1 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Mon, 19 Oct 2026 22:31:33 -0700 Subject: [PATCH] Use pngx inputs, move test button, generally make less terrible --- .../ocr-template-editor.component.html | 301 ++++++++---------- .../ocr-template-editor.component.ts | 67 ++-- 2 files changed, 170 insertions(+), 198 deletions(-) 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 38a02d65f..a460b7dcc 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 @@ -34,62 +34,88 @@ Zones {{ template.zones.length }} @if (selectedZone; as zone) { -
- - +
-
- - -
+ @if (zoneTestResult; as result) { + @if (result.error) { + + } @else { +
+
OCR text
+
{{ result.raw_text || '(nothing detected)' }}
+
Value
+
{{ result.value || '(empty)' }}
+ @if (result.regex) { +
Validation
+
+ @if (result.regex_match) { + Regex matches + } @else { + Regex does not match + } +
+ } +
+ } + } -
- - - Page this zone is on. Use -1 for the last page. Set automatically when you draw it. -
+ -
- -
- - + + + @if (showQuickCreate) { +
+
+
Create Custom Field
+
+ + +
+
+ + +
+
+ + +
+
- Write the extracted value to a custom field, or to a built-in field (Title, ASN, Date created). -
+ } @if (isFieldShared(zone)) {
@@ -132,141 +158,62 @@
} - @if (showQuickCreate) { -
-
-
Create Custom Field
-
- - -
-
- - -
-
- - -
-
-
- } - -
- - -
- -
- - +
+
+ +
+
Processing
+ + + + + @if (zone.transform === dateTransform) { -
- - - @if (usesCustomDateFormat(zone)) { -
- - -
- -

Python date codes:

-
    -
  • %d day (01-31)
  • -
  • %m month (01-12)
  • -
  • %Y year, 4-digit
  • -
  • %y year, 2-digit
  • -
  • %b month name (Jan)
  • -
- Example: %d.%m.%Y -> 03.03.2026 -
- } -
- } - -
- - -
- -
- {{ zone.x }}, {{ zone.y }} - {{ zone.width }}x{{ zone.height }}px -
- -
-
Test
- @if (!previewDocId) { -

- No sample document selected. -

- } @else { - - @if (zoneTestResult; as result) { - @if (result.error) { - - } @else { -
-
OCR text
-
{{ result.raw_text || '(nothing detected)' }}
-
Value
-
{{ result.value || '(empty)' }}
- @if (result.regex) { -
Validation
-
- @if (result.regex_match) { - Regex matches - } @else { - Regex does not match - } -
- } -
- } + + @if (usesCustomDateFormat(zone)) { +
+ + +
+ +

Python date codes:

+ + Example: %d.%m.%Y -> 03.03.2026 +
} } + + } @else { = { standalone: true, imports: [ PageHeaderComponent, + NumberComponent, TextComponent, SelectComponent, SwitchComponent, @@ -140,7 +141,6 @@ const RESIZE_CURSOR: Record = { NgbNavModule, NgbPopoverModule, NgbTypeaheadModule, - NgSelectModule, NgxBootstrapIconsModule, OcrTemplateEditorZoneListComponent, ], @@ -191,7 +191,23 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy { zones: [], } - customFields: CustomField[] = [] + private _customFields: CustomField[] = [] + /** Items for the zone field select: built-in targets, then custom fields. */ + fieldItems: { id: ZoneFieldSelection; name: string }[] = [ + ...OCR_BUILTIN_TARGETS, + ] + + get customFields(): CustomField[] { + return this._customFields + } + + set customFields(fields: CustomField[]) { + this._customFields = fields + this.fieldItems = [ + ...OCR_BUILTIN_TARGETS, + ...fields.map((cf) => ({ id: cf.id, name: cf.name })), + ] + } documentTypes: DocumentType[] = [] transformOptions = TRANSFORM_OPTIONS builtinTargets = OCR_BUILTIN_TARGETS @@ -199,6 +215,11 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy { ocrLanguageOptions = OCR_LANGUAGE_OPTIONS dateTransform = OCR_ZONE_TRANSFORM.Date customDateFormatChoice = CUSTOM_DATE_FORMAT_CHOICE + noSampleDocumentTitle = $localize`Select a sample document to test this zone` + dateFormatItems = [ + ...DATE_FORMAT_OPTIONS, + { id: CUSTOM_DATE_FORMAT_CHOICE, name: $localize`Custom...` }, + ] isNew = true saving = false @@ -231,18 +252,18 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy { overlayMode: OverlayMode = 'select' overlayCursor = 'default' - private zoneTest: ZoneTest | null = null + private readonly zoneTest = signal(null) get imageLoaded(): boolean { return this.previewStatus === 'ready' } get zoneTestResult(): OcrZoneTestResult | null { - return this.isCurrentZoneTest() ? this.zoneTest.result : null + return this.isCurrentZoneTest() ? this.zoneTest().result : null } get zoneTesting(): boolean { - return this.isCurrentZoneTest() && this.zoneTest.result === null + return this.isCurrentZoneTest() && this.zoneTest().result === null } showQuickCreate = false @@ -454,6 +475,14 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy { return getZonePage(zone, this.previewPage, this.previewPageCount) } + isLastPageZone(zone: OcrTemplateZone): boolean { + return zone.page === -1 + } + + setLastPageZone(zone: OcrTemplateZone, lastPage: boolean) { + zone.page = lastPage ? -1 : this.previewPage + 1 + } + private isOnCurrentPage(zone: OcrTemplateZone): boolean { return isZoneOnPage(zone, this.previewPage, this.previewPageCount) } @@ -835,31 +864,27 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy { request: this.zoneTestRequest(zone), result: null, } - this.zoneTest = test + this.zoneTest.set(test) this.templateService .testZone(test.documentId, test.request) .pipe(takeUntil(this.destroy$), takeUntil(this.cancelZoneTest$)) .subscribe({ - next: (res) => { - test.result = res - this.changeDetector.markForCheck() - }, - error: (err) => { - test.result = { - error: err.error?.error || $localize`Test failed`, - } - this.changeDetector.markForCheck() - }, + next: (res) => this.zoneTest.set({ ...test, result: res }), + error: (err) => + this.zoneTest.set({ + ...test, + result: { error: err.error?.error || $localize`Test failed` }, + }), }) } private clearZoneTest() { this.cancelZoneTest$.next() - this.zoneTest = null + this.zoneTest.set(null) } private isCurrentZoneTest(): boolean { - const test = this.zoneTest + const test = this.zoneTest() if ( !test || test.zone !== this.selectedZone || @@ -1067,10 +1092,10 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy { return dt ? dt.name : `Type #${id}` } - openQuickCreate(zoneIndex: number | null) { + openQuickCreate(zoneIndex: number | null, name?: string) { if (zoneIndex === null) return this.quickCreateForZoneIndex = zoneIndex - this.quickCreateName = this.template.zones[zoneIndex]?.name || '' + this.quickCreateName = name || this.template.zones[zoneIndex]?.name || '' this.quickCreateType = CustomFieldDataType.String this.showQuickCreate = true }