diff --git a/.woodpecker/build.yml b/.woodpecker/build.yml index 5b07a14..690151c 100644 --- a/.woodpecker/build.yml +++ b/.woodpecker/build.yml @@ -7,6 +7,7 @@ matrix: - api - abstraction - rules + - static steps: build-${APP}: diff --git a/.woodpecker/deploy.yml b/.woodpecker/deploy.yml index b74bda9..d98aae1 100644 --- a/.woodpecker/deploy.yml +++ b/.woodpecker/deploy.yml @@ -11,6 +11,7 @@ matrix: - api - abstraction - rules + - static steps: deploy-${APP}: diff --git a/apps/static/Dockerfile b/apps/static/Dockerfile new file mode 100644 index 0000000..bf63572 --- /dev/null +++ b/apps/static/Dockerfile @@ -0,0 +1,15 @@ +# Static assets Dockerfile (minimal webserver for /static only) + +FROM nginx:1.27-alpine + +WORKDIR /usr/share/nginx/html + +# Remove default nginx content +RUN rm -rf ./* + +# Copy only static assets from the UI project +COPY apps/ui/static/ ./ + +EXPOSE 80 + +# Use default nginx config; caller can mount custom config if needed diff --git a/apps/ui/static/README.md b/apps/static/static/README.md similarity index 100% rename from apps/ui/static/README.md rename to apps/static/static/README.md diff --git a/apps/ui/static/api-client.js b/apps/static/static/api-client.js similarity index 100% rename from apps/ui/static/api-client.js rename to apps/static/static/api-client.js diff --git a/apps/ui/static/apple-touch-icon-114x114.png b/apps/static/static/apple-touch-icon-114x114.png similarity index 100% rename from apps/ui/static/apple-touch-icon-114x114.png rename to apps/static/static/apple-touch-icon-114x114.png diff --git a/apps/ui/static/apple-touch-icon-120x120.png b/apps/static/static/apple-touch-icon-120x120.png similarity index 100% rename from apps/ui/static/apple-touch-icon-120x120.png rename to apps/static/static/apple-touch-icon-120x120.png diff --git a/apps/ui/static/apple-touch-icon-144x144.png b/apps/static/static/apple-touch-icon-144x144.png similarity index 100% rename from apps/ui/static/apple-touch-icon-144x144.png rename to apps/static/static/apple-touch-icon-144x144.png diff --git a/apps/ui/static/apple-touch-icon-152x152.png b/apps/static/static/apple-touch-icon-152x152.png similarity index 100% rename from apps/ui/static/apple-touch-icon-152x152.png rename to apps/static/static/apple-touch-icon-152x152.png diff --git a/apps/ui/static/apple-touch-icon-16x16.png b/apps/static/static/apple-touch-icon-16x16.png similarity index 100% rename from apps/ui/static/apple-touch-icon-16x16.png rename to apps/static/static/apple-touch-icon-16x16.png diff --git a/apps/ui/static/apple-touch-icon-180x180.png b/apps/static/static/apple-touch-icon-180x180.png similarity index 100% rename from apps/ui/static/apple-touch-icon-180x180.png rename to apps/static/static/apple-touch-icon-180x180.png diff --git a/apps/ui/static/apple-touch-icon-32x32.png b/apps/static/static/apple-touch-icon-32x32.png similarity index 100% rename from apps/ui/static/apple-touch-icon-32x32.png rename to apps/static/static/apple-touch-icon-32x32.png diff --git a/apps/ui/static/apple-touch-icon-57x57.png b/apps/static/static/apple-touch-icon-57x57.png similarity index 100% rename from apps/ui/static/apple-touch-icon-57x57.png rename to apps/static/static/apple-touch-icon-57x57.png diff --git a/apps/ui/static/apple-touch-icon-60x60.png b/apps/static/static/apple-touch-icon-60x60.png similarity index 100% rename from apps/ui/static/apple-touch-icon-60x60.png rename to apps/static/static/apple-touch-icon-60x60.png diff --git a/apps/ui/static/apple-touch-icon-72x72.png b/apps/static/static/apple-touch-icon-72x72.png similarity index 100% rename from apps/ui/static/apple-touch-icon-72x72.png rename to apps/static/static/apple-touch-icon-72x72.png diff --git a/apps/ui/static/apple-touch-icon-76x76.png b/apps/static/static/apple-touch-icon-76x76.png similarity index 100% rename from apps/ui/static/apple-touch-icon-76x76.png rename to apps/static/static/apple-touch-icon-76x76.png diff --git a/apps/ui/static/apple-touch-icon.png b/apps/static/static/apple-touch-icon.png similarity index 100% rename from apps/ui/static/apple-touch-icon.png rename to apps/static/static/apple-touch-icon.png diff --git a/apps/ui/static/apple-touch-icon.svg b/apps/static/static/apple-touch-icon.svg similarity index 100% rename from apps/ui/static/apple-touch-icon.svg rename to apps/static/static/apple-touch-icon.svg diff --git a/apps/ui/static/favicon.svg b/apps/static/static/favicon.svg similarity index 100% rename from apps/ui/static/favicon.svg rename to apps/static/static/favicon.svg diff --git a/apps/ui/static/garage-icon-114x114.png b/apps/static/static/garage-icon-114x114.png similarity index 100% rename from apps/ui/static/garage-icon-114x114.png rename to apps/static/static/garage-icon-114x114.png diff --git a/apps/ui/static/garage-icon-120x120.png b/apps/static/static/garage-icon-120x120.png similarity index 100% rename from apps/ui/static/garage-icon-120x120.png rename to apps/static/static/garage-icon-120x120.png diff --git a/apps/ui/static/garage-icon-144x144.png b/apps/static/static/garage-icon-144x144.png similarity index 100% rename from apps/ui/static/garage-icon-144x144.png rename to apps/static/static/garage-icon-144x144.png diff --git a/apps/ui/static/garage-icon-152x152.png b/apps/static/static/garage-icon-152x152.png similarity index 100% rename from apps/ui/static/garage-icon-152x152.png rename to apps/static/static/garage-icon-152x152.png diff --git a/apps/ui/static/garage-icon-16x16.png b/apps/static/static/garage-icon-16x16.png similarity index 100% rename from apps/ui/static/garage-icon-16x16.png rename to apps/static/static/garage-icon-16x16.png diff --git a/apps/ui/static/garage-icon-180x180.png b/apps/static/static/garage-icon-180x180.png similarity index 100% rename from apps/ui/static/garage-icon-180x180.png rename to apps/static/static/garage-icon-180x180.png diff --git a/apps/ui/static/garage-icon-32x32.png b/apps/static/static/garage-icon-32x32.png similarity index 100% rename from apps/ui/static/garage-icon-32x32.png rename to apps/static/static/garage-icon-32x32.png diff --git a/apps/ui/static/garage-icon-57x57.png b/apps/static/static/garage-icon-57x57.png similarity index 100% rename from apps/ui/static/garage-icon-57x57.png rename to apps/static/static/garage-icon-57x57.png diff --git a/apps/ui/static/garage-icon-60x60.png b/apps/static/static/garage-icon-60x60.png similarity index 100% rename from apps/ui/static/garage-icon-60x60.png rename to apps/static/static/garage-icon-60x60.png diff --git a/apps/ui/static/garage-icon-72x72.png b/apps/static/static/garage-icon-72x72.png similarity index 100% rename from apps/ui/static/garage-icon-72x72.png rename to apps/static/static/garage-icon-72x72.png diff --git a/apps/ui/static/garage-icon-76x76.png b/apps/static/static/garage-icon-76x76.png similarity index 100% rename from apps/ui/static/garage-icon-76x76.png rename to apps/static/static/garage-icon-76x76.png diff --git a/apps/ui/static/garage-icon.png b/apps/static/static/garage-icon.png similarity index 100% rename from apps/ui/static/garage-icon.png rename to apps/static/static/garage-icon.png diff --git a/apps/ui/static/garage-icon.svg b/apps/static/static/garage-icon.svg similarity index 100% rename from apps/ui/static/garage-icon.svg rename to apps/static/static/garage-icon.svg diff --git a/apps/ui/static/manifest.json b/apps/static/static/manifest.json similarity index 100% rename from apps/ui/static/manifest.json rename to apps/static/static/manifest.json diff --git a/apps/ui/static/style.css b/apps/static/static/style.css similarity index 100% rename from apps/ui/static/style.css rename to apps/static/static/style.css diff --git a/apps/ui/static/types.js b/apps/static/static/types.js similarity index 100% rename from apps/ui/static/types.js rename to apps/static/static/types.js diff --git a/apps/ui/Dockerfile b/apps/ui/Dockerfile index 2e4867e..22e7794 100644 --- a/apps/ui/Dockerfile +++ b/apps/ui/Dockerfile @@ -1,49 +1,41 @@ -# UI Service Dockerfile -# FastAPI + Jinja2 + HTMX Dashboard +# UI Service Dockerfile (Application only, without static files) FROM python:3.14-alpine -# Prevent Python from writing .pyc files and enable unbuffered output ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 \ UI_PORT=8002 \ API_BASE=http://api:8001 \ - BASE_PATH="" + BASE_PATH="" \ + STATIC_BASE=http://static:8080 -# Create non-root user RUN addgroup -g 10001 -S app && \ adduser -u 10001 -S app -G app -# Set working directory WORKDIR /app -# Install system dependencies RUN apk add --no-cache \ curl \ gcc \ musl-dev \ linux-headers -# Install Python dependencies COPY apps/ui/requirements.txt /app/requirements.txt RUN pip install --no-cache-dir -r requirements.txt -# Copy application code +# Copy only Python code and templates, but exclude static assets COPY apps/__init__.py /app/apps/__init__.py -COPY apps/ui/ /app/apps/ui/ +COPY apps/ui/__init__.py /app/apps/ui/__init__.py +COPY apps/ui/main.py /app/apps/ui/main.py +COPY apps/ui/api_client.py /app/apps/ui/api_client.py +COPY apps/ui/templates/ /app/apps/ui/templates/ -# Change ownership to app user RUN chown -R app:app /app - -# Switch to non-root user USER app -# Health check HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost:${UI_PORT}/health || exit 1 -# Expose port EXPOSE 8002 -# Run application CMD ["python", "-m", "uvicorn", "apps.ui.main:app", "--host", "0.0.0.0", "--port", "8002"] diff --git a/apps/ui/main.py b/apps/ui/main.py index 5d19fc1..ace8174 100644 --- a/apps/ui/main.py +++ b/apps/ui/main.py @@ -16,9 +16,11 @@ logger = logging.getLogger(__name__) # Read configuration from environment variables API_BASE = os.getenv("API_BASE", "http://localhost:8001") BASE_PATH = os.getenv("BASE_PATH", "") # e.g., "/ui" for reverse proxy +STATIC_BASE = os.getenv("STATIC_BASE", "/static") print(f"UI using API_BASE: {API_BASE}") print(f"UI using BASE_PATH: {BASE_PATH}") +print(f"UI using STATIC_BASE: {STATIC_BASE}") def api_url(path: str) -> str: """Helper function to construct API URLs. @@ -43,6 +45,9 @@ app = FastAPI( templates_dir = Path(__file__).parent / "templates" templates = Jinja2Templates(directory=str(templates_dir)) +# Make STATIC_BASE available in all templates +templates.env.globals["STATIC_BASE"] = STATIC_BASE + # Setup static files static_dir = Path(__file__).parent / "static" static_dir.mkdir(exist_ok=True) @@ -98,7 +103,8 @@ async def health() -> JSONResponse: "status": "ok", "service": "ui", "api_base": API_BASE, - "base_path": BASE_PATH + "base_path": BASE_PATH, + "static_base": STATIC_BASE, }) @@ -127,7 +133,7 @@ async def rooms(request: Request) -> HTMLResponse: """ return templates.TemplateResponse("rooms.html", { "request": request, - "api_base": API_BASE + "api_base": API_BASE, }) @@ -145,7 +151,7 @@ async def room_detail(request: Request, room_name: str) -> HTMLResponse: return templates.TemplateResponse("room.html", { "request": request, "api_base": API_BASE, - "room_name": room_name + "room_name": room_name, }) diff --git a/apps/ui/templates/dashboard.html b/apps/ui/templates/dashboard.html index 033d4a5..82ff8c1 100644 --- a/apps/ui/templates/dashboard.html +++ b/apps/ui/templates/dashboard.html @@ -6,17 +6,17 @@ Home Automation - - - - - - + + + + + + - +