logging#19, max 5MB#18,addinsert/update#14,drizzle
This commit is contained in:
@@ -50,6 +50,7 @@ import { PopoverService } from './services/popover.service';
|
||||
[title]="popoverTitle"
|
||||
[message]="popoverMessage"
|
||||
[showInput]="popoverShowInput"
|
||||
[showCancel]="popoverShowCancel"
|
||||
[inputValue]="popoverInputValue"
|
||||
[confirmText]="popoverConfirmText"
|
||||
(confirmed)="handleConfirm($event)"
|
||||
@@ -103,6 +104,7 @@ export class AppComponent {
|
||||
popoverTitle = '';
|
||||
popoverMessage = '';
|
||||
popoverShowInput = false;
|
||||
popoverShowCancel = true;
|
||||
popoverInputValue = '';
|
||||
popoverConfirmText = 'Confirm';
|
||||
private confirmCallback?: (inputValue?: string) => void;
|
||||
@@ -114,6 +116,7 @@ export class AppComponent {
|
||||
this.popoverTitle = options.title;
|
||||
this.popoverMessage = options.message;
|
||||
this.popoverShowInput = options.showInput;
|
||||
this.popoverShowCancel = options.showCancel;
|
||||
this.popoverInputValue = options.inputValue;
|
||||
this.popoverConfirmText = options.confirmText;
|
||||
this.confirmCallback = options.onConfirm;
|
||||
|
||||
@@ -17,7 +17,9 @@ import { FormsModule } from '@angular/forms';
|
||||
<input *ngIf="showInput" type="text" class="w-full p-2 border rounded mb-4 focus:ring-2 focus:ring-blue-500 focus:border-transparent" [(ngModel)]="inputValue" (keyup.enter)="onConfirm()" autofocus />
|
||||
|
||||
<div class="flex justify-end space-x-2">
|
||||
@if(showCancel){
|
||||
<button (click)="onCancel()" class="px-4 py-2 rounded bg-gray-100 text-gray-700 hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-gray-400">Cancel</button>
|
||||
}
|
||||
<button (click)="onConfirm()" class="px-4 py-2 rounded bg-blue-500 text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
{{ confirmText }}
|
||||
</button>
|
||||
@@ -30,6 +32,7 @@ export class PopoverComponent {
|
||||
@Input() title: string = '';
|
||||
@Input() message: string = '';
|
||||
@Input() showInput: boolean = false;
|
||||
@Input() showCancel: boolean = false;
|
||||
@Input() confirmText: string = 'Confirm';
|
||||
@Input() inputValue: string = '';
|
||||
@Input() visible: boolean = false;
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
<div class="flex items-center space-x-2">
|
||||
<div class="relative group">
|
||||
<div class="absolute left-0 bottom-full mb-2 w-48 bg-white border border-gray-300 rounded shadow-lg opacity-0 group-hover:opacity-100 transition-opacity duration-200 z-10 pointer-events-none">
|
||||
<img src="/debug_images/{{ image.id }}/thumbnail.jpg" alt="{{ image.name }}" class="w-full h-auto object-cover" />
|
||||
<img src="/debug_images/{{ image.bildid }}/thumbnail.jpg" alt="{{ image.name }}" class="w-full h-auto object-cover" />
|
||||
</div>
|
||||
<span class="font-medium cursor-pointer">{{ image.name }}</span>
|
||||
</div>
|
||||
@@ -98,7 +98,7 @@
|
||||
<div class="flex-1">
|
||||
<div class="relative">
|
||||
<label for="imageFile" class="flex justify-center items-center bg-green-500 text-white py-2 px-4 rounded hover:bg-green-600 cursor-pointer"> Add Image </label>
|
||||
<input #imageFile type="file" id="imageFile" (change)="onFileChange($event)" accept="image/*" required class="hidden" />
|
||||
<input #imageFile type="file" id="imageFile" (change)="onFileChange($event)" accept="image/jpeg,image/png,image/gif,image/webp" required class="hidden" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -144,18 +144,19 @@ export class DeckListComponent implements OnInit {
|
||||
title: 'Delete Image',
|
||||
message: `Are you sure you want to delete the image ${image.name}?`,
|
||||
confirmText: 'Delete',
|
||||
showCancel: true,
|
||||
onConfirm: () => this.confirmImageDelete(deck, image),
|
||||
});
|
||||
}
|
||||
|
||||
confirmImageDelete(deck: Deck, image: DeckImage): void {
|
||||
const imageId = image.id;
|
||||
const imageId = image.bildid;
|
||||
|
||||
this.deckService.deleteImage(imageId).subscribe({
|
||||
next: () => {
|
||||
this.loadDecks();
|
||||
if (this.activeDeck) {
|
||||
this.activeDeck.images = this.activeDeck.images.filter(img => img.id !== imageId);
|
||||
this.activeDeck.images = this.activeDeck.images.filter(img => img.bildid !== imageId);
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
},
|
||||
@@ -166,7 +167,7 @@ export class DeckListComponent implements OnInit {
|
||||
// Method to edit an image in a deck
|
||||
editImage(deck: Deck, image: DeckImage): void {
|
||||
let imageSrc = null;
|
||||
fetch(`/debug_images/${image.id}/original_compressed.jpg`)
|
||||
fetch(`/debug_images/${image.bildid}/original_compressed.jpg`)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
@@ -282,11 +283,36 @@ export class DeckListComponent implements OnInit {
|
||||
onFileChange(event: any): void {
|
||||
const file: File = event.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
// Erlaubte Dateitypen
|
||||
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
||||
|
||||
// Prüfe den Dateityp
|
||||
if (!allowedTypes.includes(file.type)) {
|
||||
this.popoverService.show({
|
||||
title: 'Information',
|
||||
message: 'Only JPG, PNG, GIF and WebP images are allowed',
|
||||
});
|
||||
this.resetFileInput();
|
||||
return;
|
||||
}
|
||||
|
||||
// Prüfe die Dateigröße (5MB = 5 * 1024 * 1024 Bytes)
|
||||
const maxSize = 5 * 1024 * 1024; // 5MB in Bytes
|
||||
if (file.size > maxSize) {
|
||||
this.popoverService.show({
|
||||
title: 'Information',
|
||||
message: 'Image file size must not exceed 5MB',
|
||||
});
|
||||
this.resetFileInput();
|
||||
return;
|
||||
}
|
||||
|
||||
const fileNameElement = document.getElementById('fileName');
|
||||
if (fileNameElement) {
|
||||
fileNameElement.textContent = file.name;
|
||||
}
|
||||
// this.imageFile = file;
|
||||
|
||||
this.loading = true;
|
||||
|
||||
const reader = new FileReader();
|
||||
@@ -319,10 +345,9 @@ export class DeckListComponent implements OnInit {
|
||||
const xMax = Math.max(...xs);
|
||||
const yMin = Math.min(...ys);
|
||||
const yMax = Math.max(...ys);
|
||||
boxes.push({ x1: xMin, x2: xMax, y1: yMin, y2: yMax });
|
||||
boxes.push({ x1: xMin, x2: xMax, y1: yMin, y2: yMax, inserted: null, updated: null });
|
||||
});
|
||||
const deckImage: DeckImage = { name: imageName, id: imageId, boxes };
|
||||
//this.imageUploaded.emit({ imageSrc, deckImage });
|
||||
const deckImage: DeckImage = { name: imageName, bildid: imageId, boxes };
|
||||
this.imageData = { imageSrc, deckImage };
|
||||
|
||||
this.resetFileInput();
|
||||
@@ -333,6 +358,7 @@ export class DeckListComponent implements OnInit {
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the file input field so the same file can be selected again.
|
||||
*/
|
||||
|
||||
@@ -10,8 +10,7 @@ export interface Deck {
|
||||
export interface DeckImage {
|
||||
boxes: Box[];
|
||||
name: string;
|
||||
//bildid: string;
|
||||
id: string;
|
||||
bildid: string;
|
||||
}
|
||||
|
||||
export interface Box {
|
||||
@@ -26,12 +25,13 @@ export interface Box {
|
||||
reps?: number;
|
||||
lapses?: number;
|
||||
isGraduated?: boolean;
|
||||
inserted: string;
|
||||
updated: string;
|
||||
}
|
||||
|
||||
export interface BackendBox {
|
||||
bildname: string;
|
||||
deckid: number;
|
||||
iconindex: number;
|
||||
id: number;
|
||||
x1: number;
|
||||
x2: number;
|
||||
@@ -76,15 +76,15 @@ export class DeckService {
|
||||
const imageMap: { [key: string]: DeckImage } = {};
|
||||
|
||||
images.forEach(image => {
|
||||
if (!imageMap[image.id]) {
|
||||
imageMap[image.id] = {
|
||||
if (!imageMap[image.bildid]) {
|
||||
imageMap[image.bildid] = {
|
||||
name: image.name,
|
||||
id: image.id,
|
||||
bildid: image.bildid,
|
||||
boxes: [],
|
||||
};
|
||||
}
|
||||
imageMap[image.id].boxes.push({
|
||||
id: image.boxid,
|
||||
imageMap[image.bildid].boxes.push({
|
||||
id: image.id,
|
||||
x1: image.x1,
|
||||
x2: image.x2,
|
||||
y1: image.y1,
|
||||
@@ -95,6 +95,8 @@ export class DeckService {
|
||||
reps: image.reps,
|
||||
lapses: image.lapses,
|
||||
isGraduated: image.isGraduated ? true : false,
|
||||
inserted: image.inserted,
|
||||
updated: image.updated,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ export class EditImageModalComponent implements AfterViewInit, OnDestroy {
|
||||
@ViewChild('canvas') canvasElement!: ElementRef<HTMLCanvasElement>;
|
||||
|
||||
detectedText: string = '';
|
||||
boxes: { x1: number; x2: number; y1: number; y2: number }[] = [];
|
||||
boxes: { x1: number; x2: number; y1: number; y2: number; id: number; inserted: string; updated: string }[] = [];
|
||||
canvas!: fabric.Canvas;
|
||||
|
||||
maxCanvasWidth: number = 0;
|
||||
@@ -133,6 +133,7 @@ export class EditImageModalComponent implements AfterViewInit, OnDestroy {
|
||||
hasControls: true,
|
||||
hasBorders: true,
|
||||
objectCaching: false,
|
||||
data: { id: box.id, inserted: box.inserted, updated: box.updated },
|
||||
});
|
||||
|
||||
rect.on('modified', () => {
|
||||
@@ -155,7 +156,6 @@ export class EditImageModalComponent implements AfterViewInit, OnDestroy {
|
||||
});
|
||||
|
||||
this.updateBoxCoordinates();
|
||||
|
||||
// this.detectedText = ocrResults.map(result => result.text).join('\n');
|
||||
} catch (error) {
|
||||
console.error('Error processing image:', error);
|
||||
@@ -198,6 +198,9 @@ export class EditImageModalComponent implements AfterViewInit, OnDestroy {
|
||||
x2: Math.round(x2),
|
||||
y1: Math.round(y1),
|
||||
y2: Math.round(y2),
|
||||
id: rect.data?.id,
|
||||
inserted: rect.data?.inserted,
|
||||
updated: rect.data?.updated,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -226,7 +229,6 @@ export class EditImageModalComponent implements AfterViewInit, OnDestroy {
|
||||
hasBorders: true,
|
||||
objectCaching: false,
|
||||
});
|
||||
|
||||
rect.on('modified', () => {
|
||||
this.updateBoxCoordinates();
|
||||
});
|
||||
@@ -256,7 +258,7 @@ export class EditImageModalComponent implements AfterViewInit, OnDestroy {
|
||||
const data = {
|
||||
deckname: this.deckName,
|
||||
bildname: this.imageData.deckImage?.name, // this.imageFile?.name,
|
||||
bildid: this.imageData.deckImage?.id,
|
||||
bildid: this.imageData.deckImage?.bildid,
|
||||
boxes: this.boxes,
|
||||
};
|
||||
this.deckService.saveImageData(data).subscribe({
|
||||
|
||||
@@ -26,7 +26,7 @@ export class MoveImageModalComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
this.deckService.moveImage(this.image.id, this.selectedDeckId).subscribe({
|
||||
this.deckService.moveImage(this.image.bildid, this.selectedDeckId).subscribe({
|
||||
next: () => {
|
||||
this.moveCompleted.emit();
|
||||
this.close();
|
||||
|
||||
@@ -8,19 +8,22 @@ export class PopoverService {
|
||||
title: string;
|
||||
message: string;
|
||||
showInput: boolean;
|
||||
showCancel: boolean;
|
||||
inputValue: string;
|
||||
confirmText: string;
|
||||
|
||||
onConfirm: () => void;
|
||||
onCancel?: () => void;
|
||||
}>();
|
||||
|
||||
popoverState$ = this.showPopoverSource.asObservable();
|
||||
|
||||
show(options: { title: string; message: string; confirmText?: string; onConfirm?: (inputValue?: string) => void; onCancel?: () => void }) {
|
||||
show(options: { title: string; message: string; confirmText?: string; showCancel?: boolean; onConfirm?: (inputValue?: string) => void; onCancel?: () => void }) {
|
||||
this.showPopoverSource.next({
|
||||
showInput: false,
|
||||
inputValue: null,
|
||||
confirmText: 'Ok',
|
||||
showCancel: false,
|
||||
onConfirm: (inputValue?: string) => {},
|
||||
...options,
|
||||
});
|
||||
@@ -28,6 +31,7 @@ export class PopoverService {
|
||||
showWithInput(options: { title: string; message: string; confirmText: string; inputValue: string; onConfirm: (inputValue?: string) => void; onCancel?: () => void }) {
|
||||
this.showPopoverSource.next({
|
||||
showInput: true,
|
||||
showCancel: true,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ export class TrainingComponent implements OnInit {
|
||||
if (!ctx || !this.currentImageData) return;
|
||||
|
||||
const img = new Image();
|
||||
img.src = `/debug_images/${this.currentImageData.id}/original_compressed.jpg`;
|
||||
img.src = `/debug_images/${this.currentImageData.bildid}/original_compressed.jpg`;
|
||||
img.onload = () => {
|
||||
// Set the canvas size to the image size
|
||||
canvas.width = img.width;
|
||||
|
||||
Reference in New Issue
Block a user