diff --git a/app.py b/app.py index dc9fb14..453b0b9 100644 --- a/app.py +++ b/app.py @@ -1164,6 +1164,56 @@ def publish_questions(obj_id: str): }) +@app.route("/api/object//questions", methods=["GET"]) +def get_object_questions_list(obj_id: str): + """Gibt alle verknüpften Fragen eines Objekts zurück.""" + token = request.headers.get("Authorization", "") + fields = "questions_id.id,questions_id.question_de,questions_id.answer_de,questions_id.level,questions_id.status" + data, _ = _directus( + "GET", + f"/items/questions_objects?filter[objects_id][_eq]={obj_id}&fields={fields}&limit=200", + token, + ) + items = [e["questions_id"] for e in (data.get("data") or []) if e.get("questions_id")] + items.sort(key=lambda x: x.get("level") or 0) + return jsonify({"data": items}) + + +@app.route("/api/object//words", methods=["GET"]) +def get_object_words_list(obj_id: str): + """Gibt alle verknüpften Wörter eines Objekts zurück.""" + token = request.headers.get("Authorization", "") + fields = "words_id.id,words_id.title_de,words_id.level,words_id.status" + data, _ = _directus( + "GET", + f"/items/words_objects?filter[objects_id][_eq]={obj_id}&fields={fields}&limit=2000", + token, + ) + items = [e["words_id"] for e in (data.get("data") or []) if e.get("words_id")] + items.sort(key=lambda x: x.get("title_de") or "") + return jsonify({"data": items}) + + +@app.route("/api/question/", methods=["DELETE"]) +def delete_question_item(q_id: str): + """Löscht eine Frage aus Directus.""" + token = request.headers.get("Authorization", "") + _, status = _directus("DELETE", f"/items/questions/{q_id}", token) + if status in (200, 204): + return jsonify({"ok": True}) + return jsonify({"error": "Delete failed"}), status + + +@app.route("/api/word/", methods=["DELETE"]) +def delete_word_item(w_id: str): + """Löscht ein Wort aus Directus.""" + token = request.headers.get("Authorization", "") + _, status = _directus("DELETE", f"/items/words/{w_id}", token) + if status in (200, 204): + return jsonify({"ok": True}) + return jsonify({"error": "Delete failed"}), status + + if __name__ == "__main__": app.run(host="0.0.0.0", port=8000, debug=True) diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 99f071e..65dfe2b 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -230,3 +230,52 @@ export async function publishQuestions( if (!res.ok) throw new Error(data.error || 'Fehler bei Publish') return data } + +export interface ObjectQuestion { + id: string + question_de: string + answer_de: string + level: number + status: string +} + +export interface ObjectWord { + id: string + title_de: string + level: number + status: string +} + +export async function getObjectQuestions(objId: string, token: string): Promise { + const res = await fetch(`/api/object/${encodeURIComponent(objId)}/questions`, { + headers: { Authorization: `Bearer ${token}` }, + }) + const data = await res.json() + if (!res.ok) throw new Error('Fehler beim Laden der Fragen') + return data.data as ObjectQuestion[] +} + +export async function getObjectWords(objId: string, token: string): Promise { + const res = await fetch(`/api/object/${encodeURIComponent(objId)}/words`, { + headers: { Authorization: `Bearer ${token}` }, + }) + const data = await res.json() + if (!res.ok) throw new Error('Fehler beim Laden der Wörter') + return data.data as ObjectWord[] +} + +export async function deleteQuestion(qId: string, token: string): Promise { + const res = await fetch(`/api/question/${encodeURIComponent(qId)}`, { + method: 'DELETE', + headers: { Authorization: `Bearer ${token}` }, + }) + if (!res.ok) throw new Error('Fehler beim Löschen der Frage') +} + +export async function deleteWord(wId: string, token: string): Promise { + const res = await fetch(`/api/word/${encodeURIComponent(wId)}`, { + method: 'DELETE', + headers: { Authorization: `Bearer ${token}` }, + }) + if (!res.ok) throw new Error('Fehler beim Löschen des Worts') +} diff --git a/frontend/src/pages/GenerateIt.tsx b/frontend/src/pages/GenerateIt.tsx index ae407ea..23bee22 100644 --- a/frontend/src/pages/GenerateIt.tsx +++ b/frontend/src/pages/GenerateIt.tsx @@ -10,7 +10,13 @@ import { getDirectusObjects, generateQuestions, publishQuestions, + getObjectQuestions, + getObjectWords, + deleteQuestion, + deleteWord, type GenerateStats, + type ObjectQuestion, + type ObjectWord, } from '../api' import { useAuth } from '../context/AuthContext' import type { DirectusObject, CanvasObject } from '../types' @@ -121,6 +127,8 @@ export default function GenerateIt() { const [generateResult, setGenerateResult] = useState(null) const [generateError, setGenerateError] = useState(null) const [publishResult, setPublishResult] = useState<{ q: number; w: number } | null>(null) + const [questions, setQuestions] = useState([]) + const [objWords, setObjWords] = useState([]) // Prompt layouts const [layouts, setLayouts] = useState(loadLayouts) @@ -152,6 +160,7 @@ export default function GenerateIt() { if (!currentPicture || !token) { setDirectusObjects([]); setSelectedObjId(null) setGenerateResult(null); setPublishResult(null); setGenerateError(null) + setQuestions([]); setObjWords([]) return } getDirectusObjects(currentPicture.id, token) @@ -163,6 +172,30 @@ export default function GenerateIt() { .catch(console.error) }, [currentPicture?.id, token]) + useEffect(() => { + if (!selectedObjId || !token) { setQuestions([]); setObjWords([]); return } + getObjectQuestions(selectedObjId, token).then(setQuestions).catch(console.error) + getObjectWords(selectedObjId, token).then(setObjWords).catch(console.error) + }, [selectedObjId, token]) + + const reloadQW = (objId: string) => { + if (!token) return + getObjectQuestions(objId, token).then(setQuestions).catch(console.error) + getObjectWords(objId, token).then(setObjWords).catch(console.error) + } + + const handleDeleteQuestion = async (qId: string) => { + if (!token) return + await deleteQuestion(qId, token) + setQuestions(qs => qs.filter(q => q.id !== qId)) + } + + const handleDeleteWord = async (wId: string) => { + if (!token) return + await deleteWord(wId, token) + setObjWords(ws => ws.filter(w => w.id !== wId)) + } + const handleGenerate = async () => { if (!selectedObjId || !token) return setIsGenerating(true) @@ -172,6 +205,7 @@ export default function GenerateIt() { try { const res = await generateQuestions(selectedObjId, promptText, token) setGenerateResult(res.stats) + reloadQW(selectedObjId) } catch (e) { setGenerateError(e instanceof Error ? e.message : 'Fehler beim Generieren') } finally { @@ -382,24 +416,60 @@ export default function GenerateIt() { - {/* Right: Generate results */} -