From f7fc5ba5d7e8e5efc282208af99dbde302dec07e Mon Sep 17 00:00:00 2001 From: 9qeklajc <9qeklajc> Date: Sat, 25 Oct 2025 22:34:38 +0200 Subject: [PATCH] fix url --- .env.example | 4 +++ scripts/build-ui.sh | 30 ++++++++++++++++-- ui/lib/api/services/configuration.ts | 17 +++++++++- ui_out/404.html | 2 +- ui_out/404/index.html | 2 +- .../_buildManifest.js | 0 .../_ssgManifest.js | 0 ...1afa7029035.js => 900-326dcea1c8c632bd.js} | 2 +- .../chunks/app/layout-0a365473079ed328.js | 1 + .../chunks/app/layout-8cbedc9fb3669ba4.js | 1 - .../chunks/app/login/page-603b845ae6bd54c9.js | 1 - .../chunks/app/login/page-d1019d7482daf05e.js | 1 + ui_out/index.html | 2 +- ui_out/index.txt | 18 +++++------ ui_out/login/index.html | 2 +- ui_out/login/index.txt | 8 ++--- ui_out/model/index.html | 2 +- ui_out/model/index.txt | 8 ++--- ui_out/out/404.html | 1 + ui_out/out/404/index.html | 1 + .../static/chunks/222-23a547ab56ff9638.js | 1 + .../static/chunks/226-b955dd578f372adc.js | 1 + .../static/chunks/29-2e340e48c1ca61fb.js | 1 + .../static/chunks/363-c1e2b04767a3c84b.js | 1 + .../static/chunks/375-7943a6dae9b88f03.js | 1 + .../static/chunks/481-7440db9fd9bb94b2.js | 1 + .../static/chunks/497-cf9737613a43115a.js | 1 + .../static/chunks/601-3f92835872ce1c3b.js | 1 + .../static/chunks/651-7f1a745b0e3db11d.js | 1 + .../chunks/65b78783-daf30cffc34759e7.js | 1 + .../static/chunks/730-eb609e4385533b6b.js | 1 + .../static/chunks/826-03658aa28a2a895d.js | 1 + .../static/chunks/900-4f9edbec4bd4635d.js | 1 + .../static/chunks/978-960e423dcb2d179d.js | 1 + .../static/chunks/982-dc9d2de6dd23b183.js | 1 + .../app/_not-found/page-67d68e30910d9cb7.js | 1 + .../chunks/app/layout-a57cd317a374e9c8.js | 1 + .../chunks/app/login/page-ff1377de4625f77a.js | 1 + .../chunks/app/model/page-862224df2a15ab65.js | 1 + .../chunks/app/page-3876b4fb2023557a.js | 1 + .../app/providers/page-d7c9b193573b160c.js | 1 + .../app/settings/page-36e251683a0d492c.js | 1 + .../app/transactions/page-b9cef669e0e237ee.js | 1 + .../app/unauthorized/page-96bd6a23715af694.js | 1 + .../chunks/framework-8c3b2116d10b4580.js | 1 + .../static/chunks/main-0a7596aef9908400.js | 1 + .../chunks/main-app-17707ee50e50ea2f.js | 1 + .../chunks/pages/_app-061aa32ebf2d84a0.js | 1 + .../chunks/pages/_error-37aa057e76496f5c.js | 1 + .../chunks/polyfills-42372ed130431b0a.js | 1 + .../static/chunks/webpack-a88517f6dce11b25.js | 1 + .../out/_next/static/css/a2fcfb52b8f42d80.css | 1 + .../out/_next/static/css/de70bee13400563f.css | 1 + .../static/media/4cf2300e9c8272f7-s.p.woff2 | Bin 0 -> 28388 bytes .../static/media/747892c23ea88013-s.woff2 | Bin 0 -> 13036 bytes .../static/media/8d697b304b401681-s.woff2 | Bin 0 -> 14676 bytes .../static/media/93f479601ee12b01-s.p.woff2 | Bin 0 -> 31288 bytes .../static/media/9610d9e46709d722-s.woff2 | Bin 0 -> 12608 bytes .../static/media/ba015fad6dcf6784-s.woff2 | Bin 0 -> 15292 bytes .../tHqKC6PJ35XBg8LRDCWKS/_buildManifest.js | 1 + .../tHqKC6PJ35XBg8LRDCWKS/_ssgManifest.js | 1 + ui_out/out/favicon.ico | Bin 0 -> 15406 bytes ui_out/out/file.svg | 1 + ui_out/out/globe.svg | 1 + ui_out/out/icon.ico | Bin 0 -> 15406 bytes ui_out/out/index.html | 1 + ui_out/out/index.txt | 29 +++++++++++++++++ ui_out/out/login/index.html | 1 + ui_out/out/login/index.txt | 27 ++++++++++++++++ ui_out/out/model/index.html | 1 + ui_out/out/model/index.txt | 27 ++++++++++++++++ ui_out/out/next.svg | 1 + ui_out/out/providers/index.html | 1 + ui_out/out/providers/index.txt | 27 ++++++++++++++++ ui_out/out/settings/index.html | 1 + ui_out/out/settings/index.txt | 27 ++++++++++++++++ ui_out/out/transactions/index.html | 1 + ui_out/out/transactions/index.txt | 27 ++++++++++++++++ ui_out/out/unauthorized/index.html | 1 + ui_out/out/unauthorized/index.txt | 27 ++++++++++++++++ ui_out/out/vercel.svg | 1 + ui_out/out/window.svg | 1 + ui_out/providers/index.html | 2 +- ui_out/providers/index.txt | 8 ++--- ui_out/settings/index.html | 2 +- ui_out/settings/index.txt | 8 ++--- ui_out/transactions/index.html | 2 +- ui_out/transactions/index.txt | 8 ++--- ui_out/unauthorized/index.html | 2 +- ui_out/unauthorized/index.txt | 6 ++-- 90 files changed, 331 insertions(+), 48 deletions(-) rename ui_out/_next/static/{6UzBhGpyRdJjWoKvuuFgP => UEmzYNZb207mpxXHDgTmm}/_buildManifest.js (100%) rename ui_out/_next/static/{6UzBhGpyRdJjWoKvuuFgP => UEmzYNZb207mpxXHDgTmm}/_ssgManifest.js (100%) rename ui_out/_next/static/chunks/{900-4ce6a1afa7029035.js => 900-326dcea1c8c632bd.js} (56%) create mode 100644 ui_out/_next/static/chunks/app/layout-0a365473079ed328.js delete mode 100644 ui_out/_next/static/chunks/app/layout-8cbedc9fb3669ba4.js delete mode 100644 ui_out/_next/static/chunks/app/login/page-603b845ae6bd54c9.js create mode 100644 ui_out/_next/static/chunks/app/login/page-d1019d7482daf05e.js create mode 100644 ui_out/out/404.html create mode 100644 ui_out/out/404/index.html create mode 100644 ui_out/out/_next/static/chunks/222-23a547ab56ff9638.js create mode 100644 ui_out/out/_next/static/chunks/226-b955dd578f372adc.js create mode 100644 ui_out/out/_next/static/chunks/29-2e340e48c1ca61fb.js create mode 100644 ui_out/out/_next/static/chunks/363-c1e2b04767a3c84b.js create mode 100644 ui_out/out/_next/static/chunks/375-7943a6dae9b88f03.js create mode 100644 ui_out/out/_next/static/chunks/481-7440db9fd9bb94b2.js create mode 100644 ui_out/out/_next/static/chunks/497-cf9737613a43115a.js create mode 100644 ui_out/out/_next/static/chunks/601-3f92835872ce1c3b.js create mode 100644 ui_out/out/_next/static/chunks/651-7f1a745b0e3db11d.js create mode 100644 ui_out/out/_next/static/chunks/65b78783-daf30cffc34759e7.js create mode 100644 ui_out/out/_next/static/chunks/730-eb609e4385533b6b.js create mode 100644 ui_out/out/_next/static/chunks/826-03658aa28a2a895d.js create mode 100644 ui_out/out/_next/static/chunks/900-4f9edbec4bd4635d.js create mode 100644 ui_out/out/_next/static/chunks/978-960e423dcb2d179d.js create mode 100644 ui_out/out/_next/static/chunks/982-dc9d2de6dd23b183.js create mode 100644 ui_out/out/_next/static/chunks/app/_not-found/page-67d68e30910d9cb7.js create mode 100644 ui_out/out/_next/static/chunks/app/layout-a57cd317a374e9c8.js create mode 100644 ui_out/out/_next/static/chunks/app/login/page-ff1377de4625f77a.js create mode 100644 ui_out/out/_next/static/chunks/app/model/page-862224df2a15ab65.js create mode 100644 ui_out/out/_next/static/chunks/app/page-3876b4fb2023557a.js create mode 100644 ui_out/out/_next/static/chunks/app/providers/page-d7c9b193573b160c.js create mode 100644 ui_out/out/_next/static/chunks/app/settings/page-36e251683a0d492c.js create mode 100644 ui_out/out/_next/static/chunks/app/transactions/page-b9cef669e0e237ee.js create mode 100644 ui_out/out/_next/static/chunks/app/unauthorized/page-96bd6a23715af694.js create mode 100644 ui_out/out/_next/static/chunks/framework-8c3b2116d10b4580.js create mode 100644 ui_out/out/_next/static/chunks/main-0a7596aef9908400.js create mode 100644 ui_out/out/_next/static/chunks/main-app-17707ee50e50ea2f.js create mode 100644 ui_out/out/_next/static/chunks/pages/_app-061aa32ebf2d84a0.js create mode 100644 ui_out/out/_next/static/chunks/pages/_error-37aa057e76496f5c.js create mode 100644 ui_out/out/_next/static/chunks/polyfills-42372ed130431b0a.js create mode 100644 ui_out/out/_next/static/chunks/webpack-a88517f6dce11b25.js create mode 100644 ui_out/out/_next/static/css/a2fcfb52b8f42d80.css create mode 100644 ui_out/out/_next/static/css/de70bee13400563f.css create mode 100644 ui_out/out/_next/static/media/4cf2300e9c8272f7-s.p.woff2 create mode 100644 ui_out/out/_next/static/media/747892c23ea88013-s.woff2 create mode 100644 ui_out/out/_next/static/media/8d697b304b401681-s.woff2 create mode 100644 ui_out/out/_next/static/media/93f479601ee12b01-s.p.woff2 create mode 100644 ui_out/out/_next/static/media/9610d9e46709d722-s.woff2 create mode 100644 ui_out/out/_next/static/media/ba015fad6dcf6784-s.woff2 create mode 100644 ui_out/out/_next/static/tHqKC6PJ35XBg8LRDCWKS/_buildManifest.js create mode 100644 ui_out/out/_next/static/tHqKC6PJ35XBg8LRDCWKS/_ssgManifest.js create mode 100644 ui_out/out/favicon.ico create mode 100644 ui_out/out/file.svg create mode 100644 ui_out/out/globe.svg create mode 100644 ui_out/out/icon.ico create mode 100644 ui_out/out/index.html create mode 100644 ui_out/out/index.txt create mode 100644 ui_out/out/login/index.html create mode 100644 ui_out/out/login/index.txt create mode 100644 ui_out/out/model/index.html create mode 100644 ui_out/out/model/index.txt create mode 100644 ui_out/out/next.svg create mode 100644 ui_out/out/providers/index.html create mode 100644 ui_out/out/providers/index.txt create mode 100644 ui_out/out/settings/index.html create mode 100644 ui_out/out/settings/index.txt create mode 100644 ui_out/out/transactions/index.html create mode 100644 ui_out/out/transactions/index.txt create mode 100644 ui_out/out/unauthorized/index.html create mode 100644 ui_out/out/unauthorized/index.txt create mode 100644 ui_out/out/vercel.svg create mode 100644 ui_out/out/window.svg diff --git a/.env.example b/.env.example index b5d86e6e..d093e006 100644 --- a/.env.example +++ b/.env.example @@ -37,3 +37,7 @@ UPSTREAM_API_KEY=your-upstream-api-key # BASE_URL=https://openrouter.ai/api/v1 # MODELS_PATH=models.json # SOURCE= + +# UI Configuration (for Next.js frontend) +# These variables are prefixed with NEXT_PUBLIC_ to be accessible in the browser +# NEXT_PUBLIC_API_URL=http://127.0.0.1:8000 diff --git a/scripts/build-ui.sh b/scripts/build-ui.sh index 1be1d424..5231d5e0 100755 --- a/scripts/build-ui.sh +++ b/scripts/build-ui.sh @@ -26,6 +26,22 @@ else exit 1 fi +# Check for root .env file (centralized configuration) +ROOT_ENV_FILE="$PROJECT_ROOT/.env" +UI_ENV_FILE="$UI_DIR/.env.local" + +if [ -f "$ROOT_ENV_FILE" ]; then + echo "Loading environment variables from $ROOT_ENV_FILE" + # Extract NEXT_PUBLIC_ variables and create .env.local for Next.js + grep '^NEXT_PUBLIC_' "$ROOT_ENV_FILE" > "$UI_ENV_FILE" + echo "Created $UI_ENV_FILE with UI configuration" +else + echo "Warning: .env file not found in project root. Using default configuration." + echo "Create a .env file based on .env.example for proper configuration." + # Create empty .env.local to avoid issues + > "$UI_ENV_FILE" +fi + echo "Building static export..." if command -v pnpm &> /dev/null; then pnpm run build @@ -35,13 +51,21 @@ fi mv out ../ui_out +# Clean up the temporary .env.local file +if [ -f "$UI_ENV_FILE" ]; then + rm "$UI_ENV_FILE" + echo "Cleaned up temporary $UI_ENV_FILE" +fi + echo "" echo "✓ UI build complete!" echo "Static files generated at: $UI_DIR/out" echo "" echo "To serve the UI from the Python backend:" -echo " 1. Make sure NEXT_PUBLIC_API_URL is not set (or set to empty) to use relative API paths" -echo " 2. Start the backend: uvicorn routstr.core.main:app --host 0.0.0.0 --port 8000" -echo " 3. Access the UI at: http://localhost:8000" +echo " 1. Configure NEXT_PUBLIC_API_URL in the root .env file" +echo " 2. For development: Set NEXT_PUBLIC_API_URL=http://127.0.0.1:8000 or leave empty for relative paths" +echo " 3. For production: Set NEXT_PUBLIC_API_URL=https://your-production-api.com" +echo " 4. Start the backend: uvicorn routstr.core.main:app --host 0.0.0.0 --port 8000" +echo " 5. Access the UI at: http://localhost:8000" echo "" diff --git a/ui/lib/api/services/configuration.ts b/ui/lib/api/services/configuration.ts index 4c651566..413a780b 100644 --- a/ui/lib/api/services/configuration.ts +++ b/ui/lib/api/services/configuration.ts @@ -59,7 +59,22 @@ export class ConfigurationService { * Get the local base URL (never use external configuration) */ static getLocalBaseUrl(): string { - return process.env.NEXT_PUBLIC_API_URL || 'http://127.0.0.1:8000'; + const apiUrl = process.env.NEXT_PUBLIC_API_URL; + + console.log(apiUrl); + if (apiUrl) { + return apiUrl; + } + + if (process.env.NODE_ENV === 'production') { + return ''; + } + + return 'http://127.0.0.1:8000'; + } + + static isProduction(): boolean { + return process.env.NODE_ENV === 'production'; } /** diff --git a/ui_out/404.html b/ui_out/404.html index 340503a1..b80798e6 100644 --- a/ui_out/404.html +++ b/ui_out/404.html @@ -1 +1 @@ -
\ No newline at end of file + \ No newline at end of file diff --git a/ui_out/404/index.html b/ui_out/404/index.html index 340503a1..b80798e6 100644 --- a/ui_out/404/index.html +++ b/ui_out/404/index.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/ui_out/_next/static/6UzBhGpyRdJjWoKvuuFgP/_buildManifest.js b/ui_out/_next/static/UEmzYNZb207mpxXHDgTmm/_buildManifest.js similarity index 100% rename from ui_out/_next/static/6UzBhGpyRdJjWoKvuuFgP/_buildManifest.js rename to ui_out/_next/static/UEmzYNZb207mpxXHDgTmm/_buildManifest.js diff --git a/ui_out/_next/static/6UzBhGpyRdJjWoKvuuFgP/_ssgManifest.js b/ui_out/_next/static/UEmzYNZb207mpxXHDgTmm/_ssgManifest.js similarity index 100% rename from ui_out/_next/static/6UzBhGpyRdJjWoKvuuFgP/_ssgManifest.js rename to ui_out/_next/static/UEmzYNZb207mpxXHDgTmm/_ssgManifest.js diff --git a/ui_out/_next/static/chunks/900-4ce6a1afa7029035.js b/ui_out/_next/static/chunks/900-326dcea1c8c632bd.js similarity index 56% rename from ui_out/_next/static/chunks/900-4ce6a1afa7029035.js rename to ui_out/_next/static/chunks/900-326dcea1c8c632bd.js index 4aaff6a6..bc5067cb 100644 --- a/ui_out/_next/static/chunks/900-4ce6a1afa7029035.js +++ b/ui_out/_next/static/chunks/900-326dcea1c8c632bd.js @@ -1 +1 @@ -"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[900],{268:(e,t,a)=>{a.d(t,{p:()=>i});var r=a(3422);a(4398);var n=a(9183);function i(e){let{className:t,type:a,...i}=e;return(0,r.jsx)("input",{type:a,"data-slot":"input",className:(0,n.cn)("file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm","focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]","aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",t),...i})}},532:(e,t,a)=>{a.d(t,{SiteHeader:()=>f});var r=a(3422),n=a(5349),i=a(953),s=a(3648),o=a(9779),l=a(1064),d=a(3270),c=a(3831);a(4398);var u=a(5746),h=a(4357),g=a(1262);function p(){let{setTheme:e,theme:t}=(0,g.D)();return(0,r.jsxs)(s.$,{variant:"ghost",size:"sm",onClick:()=>e("light"===t?"dark":"light"),className:"gap-2",children:[(0,r.jsx)(u.A,{className:"h-4 w-4 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90"}),(0,r.jsx)(h.A,{className:"h-4 w-4 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0"}),(0,r.jsx)("span",{className:"sr-only",children:"Toggle theme"})]})}function f(){let e=(0,l.useRouter)(),t=async()=>{try{await (0,d.wu)(),c.oR.success("Logged out successfully"),e.push("/login")}catch(e){console.error("Logout error:",e),c.oR.error("Failed to logout")}};return(0,r.jsx)("header",{className:"flex h-12 shrink-0 items-center gap-2 border-b transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12",children:(0,r.jsxs)("div",{className:"flex w-full items-center justify-between gap-1 px-4 lg:gap-2 lg:px-6",children:[(0,r.jsxs)("div",{className:"flex items-center gap-1 lg:gap-2",children:[(0,r.jsx)(i.x2,{className:"-ml-1"}),(0,r.jsx)(n.w,{orientation:"vertical",className:"mx-2 data-[orientation=vertical]:h-4"}),(0,r.jsx)("h1",{className:"text-base font-medium",children:"Routstr"})]}),(0,r.jsxs)("div",{className:"flex items-center gap-2",children:[(0,r.jsx)(p,{}),(0,r.jsxs)(s.$,{variant:"ghost",size:"sm",onClick:t,className:"gap-2",children:[(0,r.jsx)(o.A,{className:"h-4 w-4"}),(0,r.jsx)("span",{className:"hidden sm:inline",children:"Logout"})]})]})]})})}},953:(e,t,a)=>{a.d(t,{Bx:()=>k,Yv:()=>C,Cn:()=>A,rQ:()=>z,Gh:()=>S,SidebarInset:()=>_,wZ:()=>I,Uj:()=>U,FX:()=>B,SidebarProvider:()=>j,x2:()=>N});var r=a(3422),n=a(4398),i=a(6950),s=a(4676),o=a(3712),l=a(9183),d=a(3648);a(268),a(5349);var c=a(4316),u=a(9680);function h(e){let{...t}=e;return(0,r.jsx)(c.bL,{"data-slot":"sheet",...t})}function g(e){let{...t}=e;return(0,r.jsx)(c.ZL,{"data-slot":"sheet-portal",...t})}function p(e){let{className:t,...a}=e;return(0,r.jsx)(c.hJ,{"data-slot":"sheet-overlay",className:(0,l.cn)("data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",t),...a})}function f(e){let{className:t,children:a,side:n="right",...i}=e;return(0,r.jsxs)(g,{children:[(0,r.jsx)(p,{}),(0,r.jsxs)(c.UC,{"data-slot":"sheet-content",className:(0,l.cn)("bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500","right"===n&&"data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm","left"===n&&"data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm","top"===n&&"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b","bottom"===n&&"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",t),...i,children:[a,(0,r.jsxs)(c.bm,{className:"ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none",children:[(0,r.jsx)(u.A,{className:"size-4"}),(0,r.jsx)("span",{className:"sr-only",children:"Close"})]})]})]})}function m(e){let{className:t,...a}=e;return(0,r.jsx)("div",{"data-slot":"sheet-header",className:(0,l.cn)("flex flex-col gap-1.5 p-4",t),...a})}function b(e){let{className:t,...a}=e;return(0,r.jsx)(c.hE,{"data-slot":"sheet-title",className:(0,l.cn)("text-foreground font-semibold",t),...a})}function x(e){let{className:t,...a}=e;return(0,r.jsx)(c.VY,{"data-slot":"sheet-description",className:(0,l.cn)("text-muted-foreground text-sm",t),...a})}a(2745);var v=a(6545);let w=n.createContext(null);function y(){let e=n.useContext(w);if(!e)throw Error("useSidebar must be used within a SidebarProvider.");return e}function j(e){let{defaultOpen:t=!0,open:a,onOpenChange:i,className:s,style:o,children:d,...c}=e,u=function(){let[e,t]=n.useState(void 0);return n.useEffect(()=>{let e=window.matchMedia("(max-width: ".concat(767,"px)")),a=()=>{t(window.innerWidth<768)};return e.addEventListener("change",a),t(window.innerWidth<768),()=>e.removeEventListener("change",a)},[]),!!e}(),[h,g]=n.useState(!1),[p,f]=n.useState(t),m=null!=a?a:p,b=n.useCallback(e=>{let t="function"==typeof e?e(m):e;i?i(t):f(t),document.cookie="".concat("sidebar_state","=").concat(t,"; path=/; max-age=").concat(604800)},[i,m]),x=n.useCallback(()=>u?g(e=>!e):b(e=>!e),[u,b,g]);n.useEffect(()=>{let e=e=>{"b"===e.key&&(e.metaKey||e.ctrlKey)&&(e.preventDefault(),x())};return window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)},[x]);let y=m?"expanded":"collapsed",j=n.useMemo(()=>({state:y,open:m,setOpen:b,isMobile:u,openMobile:h,setOpenMobile:g,toggleSidebar:x}),[y,m,b,u,h,g,x]);return(0,r.jsx)(w.Provider,{value:j,children:(0,r.jsx)(v.Bc,{delayDuration:0,children:(0,r.jsx)("div",{"data-slot":"sidebar-wrapper",style:{"--sidebar-width":"16rem","--sidebar-width-icon":"3rem",...o},className:(0,l.cn)("group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full",s),...c,children:d})})})}function k(e){let{side:t="left",variant:a="sidebar",collapsible:n="offcanvas",className:i,children:s,...o}=e,{isMobile:d,state:c,openMobile:u,setOpenMobile:g}=y();return"none"===n?(0,r.jsx)("div",{"data-slot":"sidebar",className:(0,l.cn)("bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col",i),...o,children:s}):d?(0,r.jsx)(h,{open:u,onOpenChange:g,...o,children:(0,r.jsxs)(f,{"data-sidebar":"sidebar","data-slot":"sidebar","data-mobile":"true",className:"bg-sidebar text-sidebar-foreground fixed z-50 w-(--sidebar-width) p-0 [&>button]:hidden",style:{"--sidebar-width":"18rem"},side:t,children:[(0,r.jsxs)(m,{className:"sr-only",children:[(0,r.jsx)(b,{children:"Sidebar"}),(0,r.jsx)(x,{children:"Displays the mobile sidebar."})]}),(0,r.jsx)("div",{className:"flex h-full w-full flex-col overflow-y-auto",children:s})]})}):(0,r.jsxs)("div",{className:"group peer text-sidebar-foreground hidden md:block","data-state":c,"data-collapsible":"collapsed"===c?n:"","data-variant":a,"data-side":t,"data-slot":"sidebar",children:[(0,r.jsx)("div",{"data-slot":"sidebar-gap",className:(0,l.cn)("relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear","group-data-[collapsible=offcanvas]:w-0","group-data-[side=right]:rotate-180","floating"===a||"inset"===a?"group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]":"group-data-[collapsible=icon]:w-(--sidebar-width-icon)")}),(0,r.jsx)("div",{"data-slot":"sidebar-container",className:(0,l.cn)("fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex","left"===t?"left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]":"right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]","floating"===a||"inset"===a?"p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]":"group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",i),...o,children:(0,r.jsx)("div",{"data-sidebar":"sidebar","data-slot":"sidebar-inner",className:"bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm",children:s})})]})}function N(e){let{className:t,onClick:a,...n}=e,{toggleSidebar:i}=y();return(0,r.jsxs)(d.$,{"data-sidebar":"trigger","data-slot":"sidebar-trigger",variant:"ghost",size:"icon",className:(0,l.cn)("size-7",t),onClick:e=>{null==a||a(e),i()},...n,children:[(0,r.jsx)(o.A,{}),(0,r.jsx)("span",{className:"sr-only",children:"Toggle Sidebar"})]})}function _(e){let{className:t,...a}=e;return(0,r.jsx)("main",{"data-slot":"sidebar-inset",className:(0,l.cn)("bg-background relative flex w-full flex-1 flex-col","md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2","overflow-x-hidden",t),...a})}function S(e){let{className:t,...a}=e;return(0,r.jsx)("div",{"data-slot":"sidebar-header","data-sidebar":"header",className:(0,l.cn)("flex flex-col gap-2 p-2",t),...a})}function C(e){let{className:t,...a}=e;return(0,r.jsx)("div",{"data-slot":"sidebar-content","data-sidebar":"content",className:(0,l.cn)("flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",t),...a})}function A(e){let{className:t,...a}=e;return(0,r.jsx)("div",{"data-slot":"sidebar-group","data-sidebar":"group",className:(0,l.cn)("relative flex w-full min-w-0 flex-col p-2",t),...a})}function z(e){let{className:t,...a}=e;return(0,r.jsx)("div",{"data-slot":"sidebar-group-content","data-sidebar":"group-content",className:(0,l.cn)("w-full text-sm",t),...a})}function I(e){let{className:t,...a}=e;return(0,r.jsx)("ul",{"data-slot":"sidebar-menu","data-sidebar":"menu",className:(0,l.cn)("flex w-full min-w-0 flex-col gap-1",t),...a})}function B(e){let{className:t,...a}=e;return(0,r.jsx)("li",{"data-slot":"sidebar-menu-item","data-sidebar":"menu-item",className:(0,l.cn)("group/menu-item relative",t),...a})}let E=(0,s.F)("peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",{variants:{variant:{default:"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",outline:"bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]"},size:{default:"h-8 text-sm",sm:"h-7 text-xs",lg:"h-12 text-sm group-data-[collapsible=icon]:p-0!"}},defaultVariants:{variant:"default",size:"default"}});function U(e){let{asChild:t=!1,isActive:a=!1,variant:n="default",size:s="default",tooltip:o,className:d,...c}=e,u=t?i.DX:"button",{isMobile:h,state:g}=y(),p=(0,r.jsx)(u,{"data-slot":"sidebar-menu-button","data-sidebar":"menu-button","data-size":s,"data-active":a,className:(0,l.cn)(E({variant:n,size:s}),d),...c});return o?("string"==typeof o&&(o={children:o}),(0,r.jsxs)(v.m_,{children:[(0,r.jsx)(v.k$,{asChild:!0,children:p}),(0,r.jsx)(v.ZI,{side:"right",align:"center",hidden:"collapsed"!==g||h,...o})]})):p}},2745:(e,t,a)=>{a.d(t,{E:()=>i});var r=a(3422),n=a(9183);function i(e){let{className:t,...a}=e;return(0,r.jsx)("div",{"data-slot":"skeleton",className:(0,n.cn)("bg-accent animate-pulse rounded-md",t),...a})}},3234:(e,t,a)=>{a.d(t,{s:()=>i});var r=a(9945),n=a(5842);r.Ik({endpoint:r.Yj().url().or(r.eu("")),apiKey:r.Yj(),enabled:r.zM()});class i{static getServerConfig(){return{endpoint:localStorage.getItem("server_endpoint")||"",apiKey:localStorage.getItem("server_api_key")||"",enabled:"true"===localStorage.getItem("server_enabled")}}static saveServerConfig(e){localStorage.setItem("server_endpoint",e.endpoint),localStorage.setItem("server_api_key",e.apiKey),localStorage.setItem("server_enabled",e.enabled.toString())}static isServerConfigValid(){let e=this.getServerConfig();return e.enabled&&!!e.endpoint&&!!e.apiKey}static getLocalBaseUrl(){return"http://127.0.0.1:8000"}static getBaseUrl(){let e=this.getServerConfig();return e.enabled&&e.endpoint?e.endpoint:this.getLocalBaseUrl()}static getAuthHeaders(){let e={"Content-Type":"application/json"};try{{let t=localStorage.getItem("admin_token"),a=localStorage.getItem("admin_token_expiry");if(t&&a){let r=parseInt(a,10);if(Date.now(){"use strict";s.d(t,{E:()=>l});var a=s(3422);s(4398);var r=s(4676),n=s(9183);let i=(0,r.F)("inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",{variants:{variant:{default:"border-transparent bg-primary text-primary-foreground hover:bg-primary/80",secondary:"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",destructive:"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",outline:"text-foreground",success:"border-transparent bg-green-500 text-white hover:bg-green-500/80",warning:"border-transparent bg-yellow-500 text-white hover:bg-yellow-500/80",error:"border-transparent bg-red-500 text-white hover:bg-red-500/80"}},defaultVariants:{variant:"default"}});function l(e){let{className:t,variant:s,...r}=e;return(0,a.jsx)("div",{className:(0,n.cn)(i({variant:s}),t),...r})}},9442:(e,t,s)=>{"use strict";s.d(t,{Fc:()=>l,TN:()=>c});var a=s(3422);s(4398);var r=s(4676),n=s(9183);let i=(0,r.F)("relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",{variants:{variant:{default:"bg-card text-card-foreground",destructive:"text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90"}},defaultVariants:{variant:"default"}});function l(e){let{className:t,variant:s,...r}=e;return(0,a.jsx)("div",{"data-slot":"alert",role:"alert",className:(0,n.cn)(i({variant:s}),t),...r})}function c(e){let{className:t,...s}=e;return(0,a.jsx)("div",{"data-slot":"alert-description",className:(0,n.cn)("text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed",t),...s})}}},e=>{var t=t=>e(e.s=t);e.O(0,[363,222,226,29,730,900,945,497,358],()=>t(2127)),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/ui_out/out/_next/static/chunks/app/unauthorized/page-96bd6a23715af694.js b/ui_out/out/_next/static/chunks/app/unauthorized/page-96bd6a23715af694.js
new file mode 100644
index 00000000..ee3a0fd6
--- /dev/null
+++ b/ui_out/out/_next/static/chunks/app/unauthorized/page-96bd6a23715af694.js
@@ -0,0 +1 @@
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[305],{1064:(e,r,t)=>{"use strict";var s=t(8);t.o(s,"usePathname")&&t.d(r,{usePathname:function(){return s.usePathname}}),t.o(s,"useRouter")&&t.d(r,{useRouter:function(){return s.useRouter}})},2818:(e,r,t)=>{"use strict";t.r(r),t.d(r,{default:()=>o});var s=t(3422),a=t(3648),i=t(1064);let n=(0,t(3929).A)("shield-alert",[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"M12 8v4",key:"1got3b"}],["path",{d:"M12 16h.01",key:"1drbdi"}]]);function o(){let e=(0,i.useRouter)();return(0,s.jsx)("div",{className:"bg-background flex min-h-screen flex-col items-center justify-center p-4",children:(0,s.jsxs)("div",{className:"flex max-w-md flex-col items-center space-y-6 text-center",children:[(0,s.jsx)(n,{className:"text-destructive h-24 w-24"}),(0,s.jsx)("h1",{className:"text-4xl font-bold",children:"Access Denied"}),(0,s.jsx)("p",{className:"text-muted-foreground text-lg",children:"You don't have permission to access this page. Please contact your administrator if you believe this is an error."}),(0,s.jsxs)("div",{className:"flex gap-4",children:[(0,s.jsx)(a.$,{onClick:()=>e.push("/"),children:"Go to Dashboard"}),(0,s.jsx)(a.$,{variant:"outline",onClick:()=>e.back(),children:"Go Back"})]})]})})}},3648:(e,r,t)=>{"use strict";t.d(r,{$:()=>d,r:()=>o});var s=t(3422);t(4398);var a=t(6950),i=t(4676),n=t(9183);let o=(0,i.F)("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",{variants:{variant:{default:"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",destructive:"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",outline:"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",secondary:"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",ghost:"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",link:"text-primary underline-offset-4 hover:underline"},size:{default:"h-9 px-4 py-2 has-[>svg]:px-3",sm:"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",lg:"h-10 rounded-md px-6 has-[>svg]:px-4",icon:"size-9"}},defaultVariants:{variant:"default",size:"default"}});function d(e){let{className:r,variant:t,size:i,asChild:d=!1,...c}=e,l=d?a.DX:"button";return(0,s.jsx)(l,{"data-slot":"button",className:(0,n.cn)(o({variant:t,size:i,className:r})),...c})}},3929:(e,r,t)=>{"use strict";t.d(r,{A:()=>u});var s=t(4398);let a=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),i=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,r,t)=>t?t.toUpperCase():r.toLowerCase()),n=e=>{let r=i(e);return r.charAt(0).toUpperCase()+r.slice(1)},o=function(){for(var e=arguments.length,r=Array(e),t=0;t