diff --git a/docker-compose.yml b/docker-compose.yml index beab0c0..5a1eaef 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -27,8 +27,8 @@ services: frontend: build: - context: ./frontend - dockerfile: Dockerfile + context: . + dockerfile: frontend/Dockerfile container_name: excalidash-frontend ports: - "6767:80" diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 693ffee..3468da4 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,16 +1,23 @@ # Build stage FROM node:20-alpine AS builder -WORKDIR /app +WORKDIR /app/frontend -# Copy package files -COPY package*.json ./ +# Copy package files first for better caching +COPY frontend/package*.json ./ # Install dependencies RUN npm ci # Copy source code and config files -COPY . . +COPY frontend/ ./ +COPY VERSION ../VERSION + +# Build arguments +ARG VITE_APP_VERSION +ARG VITE_APP_BUILD_LABEL +ENV VITE_APP_VERSION=$VITE_APP_VERSION +ENV VITE_APP_BUILD_LABEL=$VITE_APP_BUILD_LABEL # Build the application RUN npm run build @@ -19,10 +26,10 @@ RUN npm run build FROM nginx:alpine # Copy custom nginx config -COPY nginx.conf /etc/nginx/nginx.conf +COPY frontend/nginx.conf /etc/nginx/nginx.conf # Copy built application from builder -COPY --from=builder /app/dist /usr/share/nginx/html +COPY --from=builder /app/frontend/dist /usr/share/nginx/html EXPOSE 80 diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 2a21c60..07dcd06 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -171,6 +171,7 @@ export const Sidebar: React.FC = ({

ExcaliDash + BETA

