From 0a4a1d3e48a4e62199eb830c7bcbf2b55a6a087f Mon Sep 17 00:00:00 2001 From: mboehmlaender Date: Tue, 13 Jan 2026 20:26:56 +0000 Subject: [PATCH] Nice Work --- gui/backend/db/klangkiste.sqlite-shm | Bin 32768 -> 32768 bytes gui/backend/db/klangkiste.sqlite-wal | Bin 4120032 -> 4120032 bytes gui/frontend/src/App.jsx | 72 +++++++++++++++------------ gui/frontend/src/api.js | 54 ++++++++++---------- gui/frontend/vite.config.js | 28 ++++++++--- 5 files changed, 88 insertions(+), 66 deletions(-) diff --git a/gui/backend/db/klangkiste.sqlite-shm b/gui/backend/db/klangkiste.sqlite-shm index 0c64437c3a099d1c89b72ace18a98a4c46c69d3e..35ff25b6103f0d5c52b9c85318efba896fe8188d 100644 GIT binary patch delta 269 zcmZo@U}|V!s+V}A%K!pQK+MR%Admv2d4afE>71Kj@6W#r#96ox^UWv~`MgnPo846{ zQq=>E0t1k_|B(Pxn28~2V&n0N2P!6Bh}ay$_{4egA6JKTLk1%TV+IojQwB2za|R0r zO9m?jYX%zzTLwD@dj`5tip7|d9nf1oymV(9X2a5?cm=0C6GrC0Qmzoi~s-t diff --git a/gui/backend/db/klangkiste.sqlite-wal b/gui/backend/db/klangkiste.sqlite-wal index 4fbae951bcd458e8edde0280d740df33a2c5dbba..54ed636e5b8442e5f51ec41d667c707c5578eac8 100644 GIT binary patch delta 2330 zcmZ|Qe=O8-9LI5Yj=M`olE}HZ6ot#FOMY|}H-*-(KT->cCM#K^9~u+e2|26?NgK;J zr^y@*wIpp_WpX8@<_aUTT8(O4Kh#_I*}QN2^vCnB@8k2@_m9u^8M^zEF$861F|wE~ zrqwK4riqCOugZ>P@zC<>8BJ5y%Yoy`KbtefF+65XU|Ca;MjrXvtnhLA9EB*GI=60h!tLgXJ z)Z+Fd#3kZA?2ZPuFmxWr_R(A-+6(V&?1(>pR70Es?_sBS`f7jfF^@Mir$BpoHR}dT zMb~cgbow&oRFGsR#nC3KSFRrwuPB*jf zD{*6Z54#U3D*aWpDvsvH(B7b+JAA6cbictVP4OOfvNoaBOr36m;^5Hy{geI}kc`IN z4j@j5_Ke)E!>%RP!IOzJCq#P#7o55VhwUqg+k*G7^K3D?FlXSBCZwhVV9DfBpbOCz@WKSwC8JHf1o$=iw$x8 zcn>*tL4Vi8slD9h3~?-vsWf8!XigrOm%YGIl46*vyMgDhyQ1yMkd3EuDGm7DG1B637->3fV#S&@#vY;zN#* z09pF0E1^}8D>U~XtD!ZJJLCa*LLz7_y-8hCT{(9r%a%o{tUS z7)#3DB6Iar^-W1_B-D;fMOyX;2lkhw703@lYZ>gLh1()COl_F;_<|U*$5wG)w37_S z+WZQS>+ZV-kIt)2;2$gji}*^-9mOM1Ju{>3V(7pC>LL~&OZQilwl)%Nj}89BB>}~X zij4f?(uy(z6GK-cG!uF>2cj}`$`%HES(hbUVc73@EE{t*5pp=5ntB(_9}XN2D=)h! zO`az&QYzj}j7v_ANq~=T(Ewv;84CGIV#l7#(Vay%{~rNOAtO-HWk2<Wvz?sBxE`}2a~7CIb6zxGIukp7^ZWH{>We1u2B zbLy`jqWgpDnHhDj0<&muXXRLy=oKnl)b9_P$;>bw@biV^{Uu_$Kbm^VA9-(2MXY7nvDi9_0)T)CzCu^#@HMBT)V**Rxk{G(YSm{XvC{b=oJg^XhMl_dk72 zk3XnW_fnAb60D^8LsZtCzuMw4PWpoynb~4;@N&@w=N8f*RH*Yd8@JGgI}vbhQW#P- ztj8bJ`mAuja8KqBRc4Kl{-8!O9Oci4HO0Tht}Q#!{XzB2jJk_q7R{e~-4m%h3+hYt z`-5gOGpx086j>)N$LRiO>M4IDL79r2qJ!C)71VIA`7txR(^2i8u8L07>kpbj zMxgvDk=8Aj^E$^!e^4P~o%V^6PuQnVJKD_Z@dtJ4UJ8;1!%CVzWAfq9A9~kbC;dT< z%xt2%*qNNSEboy1phEOE+FNMDy3>$Ad%8+(*kd!dikA2-y<4A+%2 zx7&QJAVqt)XjI5JobEz$2Ib)WrObp`??l0-gUcf979Re*qi71U<}-}FZB>|l1<^=m z1h=`6Q++P{S3$wajn$NSfq9a$ic)2Ma5?owVu#!;u>*{ttv*wpQD=8G@<+Yqp()G* z+AKQVZCWcoM%ccAP2qN^kg-mMr(kxNDZ5_$-Sid0F9o}Svso&29_H+adUoc@736Oc zu`6t%2^W-&cZI}H4wAy5E@q^z^NZVV-!Ez>F74&s!|hQa5>9)9jZD0Tx0}aK-;V4c z8a{&`OfMK}cqw>n{oKM6QZ%%S8Oq|{_R8Jn5evllAlxYm6*BHboq!xbS;m&g9`~@; zw{BWCJ&4`GL!WC7?VSZU|KZ&SJHquVhUPK%H@@eij!LXrAgZ_X30tZJUo&__@_`uml{MqI946U z1u%dI7y*317 setUploadProgress(percent) ); @@ -604,14 +614,16 @@ export default function App() { setActiveUploadLabel(''); setUploadAfterCreate(false); setPendingUploadFiles([]); - setCurrentPath(createdPath); + if (targetPath) { + setCurrentPath(targetPath); + } addToast('success', 'Upload abgeschlossen.'); await handleMediaRefresh(); setActiveModal(''); + return; } - if (!uploadAfterCreate) { - setActiveModal(''); - } + + setActiveModal(''); } async function handleRename() { @@ -1442,11 +1454,15 @@ export default function App() { > {activeModal === 'new-folder' && ( <> -

