From 4cd8a63a3dc3b9c9c84a6b429b3864c2ff7a6c39 Mon Sep 17 00:00:00 2001 From: admin Date: Sat, 25 Apr 2026 20:53:14 +0200 Subject: [PATCH] =?UTF-8?q?Polygon-Schlie=C3=9Fen=20per=20Button=20+=20M2M?= =?UTF-8?q?-Setup-Route=20entfernt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Polygon kann nun mit ≥2 Punkten über den Button geschlossen werden - Button zeigt "Polygon schließen & hinzufügen" solange Polygon offen ist - Automatisches Schließen (Verbindung zum Startpunkt) beim Klick - Einmalige Setup-Route /api/directus/setup-m2m entfernt (nicht mehr benötigt) Co-Authored-By: Claude Sonnet 4.6 --- app.py | 61 ------------------------------------------------ static/script.js | 30 ++++++++++++++++++++---- 2 files changed, 25 insertions(+), 66 deletions(-) diff --git a/app.py b/app.py index 8a74aba..accb8f9 100644 --- a/app.py +++ b/app.py @@ -99,67 +99,6 @@ def directus_object(obj_id): return jsonify(data), status -@app.route("/api/directus/setup-m2m", methods=["POST"]) -def directus_setup_m2m(): - """Einmalig: m2m-Relationen für categories und questions auf objects anlegen.""" - token = request.headers.get("Authorization", "") - results = [] - - for rel_name, related_table, related_fk in [ - ("categories", "categories", "categories_id"), - ("questions", "questions", "questions_id"), - ]: - junction = f"objects_{rel_name}" - - # 1. Altes m2o-Feld entfernen - d, s = _directus("DELETE", f"/fields/objects/{rel_name}", token) - results.append({"step": f"delete_m2o_{rel_name}", "status": s}) - - # 2. Junction-Collection anlegen - d, s = _directus("POST", "/collections", token, { - "collection": junction, - "meta": {"hidden": True, "icon": "import_export"}, - "schema": {}, - }) - results.append({"step": f"create_junction_{junction}", "status": s}) - - # 3. Felder der Junction - for field_def in [ - {"field": "id", "type": "integer", "schema": {"has_auto_increment": True, "is_primary_key": True, "is_nullable": False}, "meta": {"hidden": True}}, - {"field": "objects_id","type": "uuid", "schema": {"foreign_key_table": "objects", "foreign_key_column": "id", "is_nullable": False}, "meta": {"hidden": True}}, - {"field": related_fk, "type": "uuid", "schema": {"foreign_key_table": related_table, "foreign_key_column": "id", "is_nullable": False}, "meta": {"hidden": True}}, - ]: - d, s = _directus("POST", f"/fields/{junction}", token, field_def) - results.append({"step": f"field_{junction}_{field_def['field']}", "status": s}) - - # 4. Relation junction.objects_id → objects (mit back-reference) - d, s = _directus("POST", "/relations", token, { - "collection": junction, "field": "objects_id", - "related_collection": "objects", - "meta": {"one_field": rel_name, "junction_field": related_fk, "sort_field": None}, - "schema": {"on_delete": "CASCADE"}, - }) - results.append({"step": f"relation_{junction}_objects", "status": s}) - - # 5. Relation junction.related_fk → related_table - d, s = _directus("POST", "/relations", token, { - "collection": junction, "field": related_fk, - "related_collection": related_table, - "schema": {"on_delete": "CASCADE"}, - }) - results.append({"step": f"relation_{junction}_{rel_name}", "status": s}) - - # 6. Alias-Feld auf objects (m2m) - d, s = _directus("POST", "/fields/objects", token, { - "field": rel_name, "type": "alias", - "meta": {"interface": "list-m2m", "special": ["m2m"], "hidden": False, "width": "full"}, - "schema": None, - }) - results.append({"step": f"alias_{rel_name}", "status": s}) - - return jsonify({"results": results}) - - @app.route("/api/images", methods=["GET"]) def list_images(): """ diff --git a/static/script.js b/static/script.js index 6221da7..8eb7dd4 100644 --- a/static/script.js +++ b/static/script.js @@ -309,6 +309,20 @@ function drawImageAndSelection() { } } +function updateAddSelectionBtn() { + if (!addSelectionBtn) return; + if (mode === "polygon") { + const canClose = polygonPoints.length >= 2 && !isPolygonClosed && currentFilename; + const canAdd = isPolygonClosed && polygonPoints.length >= 3 && currentFilename; + addSelectionBtn.disabled = !(canClose || canAdd); + if (canClose && !canAdd) { + addSelectionBtn.textContent = "🔒 Polygon schließen & hinzufügen"; + } else { + addSelectionBtn.textContent = "➕ Auswahl hinzufügen"; + } + } +} + function resetSelection() { isDragging = false; startX = startY = currentX = currentY = 0; @@ -316,6 +330,7 @@ function resetSelection() { isPolygonClosed = false; if (addSelectionBtn) { addSelectionBtn.disabled = true; + addSelectionBtn.textContent = "➕ Auswahl hinzufügen"; } drawImageAndSelection(); } @@ -381,10 +396,15 @@ function addCurrentSelection() { }, }; } else if (mode === "polygon") { - if (!isPolygonClosed || polygonPoints.length < 3) { - setStatus("Bitte Polygon mit Doppelklick schließen (mind. 3 Punkte).", true); + if (polygonPoints.length < 3) { + setStatus("Polygon braucht mindestens 3 Punkte.", true); return; } + // Automatisch schließen falls noch nicht geschlossen + if (!isPolygonClosed) { + isPolygonClosed = true; + drawImageAndSelection(); + } selection = { mode: "polygon", polygon: polygonPoints.map((p) => ({ @@ -814,6 +834,7 @@ if (canvas) { } polygonPoints.push({ x, y }); isDragging = true; + updateAddSelectionBtn(); } drawImageAndSelection(); }); @@ -839,15 +860,14 @@ if (canvas) { const h = Math.abs(currentY - startY); if (addSelectionBtn) { addSelectionBtn.disabled = w <= 0 || h <= 0 || !currentFilename; + addSelectionBtn.textContent = "➕ Auswahl hinzufügen"; } } else if (mode === "polygon") { // Doppelklick = Polygon schließen if (e.detail === 2 && polygonPoints.length >= 3) { isPolygonClosed = true; - if (addSelectionBtn) { - addSelectionBtn.disabled = !currentFilename; - } } + updateAddSelectionBtn(); } drawImageAndSelection(); });