fix: remove hardcoded prod/local browser URLs from app dev bundle
- Create centralized src/config/apiConfig.ts for API_BASE, TLSYNC_URL, WHISPERLIVE_URL, and SEARCH_URL resolution - Fix multiplayerUser.tsx to use VITE_TLSYNC_URL instead of deriving from VITE_FRONTEND_SITE_URL (was pointing to prod TLSync) - Replace all 127.0.0.1:8080 fallbacks with /api (relative path) - Replace all localhost:8000 fallbacks with VITE_API_BASE || /api - Remove hardcoded https://api.classroomcopilot.ai production fallbacks from transcription store and panel - Fix axiosConfig.ts to use centralized API config - Update .env.dev: set VITE_TLSYNC_URL to dev frontend URL - Update .env.development: fix VITE_SEARCH_URL from localhost to prod - Add missing env var type declarations to vite-env.d.ts Fixes: t_73d78fb1
This commit is contained in:
parent
0db53bfd9c
commit
e5fa002d12
@ -37,4 +37,4 @@ VITE_MICROSOFT_CLIENT_SECRET_ID=dummy_secret_id
|
|||||||
VITE_MICROSOFT_CLIENT_SECRET=dummy_secret
|
VITE_MICROSOFT_CLIENT_SECRET=dummy_secret
|
||||||
VITE_MICROSOFT_TENANT_ID=common
|
VITE_MICROSOFT_TENANT_ID=common
|
||||||
|
|
||||||
VITE_SEARCH_URL=http://localhost:8888
|
VITE_SEARCH_URL=https://search.kevlarai.com
|
||||||
|
|||||||
62
.env.example
62
.env.example
@ -1,33 +1,34 @@
|
|||||||
# Classroom Copilot App - Environment Variables Template
|
# Classroom Copilot App - Environment Variables Template
|
||||||
# Copy this file to .env and fill in the values
|
# Copy this file to .env.dev or .env.development and fill in the values
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Frontend Configuration
|
# Frontend Configuration
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
VITE_APP_NAME=Classroom Copilot
|
VITE_APP_NAME=Classroom Copilot
|
||||||
VITE_DEV=false
|
VITE_DEV=true
|
||||||
VITE_FRONTEND_SITE_URL=https://app.classroomcopilot.ai
|
VITE_DEV=true
|
||||||
VITE_PORT_FRONTEND=3000
|
VITE_FRONTEND_SITE_URL=http://192.168.0.251:13000
|
||||||
VITE_PORT_FRONTEND_HMR=24678
|
VITE_PORT_FRONTEND=13000
|
||||||
VITE_APP_HMR_URL=http://localhost:24678
|
VITE_PORT_FRONTEND_HMR=5173
|
||||||
|
VITE_APP_HMR_URL=http://192.168.0.251:13000
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# API Configuration
|
# API Configuration (primary: VITE_API_BASE, legacy alias: VITE_API_URL)
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
VITE_API_URL=https://api.classroomcopilot.ai
|
VITE_API_URL=http://192.168.0.64:18000
|
||||||
VITE_API_BASE=https://api.classroomcopilot.ai
|
VITE_API_BASE=http://192.168.0.64:18000
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Supabase Configuration
|
# Supabase Configuration
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
VITE_SUPABASE_URL=https://your-project.supabase.co
|
VITE_SUPABASE_URL=http://192.168.0.94:8000
|
||||||
VITE_SUPABASE_ANON_KEY=your-supabase-anon-key
|
VITE_SUPABASE_ANON_KEY=your-supabase-anon-key
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# TLSync (TLDraw Sync) Configuration
|
# TLSync (TLDraw Sync Worker) Configuration
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
VITE_TLSYNC_URL=https://app.classroomcopilot.ai/tldraw
|
VITE_TLSYNC_URL=http://192.168.0.251:13000/tldraw
|
||||||
VITE_TLSYNC_SECRET=your-tlsync-secret
|
VITE_TLSYNC_SECRET=your-tlsync-shared-secret
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# WhisperLive (Transcription) Configuration
|
# WhisperLive (Transcription) Configuration
|
||||||
@ -35,19 +36,42 @@ VITE_TLSYNC_SECRET=your-tlsync-secret
|
|||||||
VITE_WHISPERLIVE_URL=wss://whisperlive.classroomcopilot.ai/ws
|
VITE_WHISPERLIVE_URL=wss://whisperlive.classroomcopilot.ai/ws
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Search Configuration
|
# Search Configuration (searxng proxy)
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
VITE_SEARCH_URL=https://search.kevlarai.com
|
VITE_SEARCH_URL=https://search.kevlarai.com
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Super Admin Configuration
|
# Neo4j Configuration
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
VITE_SUPER_ADMIN_EMAIL=admin@example.com
|
VITE_NEO4J_URL=bolt://192.168.0.209:7687
|
||||||
|
VITE_NEO4J_USER=neo4j
|
||||||
|
VITE_NEO4J_PASSWORD=password
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Port Configuration (for docker-compose)
|
# LLM / Ollama Configuration
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
PORT_FRONTEND=3000
|
VITE_LLM_PROVIDER=ollama
|
||||||
PORT_FRONTEND_HMR=24678
|
VITE_OLLAMA_API_URL=https://ollama.kevlarai.com
|
||||||
|
VITE_OLLAMA_BASE_URL=https://ollama.kevlarai.com
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Microsoft Entra ID (SSO)
|
||||||
|
# =============================================================================
|
||||||
|
VITE_MICROSOFT_CLIENT_ID=dummy_client_id
|
||||||
|
VITE_MICROSOFT_CLIENT_SECRET_DESC="Local dev OAuth client secret"
|
||||||
|
VITE_MICROSOFT_CLIENT_SECRET_ID=secret-id
|
||||||
|
VITE_MICROSOFT_CLIENT_SECRET=secret-value
|
||||||
|
VITE_MICROSOFT_TENANT_ID=common
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Super Admin Configuration
|
||||||
|
# =============================================================================
|
||||||
|
VITE_SUPER_ADMIN_EMAIL=admin@classroomcopilot.ai
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Port Configuration (for docker-compose, non-VITE_ prefix)
|
||||||
|
# =============================================================================
|
||||||
|
PORT_FRONTEND=13000
|
||||||
|
PORT_FRONTEND_HMR=3002
|
||||||
PORT_API=8000
|
PORT_API=8000
|
||||||
PORT_SUPABASE=8000
|
PORT_SUPABASE=8000
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import { API_BASE as CONFIG_API_BASE } from './config/apiConfig';
|
||||||
import { logger } from './debugConfig';
|
import { logger } from './debugConfig';
|
||||||
|
|
||||||
// Use development backend URL if no custom URL is provided
|
// Use development backend URL if no custom URL is provided
|
||||||
const baseURL = import.meta.env.VITE_API_BASE || 'http://localhost:8080';
|
const baseURL = CONFIG_API_BASE;
|
||||||
|
|
||||||
if (!import.meta.env.VITE_API_BASE) {
|
if (!import.meta.env.VITE_API_BASE && !import.meta.env.VITE_API_URL) {
|
||||||
logger.warn('axios', '⚠️ VITE_API_BASE not set, defaulting to http://localhost:8080');
|
logger.warn('axios', '⚠️ VITE_API_BASE not set, using relative /api fallback');
|
||||||
}
|
}
|
||||||
|
|
||||||
const instance = axios.create({
|
const instance = axios.create({
|
||||||
|
|||||||
44
src/config/apiConfig.ts
Normal file
44
src/config/apiConfig.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* Centralized API configuration for Classroom Copilot.
|
||||||
|
*
|
||||||
|
* Resolves the API base URL from environment variables with proper fallbacks.
|
||||||
|
* - In dev: VITE_API_BASE should always be set (e.g., http://192.168.0.64:18000)
|
||||||
|
* - In production: VITE_API_BASE should be set to the production API URL
|
||||||
|
* - Fallback: "/api" (relative path, works when API is served from same origin)
|
||||||
|
*
|
||||||
|
* IMPORTANT: Never hardcode localhost or 127.0.0.1 as fallbacks - they break
|
||||||
|
* remote dev access and do not work in containerized environments.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Primary API base URL. Use this for all API calls.
|
||||||
|
* Resolved from VITE_API_BASE (preferred) or VITE_API_URL (legacy alias).
|
||||||
|
*/
|
||||||
|
export const API_BASE: string =
|
||||||
|
import.meta.env.VITE_API_BASE ||
|
||||||
|
import.meta.env.VITE_API_URL ||
|
||||||
|
"/api";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TLSync worker URL for tldraw multiplayer.
|
||||||
|
* Resolved from VITE_TLSYNC_URL (preferred) or derived from VITE_FRONTEND_SITE_URL.
|
||||||
|
*/
|
||||||
|
export const TLSYNC_URL: string =
|
||||||
|
import.meta.env.VITE_TLSYNC_URL ||
|
||||||
|
(import.meta.env.VITE_FRONTEND_SITE_URL?.startsWith("http")
|
||||||
|
? `${import.meta.env.VITE_FRONTEND_SITE_URL}/tldraw`
|
||||||
|
: `https://${import.meta.env.VITE_FRONTEND_SITE_URL}/tldraw`);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WhisperLive WebSocket URL for live transcription.
|
||||||
|
* Resolved from VITE_WHISPERLIVE_URL. Must be set in env.
|
||||||
|
*/
|
||||||
|
export const WHISPERLIVE_URL: string | undefined =
|
||||||
|
import.meta.env.VITE_WHISPERLIVE_URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search proxy URL (searxng).
|
||||||
|
* Resolved from VITE_SEARCH_URL.
|
||||||
|
*/
|
||||||
|
export const SEARCH_URL: string =
|
||||||
|
import.meta.env.VITE_SEARCH_URL || "/searxng-api/";
|
||||||
@ -38,7 +38,7 @@ import { HEADER_HEIGHT } from './Layout';
|
|||||||
import { logger } from '../debugConfig';
|
import { logger } from '../debugConfig';
|
||||||
import { GraphNavigator } from '../components/navigation/GraphNavigator';
|
import { GraphNavigator } from '../components/navigation/GraphNavigator';
|
||||||
|
|
||||||
const API_BASE = import.meta.env.VITE_API_URL || 'http://localhost:8000';
|
const API_BASE = import.meta.env.VITE_API_BASE || import.meta.env.VITE_API_URL || '/api';
|
||||||
|
|
||||||
const Header: React.FC = () => {
|
const Header: React.FC = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { Refresh, School, People, EventNote, HourglassEmpty } from '@mui/icons-m
|
|||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
import { useAuth } from '../../contexts/AuthContext';
|
import { useAuth } from '../../contexts/AuthContext';
|
||||||
|
|
||||||
const API_BASE = import.meta.env.VITE_API_URL || 'http://localhost:8000';
|
const API_BASE = import.meta.env.VITE_API_BASE || import.meta.env.VITE_API_URL || '/api';
|
||||||
|
|
||||||
interface SchoolEntry {
|
interface SchoolEntry {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@ -123,7 +123,7 @@ const SimpleUploadTest: React.FC = () => {
|
|||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||||
const dirInputRef = useRef<HTMLInputElement>(null);
|
const dirInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
const API_BASE = import.meta.env.VITE_API_BASE || 'http://127.0.0.1:8080';
|
const API_BASE = import.meta.env.VITE_API_BASE || '/api';
|
||||||
|
|
||||||
const apiFetch = useCallback(async (url: string, init?: { method?: string; body?: FormData | string; headers?: Record<string, string> }) => {
|
const apiFetch = useCallback(async (url: string, init?: { method?: string; body?: FormData | string; headers?: Record<string, string> }) => {
|
||||||
const session = await supabase.auth.getSession();
|
const session = await supabase.auth.getSession();
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import {
|
|||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
import { useAuth } from '../../contexts/AuthContext';
|
import { useAuth } from '../../contexts/AuthContext';
|
||||||
|
|
||||||
const API_BASE = import.meta.env.VITE_API_URL || 'http://localhost:8000';
|
const API_BASE = import.meta.env.VITE_API_BASE || import.meta.env.VITE_API_URL || '/api';
|
||||||
|
|
||||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import {
|
|||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
import { useAuth } from '../../contexts/AuthContext';
|
import { useAuth } from '../../contexts/AuthContext';
|
||||||
|
|
||||||
const API_BASE = import.meta.env.VITE_API_URL || 'http://localhost:8000';
|
const API_BASE = import.meta.env.VITE_API_BASE || import.meta.env.VITE_API_URL || '/api';
|
||||||
|
|
||||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
import { Add, Search, LibraryBooks, Edit, Delete, FilterList } from '@mui/icons-material';
|
import { Add, Search, LibraryBooks, Edit, Delete, FilterList } from '@mui/icons-material';
|
||||||
import { useAuth } from '../../contexts/AuthContext';
|
import { useAuth } from '../../contexts/AuthContext';
|
||||||
|
|
||||||
const API_BASE = import.meta.env.VITE_API_URL || 'http://localhost:8000';
|
const API_BASE = import.meta.env.VITE_API_BASE || import.meta.env.VITE_API_URL || '/api';
|
||||||
|
|
||||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import {
|
|||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
import { useAuth } from '../../contexts/AuthContext';
|
import { useAuth } from '../../contexts/AuthContext';
|
||||||
|
|
||||||
const API_BASE = import.meta.env.VITE_API_URL || 'http://localhost:8000';
|
const API_BASE = import.meta.env.VITE_API_BASE || import.meta.env.VITE_API_URL || '/api';
|
||||||
|
|
||||||
const DAY_TYPE_OPTIONS = ['Academic', 'Holiday', 'Staff', 'OffTimetable'];
|
const DAY_TYPE_OPTIONS = ['Academic', 'Holiday', 'Staff', 'OffTimetable'];
|
||||||
const DAY_TYPE_COLORS: Record<string, 'default' | 'primary' | 'success' | 'warning' | 'error'> = {
|
const DAY_TYPE_COLORS: Record<string, 'default' | 'primary' | 'success' | 'warning' | 'error'> = {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import {
|
|||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
import { useAuth } from '../../contexts/AuthContext';
|
import { useAuth } from '../../contexts/AuthContext';
|
||||||
|
|
||||||
const API_BASE = import.meta.env.VITE_API_URL || 'http://localhost:8000';
|
const API_BASE = import.meta.env.VITE_API_BASE || import.meta.env.VITE_API_URL || '/api';
|
||||||
|
|
||||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import {
|
|||||||
import { ChevronLeft, ChevronRight, Today } from '@mui/icons-material';
|
import { ChevronLeft, ChevronRight, Today } from '@mui/icons-material';
|
||||||
import { useAuth } from '../../contexts/AuthContext';
|
import { useAuth } from '../../contexts/AuthContext';
|
||||||
|
|
||||||
const API_BASE = import.meta.env.VITE_API_URL || 'http://localhost:8000';
|
const API_BASE = import.meta.env.VITE_API_BASE || import.meta.env.VITE_API_URL || '/api';
|
||||||
|
|
||||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
import { useAuth } from '../../contexts/AuthContext';
|
import { useAuth } from '../../contexts/AuthContext';
|
||||||
|
|
||||||
const API_BASE = import.meta.env.VITE_API_URL || 'http://localhost:8000';
|
const API_BASE = import.meta.env.VITE_API_BASE || import.meta.env.VITE_API_URL || '/api';
|
||||||
|
|
||||||
interface Student {
|
interface Student {
|
||||||
profile_id: string;
|
profile_id: string;
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import {
|
|||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
import { useAuth } from '../../contexts/AuthContext';
|
import { useAuth } from '../../contexts/AuthContext';
|
||||||
|
|
||||||
const API_BASE = import.meta.env.VITE_API_URL || 'http://localhost:8000';
|
const API_BASE = import.meta.env.VITE_API_BASE || import.meta.env.VITE_API_URL || '/api';
|
||||||
|
|
||||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
@ -50,8 +50,8 @@ export const CCBundleViewer: React.FC<{
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
const API_BASE = useMemo(() => import.meta.env.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api'), []);
|
const API_BASE = useMemo(() => import.meta.env.VITE_API_BASE || '/api', []);
|
||||||
const API_BASE_FALLBACK = 'http://127.0.0.1:8080';
|
const API_BASE_FALLBACK = '/api';
|
||||||
|
|
||||||
const proxyUrl = useCallback(async (bucket: string, relPath: string) => {
|
const proxyUrl = useCallback(async (bucket: string, relPath: string) => {
|
||||||
const token = accessToken || '';
|
const token = accessToken || '';
|
||||||
|
|||||||
@ -182,7 +182,7 @@ export const CCDoclingViewer: React.FC<{
|
|||||||
setError(null);
|
setError(null);
|
||||||
try {
|
try {
|
||||||
// Try page-images manifest first
|
// Try page-images manifest first
|
||||||
const API_BASE = import.meta.env.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api');
|
const API_BASE = import.meta.env.VITE_API_BASE || '/api';
|
||||||
try {
|
try {
|
||||||
const mRes = await fetch(`${API_BASE}/database/files/${encodeURIComponent(fileId)}/page-images/manifest`, {
|
const mRes = await fetch(`${API_BASE}/database/files/${encodeURIComponent(fileId)}/page-images/manifest`, {
|
||||||
headers: { 'Authorization': `Bearer ${accessToken || ''}` }
|
headers: { 'Authorization': `Bearer ${accessToken || ''}` }
|
||||||
@ -199,7 +199,7 @@ export const CCDoclingViewer: React.FC<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Legacy: Load artefacts for file to find docling JSON artefacts
|
// Legacy: Load artefacts for file to find docling JSON artefacts
|
||||||
const artefactsRes = await fetch(`${import.meta.env.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api')}/database/files/${encodeURIComponent(fileId)}/artefacts`, {
|
const artefactsRes = await fetch(`${import.meta.env.VITE_API_BASE || '/api'}/database/files/${encodeURIComponent(fileId)}/artefacts`, {
|
||||||
headers: { 'Authorization': `Bearer ${accessToken || ''}` }
|
headers: { 'Authorization': `Bearer ${accessToken || ''}` }
|
||||||
});
|
});
|
||||||
if (!artefactsRes.ok) throw new Error(await artefactsRes.text());
|
if (!artefactsRes.ok) throw new Error(await artefactsRes.text());
|
||||||
@ -239,7 +239,7 @@ export const CCDoclingViewer: React.FC<{
|
|||||||
run();
|
run();
|
||||||
}, [fileId]); /* eslint-disable-line react-hooks/exhaustive-deps */
|
}, [fileId]); /* eslint-disable-line react-hooks/exhaustive-deps */
|
||||||
|
|
||||||
const API_BASE = useMemo(() => import.meta.env.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api'), []);
|
const API_BASE = useMemo(() => import.meta.env.VITE_API_BASE || '/api', []);
|
||||||
|
|
||||||
const pageProxyUrl = useMemo(() => {
|
const pageProxyUrl = useMemo(() => {
|
||||||
if (!manifest) return undefined;
|
if (!manifest) return undefined;
|
||||||
|
|||||||
@ -148,7 +148,7 @@ export const CCDocumentIntelligence: React.FC = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadBundles = async () => {
|
const loadBundles = async () => {
|
||||||
if (!validFileId) return;
|
if (!validFileId) return;
|
||||||
const API_BASE = import.meta.env.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api');
|
const API_BASE = import.meta.env.VITE_API_BASE || '/api';
|
||||||
const token = accessToken || '';
|
const token = accessToken || '';
|
||||||
const res = await fetch(`${API_BASE}/database/files/${encodeURIComponent(validFileId)}/artefacts`, { headers: { Authorization: `Bearer ${token}` } });
|
const res = await fetch(`${API_BASE}/database/files/${encodeURIComponent(validFileId)}/artefacts`, { headers: { Authorization: `Bearer ${token}` } });
|
||||||
if (!res.ok) return;
|
if (!res.ok) return;
|
||||||
@ -223,7 +223,7 @@ export const CCDocumentIntelligence: React.FC = () => {
|
|||||||
const run = async () => {
|
const run = async () => {
|
||||||
if (!validFileId) return;
|
if (!validFileId) return;
|
||||||
setOutlineOptions([]);
|
setOutlineOptions([]);
|
||||||
const API_BASE = import.meta.env.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api');
|
const API_BASE = import.meta.env.VITE_API_BASE || '/api';
|
||||||
try {
|
try {
|
||||||
const artsRes = await fetch(`${API_BASE}/database/files/${encodeURIComponent(validFileId)}/artefacts`, {
|
const artsRes = await fetch(`${API_BASE}/database/files/${encodeURIComponent(validFileId)}/artefacts`, {
|
||||||
headers: { 'Authorization': `Bearer ${accessToken || ''}` }
|
headers: { 'Authorization': `Bearer ${accessToken || ''}` }
|
||||||
@ -486,7 +486,7 @@ export const CCDocumentIntelligence: React.FC = () => {
|
|||||||
<Button variant="contained" disabled={busy || !validFileId} onClick={async () => {
|
<Button variant="contained" disabled={busy || !validFileId} onClick={async () => {
|
||||||
try {
|
try {
|
||||||
setBusy(true);
|
setBusy(true);
|
||||||
const API_BASE = import.meta.env.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api');
|
const API_BASE = import.meta.env.VITE_API_BASE || '/api';
|
||||||
const token = accessToken || '';
|
const token = accessToken || '';
|
||||||
const body: CanonicalDoclingRequest = {
|
const body: CanonicalDoclingRequest = {
|
||||||
use_split_map: selectedSectionId === 'full' ? autoSplit : false,
|
use_split_map: selectedSectionId === 'full' ? autoSplit : false,
|
||||||
|
|||||||
@ -84,7 +84,7 @@ export const CCEnhancedFilePanel: React.FC<CCEnhancedFilePanelProps> = ({
|
|||||||
const thumbnailsRef = useRef<HTMLDivElement>(null);
|
const thumbnailsRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const API_BASE = useMemo(() =>
|
const API_BASE = useMemo(() =>
|
||||||
import.meta.env.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api'),
|
import.meta.env.VITE_API_BASE || '/api',
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -65,7 +65,7 @@ export const CCFileDetailPanel: React.FC<{
|
|||||||
const [showAdmin, setShowAdmin] = useState(false);
|
const [showAdmin, setShowAdmin] = useState(false);
|
||||||
const [adminData, setAdminData] = useState<FileTasksResponse | null>(null);
|
const [adminData, setAdminData] = useState<FileTasksResponse | null>(null);
|
||||||
|
|
||||||
const API_BASE = useMemo(() => import.meta.env.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api'), []);
|
const API_BASE = useMemo(() => import.meta.env.VITE_API_BASE || '/api', []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const run = async () => {
|
const run = async () => {
|
||||||
|
|||||||
@ -26,14 +26,13 @@ import { allBindingUtils } from '../../utils/tldraw/bindings';
|
|||||||
import { multiplayerEmbeds } from '../../utils/tldraw/embeds';
|
import { multiplayerEmbeds } from '../../utils/tldraw/embeds';
|
||||||
// Layout
|
// Layout
|
||||||
import { HEADER_HEIGHT } from '../../pages/Layout';
|
import { HEADER_HEIGHT } from '../../pages/Layout';
|
||||||
|
import { TLSYNC_URL } from '../../config/apiConfig';
|
||||||
// Styles
|
// Styles
|
||||||
import '../../utils/tldraw/tldraw.css';
|
import '../../utils/tldraw/tldraw.css';
|
||||||
// App debug
|
// App debug
|
||||||
import { logger } from '../../debugConfig';
|
import { logger } from '../../debugConfig';
|
||||||
|
|
||||||
const SYNC_WORKER_URL = import.meta.env.VITE_FRONTEND_SITE_URL.startsWith('http')
|
const SYNC_WORKER_URL = TLSYNC_URL;
|
||||||
? `${import.meta.env.VITE_FRONTEND_SITE_URL}/tldraw`
|
|
||||||
: `https://${import.meta.env.VITE_FRONTEND_SITE_URL}/tldraw`;
|
|
||||||
|
|
||||||
export default function TldrawMultiUser() {
|
export default function TldrawMultiUser() {
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import {
|
|||||||
} from '../types/timetable.types';
|
} from '../types/timetable.types';
|
||||||
|
|
||||||
// API base URL
|
// API base URL
|
||||||
const API_BASE = import.meta.env.VITE_API_URL || 'http://localhost:8000';
|
const API_BASE = import.meta.env.VITE_API_BASE || import.meta.env.VITE_API_URL || '/api';
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Helper: Get auth headers
|
// Helper: Get auth headers
|
||||||
|
|||||||
@ -577,7 +577,7 @@ export const useTranscriptionStore = create<TranscriptionState>((set, get) => {
|
|||||||
set({ isExporting: true, exportError: null });
|
set({ isExporting: true, exportError: null });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const apiBaseUrl = import.meta.env.VITE_API_BASE || 'https://api.classroomcopilot.ai';
|
const apiBaseUrl = import.meta.env.VITE_API_BASE || '/api';
|
||||||
const response = await fetch(`${apiBaseUrl}/transcribe/sessions/${sessionId}/export`, {
|
const response = await fetch(`${apiBaseUrl}/transcribe/sessions/${sessionId}/export`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
@ -627,7 +627,7 @@ export const useTranscriptionStore = create<TranscriptionState>((set, get) => {
|
|||||||
try {
|
try {
|
||||||
const { _accessToken: token } = get();
|
const { _accessToken: token } = get();
|
||||||
if (!token) return;
|
if (!token) return;
|
||||||
const apiBaseUrl = import.meta.env.VITE_API_BASE || 'https://api.classroomcopilot.ai';
|
const apiBaseUrl = import.meta.env.VITE_API_BASE || '/api';
|
||||||
const response = await fetch(`${apiBaseUrl}/transcribe/keywords`, {
|
const response = await fetch(`${apiBaseUrl}/transcribe/keywords`, {
|
||||||
headers: { 'Authorization': `Bearer ${token}` },
|
headers: { 'Authorization': `Bearer ${token}` },
|
||||||
});
|
});
|
||||||
@ -643,7 +643,7 @@ export const useTranscriptionStore = create<TranscriptionState>((set, get) => {
|
|||||||
try {
|
try {
|
||||||
const { _accessToken: token, _userId: userId } = get();
|
const { _accessToken: token, _userId: userId } = get();
|
||||||
if (!token || !userId) return;
|
if (!token || !userId) return;
|
||||||
const apiBaseUrl = import.meta.env.VITE_API_BASE || 'https://api.classroomcopilot.ai';
|
const apiBaseUrl = import.meta.env.VITE_API_BASE || '/api';
|
||||||
const response = await fetch(`${apiBaseUrl}/transcribe/keywords`, {
|
const response = await fetch(`${apiBaseUrl}/transcribe/keywords`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
@ -669,7 +669,7 @@ export const useTranscriptionStore = create<TranscriptionState>((set, get) => {
|
|||||||
try {
|
try {
|
||||||
const { _accessToken: token } = get();
|
const { _accessToken: token } = get();
|
||||||
if (!token) return;
|
if (!token) return;
|
||||||
const apiBaseUrl = import.meta.env.VITE_API_BASE || 'https://api.classroomcopilot.ai';
|
const apiBaseUrl = import.meta.env.VITE_API_BASE || '/api';
|
||||||
await fetch(`${apiBaseUrl}/transcribe/keywords/${watchId}`, {
|
await fetch(`${apiBaseUrl}/transcribe/keywords/${watchId}`, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: { 'Authorization': `Bearer ${token}` },
|
headers: { 'Authorization': `Bearer ${token}` },
|
||||||
@ -709,7 +709,7 @@ export const useTranscriptionStore = create<TranscriptionState>((set, get) => {
|
|||||||
if (activeSession) {
|
if (activeSession) {
|
||||||
try {
|
try {
|
||||||
const { _accessToken: kwToken } = get();
|
const { _accessToken: kwToken } = get();
|
||||||
const apiBaseUrl = import.meta.env.VITE_API_BASE || 'https://api.classroomcopilot.ai';
|
const apiBaseUrl = import.meta.env.VITE_API_BASE || '/api';
|
||||||
await fetch(`${apiBaseUrl}/transcribe/keywords/events`, {
|
await fetch(`${apiBaseUrl}/transcribe/keywords/events`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@ -26,7 +26,7 @@ export const CCCabinetsPanel: React.FC = () => {
|
|||||||
return createTheme({ palette: { mode, divider: 'var(--color-divider)' } });
|
return createTheme({ palette: { mode, divider: 'var(--color-divider)' } });
|
||||||
}, [tldrawPreferences?.colorScheme, prefersDarkMode]);
|
}, [tldrawPreferences?.colorScheme, prefersDarkMode]);
|
||||||
|
|
||||||
const API_BASE: string = import.meta.env.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api');
|
const API_BASE: string = import.meta.env.VITE_API_BASE || '/api';
|
||||||
|
|
||||||
type RequestInitLite = { method?: string; body?: string | FormData | Blob | null; headers?: Record<string, string> } | undefined;
|
type RequestInitLite = { method?: string; body?: string | FormData | Blob | null; headers?: Record<string, string> } | undefined;
|
||||||
const apiFetch = useCallback(async (url: string, init?: RequestInitLite) => {
|
const apiFetch = useCallback(async (url: string, init?: RequestInitLite) => {
|
||||||
|
|||||||
@ -141,7 +141,7 @@ export const CCFilesPanel: React.FC = () => {
|
|||||||
type RequestInitLike = { method?: string; body?: FormData | string | Blob | null; headers?: Record<string, string> } | undefined;
|
type RequestInitLike = { method?: string; body?: FormData | string | Blob | null; headers?: Record<string, string> } | undefined;
|
||||||
type HeadersInitLike = Record<string, string>;
|
type HeadersInitLike = Record<string, string>;
|
||||||
|
|
||||||
const API_BASE: string = import.meta.env.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api');
|
const API_BASE: string = import.meta.env.VITE_API_BASE || '/api';
|
||||||
|
|
||||||
const apiFetch = useCallback(async (url: string, init?: RequestInitLike) => {
|
const apiFetch = useCallback(async (url: string, init?: RequestInitLike) => {
|
||||||
const headers: HeadersInitLike = {
|
const headers: HeadersInitLike = {
|
||||||
|
|||||||
@ -106,7 +106,7 @@ export const CCFilesPanelEnhanced: React.FC = () => {
|
|||||||
type RequestInitLike = { method?: string; body?: FormData | string | Blob | null; headers?: Record<string, string> } | undefined;
|
type RequestInitLike = { method?: string; body?: FormData | string | Blob | null; headers?: Record<string, string> } | undefined;
|
||||||
type HeadersInitLike = Record<string, string>;
|
type HeadersInitLike = Record<string, string>;
|
||||||
|
|
||||||
const API_BASE: string = (import.meta as unknown as { env?: { VITE_API_BASE?: string } })?.env?.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api');
|
const API_BASE: string = import.meta.env.VITE_API_BASE || '/api';
|
||||||
|
|
||||||
const apiFetch = async (url: string, init?: RequestInitLike) => {
|
const apiFetch = async (url: string, init?: RequestInitLike) => {
|
||||||
const headers: HeadersInitLike = {
|
const headers: HeadersInitLike = {
|
||||||
|
|||||||
@ -119,7 +119,7 @@ export const CCTranscriptionPanel: React.FC = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const detectTimetable = async () => {
|
const detectTimetable = async () => {
|
||||||
try {
|
try {
|
||||||
const apiBase = import.meta.env.VITE_API_URL || 'https://api.classroomcopilot.ai';
|
const apiBase = import.meta.env.VITE_API_BASE || import.meta.env.VITE_API_URL || '/api';
|
||||||
const response = await fetch(`${apiBase}/database/timetables/current-period`);
|
const response = await fetch(`${apiBase}/database/timetables/current-period`);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (data.period_id) {
|
if (data.period_id) {
|
||||||
|
|||||||
27
src/vite-env.d.ts
vendored
27
src/vite-env.d.ts
vendored
@ -41,6 +41,33 @@ interface ImportMetaEnv {
|
|||||||
|
|
||||||
// Search URL
|
// Search URL
|
||||||
readonly VITE_SEARCH_URL: string
|
readonly VITE_SEARCH_URL: string
|
||||||
|
|
||||||
|
// TLSync
|
||||||
|
readonly VITE_TLSYNC_URL: string
|
||||||
|
readonly VITE_TLSYNC_SECRET: string
|
||||||
|
|
||||||
|
// WhisperLive
|
||||||
|
readonly VITE_WHISPERLIVE_URL: string
|
||||||
|
|
||||||
|
// LLM / Ollama
|
||||||
|
readonly VITE_LLM_PROVIDER: string
|
||||||
|
readonly VITE_OLLAMA_API_URL: string
|
||||||
|
readonly VITE_OLLAMA_BASE_URL: string
|
||||||
|
|
||||||
|
// API URL (legacy alias for VITE_API_BASE)
|
||||||
|
readonly VITE_API_URL: string
|
||||||
|
|
||||||
|
// Dev mode flag
|
||||||
|
readonly VITE_DEV: string
|
||||||
|
|
||||||
|
// Ports
|
||||||
|
readonly VITE_PORT_FRONTEND: string
|
||||||
|
readonly VITE_PORT_FRONTEND_HMR: string
|
||||||
|
|
||||||
|
// Neo4j
|
||||||
|
readonly VITE_NEO4J_URL: string
|
||||||
|
readonly VITE_NEO4J_USER: string
|
||||||
|
readonly VITE_NEO4J_PASSWORD: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user