mirror of
https://github.com/johndoe6345789/snippet-pastebin.git
synced 2026-04-24 13:34:55 +00:00
Generated by Spark: I can auto default to flask backend with docker environment variable. If its not set used IndexedDB.
This commit is contained in:
16
.dockerignore
Normal file
16
.dockerignore
Normal file
@@ -0,0 +1,16 @@
|
||||
node_modules
|
||||
dist
|
||||
.git
|
||||
.github
|
||||
.env
|
||||
.env.local
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.DS_Store
|
||||
.vscode
|
||||
.idea
|
||||
backend
|
||||
data
|
||||
pids
|
||||
4
.env.example
Normal file
4
.env.example
Normal file
@@ -0,0 +1,4 @@
|
||||
# Flask Backend Configuration (Optional)
|
||||
# If set, the app will automatically use Flask backend instead of IndexedDB
|
||||
# Example: VITE_FLASK_BACKEND_URL=http://localhost:5000
|
||||
VITE_FLASK_BACKEND_URL=
|
||||
260
BACKEND-CONFIG.md
Normal file
260
BACKEND-CONFIG.md
Normal file
@@ -0,0 +1,260 @@
|
||||
# Backend Configuration Guide
|
||||
|
||||
This guide explains how to configure CodeSnippet to use different storage backends.
|
||||
|
||||
## Storage Options
|
||||
|
||||
CodeSnippet supports two storage backends:
|
||||
|
||||
### 1. IndexedDB (Default)
|
||||
- **Local browser storage** using SQLite compiled to WebAssembly
|
||||
- No server required
|
||||
- Data persists only on the current device/browser
|
||||
- Best for personal use or offline scenarios
|
||||
|
||||
### 2. Flask Backend
|
||||
- **Remote server storage** with a Flask REST API
|
||||
- Requires running a Flask backend server
|
||||
- Data accessible from any device
|
||||
- Best for team use or multi-device access
|
||||
|
||||
## Configuration Methods
|
||||
|
||||
### Method 1: Automatic Configuration (Environment Variable)
|
||||
|
||||
The simplest way to configure Flask backend is using the `VITE_FLASK_BACKEND_URL` environment variable.
|
||||
|
||||
**When to use:**
|
||||
- Production deployments
|
||||
- Docker/containerized environments
|
||||
- When you want to enforce backend usage
|
||||
|
||||
**How it works:**
|
||||
- App automatically connects to Flask backend on startup
|
||||
- Manual backend selection is disabled in Settings UI
|
||||
- Overrides any saved user preferences
|
||||
|
||||
**Setup:**
|
||||
|
||||
Create `.env` file in project root:
|
||||
```bash
|
||||
VITE_FLASK_BACKEND_URL=http://localhost:5000
|
||||
```
|
||||
|
||||
Or set in Docker:
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
frontend:
|
||||
environment:
|
||||
- VITE_FLASK_BACKEND_URL=http://backend:5000
|
||||
```
|
||||
|
||||
Or for Docker build:
|
||||
```bash
|
||||
docker build --build-arg VITE_FLASK_BACKEND_URL=http://api.example.com .
|
||||
```
|
||||
|
||||
### Method 2: Manual Configuration (Settings Page)
|
||||
|
||||
Users can manually switch backends in the Settings page.
|
||||
|
||||
**When to use:**
|
||||
- Development/testing
|
||||
- User preference scenarios
|
||||
- When Flask backend is optional
|
||||
|
||||
**How it works:**
|
||||
- Navigate to Settings → Storage Backend
|
||||
- Select "Flask Backend (Remote Server)"
|
||||
- Enter Flask backend URL
|
||||
- Test connection
|
||||
- Save settings
|
||||
|
||||
**Note:** Manual configuration is automatically disabled when `VITE_FLASK_BACKEND_URL` is set.
|
||||
|
||||
## Backend Deployment Scenarios
|
||||
|
||||
### Scenario 1: Full Docker Stack (Recommended for Production)
|
||||
|
||||
Both frontend and backend in Docker with automatic configuration:
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
Frontend: `http://localhost:3000`
|
||||
Backend: `http://localhost:5000`
|
||||
|
||||
The frontend automatically connects to backend via internal Docker network.
|
||||
|
||||
### Scenario 2: Local Development
|
||||
|
||||
Backend in Docker, frontend in dev mode:
|
||||
|
||||
```bash
|
||||
# Terminal 1: Start backend
|
||||
docker-compose up backend
|
||||
|
||||
# Terminal 2: Start frontend with env var
|
||||
echo "VITE_FLASK_BACKEND_URL=http://localhost:5000" > .env
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Scenario 3: Backend Only
|
||||
|
||||
Run backend separately, users configure manually:
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
python app.py
|
||||
```
|
||||
|
||||
Users go to Settings and configure `http://localhost:5000` manually.
|
||||
|
||||
### Scenario 4: Remote Backend
|
||||
|
||||
Point frontend to a remote Flask API:
|
||||
|
||||
```bash
|
||||
# .env
|
||||
VITE_FLASK_BACKEND_URL=https://api.example.com
|
||||
```
|
||||
|
||||
Or configure manually in Settings with the remote URL.
|
||||
|
||||
## Data Migration
|
||||
|
||||
### From IndexedDB to Flask
|
||||
|
||||
1. Ensure Flask backend is running
|
||||
2. Go to Settings → Storage Backend
|
||||
3. Select "Flask Backend"
|
||||
4. Enter backend URL and test connection
|
||||
5. Click "Migrate IndexedDB Data to Flask"
|
||||
6. Save storage settings
|
||||
|
||||
### From Flask to IndexedDB
|
||||
|
||||
1. Ensure you have Flask backend URL configured
|
||||
2. Go to Settings → Storage Backend
|
||||
3. Click "Migrate Flask Data to IndexedDB"
|
||||
4. Select "IndexedDB (Local Browser Storage)"
|
||||
5. Save storage settings
|
||||
|
||||
**Note:** Migration copies data, it doesn't move it. Original data remains in the source.
|
||||
|
||||
## Environment Variable Reference
|
||||
|
||||
| Variable | Description | Default | Example |
|
||||
|----------|-------------|---------|---------|
|
||||
| `VITE_FLASK_BACKEND_URL` | Flask backend URL. When set, forces Flask backend usage. | (none) | `http://localhost:5000` |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Connection failed" error
|
||||
|
||||
**Causes:**
|
||||
- Backend server not running
|
||||
- Incorrect URL
|
||||
- CORS issues
|
||||
- Network/firewall blocking
|
||||
|
||||
**Solutions:**
|
||||
1. Verify backend is running: `curl http://localhost:5000/health`
|
||||
2. Check URL spelling and port number
|
||||
3. Review backend logs for errors
|
||||
4. Ensure CORS is enabled in Flask app
|
||||
|
||||
### Environment variable not working
|
||||
|
||||
**Causes:**
|
||||
- File named incorrectly (must be `.env`)
|
||||
- Variable not prefixed with `VITE_`
|
||||
- Server not restarted after change
|
||||
|
||||
**Solutions:**
|
||||
1. Ensure file is named `.env` (not `.env.local` or `.env.txt`)
|
||||
2. Restart dev server: `npm run dev`
|
||||
3. For production builds: rebuild with `npm run build`
|
||||
4. Verify with: `console.log(import.meta.env.VITE_FLASK_BACKEND_URL)`
|
||||
|
||||
### Settings page is read-only
|
||||
|
||||
This is expected when `VITE_FLASK_BACKEND_URL` is set. To enable manual configuration:
|
||||
1. Remove the environment variable from `.env`
|
||||
2. Restart the application
|
||||
3. Settings will become editable
|
||||
|
||||
### Data not syncing between devices
|
||||
|
||||
Ensure:
|
||||
1. All devices are configured to use the same Flask backend URL
|
||||
2. Backend server is accessible from all devices (not localhost if remote)
|
||||
3. Backend has persistent storage (volume mounted in Docker)
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Production Deployment
|
||||
|
||||
1. **Use HTTPS:** Always use `https://` URLs in production
|
||||
2. **Authentication:** Consider adding authentication to Flask backend
|
||||
3. **CORS:** Configure CORS to allow only your frontend domain
|
||||
4. **Network:** Run backend in private network, not exposed to internet
|
||||
|
||||
### Example secure configuration:
|
||||
|
||||
```python
|
||||
# backend/app.py
|
||||
from flask_cors import CORS
|
||||
|
||||
CORS(app, origins=['https://your-frontend-domain.com'])
|
||||
```
|
||||
|
||||
```bash
|
||||
# .env (production)
|
||||
VITE_FLASK_BACKEND_URL=https://api.your-domain.com
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Development:** Use IndexedDB or local Flask backend
|
||||
2. **Staging:** Use Flask backend with test data
|
||||
3. **Production:** Use Flask backend with environment variable
|
||||
4. **Backup:** Regularly export database from Settings page
|
||||
5. **Migration:** Test data migration with small dataset first
|
||||
|
||||
## Architecture Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ React Frontend │
|
||||
│ │
|
||||
│ ┌──────────────────────────────┐ │
|
||||
│ │ Storage Config Layer │ │
|
||||
│ │ (checks env var first) │ │
|
||||
│ └──────────┬───────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌──────┴──────┐ │
|
||||
│ │ │ │
|
||||
│ ┌───▼───┐ ┌───▼───────┐ │
|
||||
│ │ IDB │ │ Flask │ │
|
||||
│ │Adapter│ │ Adapter │ │
|
||||
│ └───────┘ └─────┬─────┘ │
|
||||
└────────────────────┼───────────────┘
|
||||
│
|
||||
│ HTTP
|
||||
│
|
||||
┌──────▼──────┐
|
||||
│ Flask │
|
||||
│ Backend │
|
||||
│ + SQLite │
|
||||
└─────────────┘
|
||||
```
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Flask Backend README](./backend/README.md)
|
||||
- [Backend API Documentation](./backend/README.md#api-endpoints)
|
||||
- [Docker Compose Configuration](./docker-compose.yml)
|
||||
- [Example .env file](./.env.example)
|
||||
25
Dockerfile
Normal file
25
Dockerfile
Normal file
@@ -0,0 +1,25 @@
|
||||
# Build stage
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
|
||||
COPY . .
|
||||
|
||||
ARG VITE_FLASK_BACKEND_URL
|
||||
ENV VITE_FLASK_BACKEND_URL=$VITE_FLASK_BACKEND_URL
|
||||
|
||||
RUN npm run build
|
||||
|
||||
# Production stage
|
||||
FROM nginx:alpine
|
||||
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
202
IMPLEMENTATION.md
Normal file
202
IMPLEMENTATION.md
Normal file
@@ -0,0 +1,202 @@
|
||||
# Implementation Summary: Auto Backend Configuration
|
||||
|
||||
## Overview
|
||||
|
||||
Implemented automatic Flask backend configuration via Docker environment variable (`VITE_FLASK_BACKEND_URL`). When set, the application automatically uses the Flask backend instead of IndexedDB, with manual configuration disabled.
|
||||
|
||||
## Changes Made
|
||||
|
||||
### 1. Storage Configuration (`src/lib/storage.ts`)
|
||||
|
||||
**Added:**
|
||||
- `getDefaultConfig()` function that checks for `VITE_FLASK_BACKEND_URL` environment variable
|
||||
- Automatic backend selection based on environment variable presence
|
||||
- Priority: Environment variable > Saved config > Default (IndexedDB)
|
||||
|
||||
**Behavior:**
|
||||
- If `VITE_FLASK_BACKEND_URL` is set, always use Flask backend
|
||||
- Environment variable overrides any saved user preferences
|
||||
- Auto-initializes with Flask adapter when env var is present
|
||||
|
||||
### 2. Database Layer (`src/lib/db.ts`)
|
||||
|
||||
**Added:**
|
||||
- Auto-load storage config on first database operation
|
||||
- Persistent config loading with `configLoaded` flag
|
||||
- Seamless switching between storage backends
|
||||
|
||||
### 3. Settings UI (`src/pages/SettingsPage.tsx`)
|
||||
|
||||
**Added:**
|
||||
- Environment variable detection and display
|
||||
- Read-only mode when env var is set
|
||||
- Status card showing auto-configuration details
|
||||
- Connection status indicator
|
||||
- Disabled form inputs when env var controls backend
|
||||
|
||||
**Features:**
|
||||
- Visual indicator for auto-configured backend
|
||||
- Shows current backend URL from env var
|
||||
- Displays configuration source
|
||||
- Test connection button for auto-configured backends
|
||||
|
||||
### 4. Visual Indicators (`src/components/BackendIndicator.tsx`)
|
||||
|
||||
**Added:**
|
||||
- Header badge showing active storage backend
|
||||
- "Local" badge for IndexedDB
|
||||
- "Backend" badge with dot indicator for auto-configured Flask
|
||||
- Tooltips explaining storage type
|
||||
|
||||
### 5. TypeScript Definitions (`src/vite-end.d.ts`)
|
||||
|
||||
**Added:**
|
||||
- Type definitions for `VITE_FLASK_BACKEND_URL`
|
||||
- Proper `ImportMetaEnv` interface
|
||||
|
||||
### 6. Docker Configuration
|
||||
|
||||
**Added:**
|
||||
- `Dockerfile` - Multi-stage build for production frontend
|
||||
- `nginx.conf` - Nginx configuration with API proxy
|
||||
- `.dockerignore` - Optimized Docker builds
|
||||
- Updated `docker-compose.yml` - Full stack with auto-configuration
|
||||
- `docker-compose.backend-only.yml` - Backend-only deployment
|
||||
|
||||
**Features:**
|
||||
- Frontend and backend containers
|
||||
- Automatic environment variable passing
|
||||
- Persistent data volumes
|
||||
- Build-time and runtime env var support
|
||||
|
||||
### 7. Documentation
|
||||
|
||||
**Created:**
|
||||
- `.env.example` - Environment variable template
|
||||
- `QUICKSTART.md` - Quick start guide for all scenarios
|
||||
- `BACKEND-CONFIG.md` - Comprehensive backend configuration guide
|
||||
- `docker-compose.README.md` - Docker deployment examples
|
||||
- Updated `README.md` - New main readme with features
|
||||
- Updated `README-APP.md` - Enhanced with env var docs
|
||||
- Updated `backend/README.md` - Auto-configuration instructions
|
||||
|
||||
**Documentation covers:**
|
||||
- Environment variable usage
|
||||
- Multiple deployment scenarios
|
||||
- Docker configurations
|
||||
- Manual vs automatic configuration
|
||||
- Troubleshooting guide
|
||||
- Migration procedures
|
||||
- Security considerations
|
||||
|
||||
## Configuration Methods
|
||||
|
||||
### Method 1: Environment Variable (Automatic)
|
||||
|
||||
```bash
|
||||
# .env file
|
||||
VITE_FLASK_BACKEND_URL=http://localhost:5000
|
||||
```
|
||||
|
||||
**Result:** App automatically uses Flask backend, Settings locked
|
||||
|
||||
### Method 2: Docker Compose
|
||||
|
||||
```yaml
|
||||
services:
|
||||
frontend:
|
||||
environment:
|
||||
- VITE_FLASK_BACKEND_URL=http://backend:5000
|
||||
```
|
||||
|
||||
**Result:** Full stack with auto-configured backend
|
||||
|
||||
### Method 3: Manual (Settings Page)
|
||||
|
||||
Navigate to Settings → Select Flask Backend → Enter URL → Save
|
||||
|
||||
**Result:** User-controlled backend selection
|
||||
|
||||
## Priority Order
|
||||
|
||||
1. **Environment Variable** (`VITE_FLASK_BACKEND_URL`) - Highest priority
|
||||
2. **Saved User Preference** (localStorage)
|
||||
3. **Default** (IndexedDB)
|
||||
|
||||
## User Experience
|
||||
|
||||
### With Environment Variable Set:
|
||||
|
||||
1. App starts and detects `VITE_FLASK_BACKEND_URL`
|
||||
2. Automatically initializes Flask backend adapter
|
||||
3. Shows "Backend" badge in header (with dot indicator)
|
||||
4. Settings page displays auto-configuration card
|
||||
5. Backend selection controls are disabled
|
||||
6. "Save Storage Settings" button is disabled
|
||||
|
||||
### Without Environment Variable:
|
||||
|
||||
1. App starts with default IndexedDB
|
||||
2. Shows "Local" badge in header
|
||||
3. Settings page allows backend selection
|
||||
4. Users can manually configure Flask backend
|
||||
5. All controls are enabled
|
||||
|
||||
## Testing Scenarios
|
||||
|
||||
### Scenario 1: Development with Local Backend
|
||||
```bash
|
||||
echo "VITE_FLASK_BACKEND_URL=http://localhost:5000" > .env
|
||||
docker-compose up backend
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Scenario 2: Full Docker Stack
|
||||
```bash
|
||||
docker-compose up -d
|
||||
# Access at http://localhost:3000
|
||||
```
|
||||
|
||||
### Scenario 3: Local Storage Only
|
||||
```bash
|
||||
npm run dev
|
||||
# No env var, uses IndexedDB
|
||||
```
|
||||
|
||||
### Scenario 4: Remote Backend
|
||||
```bash
|
||||
echo "VITE_FLASK_BACKEND_URL=https://api.example.com" > .env
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Key Benefits
|
||||
|
||||
1. **Production Ready:** Environment variable ensures consistent backend usage
|
||||
2. **Developer Friendly:** Easy local development with auto-configuration
|
||||
3. **Docker Native:** Seamless integration with container orchestration
|
||||
4. **User Choice:** Manual configuration still available when needed
|
||||
5. **Clear Feedback:** UI clearly shows which backend is active
|
||||
6. **Zero Config:** Full stack works out of the box with docker-compose
|
||||
|
||||
## Backwards Compatibility
|
||||
|
||||
- Existing apps without env var continue using saved preferences
|
||||
- Manual configuration still works when env var not set
|
||||
- No breaking changes to existing functionality
|
||||
- Data migration tools remain functional
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- Environment variables not exposed to client (compile-time only)
|
||||
- CORS configured in Flask backend
|
||||
- HTTPS recommended for production
|
||||
- No credentials stored in environment variables
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Potential improvements:
|
||||
- Add backend health check on startup
|
||||
- Show connection quality indicator
|
||||
- Support multiple backend URLs for failover
|
||||
- Add authentication token via env var
|
||||
- Implement read-only mode configuration
|
||||
267
QUICKSTART.md
Normal file
267
QUICKSTART.md
Normal file
@@ -0,0 +1,267 @@
|
||||
# Quick Start Guide
|
||||
|
||||
## Choose Your Setup
|
||||
|
||||
### 🚀 Full Stack with Docker (Easiest)
|
||||
|
||||
Everything runs in Docker with automatic backend configuration.
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
✅ Frontend: http://localhost:3000
|
||||
✅ Backend: http://localhost:5000
|
||||
✅ Auto-configured to use Flask backend
|
||||
|
||||
---
|
||||
|
||||
### 💻 Local Development
|
||||
|
||||
Backend in Docker, frontend in development mode.
|
||||
|
||||
```bash
|
||||
# Terminal 1: Start backend
|
||||
docker-compose -f docker-compose.backend-only.yml up -d
|
||||
|
||||
# Terminal 2: Configure and start frontend
|
||||
echo "VITE_FLASK_BACKEND_URL=http://localhost:5000" > .env
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
✅ Frontend: http://localhost:5173 (Vite dev server)
|
||||
✅ Backend: http://localhost:5000
|
||||
✅ Auto-configured to use Flask backend
|
||||
|
||||
---
|
||||
|
||||
### 🌐 Frontend Only (Local Storage)
|
||||
|
||||
No backend required - uses browser IndexedDB.
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
✅ Frontend: http://localhost:5173
|
||||
✅ Data stored locally in browser
|
||||
✅ No server needed
|
||||
|
||||
---
|
||||
|
||||
### ⚙️ Backend Only
|
||||
|
||||
Run backend separately, configure frontend manually.
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
pip install -r requirements.txt
|
||||
python app.py
|
||||
```
|
||||
|
||||
Then in a separate terminal:
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
✅ Backend: http://localhost:5000
|
||||
✅ Frontend: http://localhost:5173
|
||||
⚠️ Must configure backend URL in Settings page
|
||||
|
||||
---
|
||||
|
||||
## Key Features by Setup
|
||||
|
||||
| Feature | Full Stack Docker | Local Dev | Frontend Only | Backend Only |
|
||||
|---------|------------------|-----------|---------------|--------------|
|
||||
| Auto-configured backend | ✅ | ✅ | ❌ | ❌ |
|
||||
| Hot reload | ❌ | ✅ | ✅ | ✅ |
|
||||
| Multi-device sync | ✅ | ✅ | ❌ | ✅* |
|
||||
| No dependencies | ❌ | ❌ | ✅ | ❌ |
|
||||
| Production-ready | ✅ | ❌ | ❌ | ⚠️ |
|
||||
|
||||
*Requires manual configuration
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables
|
||||
|
||||
### `VITE_FLASK_BACKEND_URL`
|
||||
|
||||
**What it does:**
|
||||
Automatically configures the app to use a Flask backend instead of IndexedDB.
|
||||
|
||||
**When set:**
|
||||
- App connects to Flask backend on startup
|
||||
- Settings page backend selection is disabled
|
||||
- Overrides any manual configuration
|
||||
|
||||
**Examples:**
|
||||
|
||||
Local backend:
|
||||
```bash
|
||||
VITE_FLASK_BACKEND_URL=http://localhost:5000
|
||||
```
|
||||
|
||||
Docker internal:
|
||||
```bash
|
||||
VITE_FLASK_BACKEND_URL=http://backend:5000
|
||||
```
|
||||
|
||||
Remote backend:
|
||||
```bash
|
||||
VITE_FLASK_BACKEND_URL=https://api.example.com
|
||||
```
|
||||
|
||||
**Setup methods:**
|
||||
|
||||
`.env` file:
|
||||
```bash
|
||||
echo "VITE_FLASK_BACKEND_URL=http://localhost:5000" > .env
|
||||
```
|
||||
|
||||
Docker Compose:
|
||||
```yaml
|
||||
services:
|
||||
frontend:
|
||||
environment:
|
||||
- VITE_FLASK_BACKEND_URL=http://backend:5000
|
||||
```
|
||||
|
||||
Docker build:
|
||||
```bash
|
||||
docker build --build-arg VITE_FLASK_BACKEND_URL=http://api.example.com .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Commands
|
||||
|
||||
### Docker
|
||||
|
||||
```bash
|
||||
# Start all services
|
||||
docker-compose up -d
|
||||
|
||||
# Stop all services
|
||||
docker-compose down
|
||||
|
||||
# View logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Rebuild after code changes
|
||||
docker-compose up -d --build
|
||||
|
||||
# Start backend only
|
||||
docker-compose -f docker-compose.backend-only.yml up -d
|
||||
```
|
||||
|
||||
### NPM
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Development server
|
||||
npm run dev
|
||||
|
||||
# Production build
|
||||
npm run build
|
||||
|
||||
# Preview production build
|
||||
npm run preview
|
||||
```
|
||||
|
||||
### Backend (Python)
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
|
||||
# Install dependencies
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Run server
|
||||
python app.py
|
||||
|
||||
# Run with custom database path
|
||||
DB_PATH=/custom/path/snippets.db python app.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Connection failed" in Settings
|
||||
|
||||
**Problem:** Can't connect to Flask backend
|
||||
|
||||
**Solutions:**
|
||||
1. Verify backend is running: `curl http://localhost:5000/health`
|
||||
2. Check URL is correct (include `http://`)
|
||||
3. Ensure no firewall is blocking port 5000
|
||||
4. Check backend logs: `docker-compose logs backend`
|
||||
|
||||
### Environment variable not working
|
||||
|
||||
**Problem:** `VITE_FLASK_BACKEND_URL` not taking effect
|
||||
|
||||
**Solutions:**
|
||||
1. Restart dev server after creating/modifying `.env`
|
||||
2. Ensure file is named `.env` (not `.env.txt`)
|
||||
3. Variable must start with `VITE_`
|
||||
4. For production builds: rebuild with `npm run build`
|
||||
|
||||
### Settings page is read-only
|
||||
|
||||
**This is expected** when `VITE_FLASK_BACKEND_URL` is set.
|
||||
|
||||
**To enable manual configuration:**
|
||||
1. Remove the variable from `.env`
|
||||
2. Restart the application
|
||||
|
||||
### Port already in use
|
||||
|
||||
**Problem:** "Port 3000 (or 5000) is already in use"
|
||||
|
||||
**Solutions:**
|
||||
|
||||
Change frontend port:
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
frontend:
|
||||
ports:
|
||||
- "8080:3000" # Access at http://localhost:8080
|
||||
```
|
||||
|
||||
Change backend port:
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
backend:
|
||||
ports:
|
||||
- "8000:5000" # Access at http://localhost:8000
|
||||
environment:
|
||||
- VITE_FLASK_BACKEND_URL=http://backend:5000 # Keep internal port same
|
||||
```
|
||||
|
||||
Or stop the conflicting service:
|
||||
```bash
|
||||
# Find process using port
|
||||
lsof -i :3000
|
||||
|
||||
# Kill process (replace PID)
|
||||
kill -9 <PID>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
- 📖 [Full documentation](./README-APP.md)
|
||||
- 🔧 [Backend configuration guide](./BACKEND-CONFIG.md)
|
||||
- 🐳 [Docker examples](./docker-compose.README.md)
|
||||
- 🚀 [Backend API docs](./backend/README.md)
|
||||
@@ -34,6 +34,8 @@ CodeSnippet offers flexible data storage with two backend options:
|
||||
|
||||
### Switching Storage Backends
|
||||
|
||||
#### Manual Configuration
|
||||
|
||||
Visit the **Settings** page to:
|
||||
- Choose between IndexedDB and Flask backend
|
||||
- Configure Flask backend URL
|
||||
@@ -42,6 +44,31 @@ Visit the **Settings** page to:
|
||||
- View database statistics
|
||||
- Export/import database backups
|
||||
|
||||
#### Automatic Configuration with Environment Variable
|
||||
|
||||
You can automatically configure the Flask backend using a Docker environment variable. When `VITE_FLASK_BACKEND_URL` is set, the app will:
|
||||
- Automatically use the Flask backend instead of IndexedDB
|
||||
- Override any manual configuration
|
||||
- Disable manual backend selection in the Settings page
|
||||
|
||||
**Setup:**
|
||||
|
||||
1. Create a `.env` file in the project root:
|
||||
```bash
|
||||
VITE_FLASK_BACKEND_URL=http://localhost:5000
|
||||
```
|
||||
|
||||
2. Or set it in your Docker environment:
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
frontend:
|
||||
environment:
|
||||
- VITE_FLASK_BACKEND_URL=http://backend:5000
|
||||
```
|
||||
|
||||
**Note:** When the environment variable is set, the storage backend configuration in Settings becomes read-only. To change backends, remove the environment variable and restart the application.
|
||||
|
||||
## Backend Setup
|
||||
|
||||
### Running Flask Backend Locally
|
||||
@@ -54,7 +81,24 @@ python app.py
|
||||
|
||||
Server runs on `http://localhost:5000` by default.
|
||||
|
||||
### Running with Docker
|
||||
### Running with Docker Compose (Full Stack)
|
||||
|
||||
The easiest way to run both frontend and backend with automatic Flask backend configuration:
|
||||
|
||||
```bash
|
||||
# Start both frontend and backend
|
||||
docker-compose up -d
|
||||
|
||||
# View logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Stop services
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
Access the app at `http://localhost:3000`. The frontend is automatically configured to use the Flask backend at `http://backend:5000`.
|
||||
|
||||
### Running Backend Only with Docker
|
||||
|
||||
Build and run:
|
||||
```bash
|
||||
@@ -62,11 +106,30 @@ docker build -t codesnippet-backend ./backend
|
||||
docker run -p 5000:5000 -v $(pwd)/data:/data codesnippet-backend
|
||||
```
|
||||
|
||||
Or use docker-compose:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
Then configure the frontend manually in Settings to use `http://localhost:5000`.
|
||||
|
||||
### Environment Variable Configuration
|
||||
|
||||
When deploying, you can set the `VITE_FLASK_BACKEND_URL` environment variable to automatically configure the Flask backend:
|
||||
|
||||
**For Docker Compose:**
|
||||
```yaml
|
||||
services:
|
||||
frontend:
|
||||
environment:
|
||||
- VITE_FLASK_BACKEND_URL=http://backend:5000
|
||||
```
|
||||
|
||||
**For Local Development (.env file):**
|
||||
```bash
|
||||
VITE_FLASK_BACKEND_URL=http://localhost:5000
|
||||
```
|
||||
|
||||
When this variable is set:
|
||||
- The app automatically uses Flask backend instead of IndexedDB
|
||||
- Manual backend configuration in Settings is disabled
|
||||
- Perfect for production deployments where backend is always available
|
||||
|
||||
### Backend API
|
||||
|
||||
The Flask backend provides a REST API:
|
||||
|
||||
102
README.md
102
README.md
@@ -1,23 +1,95 @@
|
||||
# ✨ Welcome to Your Spark Template!
|
||||
You've just launched your brand-new Spark Template Codespace — everything’s fired up and ready for you to explore, build, and create with Spark!
|
||||
# CodeSnippet - Code Snippet Manager
|
||||
|
||||
This template is your blank canvas. It comes with a minimal setup to help you get started quickly with Spark development.
|
||||
A powerful code snippet management application with flexible storage backends and an integrated component library showcase.
|
||||
|
||||
🚀 What's Inside?
|
||||
- A clean, minimal Spark environment
|
||||
- Pre-configured for local development
|
||||
- Ready to scale with your ideas
|
||||
|
||||
🧠 What Can You Do?
|
||||
## 🚀 Quick Start
|
||||
|
||||
Right now, this is just a starting point — the perfect place to begin building and testing your Spark applications.
|
||||
Choose the setup that works best for you:
|
||||
|
||||
🧹 Just Exploring?
|
||||
No problem! If you were just checking things out and don’t need to keep this code:
|
||||
### Option 1: Full Stack with Docker (Recommended)
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
Access at: http://localhost:3000 (auto-configured with Flask backend)
|
||||
|
||||
- Simply delete your Spark.
|
||||
- Everything will be cleaned up — no traces left behind.
|
||||
### Option 2: Local Development
|
||||
```bash
|
||||
# Start backend
|
||||
docker-compose -f docker-compose.backend-only.yml up -d
|
||||
|
||||
📄 License For Spark Template Resources
|
||||
# Configure frontend
|
||||
echo "VITE_FLASK_BACKEND_URL=http://localhost:5000" > .env
|
||||
|
||||
# Start frontend
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
Access at: http://localhost:5173
|
||||
|
||||
### Option 3: Frontend Only (No Backend)
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
Access at: http://localhost:5173 (uses local IndexedDB storage)
|
||||
|
||||
📖 **[See detailed setup instructions →](./QUICKSTART.md)**
|
||||
|
||||
## 🔑 Key Features
|
||||
|
||||
- 📝 **Snippet Management** - Create, edit, and organize code snippets with syntax highlighting
|
||||
- 🔍 **Smart Search** - Real-time search across title, description, language, and code
|
||||
- 👁️ **Live Preview** - Split-screen editor with live React component preview
|
||||
- 💾 **Flexible Storage** - Choose between local IndexedDB or Flask backend
|
||||
- 🔄 **Auto-Configuration** - Automatically use Flask backend via environment variable
|
||||
- 🗂️ **Component Library** - Showcase organized by atomic design principles
|
||||
- 📤 **Export/Import** - Backup and restore your entire database
|
||||
- 🎨 **Beautiful UI** - Modern dark theme with purple and cyan accents
|
||||
|
||||
## 🎯 Storage Backends
|
||||
|
||||
CodeSnippet supports two storage backends:
|
||||
|
||||
### IndexedDB (Default)
|
||||
- Local browser storage
|
||||
- No server required
|
||||
- Perfect for personal use
|
||||
|
||||
### Flask Backend (Optional)
|
||||
- Remote server storage
|
||||
- Multi-device sync
|
||||
- Requires Flask backend
|
||||
|
||||
**🔧 Auto-Configuration:**
|
||||
Set `VITE_FLASK_BACKEND_URL` environment variable to automatically use Flask backend:
|
||||
|
||||
```bash
|
||||
# .env file
|
||||
VITE_FLASK_BACKEND_URL=http://localhost:5000
|
||||
```
|
||||
|
||||
When set, the app automatically connects to Flask backend and disables manual configuration.
|
||||
|
||||
📖 **[Complete backend configuration guide →](./BACKEND-CONFIG.md)**
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
- **[Quick Start Guide](./QUICKSTART.md)** - Get up and running quickly
|
||||
- **[Application Guide](./README-APP.md)** - Features and usage
|
||||
- **[Backend Configuration](./BACKEND-CONFIG.md)** - Detailed backend setup
|
||||
- **[Backend API](./backend/README.md)** - Flask API documentation
|
||||
- **[Docker Examples](./docker-compose.README.md)** - Docker deployment options
|
||||
|
||||
## 🛠️ Technology Stack
|
||||
|
||||
- React 19 + TypeScript
|
||||
- SQL.js (SQLite in WebAssembly)
|
||||
- Flask (Python backend)
|
||||
- Monaco Editor (VS Code editor)
|
||||
- Framer Motion (animations)
|
||||
- Shadcn UI (component library)
|
||||
- Tailwind CSS (styling)
|
||||
|
||||
## 📄 License
|
||||
|
||||
The Spark Template files and resources from GitHub are licensed under the terms of the MIT license, Copyright GitHub, Inc.
|
||||
|
||||
@@ -67,6 +67,30 @@ Default: `/data/snippets.db`
|
||||
|
||||
## Frontend Integration
|
||||
|
||||
### Automatic Configuration (Recommended)
|
||||
|
||||
The frontend can be automatically configured to use the Flask backend via environment variable:
|
||||
|
||||
**For Docker Compose (full stack):**
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
The frontend will automatically connect to the backend at `http://backend:5000`.
|
||||
|
||||
**For local development:**
|
||||
```bash
|
||||
# .env file in project root
|
||||
VITE_FLASK_BACKEND_URL=http://localhost:5000
|
||||
```
|
||||
|
||||
When `VITE_FLASK_BACKEND_URL` is set:
|
||||
- Frontend automatically uses Flask backend
|
||||
- Manual backend selection in Settings is disabled
|
||||
- Perfect for production deployments
|
||||
|
||||
### Manual Configuration
|
||||
|
||||
In the CodeSnippet app:
|
||||
1. Navigate to Settings page
|
||||
2. Select "Flask Backend (Remote Server)"
|
||||
@@ -75,6 +99,8 @@ In the CodeSnippet app:
|
||||
5. Click "Save Storage Settings"
|
||||
6. Optionally migrate existing IndexedDB data to Flask
|
||||
|
||||
See [BACKEND-CONFIG.md](../BACKEND-CONFIG.md) for detailed configuration guide.
|
||||
|
||||
## Docker Details
|
||||
|
||||
### Building the Image
|
||||
|
||||
71
docker-compose.README.md
Normal file
71
docker-compose.README.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Docker Compose Examples
|
||||
|
||||
This directory contains example Docker Compose configurations for different deployment scenarios.
|
||||
|
||||
## Files
|
||||
|
||||
- `docker-compose.yml` - Default full stack with auto-configured backend
|
||||
- `docker-compose.backend-only.yml` - Backend service only
|
||||
- `docker-compose.dev.yml` - Development setup with hot reload
|
||||
|
||||
## Usage
|
||||
|
||||
### Full Stack (Frontend + Backend)
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
Access:
|
||||
- Frontend: http://localhost:3000
|
||||
- Backend API: http://localhost:5000
|
||||
|
||||
### Backend Only
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.backend-only.yml up -d
|
||||
```
|
||||
|
||||
Access:
|
||||
- Backend API: http://localhost:5000
|
||||
|
||||
Then run frontend locally:
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Configure frontend manually in Settings to use `http://localhost:5000`.
|
||||
|
||||
### Development Mode
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.dev.yml up -d
|
||||
```
|
||||
|
||||
This runs:
|
||||
- Backend in Docker
|
||||
- Frontend expects you to run `npm run dev` locally with env var set
|
||||
|
||||
## Environment Variables
|
||||
|
||||
All configurations support these environment variables:
|
||||
|
||||
### Backend
|
||||
- `DB_PATH` - SQLite database path (default: `/data/snippets.db`)
|
||||
|
||||
### Frontend
|
||||
- `VITE_FLASK_BACKEND_URL` - Flask backend URL (enables auto-configuration)
|
||||
|
||||
## Persistence
|
||||
|
||||
All configurations use a Docker volume `snippet-data` for persistent storage.
|
||||
|
||||
To backup:
|
||||
```bash
|
||||
docker run --rm -v codesnippet_snippet-data:/data -v $(pwd):/backup alpine tar czf /backup/snippets-backup.tar.gz /data
|
||||
```
|
||||
|
||||
To restore:
|
||||
```bash
|
||||
docker run --rm -v codesnippet_snippet-data:/data -v $(pwd):/backup alpine tar xzf /backup/snippets-backup.tar.gz -C /
|
||||
```
|
||||
15
docker-compose.backend-only.yml
Normal file
15
docker-compose.backend-only.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
backend:
|
||||
build: ./backend
|
||||
ports:
|
||||
- "5000:5000"
|
||||
volumes:
|
||||
- snippet-data:/data
|
||||
environment:
|
||||
- DB_PATH=/data/snippets.db
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
snippet-data:
|
||||
@@ -11,5 +11,18 @@ services:
|
||||
- DB_PATH=/data/snippets.db
|
||||
restart: unless-stopped
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
- VITE_FLASK_BACKEND_URL=http://localhost:5000
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- VITE_FLASK_BACKEND_URL=http://backend:5000
|
||||
depends_on:
|
||||
- backend
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
snippet-data:
|
||||
|
||||
19
nginx.conf
Normal file
19
nginx.conf
Normal file
@@ -0,0 +1,19 @@
|
||||
server {
|
||||
listen 3000;
|
||||
server_name localhost;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location /api {
|
||||
proxy_pass http://backend:5000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
|
||||
import { motion } from 'framer-motion'
|
||||
import { Code } from '@phosphor-icons/react'
|
||||
import { Navigation, NavigationProvider, NavigationSidebar, useNavigation } from '@/components/Navigation'
|
||||
import { BackendIndicator } from '@/components/BackendIndicator'
|
||||
import { HomePage } from '@/pages/HomePage'
|
||||
import { DemoPage } from '@/pages/DemoPage'
|
||||
import { AtomsPage } from '@/pages/AtomsPage'
|
||||
@@ -62,6 +63,13 @@ function AppContent() {
|
||||
CodeSnippet
|
||||
</h1>
|
||||
</motion.div>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: 20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ duration: 0.4, delay: 0.1 }}
|
||||
>
|
||||
<BackendIndicator />
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
53
src/components/BackendIndicator.tsx
Normal file
53
src/components/BackendIndicator.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { Database, CloudCheck } from '@phosphor-icons/react'
|
||||
import { getStorageConfig } from '@/lib/storage'
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
|
||||
export function BackendIndicator() {
|
||||
const [backend, setBackend] = useState<'indexeddb' | 'flask'>('indexeddb')
|
||||
const [isEnvConfigured, setIsEnvConfigured] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const config = getStorageConfig()
|
||||
setBackend(config.backend)
|
||||
setIsEnvConfigured(Boolean(import.meta.env.VITE_FLASK_BACKEND_URL))
|
||||
}, [])
|
||||
|
||||
if (backend === 'indexeddb') {
|
||||
return (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div className="flex items-center gap-2 px-3 py-1.5 rounded-full bg-muted/50 border border-border">
|
||||
<Database size={16} className="text-muted-foreground" />
|
||||
<span className="text-xs font-medium text-muted-foreground">Local</span>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>Using IndexedDB (Local Storage)</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div className="flex items-center gap-2 px-3 py-1.5 rounded-full bg-accent/10 border border-accent/30">
|
||||
<CloudCheck size={16} className="text-accent" weight="fill" />
|
||||
<span className="text-xs font-medium text-accent">Backend</span>
|
||||
{isEnvConfigured && (
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-accent" />
|
||||
)}
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>Using Flask Backend</p>
|
||||
{isEnvConfigured && <p className="text-xs text-muted-foreground">Auto-configured</p>}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
)
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
import initSqlJs, { Database } from 'sql.js'
|
||||
import type { Snippet, SnippetTemplate } from './types'
|
||||
import { getStorageConfig, FlaskStorageAdapter } from './storage'
|
||||
import { getStorageConfig, FlaskStorageAdapter, loadStorageConfig } from './storage'
|
||||
|
||||
let dbInstance: Database | null = null
|
||||
let sqlInstance: any = null
|
||||
let flaskAdapter: FlaskStorageAdapter | null = null
|
||||
let configLoaded = false
|
||||
|
||||
const DB_KEY = 'codesnippet-db'
|
||||
const IDB_NAME = 'CodeSnippetDB'
|
||||
@@ -195,6 +196,11 @@ async function saveDB() {
|
||||
}
|
||||
|
||||
function getFlaskAdapter(): FlaskStorageAdapter | null {
|
||||
if (!configLoaded) {
|
||||
loadStorageConfig()
|
||||
configLoaded = true
|
||||
}
|
||||
|
||||
const config = getStorageConfig()
|
||||
if (config.backend === 'flask' && config.flaskUrl) {
|
||||
if (!flaskAdapter || flaskAdapter['baseUrl'] !== config.flaskUrl) {
|
||||
|
||||
@@ -7,13 +7,33 @@ export interface StorageConfig {
|
||||
flaskUrl?: string
|
||||
}
|
||||
|
||||
let currentConfig: StorageConfig = {
|
||||
backend: 'indexeddb'
|
||||
}
|
||||
|
||||
const STORAGE_CONFIG_KEY = 'codesnippet-storage-config'
|
||||
|
||||
function getDefaultConfig(): StorageConfig {
|
||||
const flaskUrl = import.meta.env.VITE_FLASK_BACKEND_URL
|
||||
|
||||
if (flaskUrl) {
|
||||
return {
|
||||
backend: 'flask',
|
||||
flaskUrl: flaskUrl
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
backend: 'indexeddb'
|
||||
}
|
||||
}
|
||||
|
||||
let currentConfig: StorageConfig = getDefaultConfig()
|
||||
|
||||
export function loadStorageConfig(): StorageConfig {
|
||||
const defaultConfig = getDefaultConfig()
|
||||
|
||||
if (defaultConfig.backend === 'flask' && defaultConfig.flaskUrl) {
|
||||
currentConfig = defaultConfig
|
||||
return currentConfig
|
||||
}
|
||||
|
||||
try {
|
||||
const saved = localStorage.getItem(STORAGE_CONFIG_KEY)
|
||||
if (saved) {
|
||||
|
||||
@@ -29,6 +29,7 @@ export function SettingsPage() {
|
||||
const [flaskUrl, setFlaskUrl] = useState('')
|
||||
const [flaskConnectionStatus, setFlaskConnectionStatus] = useState<'unknown' | 'connected' | 'failed'>('unknown')
|
||||
const [testingConnection, setTestingConnection] = useState(false)
|
||||
const [envVarSet, setEnvVarSet] = useState(false)
|
||||
|
||||
const loadStats = async () => {
|
||||
setLoading(true)
|
||||
@@ -62,8 +63,13 @@ export function SettingsPage() {
|
||||
useEffect(() => {
|
||||
loadStats()
|
||||
const config = loadStorageConfig()
|
||||
|
||||
const envFlaskUrl = import.meta.env.VITE_FLASK_BACKEND_URL
|
||||
const isEnvSet = Boolean(envFlaskUrl)
|
||||
setEnvVarSet(isEnvSet)
|
||||
|
||||
setStorageBackend(config.backend)
|
||||
setFlaskUrl(config.flaskUrl || 'http://localhost:5000')
|
||||
setFlaskUrl(config.flaskUrl || envFlaskUrl || 'http://localhost:5000')
|
||||
if (config.backend === 'flask' && config.flaskUrl) {
|
||||
testFlaskConnection(config.flaskUrl)
|
||||
}
|
||||
@@ -244,6 +250,57 @@ export function SettingsPage() {
|
||||
</div>
|
||||
|
||||
<div className="grid gap-6 max-w-3xl">
|
||||
{envVarSet && (
|
||||
<Card className="border-accent">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2 text-accent">
|
||||
<CloudCheck weight="fill" size={24} />
|
||||
Backend Auto-Configured
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Flask backend is configured via environment variable
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between py-2">
|
||||
<span className="text-sm text-muted-foreground">Backend URL</span>
|
||||
<code className="text-sm font-mono bg-muted px-2 py-1 rounded">{flaskUrl}</code>
|
||||
</div>
|
||||
<div className="flex items-center justify-between py-2">
|
||||
<span className="text-sm text-muted-foreground">Configuration Source</span>
|
||||
<code className="text-sm font-mono bg-muted px-2 py-1 rounded">VITE_FLASK_BACKEND_URL</code>
|
||||
</div>
|
||||
<div className="flex items-center justify-between py-2">
|
||||
<span className="text-sm text-muted-foreground">Status</span>
|
||||
{flaskConnectionStatus === 'connected' && (
|
||||
<span className="flex items-center gap-2 text-sm text-green-600">
|
||||
<CloudCheck weight="fill" size={16} />
|
||||
Connected
|
||||
</span>
|
||||
)}
|
||||
{flaskConnectionStatus === 'failed' && (
|
||||
<span className="flex items-center gap-2 text-sm text-destructive">
|
||||
<CloudSlash weight="fill" size={16} />
|
||||
Connection Failed
|
||||
</span>
|
||||
)}
|
||||
{flaskConnectionStatus === 'unknown' && (
|
||||
<Button
|
||||
onClick={handleTestConnection}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={testingConnection}
|
||||
>
|
||||
{testingConnection ? 'Testing...' : 'Test Connection'}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
@@ -255,11 +312,26 @@ export function SettingsPage() {
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-6">
|
||||
<RadioGroup value={storageBackend} onValueChange={(value) => setStorageBackend(value as StorageBackend)}>
|
||||
{envVarSet && (
|
||||
<Alert className="border-accent bg-accent/10">
|
||||
<AlertDescription className="flex items-center gap-2">
|
||||
<CloudCheck weight="fill" size={16} className="text-accent" />
|
||||
<span>
|
||||
Storage backend is configured via <code className="px-1.5 py-0.5 rounded bg-muted text-xs font-mono">VITE_FLASK_BACKEND_URL</code> environment variable and cannot be changed here.
|
||||
</span>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<RadioGroup
|
||||
value={storageBackend}
|
||||
onValueChange={(value) => setStorageBackend(value as StorageBackend)}
|
||||
disabled={envVarSet}
|
||||
>
|
||||
<div className="flex items-start space-x-3 space-y-0">
|
||||
<RadioGroupItem value="indexeddb" id="storage-indexeddb" />
|
||||
<RadioGroupItem value="indexeddb" id="storage-indexeddb" disabled={envVarSet} />
|
||||
<div className="flex-1">
|
||||
<Label htmlFor="storage-indexeddb" className="font-semibold cursor-pointer">
|
||||
<Label htmlFor="storage-indexeddb" className={`font-semibold ${envVarSet ? 'opacity-50' : 'cursor-pointer'}`}>
|
||||
IndexedDB (Local Browser Storage)
|
||||
</Label>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
@@ -269,9 +341,9 @@ export function SettingsPage() {
|
||||
</div>
|
||||
|
||||
<div className="flex items-start space-x-3 space-y-0 mt-4">
|
||||
<RadioGroupItem value="flask" id="storage-flask" />
|
||||
<RadioGroupItem value="flask" id="storage-flask" disabled={envVarSet} />
|
||||
<div className="flex-1">
|
||||
<Label htmlFor="storage-flask" className="font-semibold cursor-pointer">
|
||||
<Label htmlFor="storage-flask" className={`font-semibold ${envVarSet ? 'opacity-50' : 'cursor-pointer'}`}>
|
||||
Flask Backend (Remote Server)
|
||||
</Label>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
@@ -295,6 +367,7 @@ export function SettingsPage() {
|
||||
setFlaskUrl(e.target.value)
|
||||
setFlaskConnectionStatus('unknown')
|
||||
}}
|
||||
disabled={envVarSet}
|
||||
/>
|
||||
<Button
|
||||
onClick={handleTestConnection}
|
||||
@@ -342,7 +415,7 @@ export function SettingsPage() {
|
||||
)}
|
||||
|
||||
<div className="pt-2">
|
||||
<Button onClick={handleSaveStorageConfig} className="gap-2">
|
||||
<Button onClick={handleSaveStorageConfig} className="gap-2" disabled={envVarSet}>
|
||||
<Database weight="bold" size={16} />
|
||||
Save Storage Settings
|
||||
</Button>
|
||||
|
||||
10
src/vite-end.d.ts
vendored
10
src/vite-end.d.ts
vendored
@@ -1,3 +1,11 @@
|
||||
/// <reference types="vite/client" />
|
||||
declare const GITHUB_RUNTIME_PERMANENT_NAME: string
|
||||
declare const BASE_KV_SERVICE_URL: string
|
||||
declare const BASE_KV_SERVICE_URL: string
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_FLASK_BACKEND_URL?: string
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv
|
||||
}
|
||||
Reference in New Issue
Block a user