From a28e6fbcbfc8feccdcba200c2421f5c42a78d97a Mon Sep 17 00:00:00 2001 From: Arne Rief Date: Sat, 10 Jan 2026 22:33:36 +0100 Subject: Docker --- frontend/.dockerignore | 10 ++++++++++ frontend/.env | 1 - frontend/.env.docker | 1 + frontend/Dockerfile | 28 ++++++++++++++++++++++++++++ frontend/eslint.config.js | 23 ----------------------- frontend/eslint.config.ts | 23 +++++++++++++++++++++++ frontend/nginx.conf | 27 +++++++++++++++++++++++++++ frontend/src/components/ErrorBanner.tsx | 5 +++++ frontend/src/components/Sidebar.tsx | 8 +++----- frontend/src/pages/Login.tsx | 13 ++++++++----- frontend/src/styles/login.css | 1 - 11 files changed, 105 insertions(+), 35 deletions(-) create mode 100644 frontend/.dockerignore delete mode 100644 frontend/.env create mode 100644 frontend/.env.docker create mode 100644 frontend/Dockerfile delete mode 100644 frontend/eslint.config.js create mode 100644 frontend/eslint.config.ts create mode 100644 frontend/nginx.conf create mode 100644 frontend/src/components/ErrorBanner.tsx (limited to 'frontend') diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..9f8fe0e --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,10 @@ +**/.env +**/.git +**/.gitignore +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/build +**/dist +LICENSE +README.md \ No newline at end of file diff --git a/frontend/.env b/frontend/.env deleted file mode 100644 index cd41370..0000000 --- a/frontend/.env +++ /dev/null @@ -1 +0,0 @@ -VITE_API_URL=http://localhost:3000 \ No newline at end of file diff --git a/frontend/.env.docker b/frontend/.env.docker new file mode 100644 index 0000000..cd41370 --- /dev/null +++ b/frontend/.env.docker @@ -0,0 +1 @@ +VITE_API_URL=http://localhost:3000 \ No newline at end of file diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..791cd87 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,28 @@ +# syntax=docker/dockerfile:1 + +# BUILD STAGE +FROM node:22-alpine AS builder + +WORKDIR /app + +COPY package*.json ./ + +RUN npm ci + +# Copy .env.docker as .env for Vite +COPY .env.docker .env + +COPY . . + +# Compile TypeScript & create optimized production build +RUN npm run build + +# PRODUCTION STAGE +FROM nginx:alpine AS production + +# Copy production build files to nginx +COPY --from=builder /app/dist /usr/share/nginx/html + +COPY nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 80 \ No newline at end of file diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js deleted file mode 100644 index 6343bef..0000000 --- a/frontend/eslint.config.js +++ /dev/null @@ -1,23 +0,0 @@ -import js from "@eslint/js"; -import globals from "globals"; -import reactHooks from "eslint-plugin-react-hooks"; -import reactRefresh from "eslint-plugin-react-refresh"; -import tseslint from "typescript-eslint"; -import { defineConfig, globalIgnores } from "eslint/config"; - -export default defineConfig([ - globalIgnores(["dist"]), - { - files: ["**/*.{ts,tsx}"], - extends: [ - js.configs.recommended, - tseslint.configs.recommended, - reactHooks.configs.flat.recommended, - reactRefresh.configs.vite, - ], - languageOptions: { - ecmaVersion: 2020, - globals: globals.browser, - }, - }, -]); diff --git a/frontend/eslint.config.ts b/frontend/eslint.config.ts new file mode 100644 index 0000000..6343bef --- /dev/null +++ b/frontend/eslint.config.ts @@ -0,0 +1,23 @@ +import js from "@eslint/js"; +import globals from "globals"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; +import tseslint from "typescript-eslint"; +import { defineConfig, globalIgnores } from "eslint/config"; + +export default defineConfig([ + globalIgnores(["dist"]), + { + files: ["**/*.{ts,tsx}"], + extends: [ + js.configs.recommended, + tseslint.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + }, +]); diff --git a/frontend/nginx.conf b/frontend/nginx.conf new file mode 100644 index 0000000..151afe8 --- /dev/null +++ b/frontend/nginx.conf @@ -0,0 +1,27 @@ +# For Docker Compose +server { + listen 80; + server_name localhost; + root /usr/share/nginx/html; + index index.html; + + # Enable gzip compression + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + # SPA routing - send all requests to index.html + location / { + try_files $uri $uri/ /index.html; + } + + # Cache static assets + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; +} \ No newline at end of file diff --git a/frontend/src/components/ErrorBanner.tsx b/frontend/src/components/ErrorBanner.tsx new file mode 100644 index 0000000..fdb3bf1 --- /dev/null +++ b/frontend/src/components/ErrorBanner.tsx @@ -0,0 +1,5 @@ +function ErrorBanner({ message }: { message: string }) { + return
{message}
; +} + +export default ErrorBanner; diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 3760d4e..bdfadad 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -4,6 +4,7 @@ import "../styles/button.css"; import "../styles/sidebar.css"; import type { Robot } from "../types/robot"; import AddRobotForm from "./AddRobotForm"; +import ErrorBanner from "./ErrorBanner"; import RobotList from "./RobotList"; import SimulationActions from "./SimulationActions"; @@ -58,10 +59,8 @@ function Sidebar({ /> )} - {errorMessage && ( -
{errorMessage}
- )} - + {errorMessage && } + +

🤖 Please log in to use the app 🤖

@@ -119,10 +124,8 @@ function Login() { />
- {errorMessage && ( -
{errorMessage}
- )} - + {errorMessage && } +