Neuen Ordner anlegen

+

{uploadAfterCreate ? 'Upload vorbereiten' : 'Neuen Ordner anlegen'}

setNewFolderName(event.target.value)} - placeholder="Ordnername" + placeholder={ + uploadAfterCreate + ? 'Optionaler Ordnername (leer = aktueller Ordner)' + : 'Ordnername' + } /> {uploadAfterCreate && ( <> @@ -1509,7 +1525,9 @@ export default function App() { }} /> -

Upload startet direkt nach dem Anlegen.

+

+ Upload startet direkt. Ohne Ordnername landet er im aktuellen Ordner. +

{uploadInProgress && (
@@ -1894,23 +1912,15 @@ export default function App() { className="icon-button upload" title="Upload" onClick={(event) => { - if (!currentPath) { - event.preventDefault(); - event.stopPropagation(); - addToast('error', 'Bitte zuerst einen Ordner anlegen.'); - setUploadAfterCreate(true); - setPendingUploadFiles([]); - setActiveModal('new-folder'); - } + event.preventDefault(); + event.stopPropagation(); + setUploadAfterCreate(true); + setPendingUploadFiles([]); + setNewFolderName(''); + setActiveModal('new-folder'); }} > -
diff --git a/gui/frontend/src/api.js b/gui/frontend/src/api.js index 283e123..666a89d 100644 --- a/gui/frontend/src/api.js +++ b/gui/frontend/src/api.js @@ -1,6 +1,6 @@ const defaultHost = typeof window !== 'undefined' && window.location ? window.location.hostname : '127.0.0.1'; -const API_BASE = import.meta.env.VITE_BACKEND_URL || `http://${defaultHost}:5001`; +const API_BASE = '/api'; async function readJson(response) { const text = await response.text(); @@ -12,12 +12,12 @@ async function readJson(response) { } export async function getBoxes() { - const response = await fetch(`${API_BASE}/api/boxes`); + const response = await fetch(`${API_BASE}/boxes`); return readJson(response); } export async function pairBox(boxId) { - const response = await fetch(`${API_BASE}/api/boxes/pair`, { + const response = await fetch(`${API_BASE}/boxes/pair`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ box_id: boxId }), @@ -26,17 +26,17 @@ export async function pairBox(boxId) { } export async function getStatus(boxId) { - const response = await fetch(`${API_BASE}/api/boxes/${boxId}/status`); + const response = await fetch(`${API_BASE}/boxes/${boxId}/status`); return readJson(response); } export async function getMediaTree() { - const response = await fetch(`${API_BASE}/api/media-tree`); + const response = await fetch(`${API_BASE}/media-tree`); return readJson(response); } export async function createMediaFolder(parentPath, name) { - const response = await fetch(`${API_BASE}/api/media/folder`, { + const response = await fetch(`${API_BASE}/media/folder`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ parent_path: parentPath, name }), @@ -45,7 +45,7 @@ export async function createMediaFolder(parentPath, name) { } export async function renameMedia(path, name) { - const response = await fetch(`${API_BASE}/api/media/rename`, { + const response = await fetch(`${API_BASE}/media/rename`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ path, name }), @@ -54,7 +54,7 @@ export async function renameMedia(path, name) { } export async function moveMedia(path, targetParent) { - const response = await fetch(`${API_BASE}/api/media/move`, { + const response = await fetch(`${API_BASE}/media/move`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ path, target_parent: targetParent }), @@ -63,7 +63,7 @@ export async function moveMedia(path, targetParent) { } export async function deleteMedia(path) { - const response = await fetch(`${API_BASE}/api/media/delete`, { + const response = await fetch(`${API_BASE}/media/delete`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ path }), @@ -80,7 +80,7 @@ export function uploadMedia(targetPath, files, onProgress) { return new Promise((resolve) => { const request = new XMLHttpRequest(); - request.open('POST', `${API_BASE}/api/media/upload`); + request.open('POST', `${API_BASE}/media/upload`); request.upload.onprogress = (event) => { if (!event.lengthComputable || !onProgress) return; const percent = Math.round((event.loaded / event.total) * 100); @@ -106,12 +106,12 @@ export function uploadMedia(targetPath, files, onProgress) { } export async function getTags() { - const response = await fetch(`${API_BASE}/api/tags`); + const response = await fetch(`${API_BASE}/tags`); return readJson(response); } export async function generateTag(label) { - const response = await fetch(`${API_BASE}/api/tags/generate`, { + const response = await fetch(`${API_BASE}/tags/generate`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ label }), @@ -120,7 +120,7 @@ export async function generateTag(label) { } export async function claimTag(uid, label) { - const response = await fetch(`${API_BASE}/api/tags/claim`, { + const response = await fetch(`${API_BASE}/tags/claim`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ uid, label }), @@ -129,7 +129,7 @@ export async function claimTag(uid, label) { } export async function markTagWritten(uid) { - const response = await fetch(`${API_BASE}/api/tags/${uid}/write`, { + const response = await fetch(`${API_BASE}/tags/${uid}/write`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, }); @@ -137,22 +137,22 @@ export async function markTagWritten(uid) { } export async function getBoxTags(boxId) { - const response = await fetch(`${API_BASE}/api/boxes/${boxId}/tags`); + const response = await fetch(`${API_BASE}/boxes/${boxId}/tags`); return readJson(response); } export async function getBoxLocalTags(boxId) { - const response = await fetch(`${API_BASE}/api/boxes/${boxId}/local-tags`); + const response = await fetch(`${API_BASE}/boxes/${boxId}/local-tags`); return readJson(response); } export async function getTagBlocks(boxId) { - const response = await fetch(`${API_BASE}/api/boxes/${boxId}/tag-blocks`); + const response = await fetch(`${API_BASE}/boxes/${boxId}/tag-blocks`); return readJson(response); } export async function setTagBlock(boxId, uid, blocked) { - const response = await fetch(`${API_BASE}/api/boxes/${boxId}/tag-blocks`, { + const response = await fetch(`${API_BASE}/boxes/${boxId}/tag-blocks`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ uid, blocked }), @@ -161,7 +161,7 @@ export async function setTagBlock(boxId, uid, blocked) { } export async function setBoxAlias(boxId, alias) { - const response = await fetch(`${API_BASE}/api/boxes/${boxId}/alias`, { + const response = await fetch(`${API_BASE}/boxes/${boxId}/alias`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ alias }), @@ -170,7 +170,7 @@ export async function setBoxAlias(boxId, alias) { } export async function setTagAlias(uid, alias) { - const response = await fetch(`${API_BASE}/api/tags/${uid}/alias`, { + const response = await fetch(`${API_BASE}/tags/${uid}/alias`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ alias }), @@ -179,7 +179,7 @@ export async function setTagAlias(uid, alias) { } export async function assignTag(uid, boxId) { - const response = await fetch(`${API_BASE}/api/tags/${uid}/assign`, { + const response = await fetch(`${API_BASE}/tags/${uid}/assign`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ box_id: boxId }), @@ -188,7 +188,7 @@ export async function assignTag(uid, boxId) { } export async function unassignTag(uid, boxId) { - const response = await fetch(`${API_BASE}/api/tags/${uid}/unassign`, { + const response = await fetch(`${API_BASE}/tags/${uid}/unassign`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ box_id: boxId }), @@ -197,14 +197,14 @@ export async function unassignTag(uid, boxId) { } export async function deleteTag(uid) { - const response = await fetch(`${API_BASE}/api/tags/${uid}`, { + const response = await fetch(`${API_BASE}/tags/${uid}`, { method: 'DELETE', }); return readJson(response); } export async function setTagMedia(uid, mediaPath) { - const response = await fetch(`${API_BASE}/api/tags/${uid}/media`, { + const response = await fetch(`${API_BASE}/tags/${uid}/media`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ media_path: mediaPath }), @@ -213,7 +213,7 @@ export async function setTagMedia(uid, mediaPath) { } export async function pullTagFromBox(boxId, uid, targetFolder) { - const response = await fetch(`${API_BASE}/api/boxes/${boxId}/pull-tag`, { + const response = await fetch(`${API_BASE}/boxes/${boxId}/pull-tag`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ uid, target_folder: targetFolder }), @@ -222,7 +222,7 @@ export async function pullTagFromBox(boxId, uid, targetFolder) { } export async function sendCommand(boxId, command, payload = {}) { - const response = await fetch(`${API_BASE}/api/boxes/${boxId}/command`, { + const response = await fetch(`${API_BASE}/boxes/${boxId}/command`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ command, payload }), @@ -231,7 +231,7 @@ export async function sendCommand(boxId, command, payload = {}) { } export async function unpairBox(boxId) { - const response = await fetch(`${API_BASE}/api/boxes/${boxId}/unpair`, { + const response = await fetch(`${API_BASE}/boxes/${boxId}/unpair`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, }); diff --git a/gui/frontend/vite.config.js b/gui/frontend/vite.config.js index eaf2322..ee322b1 100644 --- a/gui/frontend/vite.config.js +++ b/gui/frontend/vite.config.js @@ -1,11 +1,23 @@ -import { defineConfig } from 'vite'; +import { defineConfig, loadEnv } from 'vite'; import react from '@vitejs/plugin-react'; -export default defineConfig({ - plugins: [react()], - server: { - host: true, - port: 5174, - strictPort: true, - }, +export default defineConfig(({ mode }) => { + const env = loadEnv(mode, process.cwd(), ''); + const rawTarget = env.VITE_BACKEND_URL || 'http://127.0.0.1:5001'; + const apiTarget = rawTarget.replace(/\/api\/?$/, ''); + + return { + plugins: [react()], + server: { + host: true, + port: 5174, + strictPort: true, + proxy: { + '/api': { + target: apiTarget, + changeOrigin: true, + }, + }, + }, + }; });