diff --git a/app.py b/app.py index 004d9f5..56c2d67 100644 --- a/app.py +++ b/app.py @@ -67,9 +67,18 @@ def directus_auth_login(): @app.route("/api/directus/pictures", methods=["GET"]) def directus_pictures(): - """Proxy: Directus-Bilder (status=new).""" + """Proxy: Directus-Bilder nach Status filtern.""" token = request.headers.get("Authorization", "") - data, status = _directus("GET", "/items/pictures?filter[status][_eq]=new&fields=id,media,status&sort=date_created", token) + pic_status = request.args.get("status", "new") + data, status = _directus("GET", f"/items/pictures?filter[status][_eq]={pic_status}&fields=id,media,status&sort=date_created", token) + return jsonify(data), status + + +@app.route("/api/directus/pictures/", methods=["PATCH"]) +def directus_picture(pic_id): + """Proxy: Bild-Status aktualisieren.""" + token = request.headers.get("Authorization", "") + data, status = _directus("PATCH", f"/items/pictures/{pic_id}", token, body=request.get_json()) return jsonify(data), status diff --git a/frontend/src/api.ts b/frontend/src/api.ts index c02c140..f9ae0cb 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -19,8 +19,8 @@ export interface DirectusPicture { status: string } -export async function getDirectusPictures(token: string): Promise { - const res = await fetch('/api/directus/pictures', { +export async function getDirectusPictures(token: string, status = 'new'): Promise { + const res = await fetch(`/api/directus/pictures?status=${status}`, { headers: { Authorization: `Bearer ${token}` }, }) if (!res.ok) throw new Error('Fehler beim Laden der Directus-Bilder') @@ -28,6 +28,15 @@ export async function getDirectusPictures(token: string): Promise { + const res = await fetch(`/api/directus/pictures/${pictureId}`, { + method: 'PATCH', + headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` }, + body: JSON.stringify({ status }), + }) + if (!res.ok) throw new Error('Fehler beim Aktualisieren des Status') +} + export function directusAssetUrl(mediaId: string, token: string): string { return `${DIRECTUS_URL}/assets/${mediaId}?access_token=${token}` } diff --git a/frontend/src/pages/DrawIt.tsx b/frontend/src/pages/DrawIt.tsx index 9221538..26539fc 100644 --- a/frontend/src/pages/DrawIt.tsx +++ b/frontend/src/pages/DrawIt.tsx @@ -4,6 +4,7 @@ import Topbar from '../components/Topbar' import { getDirectusPictures, directusAssetUrl, type DirectusPicture, getDirectusObjects, createDirectusObject, updateDirectusObject, deleteDirectusObject, + updatePictureStatus, } from '../api' import { useAuth } from '../context/AuthContext' import type { DirectusObject, Selection, CanvasObject } from '../types' @@ -38,6 +39,7 @@ export default function DrawIt() { const [mode, setMode] = useState<'rect' | 'polygon'>('polygon') const [hasSelection, setHasSelection] = useState(false) const [saving, setSaving] = useState(false) + const [finishing, setFinishing] = useState(false) const [status, setStatus] = useState('') const [statusError, setStatusError] = useState(false) @@ -106,6 +108,22 @@ export default function DrawIt() { } } + const finishPicture = async () => { + if (!currentPicture || !token) return + setFinishing(true) + try { + await updatePictureStatus(currentPicture.id, 'drawing_created', token) + setPictureList(prev => prev.filter(p => p.id !== currentPicture.id)) + setCurrentIndex(i => Math.max(0, i - 1)) + setObjects([]) + showStatus('Bild fertiggestellt.') + } catch (e) { + showStatus(e instanceof Error ? e.message : 'Fehler.', true) + } finally { + setFinishing(false) + } + } + const saveNoteEdit = async () => { if (!editingNotes || !token) return try { @@ -220,6 +238,19 @@ export default function DrawIt() { )} + + {objects.length > 0 && ( +
+ +
+ )} {/* Center: Canvas */} diff --git a/frontend/src/pages/GenerateIt.tsx b/frontend/src/pages/GenerateIt.tsx index ca49f6f..90b562b 100644 --- a/frontend/src/pages/GenerateIt.tsx +++ b/frontend/src/pages/GenerateIt.tsx @@ -3,7 +3,9 @@ import ObjectsList from '../components/ObjectsList' import DetailsPanel from '../components/DetailsPanel' import SentencesList from '../components/SentencesList' import Topbar from '../components/Topbar' -import { getImages, getObjects, generateDetails, generateSentence, getSentences } from '../api' +import { getDirectusPictures, directusAssetUrl, type DirectusPicture, getDirectusObjects, generateDetails, generateSentence, getSentences } from '../api' +import { useAuth } from '../context/AuthContext' +import type { DirectusObject, Selection } from '../types' import type { ObjectMeta, Sentence } from '../types' const ChevronLeftIcon = () => ( @@ -30,54 +32,58 @@ const ChatIcon = () => ( ) +function directusObjToMeta(obj: DirectusObject, index: number): ObjectMeta { + const first = obj.selections?.[0] + return { + id: obj.id, + image_file: '', + title_de: '', + position_de: '', + action_de: '', + condition_de: '', + hierarchy: 1, + parent_id: obj.parent ?? undefined, + user_notes: obj.user_notes ?? '', + selections: obj.selections ?? [], + } as unknown as ObjectMeta +} + export default function GenerateIt() { - const [imageList, setImageList] = useState([]) + const { token } = useAuth() + const [pictureList, setPictureList] = useState([]) const [currentIndex, setCurrentIndex] = useState(-1) + const [directusObjects, setDirectusObjects] = useState([]) const [objects, setObjects] = useState([]) const [selectedObj, setSelectedObj] = useState(null) const [sentences, setSentences] = useState([]) const [isGeneratingDetails, setIsGeneratingDetails] = useState(false) const [isGeneratingSentence, setIsGeneratingSentence] = useState(false) - const currentFilename = - currentIndex >= 0 && currentIndex < imageList.length ? imageList[currentIndex] : null + const currentPicture: DirectusPicture | null = + currentIndex >= 0 && currentIndex < pictureList.length ? pictureList[currentIndex] : null useEffect(() => { - getImages('generate') - .then(imgs => { - setImageList(imgs) - setCurrentIndex(imgs.length - 1) - }) + if (!token) return + getDirectusPictures(token, 'drawing_created') + .then(pics => { setPictureList(pics); setCurrentIndex(pics.length > 0 ? 0 : -1) }) .catch(console.error) - }, []) + }, [token]) useEffect(() => { - if (!currentFilename) { - setObjects([]) - setSelectedObj(null) - setSentences([]) - return - } - getObjects(currentFilename) + if (!currentPicture || !token) { setDirectusObjects([]); setObjects([]); setSelectedObj(null); setSentences([]); return } + getDirectusObjects(currentPicture.id, token) .then(objs => { - setObjects(objs) - if (objs.length > 0) { - setSelectedObj(objs[0]) - loadSentences(objs[0].id) - } else { - setSelectedObj(null) - setSentences([]) - } + setDirectusObjects(objs) + const metas = objs.map((o, i) => directusObjToMeta(o, i)) + setObjects(metas) + if (metas.length > 0) { setSelectedObj(metas[0]); loadSentences(metas[0].id) } + else { setSelectedObj(null); setSentences([]) } }) .catch(console.error) - }, [currentFilename]) + }, [currentPicture?.id, token]) const loadSentences = async (objId: string) => { - try { - setSentences(await getSentences(objId)) - } catch (e) { - console.error(e) - } + try { setSentences(await getSentences(objId)) } catch (e) { console.error(e) } } const handleGenerateDetails = async () => { @@ -114,48 +120,32 @@ export default function GenerateIt() { const imageNav = (
- - {imageList.length > 0 ? ( + {pictureList.length > 0 ? ( <> {currentIndex + 1} / - {imageList.length} + {pictureList.length} ) : ( Keine Bilder )} -
- - @@ -170,16 +160,16 @@ export default function GenerateIt() { {/* Left: Objects */} - {/* Center: Details */} -
-
+ {/* Center: Image + Details */} +
+ {currentPicture && token && ( + Bild + )} +