From e2e6cabd68e10093f5d569c63439abbd1327d4a2 Mon Sep 17 00:00:00 2001 From: Daniel da Silva Date: Wed, 7 May 2025 11:19:04 +0100 Subject: [PATCH 1/5] Adds Dockerfile for easy setup Provides a Dockerfile for containerizing the application. Updates the README with instructions on how to build and run the application in a Docker container. --- .dockerignore | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ Dockerfile | 21 +++++++++++++++++++++ README.md | 18 +++++++++++++++++- 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..522dfa2 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,49 @@ +# Dependencies +node_modules +**/node_modules +.pnp +.pnp.js + +# Testing +coverage +**/coverage + +# Production builds +dist +**/dist +build +**/build + +# Cache directories +.cache +**/.cache +.npm +.eslintcache +.vite +.nx +**/.parcel-cache + +# Environment files +.env.* +!.env.example + +# IDE specific files +.idea +.vscode +*.swp +*.swo + +# OS specific files +.DS_Store +Thumbs.db + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Temporary files +*.tmp +*.temp \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9d32b5e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +# Use an official Node.js runtime as a parent image +FROM node:20-alpine + +# Set the working directory +WORKDIR /app + +# Copy the rest of the application code +COPY . . + +# Install dependencies +RUN npm i +RUN npm i -g http-server + +RUN npm run plugins:build + +RUN echo -e "npx nx reset\nnpm run client:build\nhttp-server -p 80 packages/client/dist" > ./start.sh +RUN chmod +x ./start.sh + +EXPOSE 80 + +CMD ["sh", "./start.sh"] \ No newline at end of file diff --git a/README.md b/README.md index 648c7b0..cd028f0 100644 --- a/README.md +++ b/README.md @@ -20,4 +20,20 @@ All the packages are located in the `packages` directory structured as follows: To set up the project for development, follow the instructions in the [development documentation](./DEVELOPMENT.md) and get familiar with the app architecture and the plugin system by reading the [technical documentation](./docs/README.md). ## License -This project is licensed under the MIT license - see the LICENSE.md file for details. \ No newline at end of file +This project is licensed under the MIT license - see the LICENSE.md file for details. + +## Docker +To run the STAC-Manager in a Docker container, you can use the provided Dockerfile. + +**Build the Docker image** +```bash +docker build -t stac-manager . +``` + +**Run the Docker container** +```bash +docker run --rm -p 8080:80 --name stac-manager -e 'PUBLIC_URL=http://your-url.com' stac-manager +``` + +> [!NOTE] +> The application performs a complete build during container startup to ensure environment variables are properly integrated. This process may take a couple minutes to complete. \ No newline at end of file From 0fb401454e95ab5b2afd174265558ca0a9e2c57f Mon Sep 17 00:00:00 2001 From: j08lue Date: Wed, 7 May 2025 15:50:13 +0200 Subject: [PATCH 2/5] Build all on image build --- Dockerfile | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9d32b5e..6098f22 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Use an official Node.js runtime as a parent image -FROM node:20-alpine +FROM node:slim # Set the working directory WORKDIR /app @@ -11,11 +11,8 @@ COPY . . RUN npm i RUN npm i -g http-server -RUN npm run plugins:build - -RUN echo -e "npx nx reset\nnpm run client:build\nhttp-server -p 80 packages/client/dist" > ./start.sh -RUN chmod +x ./start.sh +RUN npm run all:build EXPOSE 80 -CMD ["sh", "./start.sh"] \ No newline at end of file +ENTRYPOINT ["http-server", "-p", "80", "packages/client/dist"] \ No newline at end of file From c1fd4d061bf632196acf50cf050a6b57d845e200 Mon Sep 17 00:00:00 2001 From: Daniel da Silva Date: Thu, 8 May 2025 15:48:47 +0100 Subject: [PATCH 3/5] Untrack .env --- .gitignore | 2 +- packages/client/.env | 18 ------------------ 2 files changed, 1 insertion(+), 19 deletions(-) delete mode 100644 packages/client/.env diff --git a/.gitignore b/.gitignore index 2023cdf..7c2896a 100644 --- a/.gitignore +++ b/.gitignore @@ -58,4 +58,4 @@ tmp .tmp dist parcel-bundle-reports -.nx +.nx \ No newline at end of file diff --git a/packages/client/.env b/packages/client/.env deleted file mode 100644 index 88af1cf..0000000 --- a/packages/client/.env +++ /dev/null @@ -1,18 +0,0 @@ -# App metadata -APP_TITLE=STAC Manager -APP_DESCRIPTION=Plugin based STAC editor -## Don't set the public url here. Check the README.md file for more information -# PUBLIC_URL= Do not set here - -# Api variables -REACT_APP_STAC_BROWSER= -REACT_APP_STAC_API= - -## Keycloak auth variables -REACT_APP_KEYCLOAK_URL= -REACT_APP_KEYCLOAK_CLIENT_ID= -REACT_APP_KEYCLOAK_REALM= - -## Theming -# REACT_APP_THEME_PRIMARY_COLOR='#6A5ACD' -# REACT_APP_THEME_SECONDARY_COLOR='#048A81' From 635ee0948d76ec318f4bee1af14206ceaa332539 Mon Sep 17 00:00:00 2001 From: Daniel da Silva Date: Thu, 8 May 2025 16:19:24 +0100 Subject: [PATCH 4/5] Configures environment variables for client app Introduces environment variable configuration for the client application. Adds an `.env.example` file to serve as a template for configuration. Moves environment variable loading and checking to a dedicated module for better organization and reusability. Modifies build and server tasks to utilize the new environment variable handling. Updates the README to include instructions on configuring the environment. Fix #43 --- packages/client/.env.example | 60 ++++++++++++++++++++++++ packages/client/.gitignore | 3 +- packages/client/README.md | 11 ++++- packages/client/posthtml.config.js | 23 +-------- packages/client/tasks/build.mjs | 8 ++++ packages/client/tasks/check-env-vars.mjs | 54 +++++++++++++++++++++ packages/client/tasks/server.mjs | 8 ++++ 7 files changed, 143 insertions(+), 24 deletions(-) create mode 100644 packages/client/.env.example create mode 100644 packages/client/tasks/check-env-vars.mjs diff --git a/packages/client/.env.example b/packages/client/.env.example new file mode 100644 index 0000000..1d64453 --- /dev/null +++ b/packages/client/.env.example @@ -0,0 +1,60 @@ +# ============================================= +# STAC Manager Environment Example File +# ============================================= +# IMPORTANT: DO NOT MODIFY THIS FILE! +# Instead, create a copy named '.env' and modify that file. +# This example file serves as a template and documentation. +# ============================================= + +# ================= +# App Configuration +# ================= + +# The title of the application shown in browser tab and headers +APP_TITLE=STAC Manager + +# A brief description of the application for metadata purposes +APP_DESCRIPTION=Plugin based STAC editor + +# The base URL where the app is being served from +# DO NOT set this in the .env file. Set it as an environment variable before building. +# See the README for instructions. +# PUBLIC_URL= Do not set here + +# =============== +# API Integration +# =============== + +# URL of the STAC Browser instance (optional) +# If not set, will default to Radiant Earth's STAC Browser +REACT_APP_STAC_BROWSER= + +# URL of the STAC API endpoint (required) +# This is the API the app will interact with for STAC operations +REACT_APP_STAC_API= + +# ==================== +# Keycloak Auth Config +# ==================== +# If not provided, authentication will be disabled. + +# Base URL of the Keycloak server +REACT_APP_KEYCLOAK_URL= + +# Client ID registered in Keycloak +REACT_APP_KEYCLOAK_CLIENT_ID= + +# Realm name in Keycloak +REACT_APP_KEYCLOAK_REALM= + +# ================= +# Theme Customization +# ================= + +# Primary color for the application theme (hex color code) +# Default: #6A5ACD (SlateBlue) +# REACT_APP_THEME_PRIMARY_COLOR='#6A5ACD' + +# Secondary color for the application theme (hex color code) +# Default: #048A81 (Teal) +# REACT_APP_THEME_SECONDARY_COLOR='#048A81' diff --git a/packages/client/.gitignore b/packages/client/.gitignore index f232579..dfbed60 100644 --- a/packages/client/.gitignore +++ b/packages/client/.gitignore @@ -2,4 +2,5 @@ # Environment ################################################ -.env.* \ No newline at end of file +.env* +!.env.example \ No newline at end of file diff --git a/packages/client/README.md b/packages/client/README.md index 137023e..0245fe9 100644 --- a/packages/client/README.md +++ b/packages/client/README.md @@ -8,6 +8,15 @@ See root README.md for instructions on how to install and run the project. ## Client specific instructions +### Environment Configuration + +The application uses environment variables for configuration. A template file `.env.example` is provided as a template. + +To configure the application: +1. Copy `.env.example` to `.env` +2. Modify the `.env` file with your specific configuration values +3. Never modify `.env.example` directly as it serves as documentation + Some client options are controlled by environment variables. These are: ``` # App config @@ -66,4 +75,4 @@ icon-512.png 512x512 favicon.png 32x32 apple-touch-icon.png 360x360 meta-image.png 1920x1080 -``` +``` \ No newline at end of file diff --git a/packages/client/posthtml.config.js b/packages/client/posthtml.config.js index c8c18dc..5213067 100644 --- a/packages/client/posthtml.config.js +++ b/packages/client/posthtml.config.js @@ -1,26 +1,5 @@ +/* global process, module */ // https://github.com/parcel-bundler/parcel/issues/1209#issuecomment-942927265 -const dotenv = require('dotenv'); - -const NODE_ENV = process.env.NODE_ENV; - -const dotenvFiles = [ - '.env', - // Don't include `.env.local` for `test` environment - // since normally you expect tests to produce the same - // results for everyone - NODE_ENV === 'test' ? null : '.env.local', - `.env.${NODE_ENV}`, - `.env.${NODE_ENV}.local` -].filter(Boolean); - -const env = {}; - -for (let dotenvFile of dotenvFiles) { - const config = dotenv.config({ path: dotenvFile }); - if (config.parsed) { - Object.assign(env, config.parsed); - } -} module.exports = { plugins: { diff --git a/packages/client/tasks/build.mjs b/packages/client/tasks/build.mjs index fcea7ad..de5e3b3 100644 --- a/packages/client/tasks/build.mjs +++ b/packages/client/tasks/build.mjs @@ -5,9 +5,17 @@ import fs from 'fs-extra'; import log from 'fancy-log'; import { Parcel } from '@parcel/core'; +import { + checkRequiredEnvVars, + loadEnvironmentVariables +} from './check-env-vars.mjs'; + const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); +loadEnvironmentVariables(); +checkRequiredEnvVars(['REACT_APP_STAC_API', 'PUBLIC_URL']); + // ///////////////////////////////////////////////////////////////////////////// // --------------------------- Variables -------------------------------------// // ---------------------------------------------------------------------------// diff --git a/packages/client/tasks/check-env-vars.mjs b/packages/client/tasks/check-env-vars.mjs new file mode 100644 index 0000000..ac4be9a --- /dev/null +++ b/packages/client/tasks/check-env-vars.mjs @@ -0,0 +1,54 @@ +/* global process */ +import log from 'fancy-log'; +import dotenv from 'dotenv'; + +/** + * Check if required environment variables are set + * @param {string[]} requiredVars - Array of required environment variable names + * @throws {Error} - If any required variables are missing + */ +export function checkRequiredEnvVars(requiredVars) { + const missingVars = requiredVars.filter((varName) => !process.env[varName]); + + if (missingVars.length > 0) { + log.error('ERROR: Missing required environment variables:'); + missingVars.forEach((v) => log.error(` - ${v}`)); + console.log(); // eslint-disable-line no-console + log.info('Make sure to:'); + log.info('1. Copy .env.example to .env'); + log.info('2. Fill in all required values in .env'); + console.log(); // eslint-disable-line no-console + process.exit(1); + } +} + +/** + * Loads environment variables from `.env` files based on the current + * `NODE_ENV`. + * + * The function determines the appropriate `.env` files to load in the following + * order: + * 1. `.env` - Always included. + * 2. `.env.local` - Included unless the `NODE_ENV` is `test`. + * 3. `.env.` - Included based on the current `NODE_ENV`. + * 4. `.env..local` - Included based on the current `NODE_ENV`. + * + * Files are loaded in the order specified above, and later files override + * variables from earlier ones. The `.env.local` file is skipped for the `test` + * environment to ensure consistent test results across different environments. + */ +export function loadEnvironmentVariables() { + const dotenvFiles = [ + '.env', + // Don't include `.env.local` for `test` environment + // since normally you expect tests to produce the same + // results for everyone + process.env.NODE_ENV === 'test' ? null : '.env.local', + `.env.${process.env.NODE_ENV}`, + `.env.${process.env.NODE_ENV}.local` + ].filter(Boolean); + + dotenvFiles.forEach((dotenvFile) => { + dotenv.config({ path: dotenvFile }); + }); +} diff --git a/packages/client/tasks/server.mjs b/packages/client/tasks/server.mjs index 1ab59da..4c61459 100644 --- a/packages/client/tasks/server.mjs +++ b/packages/client/tasks/server.mjs @@ -7,10 +7,18 @@ import portscanner from 'portscanner'; import log from 'fancy-log'; import { Parcel } from '@parcel/core'; +import { + checkRequiredEnvVars, + loadEnvironmentVariables +} from './check-env-vars.mjs'; + const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const __appRoot = path.join(__dirname, '..'); +loadEnvironmentVariables(); +checkRequiredEnvVars(['REACT_APP_STAC_API']); + // ///////////////////////////////////////////////////////////////////////////// // --------------------------- Variables -------------------------------------// // ---------------------------------------------------------------------------// From 7aa35b3d35dd16719112f65770c0aa8cc6e06848 Mon Sep 17 00:00:00 2001 From: Daniel da Silva Date: Mon, 12 May 2025 09:58:15 +0100 Subject: [PATCH 5/5] Fix gh actions build --- .github/workflows/checks.yml | 7 +++++++ .github/workflows/deploy-gh.yml | 3 +++ 2 files changed, 10 insertions(+) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 4e4d2ee..b4577c4 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -103,6 +103,10 @@ jobs: build: needs: prep runs-on: ubuntu-latest + # Just testing purposes + env: + REACT_APP_STAC_API: https://stac.eoapi.dev + PUBLIC_URL: http://stac-manager.ds.io steps: - name: Checkout @@ -123,5 +127,8 @@ jobs: - name: Install run: npm install + - name: Create .env file + run: mv packages/client/.env.example packages/client/.env + - name: Test run: npm run all:build \ No newline at end of file diff --git a/.github/workflows/deploy-gh.yml b/.github/workflows/deploy-gh.yml index 25c35b1..e09b99b 100644 --- a/.github/workflows/deploy-gh.yml +++ b/.github/workflows/deploy-gh.yml @@ -47,6 +47,9 @@ jobs: - name: Install run: npm install + - name: Create .env file + run: mv packages/client/.env.example packages/client/.env + - name: Setup SPA on Github Pages run: node packages/client/tasks/setup-gh-pages.mjs