diff --git a/backend/config/settings.py b/backend/config/settings.py index 087c627..1efe311 100644 --- a/backend/config/settings.py +++ b/backend/config/settings.py @@ -3,6 +3,7 @@ Django settings for the J621 backend. """ import os +import subprocess from pathlib import Path from dotenv import load_dotenv @@ -19,6 +20,24 @@ ALLOWED_HOSTS = [ if host.strip() ] + +def _git_commit_hash(): + """Short git hash of the running build, mirroring the original app.""" + try: + return subprocess.check_output( + ["git", "rev-parse", "--short", "HEAD"], + cwd=BASE_DIR, + text=True, + stderr=subprocess.DEVNULL, + ).strip() + except (subprocess.SubprocessError, OSError): + return "unknown" + + +GIT_COMMIT_HASH = _git_commit_hash() +APP_ENV = "dev" if DEBUG else "prod" +APP_VERSION = f"{APP_ENV} @ {GIT_COMMIT_HASH}" + # Application definition INSTALLED_APPS = [ diff --git a/frontend/design.md_j621_frontend_spec.md b/frontend/design.md_j621_frontend_spec.md index 94cc9de..288cd8e 100644 --- a/frontend/design.md_j621_frontend_spec.md +++ b/frontend/design.md_j621_frontend_spec.md @@ -1,6 +1,6 @@ # DESIGN.md — J621 Frontend Design System & Architecture Specification -> **Version:** 1.4.2-stable +> **Version:** the git commit hash of the build (e.g. `3f35330`) > **Theme Foundation:** Catppuccin Mocha + e621 Authentic Taxonomy Architecture > **Target Platform:** Desktop-first, fully responsive self-hosted home-server media web application (the library is a watched folder on disk, not a NAS appliance) > **Reference Design System:** `Mocha Archive Terminal` (`{{DATA:DESIGN_SYSTEM:DESIGN_SYSTEM_3}}`) @@ -79,12 +79,12 @@ All tag chips, counters, and sidebar taxonomy badges strictly adhere to e621's e - **Top App Bar (`#11111b`, height: 56px):** - Left: Brand mark `J621` badge (`#cba6f7`) followed by the **storage line** — the path of the watched folder that J621 indexes (e.g. `/mnt/media/library`). J621 is folder-based: this is just a path on disk, not a NAS/appliance indicator. - Center: Nav pills: `Library`, `Online`, `Pools`, `Followed`, `Upload`, `Duplicates`, and `Stats [STAFF]`. - - Right: System status pill with real backend values, never hardcoded: environment (`DEV`/`PROD`), the actual host OS, page generation time, and the total e621 API request time for that page load — e.g. `ENV: PROD · LINUX · 18ms (e621: 4ms)`. Followed by the user avatar. + - Right: System status pill with real backend values, never hardcoded: environment (`DEV`/`PROD`), git commit hash, the actual host OS, page generation time, and the total e621 API request time for that page load — e.g. `ENV: PROD · a1b2c3d · LINUX · 18ms (e621: 4ms)`. Followed by the user avatar. - **Global Footer Status Strip (`#11111b`, height: 32px):** - The strip placement is a proposal; its values are real and drawn from the existing stats data. - Left: the watched folder path — `📁 Local Storage: /mnt/media/library`. - Center: `⚡ Active Workers: N running | Queue: M pending` — the count of active optimization/ingest jobs and queued downloads (the original app surfaced this on its stats page; the footer simply keeps it visible). - - Right: the build actually running — `J621 ` / commit hash. + - Right: the running build — ` @ ` (e.g. `dev @ 3f35330`), matching the original app. - **Collapsible Sidebar (Behavior):** - **Closed by default** across all gallery and viewer views to prioritize screen real estate. - Toggled via `☰` button or quick keyboard shortcut (`Ctrl+B` or `⌘B`). diff --git a/frontend/src/components/AppShell.tsx b/frontend/src/components/AppShell.tsx index 2f1bd1f..1594a0d 100644 --- a/frontend/src/components/AppShell.tsx +++ b/frontend/src/components/AppShell.tsx @@ -2,6 +2,7 @@ import { LogOut } from "lucide-react"; import { Link, NavLink, Outlet } from "react-router-dom"; import { cn } from "@/lib/cn"; +import { APP_VERSION } from "@/lib/version"; import { useAuth } from "@/store/auth"; const navItems = [ @@ -21,9 +22,6 @@ export function AppShell() { J621 - - Mocha Archive Terminal -
+ + {APP_VERSION} + {user ? ( <>
diff --git a/frontend/src/lib/version.ts b/frontend/src/lib/version.ts new file mode 100644 index 0000000..34e7467 --- /dev/null +++ b/frontend/src/lib/version.ts @@ -0,0 +1,5 @@ +declare const __GIT_COMMIT_HASH__: string; + +export const GIT_COMMIT_HASH = __GIT_COMMIT_HASH__; +export const APP_ENV = import.meta.env.DEV ? "dev" : "prod"; +export const APP_VERSION = `${APP_ENV} @ ${GIT_COMMIT_HASH}`; diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 5ac699a..63ba397 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,13 +1,30 @@ +import { execSync } from "node:child_process"; import { fileURLToPath, URL } from "node:url"; import tailwindcss from "@tailwindcss/vite"; import react from "@vitejs/plugin-react"; import { defineConfig } from "vite"; +function gitCommitHash(): string { + try { + return execSync("git rev-parse --short HEAD", { + cwd: fileURLToPath(new URL(".", import.meta.url)), + stdio: ["ignore", "pipe", "ignore"], + }) + .toString() + .trim(); + } catch { + return "unknown"; + } +} + const backend = process.env.VITE_BACKEND ?? "http://127.0.0.1:8000"; // https://vite.dev/config/ export default defineConfig({ + define: { + __GIT_COMMIT_HASH__: JSON.stringify(gitCommitHash()), + }, plugins: [react(), tailwindcss()], resolve: { alias: {