Polygon-Schließen per Button + M2M-Setup-Route entfernt
- 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 <noreply@anthropic.com>
This commit is contained in:
61
app.py
61
app.py
@@ -99,67 +99,6 @@ def directus_object(obj_id):
|
|||||||
return jsonify(data), status
|
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"])
|
@app.route("/api/images", methods=["GET"])
|
||||||
def list_images():
|
def list_images():
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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() {
|
function resetSelection() {
|
||||||
isDragging = false;
|
isDragging = false;
|
||||||
startX = startY = currentX = currentY = 0;
|
startX = startY = currentX = currentY = 0;
|
||||||
@@ -316,6 +330,7 @@ function resetSelection() {
|
|||||||
isPolygonClosed = false;
|
isPolygonClosed = false;
|
||||||
if (addSelectionBtn) {
|
if (addSelectionBtn) {
|
||||||
addSelectionBtn.disabled = true;
|
addSelectionBtn.disabled = true;
|
||||||
|
addSelectionBtn.textContent = "➕ Auswahl hinzufügen";
|
||||||
}
|
}
|
||||||
drawImageAndSelection();
|
drawImageAndSelection();
|
||||||
}
|
}
|
||||||
@@ -381,10 +396,15 @@ function addCurrentSelection() {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
} else if (mode === "polygon") {
|
} else if (mode === "polygon") {
|
||||||
if (!isPolygonClosed || polygonPoints.length < 3) {
|
if (polygonPoints.length < 3) {
|
||||||
setStatus("Bitte Polygon mit Doppelklick schließen (mind. 3 Punkte).", true);
|
setStatus("Polygon braucht mindestens 3 Punkte.", true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Automatisch schließen falls noch nicht geschlossen
|
||||||
|
if (!isPolygonClosed) {
|
||||||
|
isPolygonClosed = true;
|
||||||
|
drawImageAndSelection();
|
||||||
|
}
|
||||||
selection = {
|
selection = {
|
||||||
mode: "polygon",
|
mode: "polygon",
|
||||||
polygon: polygonPoints.map((p) => ({
|
polygon: polygonPoints.map((p) => ({
|
||||||
@@ -814,6 +834,7 @@ if (canvas) {
|
|||||||
}
|
}
|
||||||
polygonPoints.push({ x, y });
|
polygonPoints.push({ x, y });
|
||||||
isDragging = true;
|
isDragging = true;
|
||||||
|
updateAddSelectionBtn();
|
||||||
}
|
}
|
||||||
drawImageAndSelection();
|
drawImageAndSelection();
|
||||||
});
|
});
|
||||||
@@ -839,15 +860,14 @@ if (canvas) {
|
|||||||
const h = Math.abs(currentY - startY);
|
const h = Math.abs(currentY - startY);
|
||||||
if (addSelectionBtn) {
|
if (addSelectionBtn) {
|
||||||
addSelectionBtn.disabled = w <= 0 || h <= 0 || !currentFilename;
|
addSelectionBtn.disabled = w <= 0 || h <= 0 || !currentFilename;
|
||||||
|
addSelectionBtn.textContent = "➕ Auswahl hinzufügen";
|
||||||
}
|
}
|
||||||
} else if (mode === "polygon") {
|
} else if (mode === "polygon") {
|
||||||
// Doppelklick = Polygon schließen
|
// Doppelklick = Polygon schließen
|
||||||
if (e.detail === 2 && polygonPoints.length >= 3) {
|
if (e.detail === 2 && polygonPoints.length >= 3) {
|
||||||
isPolygonClosed = true;
|
isPolygonClosed = true;
|
||||||
if (addSelectionBtn) {
|
|
||||||
addSelectionBtn.disabled = !currentFilename;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
updateAddSelectionBtn();
|
||||||
}
|
}
|
||||||
drawImageAndSelection();
|
drawImageAndSelection();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user