Text Extraction Done, UI Fixes Done, Extracted Template Layout Saved in DB
This commit is contained in:
162
frontend/src/app/templates/templates.component.ts
Normal file
162
frontend/src/app/templates/templates.component.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { DragDropModule, CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
|
||||
import { SplitterModule } from 'primeng/splitter';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { DialogModule } from 'primeng/dialog';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { DropdownModule } from 'primeng/dropdown';
|
||||
import { TableModule } from 'primeng/table';
|
||||
import { ToastModule } from 'primeng/toast';
|
||||
import { MessageService } from 'primeng/api';
|
||||
|
||||
import { TemplateService, DocumentLayout, TemplateField } from '../services/template.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-templates',
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
DragDropModule,
|
||||
SplitterModule,
|
||||
ButtonModule,
|
||||
DialogModule,
|
||||
InputTextModule,
|
||||
DropdownModule,
|
||||
TableModule,
|
||||
ToastModule
|
||||
],
|
||||
providers: [MessageService],
|
||||
templateUrl: './templates.component.html',
|
||||
styleUrls: ['./templates.component.scss']
|
||||
})
|
||||
export class TemplatesComponent implements OnInit {
|
||||
// Document State
|
||||
documentId: string | null = null;
|
||||
layoutNodes: DocumentLayout[] = [];
|
||||
|
||||
// Template State
|
||||
templateName: string = '';
|
||||
templateFields: TemplateField[] = [];
|
||||
mappings: { [fieldId: number]: DocumentLayout[] } = {};
|
||||
|
||||
// UI State
|
||||
displayAddField: boolean = false;
|
||||
newField: TemplateField = { field_label: '', field_type: 'TEXT', display_order: 0, required_flag: false };
|
||||
fieldTypes = [
|
||||
{ label: 'TEXT', value: 'TEXT' },
|
||||
{ label: 'NUMBER', value: 'NUMBER' },
|
||||
{ label: 'DATE', value: 'DATE' },
|
||||
{ label: 'AMOUNT', value: 'AMOUNT' },
|
||||
{ label: 'ADDRESS', value: 'ADDRESS' },
|
||||
{ label: 'TABLE_COLUMN', value: 'TABLE_COLUMN' }
|
||||
];
|
||||
|
||||
constructor(
|
||||
private templateService: TemplateService,
|
||||
private messageService: MessageService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
onFileUpload(event: any) {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
this.templateService.uploadDocument(file).subscribe({
|
||||
next: (res) => {
|
||||
this.documentId = res.id || res.pk_document_id;
|
||||
this.messageService.add({ severity: 'success', summary: 'Uploaded', detail: 'Document uploaded successfully.' });
|
||||
this.fetchLayout();
|
||||
},
|
||||
error: (err) => {
|
||||
this.messageService.add({ severity: 'error', summary: 'Error', detail: 'Upload failed.' });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fetchLayout() {
|
||||
if (!this.documentId) return;
|
||||
this.templateService.getDocumentLayout(this.documentId).subscribe({
|
||||
next: (layouts) => {
|
||||
if (layouts.length === 0) {
|
||||
// Document might still be processing in the background Celery worker
|
||||
// Poll again after 2 seconds
|
||||
setTimeout(() => this.fetchLayout(), 2000);
|
||||
return;
|
||||
}
|
||||
this.layoutNodes = layouts;
|
||||
// Trigger auto-recognition
|
||||
this.autoRecognize();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
autoRecognize() {
|
||||
if (!this.documentId) return;
|
||||
this.templateService.recognizeTemplate(this.documentId).subscribe({
|
||||
next: (res) => {
|
||||
if (res.templateMatched) {
|
||||
this.messageService.add({ severity: 'info', summary: 'Template Recognized', detail: `Confidence: ${res.confidence}%` });
|
||||
// In a full implementation, we'd load the template fields and populate the mappings.
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
showAddFieldDialog() {
|
||||
this.newField = { field_label: '', field_type: 'TEXT', display_order: this.templateFields.length, required_flag: false };
|
||||
this.displayAddField = true;
|
||||
}
|
||||
|
||||
addField() {
|
||||
if (!this.newField.field_label) return;
|
||||
this.newField.pk_template_field_id = new Date().getTime(); // mock ID until saved
|
||||
this.templateFields.push({ ...this.newField });
|
||||
this.mappings[this.newField.pk_template_field_id] = [];
|
||||
this.displayAddField = false;
|
||||
}
|
||||
|
||||
saveTemplateAndMappings() {
|
||||
if (!this.templateName || this.templateName.trim() === '') {
|
||||
this.messageService.add({ severity: 'warn', summary: 'Warning', detail: 'Please provide a template name.' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.templateFields.length === 0) {
|
||||
this.messageService.add({ severity: 'warn', summary: 'Warning', detail: 'Please add at least one template field.' });
|
||||
return;
|
||||
}
|
||||
|
||||
this.templateService.createTemplate({
|
||||
template_name: this.templateName,
|
||||
fields: this.templateFields
|
||||
}).subscribe({
|
||||
next: (res) => {
|
||||
// In a real scenario, we pass res.templateId and map the layoutNodes
|
||||
this.messageService.add({ severity: 'success', summary: 'Success', detail: 'Template & Mappings saved successfully.' });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Drag and Drop Logic
|
||||
drop(event: CdkDragDrop<DocumentLayout[]>, fieldId?: number) {
|
||||
if (event.previousContainer === event.container) {
|
||||
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
|
||||
} else {
|
||||
transferArrayItem(
|
||||
event.previousContainer.data,
|
||||
event.container.data,
|
||||
event.previousIndex,
|
||||
event.currentIndex,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getConnectedDropLists() {
|
||||
// Return all field ID strings as drop lists
|
||||
return this.templateFields.map(f => 'field-' + f.pk_template_field_id);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user