diff --git a/.dockerignore b/.dockerignore index cf5282e..6f0d9c3 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,9 +1,9 @@ +npm-debug.log node_modules dist -.git -npm-debug.log Dockerfile +Dockerfile.dev .dockerignore -.git .gitignore -.env \ No newline at end of file +.env +.env.example \ No newline at end of file diff --git a/.env.development b/.env.development deleted file mode 100644 index 02d4367..0000000 --- a/.env.development +++ /dev/null @@ -1,10 +0,0 @@ -# These variables are used for development environment -VITE_SOARCA_URI=http://localhost:8080 # for vite each env var must start with VITE_ otherwise it won't be exposed to the client side -VITE_SOARCA_GUI_DOMAIN=http://localhost -VITE_PORT="3000" -VITE_OIDC_ISSUER="https://localhost:9443/application/u/test/" -VITE_OIDC_CLIENT_ID="SOME_CLIENT_ID" -VITE_OIDC_CLIENT_SECRET="SOME_CLIENT_SECRET" -VITE_OIDC_REDIRECT_URL="http://localhost:3000/auth/soarca_gui/callback" -VITE_COOKIE_SECRET_KEY="SOME_COOKIE_SECRET" #openssl rand -base64 32 or head -c 32 /dev/urandom | base64 -VITE_OIDC_SKIP_TLS_VERIFY=true \ No newline at end of file diff --git a/.env.example b/.env.example index 490ec00..a5297b7 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,27 @@ -VITE_SOARCA_URI=http://localhost:8080 # for vite each env var must start with VITE_ otherwise it won't be exposed to the client side \ No newline at end of file +# .env.example — example environment variables for SOARCA-GUI +# Copy this file to `.env.development` for local dev or to `.env` for Docker Compose +# Notes: +# - Vite exposes ONLY variables prefixed with `VITE_` to the client (import.meta.env). +# - Client-visible `VITE_` values are embedded at *build time* (rebuild to change). +# - Docker Compose reads the project `.env` for substitution and container envs. +# - We also follow a consumer based prefix convention for clarity, so variables used by nginx start with NGINX_, those used by the dev server start with VITE_ etc. + +########## Development (Vite) ########## +# Used by `npm run dev` / Vite dev server. Client-facing variables MUST start with VITE_. +# copy these lines into `.env.development` or `.env` (see Vite docs at https://vite.dev/guide/env-and-mode) and adjust as needed for local development +VITE_BACKEND_URL=http://localhost:8080 # backend API URL used by the frontend (dev server proxy target) +VITE_SERVER_PORT=5173 # dev server port + +########## Docker Compose (dev) ########## +# Values used by `docker-compose.dev.yml`. Compose will substitute ${VAR} from the +# project `.env` or the shell environment when you run `docker compose`. +VITE_APP_VERSION=development +VITE_BACKEND_URL=http://host.docker.internal:8080 # backend API URL used by the frontend inside the container (host.docker.internal points to the host machine) +VITE_SERVER_PORT=5173 # dev server port inside the container +DOCKER_HOST_PORT=5173 # port on the host machine mapped to the container's VITE_SERVER_PORT (for browser access) + +########## Production (nginx) ########## +# Values used at container runtime by nginx to proxy /api/ +NGINX_BACKEND_URL=http://host.docker.internal:8080/ # backend API URL used by nginx inside the container (host.docker.internal points to the host machine) +NGINX_SERVER_PORT=8081 # port nginx listens on inside the container +DOCKER_HOST_PORT=8081 # port on the host machine mapped to the container's NGINX_SERVER_PORT (for browser access) \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index deb2e95..6afb121 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,19 +1,15 @@ -# Stage 1: Development environment -FROM node:24-alpine AS development +# Install dependencies and build the application +FROM node:24-alpine AS builder RUN apk add --no-cache git WORKDIR /app COPY package*.json ./ -RUN npm install --include=dev -EXPOSE 3000 -CMD ["npm", "run", "dev"] - -# Stage 2: Build for production -FROM development AS builder +RUN npm install COPY . . RUN npm run build -# Stage 3: Production environment +# Serve with nginx FROM nginx:alpine AS production +COPY nginx.conf /etc/nginx/templates/default.conf.template COPY --from=builder /app/dist /usr/share/nginx/html -EXPOSE 80 +EXPOSE 8081 CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/Dockerfile.dev b/Dockerfile.dev new file mode 100644 index 0000000..ffd98f2 --- /dev/null +++ b/Dockerfile.dev @@ -0,0 +1,9 @@ +# Install (dev) dependencies and run development server +# NOTE: we install git to allow the versioning of the application to be included in the build (e.g., for display in the UI) +FROM node:24-alpine +RUN apk add --no-cache git +WORKDIR /app +COPY package*.json ./ +RUN npm install --include=dev +EXPOSE 5173 +CMD ["npm", "run", "dev"] \ No newline at end of file diff --git a/README.md b/README.md index 50fbbac..3229e2d 100644 --- a/README.md +++ b/README.md @@ -5,56 +5,317 @@ # SOARCA-GUI [![https://cossas-project.org/portfolio/SOARCA/](https://img.shields.io/badge/website-cossas.github.io-orange)](https://cossas.github.io/SOARCA/docs/) +[![Release](https://img.shields.io/github/v/release/cossas/soarca-gui?label=release&sort=semver)](https://github.com/cossas/soarca-gui/releases) [![Pipeline status](https://github.com/cossas/soarca-gui/actions/workflows/ci.yml/badge.svg?development)](https://github.com/COSSAS/SOARCA/actions) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) Modern [React](https://react.dev) + [Vite](https://vitejs.dev) frontend for the [SOARCA](https://github.com/COSSAS/SOARCA) platform, providing a lightweight UI to interact with SOARCA services. The app uses [TypeScript](https://www.typescriptlang.org/), [styled-components](https://styled-components.com/) for theming, [React Router](https://reactrouter.com/) for navigation, and [React Query](https://tanstack.com/query) for data fetching. > [!WARNING] -> SOARCA-GUI is still in development and features for the base version v0.1 are still being added. +> SOARCA-GUI is still in development and features and look may change with time. -## Requirements for running +## Requirements -- [Node.js](https://nodejs.org/) 20+ -- [npm](https://www.npmjs.com/) 10+ -- (Optional) [Docker](https://www.docker.com/) and [Docker Compose](https://docs.docker.com/compose/) for running the full stack locally +- [Node.js](https://nodejs.org/) 20+ (if runned locally) +- [npm](https://www.npmjs.com/) 10+ (if runned locally) +- [Docker](https://www.docker.com/) and [Docker Compose](https://docs.docker.com/compose/) (for building/running from docker image) -## Getting Started (Development) +## Running the Project + +### Development Mode + +Development mode provides hot-reload capabilities and a proxy server for API requests to the SOARCA backend. In order to provide an enjoyable development experience, we provide both a local environment and a Docker setup. In order to accomodate both scenarios and provided minimal user configuration needed, we opted for the architecture shown below. + +#### Development Architecture + +Development can happen in two ways: locally running Vite on your machine or in a Docker container. + +```mermaid +flowchart TB + subgraph User[" "] + direction TB + UserLabel["User Machine"] + Browser["Browser
localhost:HOST_PORT"] + end + + subgraph LocalDev["Local Development Mode"] + direction TB + LocalLabel["Local Development"] + LocalVite["Vite Dev Server
Port: VITE_SERVER_PORT"] + LocalProxy["Vite Proxy
/api → VITE_BACKEND_URL"] + LocalHMR["Hot Module
Replacement"] + end + + subgraph DockerDev["Docker Container Mode"] + direction TB + ContainerLabel["Development Container"] + ContainerVite["Vite Dev Server
Port: VITE_SERVER_PORT"] + ContainerProxy["Vite Proxy
/api → VITE_BACKEND_URL"] + ContainerHMR["Hot Module
Replacement"] + end + + subgraph Backend[" "] + direction TB + BackendLabel["SOARCA Backend"] + API["API Endpoints"] + end + + UserLabel ~~~ Browser + LocalLabel ~~~ LocalVite + ContainerLabel ~~~ ContainerVite + BackendLabel ~~~ API + + %% Local development flow + Browser -->|Local Mode| LocalVite + LocalVite -->|Source Files| LocalHMR + LocalHMR -->|Live Updates| Browser + Browser -->|"/api/*"| LocalProxy + LocalProxy -->|"Rewrite & Forward"| API + + %% Docker development flow + Browser -->|Container Mode| ContainerVite + ContainerVite -->|Source Files| ContainerHMR + ContainerHMR -->|Live Updates| Browser + Browser -->|"/api/*"| ContainerProxy + ContainerProxy -->|"Rewrite & Forward"| API + + %% Backend responses + API -->|Response| LocalProxy + LocalProxy -->|Response| Browser + API -->|Response| ContainerProxy + ContainerProxy -->|Response| Browser + + style LocalVite fill:#C5E1FF,stroke:#4A90E2,color:#000 + style ContainerVite fill:#C5E1FF,stroke:#4A90E2,color:#000 + style Browser fill:#B8F5D3,stroke:#2ECC71,color:#000 + style API fill:#FFE5CC,stroke:#E67E22,color:#000 + style LocalHMR fill:#FFD1DC,stroke:#E74C3C,color:#000 + style ContainerHMR fill:#FFD1DC,stroke:#E74C3C,color:#000 + style LocalProxy fill:#C2F0F0,stroke:#16A085,color:#000 + style ContainerProxy fill:#C2F0F0,stroke:#16A085,color:#000 + + style UserLabel fill:#F0F0F0,stroke:#999,color:#333 + style LocalLabel fill:#F0F0F0,stroke:#999,color:#333 + style ContainerLabel fill:#F0F0F0,stroke:#999,color:#333 + style BackendLabel fill:#F0F0F0,stroke:#999,color:#333 + + classDef envVar fill:#D4F1D4,stroke:#27AE60,stroke-width:2px,color:#000 + class VITE_SERVER_PORT envVar + class HOST_PORT envVar + class VITE_BACKEND_URL envVar +``` + +**Environment variables involved:** + +- `VITE_BACKEND_URL` - Backend API URL (proxied by Vite dev server) +- `VITE_SERVER_PORT` - Port where Vite dev server listens +- `DOCKER_HOST_PORT` - The port of the host machine that is mapped to the `VITE_SERVER_PORT` of the Vite dev server running in the container. This is only relevant when running the Development Container. +- `HOST_PORT` - is the same of the `VITE_SERVER_PORT` if run locally or `DOCKER_HOST_PORT` if running the Development Container. + +#### Running Locally (recommended for development) + +1. **Install (dev)dependencies:** -1. Install dependencies: ```bash - npm install + npm install -D ``` -2. Start the dev server (Vite): + +2. **Configure environment variables:** + Optionally create a `.env` file (explanation and defaults can be found in `.env.example`). Vite will load `*.env` files for the active mode and only expose variables that begin with `VITE_` to the browser (see https://vite.dev/guide/env-and-mode). + + If no enviroment variables are provided, the defaults are: + - `VITE_BACKEND_URL`: `http://localhost:8080` - (SOARCA default) + - `VITE_SERVER_PORT`: `5713` - (Vite default) + +3. **Start the dev server:** + ```bash npm run dev ``` - The dev server runs at http://localhost:3000 but the port can be modified in the `vite.config.ts` and `Dockerfile`. -## NPM Scripts + The app will be available at `http://localhost:HOST_PORT` with hot-reload enabled. You will see in the terminal where exactly the app is being served. -- `npm run dev` — start Vite dev server -- `npm run lint` — run ESLint -- `npm run build` — type-check and create production bundle -- `npm run preview` — serve the production build locally +#### Running in Docker Container (reccomended for development without Node/npm setup) -## Running with Docker (optional) +1. **Configure environment variables:** + Optionally provide values via the shell, a project `.env`, or `--env-file` when starting Compose (explanation and defaults can be found in `.env.example`). -Currently the docker image in not published yet, so you will have to buid your own + If no enviroment variables are provided, the defaults are: + - `VITE_BACKEND_URL`: `http://host.docker.internal:8080` - (The `localhost:8080` equivalent of the Container internal network) + - `VITE_SERVER_PORT`: `5173` + - `DOCKER_HOST_PORT` — port on the host mapped to the `VITE_SERVER_PORT` (default: `5173`) -```bash -docker build -t soarca-ui-react-dev --target development . -``` +2. **Start the container:** + ```bash + docker compose -f docker-compose.dev.yml up + ``` + The app will be available at `http://localhost:HOST_PORT` with hot-reload enabled. + +### Production Mode + +Production mode builds optimized static assets and serves them via Nginx. We use this mode to publish Docker images and make releases, but it can be useful to run a production build locally through Vite as well by building the project locally and previewing it. Also this mode is supported for both local and Docker Container environment. +As before, a diagram of the architecture is shown down below. + +#### Production Architecture + +Production deployment can happen in two ways: locally using Vite's preview server or in a Docker container using Nginx. + +```mermaid +flowchart TB + subgraph User[" "] + direction TB + UserLabel["User Machine"] + Browser["Browser
localhost:HOST_PORT"] + end -To spin up the UI with the included compose setup: + subgraph LocalProd["Local Production Mode"] + direction TB + LocalLabel["Local Build & Preview"] + LocalBuild["npm run build"] + LocalDist["dist/
Static Assets"] + VitePreview["Vite Preview Server
Port: 3000
Proxy: VITE_BACKEND_URL"] + end -```bash -docker compose up -d + subgraph DockerProd["Docker Container Mode"] + direction TB + ContainerLabel["Multi-stage Docker Build"] + + subgraph BuildStage[" "] + direction TB + BuildLabel["Build Stage"] + NPM["npm install"] + Build["npm run build"] + Dist["dist/"] + end + + subgraph ProdStage[" "] + direction TB + ProdLabel["Production Stage"] + StaticFiles["Static Files
/usr/share/nginx/html"] + NginxConf["Nginx Config
Port: NGINX_SERVER_PORT
Proxy: NGINX_BACKEND_URL"] + Nginx["Nginx Server"] + end + end + + subgraph Backend[" "] + direction TB + BackendLabel["SOARCA Backend"] + API["API Endpoints"] + end + + UserLabel ~~~ Browser + LocalLabel ~~~ LocalBuild + ContainerLabel ~~~ BuildStage + BuildLabel ~~~ NPM + ProdLabel ~~~ StaticFiles + BackendLabel ~~~ API + + %% Local production flow + LocalBuild --> LocalDist + LocalDist --> VitePreview + Browser -->|Local Mode| VitePreview + VitePreview -->|"/api/*"| API + + %% Docker production flow + NPM --> Build + Build --> Dist + Dist -->|Copy| StaticFiles + StaticFiles --> Nginx + Nginx --> NginxConf + Browser -->|Container Mode| Nginx + NginxConf -->|"/api/*"| API + API -->|Response| NginxConf + NginxConf -->|Response| Browser + API -->|Response| VitePreview + VitePreview -->|Response| Browser + + style LocalBuild fill:#C5E1FF,stroke:#4A90E2,color:#000 + style Build fill:#C5E1FF,stroke:#4A90E2,color:#000 + style Browser fill:#B8F5D3,stroke:#2ECC71,color:#000 + style API fill:#FFE5CC,stroke:#E67E22,color:#000 + style VitePreview fill:#C2F0F0,stroke:#16A085,color:#000 + style Nginx fill:#C2F0F0,stroke:#16A085,color:#000 + style NginxConf fill:#C2F0F0,stroke:#16A085,color:#000 + style LocalDist fill:#FFF4CC,stroke:#F39C12,color:#000 + style Dist fill:#FFF4CC,stroke:#F39C12,color:#000 + style StaticFiles fill:#FFF4CC,stroke:#F39C12,color:#000 + style NPM fill:#E8D4FF,stroke:#9B59B6,color:#000 + + style UserLabel fill:#F0F0F0,stroke:#999,color:#333 + style LocalLabel fill:#F0F0F0,stroke:#999,color:#333 + style ContainerLabel fill:#F0F0F0,stroke:#999,color:#333 + style BuildLabel fill:#F0F0F0,stroke:#999,color:#333 + style ProdLabel fill:#F0F0F0,stroke:#999,color:#333 + style BackendLabel fill:#F0F0F0,stroke:#999,color:#333 + + classDef envVar fill:#D4F1D4,stroke:#27AE60,stroke-width:2px,color:#000 + class VITE_BACKEND_URL envVar + class NGINX_BACKEND_URL envVar + class NGINX_SERVER_PORT envVar + class HOST_PORT envVar ``` -## Hot-reload +**Environment variables involved:** + +- `VITE_BACKEND_URL` - Backend API URL embedded into the client bundle at build time (must be set before running `npm run build`) +- `VITE_APP_VERSION` - Application version embedded into the client bundle at build time (optional, falls back to git describe or "development") +- `NGINX_BACKEND_URL` - Backend API URL used by Nginx at runtime to proxy `/api/*` requests. This is only relevant when running in Docker Container Mode. +- `NGINX_SERVER_PORT` - Port where Nginx listens inside the container. This is only relevant when running in Docker Container Mode. +- `DOCKER_HOST_PORT` - The port of the host machine that is mapped to the `NGINX_SERVER_PORT` of the Nginx server running in the container. This is only relevant when running in Docker Container Mode. +- `HOST_PORT` - Port 4173 (Vite default) for local preview mode (`npm run preview`) or `DOCKER_HOST_PORT` when running in Docker Container Mode. + +#### Running Locally (recommended for preview) + +1. **Install dependencies:** + + ```bash + npm install + ``` + +2. **Configure environment variables:** + Optionally create a `.env` file (explanation and defaults can be found in `.env.example`). Note that `VITE_` variables must be set at _build time_ to be embedded into the static bundle. + + If no environment variables are provided, the defaults are: + - `VITE_BACKEND_URL`: `http://localhost:8080` - (SOARCA default) + +3. **Build and preview:** + + ```bash + npm run build + npm run preview + ``` + + The app will be available at `http://localhost:4173` (Vite preview server default). + + > [!WARNING] + > For actual production deployment, use a proper web server like Nginx (see Docker section below). + +#### Running in Docker Container (recommended for production) + +1. **Configure environment variables:** + Optionally provide values via the shell, a project `.env`, or `--env-file` when starting Compose (explanation and defaults can be found in `.env.example`). Note that `VITE_` variables are build-time only (embedded at image build), while `NGINX_` variables are runtime (used by the running container). + + If no environment variables are provided, the defaults are: + - `VITE_BACKEND_URL`: `http://localhost:8080` - embedded at build time + - `NGINX_BACKEND_URL`: `http://host.docker.internal:8080/` - used at runtime + - `NGINX_SERVER_PORT`: `8081` + - `DOCKER_HOST_PORT`: `8081` — port on the host mapped to the `NGINX_SERVER_PORT` + +2. **Build and start the container:** + + ```bash + docker compose up --build + ``` + + The app will be available at `http://localhost:DOCKER_HOST_PORT`. + +### NPM Scripts for local run -In both the local and Docker dev environment, Vite provides instant hot reload, so any change to the files will be reflected in the browser upon saving. +- `npm run dev` - Start Vite dev server with hot-reload +- `npm run build` - Type-check and create production bundle +- `npm run preview` - Serve the production build locally (Vite preview server) +- `npm run lint` - Run ESLint +- `npm test` - Run unit tests (Vitest) ## Documentation diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..da5ea2d --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,23 @@ +services: + soarca-gui-dev: + container_name: soarca-gui-dev + image: soarca-gui:dev + build: + context: . + dockerfile: Dockerfile.dev + args: + VITE_BACKEND_URL: ${VITE_BACKEND_URL:-http://host.docker.internal:8080} + VITE_SERVER_PORT: ${VITE_SERVER_PORT:-5173} + ports: + - "${DOCKER_HOST_PORT:-5173}:${VITE_SERVER_PORT:-5173}" + environment: + - NODE_ENV=development + - VITE_BACKEND_URL=${VITE_BACKEND_URL:-http://host.docker.internal:8080} + - VITE_SERVER_PORT=${VITE_SERVER_PORT:-5173} + volumes: + - .:/app + - node_modules_volume:/app/node_modules + command: sh -c "npm install && npm run dev" + +volumes: + node_modules_volume: diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml deleted file mode 100644 index 5e74080..0000000 --- a/docker-compose.prod.yml +++ /dev/null @@ -1,11 +0,0 @@ -services: - soarca-ui-react: - image: soarca-ui-react:latest - build: - context: . - target: production - ports: - - "80:80" - environment: - - NODE_ENV=production - restart: unless-stopped diff --git a/docker-compose.yml b/docker-compose.yml index 29d3a09..c84a4ba 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,17 +1,18 @@ services: - soarca-ui-react: - image: soarca-ui-react:development + soarca-gui: + container_name: soarca-gui + image: soarca-gui:latest build: context: . - target: development + dockerfile: Dockerfile + args: + VITE_APP_VERSION: ${VITE_APP_VERSION:-development} + NGINX_BACKEND_URL: ${NGINX_BACKEND_URL:-http://host.docker.internal:8080/} + NGINX_SERVER_PORT: ${NGINX_SERVER_PORT:-8081} ports: - - "3000:3000" + - "${DOCKER_HOST_PORT:-8081}:${NGINX_SERVER_PORT:-8081}" environment: - - NODE_ENV=development - volumes: - - .:/app - - node_modules_volume:/app/node_modules - command: sh -c "npm install && npm run dev" - -volumes: - node_modules_volume: + - NODE_ENV=production + - NGINX_BACKEND_URL=${NGINX_BACKEND_URL:-http://host.docker.internal:8080/} + - NGINX_SERVER_PORT=${NGINX_SERVER_PORT:-8081} + restart: unless-stopped diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..372c1f2 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,24 @@ +# Nginx template: variables are substituted at container start (envsubst) +# Variables expected: +# - ${NGINX_SERVER_PORT} (default: 8081): port nginx will listen on inside the container +# - ${NGINX_BACKEND_URL} (default: http://host.docker.internal:8080/): backend to proxy /api/ to (include trailing slash) +server { + listen ${NGINX_SERVER_PORT}; + server_name localhost; + + location / { + root /usr/share/nginx/html; + index index.html; + try_files $uri /index.html; + } + + location /api/ { + proxy_pass ${NGINX_BACKEND_URL}; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $http_connection; + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 213ff04..f31aacf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "soarca-ui-react", + "name": "soarca-ui", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "soarca-ui-react", + "name": "soarca-ui", "version": "0.0.0", "dependencies": { "@tanstack/react-query": "^4.42.0", @@ -68,6 +68,7 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", diff --git a/package.json b/package.json index ee07c4e..6a91d27 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "soarca-ui-react", + "name": "soarca-ui", "private": true, "version": "0.0.0", "type": "module", diff --git a/src/api/manual.ts b/src/api/manual.ts index e003cf2..e3d7146 100644 --- a/src/api/manual.ts +++ b/src/api/manual.ts @@ -1,9 +1,9 @@ import { Execution, ManualOutArgsUpdatePayload } from "@/types"; -import { HttpMutationMethod, mutationToApi, SOARCA_URI } from "./utils"; +import { HttpMutationMethod, mutationToApi } from "./utils"; export const postStepActionResult = (data: ManualOutArgsUpdatePayload) => mutationToApi( HttpMutationMethod.POST, - `${SOARCA_URI}/manual/continue`, + `/api/manual/continue`, data, ); diff --git a/src/api/playbooks.ts b/src/api/playbooks.ts index d58d936..212e333 100644 --- a/src/api/playbooks.ts +++ b/src/api/playbooks.ts @@ -4,28 +4,22 @@ import { fetchFromApi, HttpMutationMethod, mutationToApi, - SOARCA_URI, } from "./utils"; -export const getPlaybooks = () => - fetchFromApi(`${SOARCA_URI}/playbook/`); +export const getPlaybooks = () => fetchFromApi(`/api/playbook/`); export const getPlaybookById = (playbookId: string) => - fetchFromApi(`${SOARCA_URI}/playbook/${playbookId}`); + fetchFromApi(`/api/playbook/${playbookId}`); export const createPlaybook = (playbook: Partial) => - mutationToApi( - HttpMutationMethod.POST, - `${SOARCA_URI}/playbook/`, - playbook, - ); + mutationToApi(HttpMutationMethod.POST, `/api/playbook/`, playbook); export const updatePlaybook = (playbookId: string, patch: Partial) => mutationToApi( HttpMutationMethod.PUT, - `${SOARCA_URI}/playbook/${playbookId}`, + `/api/playbook/${playbookId}`, patch, ); export const deletePlaybook = (playbookId: string) => - deleteToApi(`${SOARCA_URI}/playbook/${playbookId}`); + deleteToApi(`/api/playbook/${playbookId}`); diff --git a/src/api/reporter.ts b/src/api/reporter.ts index f225a2c..763ad4b 100644 --- a/src/api/reporter.ts +++ b/src/api/reporter.ts @@ -1,10 +1,8 @@ import { PlaybookExecutionReport } from "@/types"; -import { fetchFromApi, SOARCA_URI } from "./utils"; +import { fetchFromApi } from "./utils"; export const getReporterState = () => - fetchFromApi(`${SOARCA_URI}/reporter/`); + fetchFromApi(`/api/reporter/`); export const getReportOfExecutionById = (executionId: string) => - fetchFromApi( - `${SOARCA_URI}/reporter/${executionId}`, - ); + fetchFromApi(`/api/reporter/${executionId}`); diff --git a/src/api/status.ts b/src/api/status.ts index dc52f37..5ea4a3b 100644 --- a/src/api/status.ts +++ b/src/api/status.ts @@ -1,7 +1,6 @@ import { Status } from "@/types"; -import { fetchFromApi, SOARCA_URI } from "./utils"; +import { fetchFromApi } from "./utils"; -export const getPingStatus = async () => fetch(`${SOARCA_URI}/status/ping`); +export const getPingStatus = async () => fetch(`/api/status/ping`); -export const getSystemStatus = async () => - fetchFromApi(`${SOARCA_URI}/status/`); +export const getSystemStatus = async () => fetchFromApi(`/api/status/`); diff --git a/src/api/trigger.ts b/src/api/trigger.ts index 108e31d..da900bd 100644 --- a/src/api/trigger.ts +++ b/src/api/trigger.ts @@ -1,10 +1,10 @@ import { Execution } from "@/types"; -import { HttpMutationMethod, mutationToApi, SOARCA_URI } from "./utils"; +import { HttpMutationMethod, mutationToApi } from "./utils"; export const triggerPlaybookById = (playbookId: string) => { return mutationToApi( HttpMutationMethod.POST, - `${SOARCA_URI}/trigger/playbook/${playbookId}`, + `/api/trigger/playbook/${playbookId}`, {}, ); }; diff --git a/src/api/utils.ts b/src/api/utils.ts index a498ff9..4beb986 100644 --- a/src/api/utils.ts +++ b/src/api/utils.ts @@ -1,7 +1,5 @@ import { ErrorResponse } from "@/types"; -export const SOARCA_URI = import.meta.env.VITE_SOARCA_URI; - /** * Fetches from the API and handles errors uniformly. * @param url - API endpoint URL diff --git a/vite.config.ts b/vite.config.ts index a555aad..73a10ee 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,29 +4,43 @@ import sbom from "rollup-plugin-sbom"; import { defineConfig } from "vite"; import tsconfigPaths from "vite-tsconfig-paths"; -// Get version from git describe --tags (tag name only, without hash/dirty suffix) -const getGitVersion = () => { +/** + * Resolve the app version. + */ +const getAppVersion = (): string => { + // Explicit env var (ideal for CI and Docker builds) + if (process.env.VITE_APP_VERSION) { + return process.env.VITE_APP_VERSION; + } + + // Git tag (works locally; fails in Docker where .git is excluded) try { - // Try to get the most recent tag const tag = execSync("git describe --tags --abbrev=0", { encoding: "utf-8", - stdio: ["pipe", "pipe", "ignore"], // Suppress stderr + stdio: ["pipe", "pipe", "ignore"], }).trim(); - return tag; + if (tag) return tag; } catch { - // If no tags exist, fall back to development - return "development"; + // .git not available — continue to fallback } + // Fallback for local development without .git or CI/CD environment + return "development"; }; export default defineConfig({ plugins: [react(), tsconfigPaths(), sbom()], define: { - __APP_VERSION__: JSON.stringify(getGitVersion()), + __APP_VERSION__: JSON.stringify(getAppVersion()), }, server: { + proxy: { + "/api": { + target: process.env.VITE_BACKEND_URL || "http://localhost:8080", + rewrite: (path) => path.replace(/^\/api/, ""), + }, + }, host: true, - port: 3000, + port: Number(process.env.VITE_SERVER_PORT) || 5173, strictPort: true, // Fail if port is already in use, as the docker container won't be able to use a different one watch: { usePolling: true, @@ -34,6 +48,6 @@ export default defineConfig({ }, preview: { host: true, - port: 3000, + port: 4173, }, });