-
-
-
- {{ zone.name }}
-
+
No zones yet. Use Draw to outline one on the sample document.
+} @else {
+
+ @for (zone of zones; track $index; let i = $index) {
+
+
+
+
+
{{ getZoneTargetName(zone) }}
-
- {{ getZoneTargetName(zone) }} - {{ zone.width }}x{{ zone.height }}px
- p.{{ zonePage(zone) }}
-
-
-
-
-
-
- }
-
+ }
+
+}
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 a7895fcee..a9e41d1fe 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
@@ -41,19 +41,19 @@ describe('OcrTemplateEditorZoneListComponent', () => {
it('shows empty state when no zones are defined', () => {
fixture.detectChanges()
- expect(fixture.nativeElement.textContent).toContain('No zones defined')
+ expect(fixture.nativeElement.textContent).toContain('No zones yet')
})
- it('renders zone target, size, and page', () => {
- component.zones = [zone()]
+ it('renders zone name, target, and page', () => {
+ component.zones = [zone(), zone({ name: 'Zone 2', page: -1 })]
component.customFields = [{ id: 7, name: 'Invoice Number' } as CustomField]
fixture.detectChanges()
const text = fixture.nativeElement.textContent
expect(text).toContain('Zone 1')
expect(text).toContain('Invoice Number')
- expect(text).toContain('30x40px')
- expect(text).toContain('p.1')
+ expect(text).toContain('Page 1')
+ expect(text).toContain('Last page')
})
it('emits select and remove events', () => {
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 0a633842c..9867e1d10 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
@@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import { CustomField } from 'src/app/data/custom-field'
import { OCR_BUILTIN_TARGETS, OcrTemplateZone } from 'src/app/data/ocr-template'
-import { getZonePage } from '../zone-geometry'
+import { getZoneColor } from '../zone-geometry'
@Component({
selector: 'pngx-ocr-template-zone-list',
@@ -11,17 +11,12 @@ import { getZonePage } from '../zone-geometry'
})
export class OcrTemplateEditorZoneListComponent {
@Input() zones: OcrTemplateZone[] = []
- @Input() selectedZoneIndex: number | null = null
- @Input() previewPage = 0
- @Input() previewPageCount: number | null = null
@Input() customFields: CustomField[] = []
@Output() zoneSelected = new EventEmitter
()
@Output() zoneRemoved = new EventEmitter()
- zonePage(zone: OcrTemplateZone): number {
- return getZonePage(zone, this.previewPage, this.previewPageCount)
- }
+ readonly zoneColor = getZoneColor
getZoneTargetName(zone: OcrTemplateZone): string {
const target = zone.target || 'custom_field'
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 235a9af1d..92ba66fb3 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
@@ -187,9 +187,6 @@
} @else {
= {
nw: 'nw-resize',
ne: 'ne-resize',
@@ -738,7 +729,7 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy {
}
zoneColor(index: number): string {
- return ZONE_COLORS[index % ZONE_COLORS.length]
+ return getZoneColor(index)
}
zoneFill(index: number): string {
@@ -960,11 +951,6 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy {
})
}
- getCustomFieldName(id: number): string {
- const cf = this.customFields.find((f) => f.id === id)
- return cf ? cf.name : `Field #${id}`
- }
-
/** Value bound to the field select: a built-in id string or a custom-field id. */
zoneFieldValue(zone: OcrTemplateZone): ZoneFieldSelection {
const target = zone.target || DEFAULT_OCR_ZONE_TARGET
@@ -1069,16 +1055,6 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy {
)
}
- getZoneTargetName(zone: OcrTemplateZone): string {
- const target = zone.target || DEFAULT_OCR_ZONE_TARGET
- if (target === OCR_ZONE_TARGET.CustomField) {
- return zone.custom_field
- ? this.getCustomFieldName(zone.custom_field)
- : $localize`(no field)`
- }
- return this.builtinTargets.find((t) => t.id === target)?.name ?? target
- }
-
getDocumentTypeName(id: number): string {
const dt = this.documentTypes.find((d) => d.id === id)
return dt ? dt.name : `Type #${id}`
diff --git a/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/zone-geometry.ts b/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/zone-geometry.ts
index 489dd58ba..8d6ff220b 100644
--- a/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/zone-geometry.ts
+++ b/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/zone-geometry.ts
@@ -36,6 +36,22 @@ export type ResizeHandle = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw'
export const HANDLE_SIZE = 8
export const MIN_ZONE_SIZE = 10
+const ZONE_COLORS = [
+ '#4f8ff7',
+ '#ff6b6b',
+ '#51cf66',
+ '#ffd43b',
+ '#cc5de8',
+ '#ff922b',
+ '#20c997',
+ '#e599f7',
+]
+
+/** Outline color for a zone, shared by the preview overlay and the zone list. */
+export function getZoneColor(index: number): string {
+ return ZONE_COLORS[index % ZONE_COLORS.length]
+}
+
export function getZonePage(
zone: OcrTemplateZone,
previewPage: number,