add version card to settings, branch push protection

This commit is contained in:
Zimeng Xiong
2025-11-23 08:35:36 -08:00
parent 8f9ac1f9c0
commit c502f1c0bd
7 changed files with 107 additions and 22 deletions
+2 -2
View File
@@ -27,8 +27,8 @@ services:
frontend: frontend:
build: build:
context: ./frontend context: .
dockerfile: Dockerfile dockerfile: frontend/Dockerfile
container_name: excalidash-frontend container_name: excalidash-frontend
ports: ports:
- "6767:80" - "6767:80"
+13 -6
View File
@@ -1,16 +1,23 @@
# Build stage # Build stage
FROM node:20-alpine AS builder FROM node:20-alpine AS builder
WORKDIR /app WORKDIR /app/frontend
# Copy package files # Copy package files first for better caching
COPY package*.json ./ COPY frontend/package*.json ./
# Install dependencies # Install dependencies
RUN npm ci RUN npm ci
# Copy source code and config files # 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 # Build the application
RUN npm run build RUN npm run build
@@ -19,10 +26,10 @@ RUN npm run build
FROM nginx:alpine FROM nginx:alpine
# Copy custom nginx config # 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 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 EXPOSE 80
+1
View File
@@ -171,6 +171,7 @@ export const Sidebar: React.FC<SidebarProps> = ({
<h1 className="text-2xl text-slate-900 dark:text-white flex items-center gap-3 tracking-tight" style={{ fontFamily: 'Excalifont' }}> <h1 className="text-2xl text-slate-900 dark:text-white flex items-center gap-3 tracking-tight" style={{ fontFamily: 'Excalifont' }}>
<Logo className="w-10 h-10" /> <Logo className="w-10 h-10" />
<span className="mt-1">ExcaliDash</span> <span className="mt-1">ExcaliDash</span>
<span className="text-xs font-bold text-red-500 mt-2" style={{ fontFamily: 'sans-serif' }}>BETA</span>
</h1> </h1>
</div> </div>
+23 -2
View File
@@ -3,7 +3,7 @@ import { Layout } from '../components/Layout';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import * as api from '../api'; import * as api from '../api';
import type { Collection } from '../types'; 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 { ConfirmModal } from '../components/ConfirmModal';
import { importDrawings } from '../utils/importUtils'; import { importDrawings } from '../utils/importUtils';
import { useTheme } from '../context/ThemeContext'; 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 [importError, setImportError] = useState<{ isOpen: boolean; message: string }>({ isOpen: false, message: '' });
const [importSuccess, setImportSuccess] = useState(false); 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(() => { useEffect(() => {
const fetchCollections = async () => { const fetchCollections = async () => {
try { try {
@@ -203,7 +206,25 @@ export const Settings: React.FC = () => {
</button> </button>
</div> </div>
{/* Version Info */}
<div className="flex flex-col items-center justify-center gap-4 p-8 bg-white dark:bg-neutral-900 border-2 border-black dark:border-neutral-700 rounded-2xl shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] dark:shadow-[4px_4px_0px_0px_rgba(255,255,255,0.2)]">
<div className="w-16 h-16 bg-gray-50 dark:bg-neutral-800 rounded-2xl flex items-center justify-center border-2 border-gray-100 dark:border-neutral-700">
<Info size={32} className="text-gray-600 dark:text-gray-400" />
</div>
<div className="text-center">
<h3 className="text-xl font-bold text-slate-900 dark:text-white mb-1">Version Info</h3>
<div className="text-sm text-slate-500 dark:text-neutral-400 font-medium flex flex-col items-center gap-1">
<span className="font-mono text-base text-slate-900 dark:text-white">
{appVersion}
</span>
{buildLabel && (
<span className="text-xs uppercase tracking-wide text-red-500 dark:text-red-400">
{buildLabel}
</span>
)}
</div>
</div>
</div>
</div> </div>
{/* Modals */} {/* Modals */}
+24
View File
@@ -1,5 +1,29 @@
import { defineConfig } from "vite"; import { defineConfig } from "vite";
import react from "@vitejs/plugin-react"; 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/ // https://vite.dev/config/
export default defineConfig({ export default defineConfig({
+22 -6
View File
@@ -1,11 +1,6 @@
#!/bin/bash #!/bin/bash
set -e 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 # Colors for output
RED='\033[0;31m' RED='\033[0;31m'
GREEN='\033[0;32m' GREEN='\033[0;32m'
@@ -13,6 +8,26 @@ YELLOW='\033[1;33m'
BLUE='\033[0;34m' BLUE='\033[0;34m'
NC='\033[0m' # No Color 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}===========================================${NC}"
echo -e "${BLUE}ExcaliDash Pre-Release Docker Builder${NC}" echo -e "${BLUE}ExcaliDash Pre-Release Docker Builder${NC}"
echo -e "${BLUE}===========================================${NC}" echo -e "${BLUE}===========================================${NC}"
@@ -68,9 +83,10 @@ docker buildx build \
--platform linux/amd64,linux/arm64 \ --platform linux/amd64,linux/arm64 \
--tag $DOCKER_USERNAME/$IMAGE_NAME-frontend:$VERSION \ --tag $DOCKER_USERNAME/$IMAGE_NAME-frontend:$VERSION \
--tag $DOCKER_USERNAME/$IMAGE_NAME-frontend:dev \ --tag $DOCKER_USERNAME/$IMAGE_NAME-frontend:dev \
--build-arg VITE_APP_VERSION=$VERSION \
--file frontend/Dockerfile \ --file frontend/Dockerfile \
--push \ --push \
frontend/ .
echo -e "${GREEN}✓ Frontend pre-release image pushed successfully${NC}" echo -e "${GREEN}✓ Frontend pre-release image pushed successfully${NC}"
+22 -6
View File
@@ -1,17 +1,32 @@
#!/bin/bash #!/bin/bash
set -e 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 # Colors for output
RED='\033[0;31m' RED='\033[0;31m'
GREEN='\033[0;32m' GREEN='\033[0;32m'
YELLOW='\033[1;33m' YELLOW='\033[1;33m'
NC='\033[0m' # No Color 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}===========================================${NC}"
echo -e "${GREEN}ExcaliDash Multi-Platform Docker Builder${NC}" echo -e "${GREEN}ExcaliDash Multi-Platform Docker Builder${NC}"
echo -e "${GREEN}===========================================${NC}" echo -e "${GREEN}===========================================${NC}"
@@ -56,9 +71,10 @@ docker buildx build \
--platform linux/amd64,linux/arm64 \ --platform linux/amd64,linux/arm64 \
--tag $DOCKER_USERNAME/$IMAGE_NAME-frontend:$VERSION \ --tag $DOCKER_USERNAME/$IMAGE_NAME-frontend:$VERSION \
--tag $DOCKER_USERNAME/$IMAGE_NAME-frontend:latest \ --tag $DOCKER_USERNAME/$IMAGE_NAME-frontend:latest \
--build-arg VITE_APP_VERSION=$VERSION \
--file frontend/Dockerfile \ --file frontend/Dockerfile \
--push \ --push \
frontend/ .
echo -e "${GREEN}✓ Frontend image pushed successfully${NC}" echo -e "${GREEN}✓ Frontend image pushed successfully${NC}"