diff --git a/frontend/src/pages/Settings.tsx b/frontend/src/pages/Settings.tsx index 3d83d85..d405890 100644 --- a/frontend/src/pages/Settings.tsx +++ b/frontend/src/pages/Settings.tsx @@ -3,7 +3,7 @@ import { Layout } from '../components/Layout'; import { useNavigate } from 'react-router-dom'; import * as api from '../api'; import type { Collection } from '../types'; -import { Database, FileJson, Upload, Moon, Sun } from 'lucide-react'; +import { Database, FileJson, Upload, Moon, Sun, Info } from 'lucide-react'; import { ConfirmModal } from '../components/ConfirmModal'; import { importDrawings } from '../utils/importUtils'; import { useTheme } from '../context/ThemeContext'; @@ -18,6 +18,9 @@ export const Settings: React.FC = () => { const [importError, setImportError] = useState<{ isOpen: boolean; message: string }>({ isOpen: false, message: '' }); const [importSuccess, setImportSuccess] = useState(false); + const appVersion = import.meta.env.VITE_APP_VERSION || 'Unknown version'; + const buildLabel = import.meta.env.VITE_APP_BUILD_LABEL; + useEffect(() => { const fetchCollections = async () => { try { @@ -203,7 +206,25 @@ export const Settings: React.FC = () => { - + {/* Version Info */} +
+
+ +
+
+

Version Info

+
+ + {appVersion} + + {buildLabel && ( + + {buildLabel} + + )} +
+
+
{/* Modals */} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index b951a3e..4b3dcdf 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,5 +1,29 @@ import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; +import fs from "fs"; +import path from "path"; + +const versionFilePath = path.resolve(__dirname, "../VERSION"); +let versionFromFile = "0.0.0"; + +try { + const raw = fs.readFileSync(versionFilePath, "utf8").trim(); + if (raw) { + versionFromFile = raw; + } +} catch (error) { + console.warn("Unable to read VERSION file:", error); +} + +if ( + !process.env.VITE_APP_VERSION || + process.env.VITE_APP_VERSION.trim().length === 0 +) { + process.env.VITE_APP_VERSION = versionFromFile; + if (!process.env.VITE_APP_BUILD_LABEL) { + process.env.VITE_APP_BUILD_LABEL = "local development build"; + } +} // https://vite.dev/config/ export default defineConfig({ diff --git a/publish-docker-prerelease.sh b/publish-docker-prerelease.sh index bff0e19..ebe1389 100755 --- a/publish-docker-prerelease.sh +++ b/publish-docker-prerelease.sh @@ -1,11 +1,6 @@ #!/bin/bash set -e -# Configuration -DOCKER_USERNAME="zimengxiong" -IMAGE_NAME="excalidash" -VERSION=${1:-$(node -e "try { console.log(require('fs').readFileSync('VERSION', 'utf8').trim() + '-dev') } catch { console.log('pre-release') }")} - # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' @@ -13,6 +8,26 @@ YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color +# Branch validation - only allow pre-release branch +echo -e "${YELLOW}Validating branch...${NC}" +CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) +ALLOWED_BRANCH="pre-release" + +if [ "$CURRENT_BRANCH" != "$ALLOWED_BRANCH" ]; then + echo -e "${RED}ERROR: This script can only be run on the '$ALLOWED_BRANCH' branch!${NC}" + echo -e "${RED}Current branch: '$CURRENT_BRANCH'${NC}" + echo -e "${YELLOW}Please switch to the '$ALLOWED_BRANCH' branch and try again.${NC}" + exit 1 +fi + +echo -e "${GREEN}✓ Branch validation passed - running on '$CURRENT_BRANCH' branch${NC}" +echo "" + +# Configuration +DOCKER_USERNAME="zimengxiong" +IMAGE_NAME="excalidash" +VERSION=${1:-$(node -e "try { console.log(require('fs').readFileSync('VERSION', 'utf8').trim() + '-dev') } catch { console.log('pre-release') }")} + echo -e "${BLUE}===========================================${NC}" echo -e "${BLUE}ExcaliDash Pre-Release Docker Builder${NC}" echo -e "${BLUE}===========================================${NC}" @@ -68,9 +83,10 @@ docker buildx build \ --platform linux/amd64,linux/arm64 \ --tag $DOCKER_USERNAME/$IMAGE_NAME-frontend:$VERSION \ --tag $DOCKER_USERNAME/$IMAGE_NAME-frontend:dev \ + --build-arg VITE_APP_VERSION=$VERSION \ --file frontend/Dockerfile \ --push \ - frontend/ + . echo -e "${GREEN}✓ Frontend pre-release image pushed successfully${NC}" diff --git a/publish-docker.sh b/publish-docker.sh index 8551dd8..d3360b3 100755 --- a/publish-docker.sh +++ b/publish-docker.sh @@ -1,17 +1,32 @@ #!/bin/bash set -e -# Configuration -DOCKER_USERNAME="zimengxiong" -IMAGE_NAME="excalidash" -VERSION=${1:-$(node -e "try { console.log(require('fs').readFileSync('VERSION', 'utf8').trim()) } catch { console.log('latest') }")} - # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color +# Branch validation - only allow main branch +echo -e "${YELLOW}Validating branch...${NC}" +CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) +ALLOWED_BRANCH="main" + +if [ "$CURRENT_BRANCH" != "$ALLOWED_BRANCH" ]; then + echo -e "${RED}ERROR: This script can only be run on the '$ALLOWED_BRANCH' branch!${NC}" + echo -e "${RED}Current branch: '$CURRENT_BRANCH'${NC}" + echo -e "${YELLOW}Please switch to the '$ALLOWED_BRANCH' branch and try again.${NC}" + exit 1 +fi + +echo -e "${GREEN}✓ Branch validation passed - running on '$CURRENT_BRANCH' branch${NC}" +echo "" + +# Configuration +DOCKER_USERNAME="zimengxiong" +IMAGE_NAME="excalidash" +VERSION=${1:-$(node -e "try { console.log(require('fs').readFileSync('VERSION', 'utf8').trim()) } catch { console.log('latest') }")} + echo -e "${GREEN}===========================================${NC}" echo -e "${GREEN}ExcaliDash Multi-Platform Docker Builder${NC}" echo -e "${GREEN}===========================================${NC}" @@ -56,9 +71,10 @@ docker buildx build \ --platform linux/amd64,linux/arm64 \ --tag $DOCKER_USERNAME/$IMAGE_NAME-frontend:$VERSION \ --tag $DOCKER_USERNAME/$IMAGE_NAME-frontend:latest \ + --build-arg VITE_APP_VERSION=$VERSION \ --file frontend/Dockerfile \ --push \ - frontend/ + . echo -e "${GREEN}✓ Frontend image pushed successfully${NC}"