Configure Docker publishing with correct GitHub username

This commit is contained in:
Tomas Dvorak
2026-02-27 17:34:20 +01:00
parent 4c812e376d
commit 0a80ecd9f7
138 changed files with 12130 additions and 7831 deletions
+20
View File
@@ -0,0 +1,20 @@
const DEFAULT_API_ORIGIN = 'http://localhost:8080';
const trimTrailingSlash = (value: string): string => value.replace(/\/+$/, '');
const trimApiSuffix = (value: string): string => value.replace(/\/api\/v1$/, '');
export const getApiOrigin = (): string => {
const raw = (import.meta.env.VITE_API_URL as string | undefined)?.trim();
if (!raw) {
return DEFAULT_API_ORIGIN;
}
const normalized = trimTrailingSlash(raw);
return trimApiSuffix(normalized);
};
export const getApiV1BaseUrl = (): string => {
const origin = getApiOrigin();
return `${origin}/api/v1`;
};
+10 -10
View File
@@ -1,10 +1,11 @@
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:9090/api/v1';
import { isEnvDemoMode } from '@/lib/demo-mode';
import { getApiV1BaseUrl } from '@/lib/api-url';
// Check if we're in demo mode
const API_BASE_URL = getApiV1BaseUrl();
// Demo mode is controlled by environment only.
const isDemoMode = () => {
return localStorage.getItem('demoMode') === 'true' ||
document.title.includes('Demo Mode') ||
window.location.search.includes('demo=true');
return isEnvDemoMode();
};
// Helper function to get auth headers
@@ -47,15 +48,14 @@ class ApiClient {
const response = await fetch(url, config);
if (!response.ok) {
// If backend fails, fall back to demo mode
console.warn(`API endpoint ${endpoint} failed, falling back to demo mode`);
return this.getMockResponse(endpoint, options);
const message = await response.text();
throw new Error(message || `HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.warn(`API request failed for ${endpoint}, falling back to demo mode:`, error);
return this.getMockResponse(endpoint, options);
console.error(`API request failed for ${endpoint}:`, error);
throw error;
}
}
+8 -14
View File
@@ -1,11 +1,11 @@
import { createContext, useContext, type ParentComponent, onMount } from 'solid-js';
import { createStore } from 'solid-js/store';
import { isEnvDemoMode } from '@/lib/demo-mode';
import { getApiV1BaseUrl } from '@/lib/api-url';
// Check if we're in demo mode (same logic as api.ts)
// Demo mode is controlled by environment only.
const isDemoMode = () => {
return localStorage.getItem('demoMode') === 'true' ||
document.title.includes('Demo Mode') ||
window.location.search.includes('demo=true');
return isEnvDemoMode();
};
// Types
@@ -44,7 +44,7 @@ export interface AuthResponse {
}
// API base URL
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:8080/api/v1';
const API_BASE_URL = getApiV1BaseUrl();
// Create auth context
const AuthContext = createContext<AuthContextType>();
@@ -67,7 +67,7 @@ export const AuthProvider: ParentComponent = (props) => {
user: null,
token: null,
isAuthenticated: false,
isLoading: false, // Start with false to avoid loading spinner in ProtectedRoute
isLoading: true,
});
// Initialize auth state from localStorage
@@ -400,18 +400,12 @@ export const useAuth = () => {
// Helper function to get auth headers for API requests
export const getAuthHeaders = () => {
// Check if we're in demo mode first
const isDemo = localStorage.getItem('demoMode') === 'true' ||
document.title.includes('Demo Mode') ||
window.location.search.includes('demo=true');
const isDemo = isDemoMode();
let token = null;
if (isDemo) {
// In demo mode, use a mock token
token = 'demo-token-' + Date.now();
token = localStorage.getItem('token') || localStorage.getItem('trackeep_token') || ('demo-token-' + Date.now());
} else {
// In normal mode, get token from localStorage
token = localStorage.getItem('token') || localStorage.getItem('trackeep_token');
}
+5 -5
View File
@@ -1,5 +1,8 @@
// Brave Search API integration
const BACKEND_API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8080/api/v1';
import { isDemoMode } from '@/lib/demo-mode';
import { getApiV1BaseUrl } from '@/lib/api-url';
const BACKEND_API_URL = getApiV1BaseUrl();
const BRAVE_API_KEY = import.meta.env.VITE_BRAVE_API_KEY || 'BSAw0HNI1v3rKmXlSTr0C_UfZDjw7fT';
// Use the variable to avoid unused warning
@@ -7,10 +10,7 @@ console.log('Brave API key available:', !!BRAVE_API_KEY);
// Helper function to get auth headers
const getAuthHeaders = () => {
// Check if we're in demo mode
const isDemo = import.meta.env.VITE_DEMO_MODE === 'true' ||
document.title.includes('Demo Mode') ||
window.location.search.includes('demo=true');
const isDemo = isDemoMode();
let token = null;
+1 -7
View File
@@ -11,13 +11,7 @@ import {
getMockLearningPaths,
getMockStats
} from './mockData';
// Check if we're in demo mode
const isDemoMode = () => {
return localStorage.getItem('demoMode') === 'true' ||
document.title.includes('Demo Mode') ||
window.location.search.includes('demo=true');
};
import { isDemoMode } from './demo-mode';
// Demo mode API client that falls back to mock data
export class DemoModeApiClient {
+36
View File
@@ -106,6 +106,15 @@ export interface VaultItem {
target_conversation_id?: number | null;
}
export interface UserFile {
id: number;
original_name: string;
mime_type: string;
file_size: number;
created_at: string;
description?: string;
}
export interface WsEvent {
type: string;
conversation_id?: number;
@@ -186,6 +195,11 @@ export const messagesApi = {
method: 'POST',
body: JSON.stringify({}),
}),
revealSensitiveMessage: (messageId: number) =>
apiRequest<{ message_id: number; plaintext: string }>(`/messages/${messageId}/reveal-sensitive`, {
method: 'POST',
body: JSON.stringify({}),
}),
listVaultItems: () => apiRequest<{ items: VaultItem[] }>('/password-vault/items'),
createVaultItem: (payload: any) => apiRequest<any>('/password-vault/items', {
method: 'POST',
@@ -206,6 +220,28 @@ export const messagesApi = {
method: 'POST',
body: JSON.stringify(payload),
}),
listUserFiles: async (query: string = '', limit: number = 20): Promise<UserFile[]> => {
const token = getToken();
const params = new URLSearchParams();
if (query.trim()) {
params.set('q', query.trim());
}
if (Number.isFinite(limit) && limit > 0) {
params.set('limit', String(Math.min(100, Math.floor(limit))));
}
const suffix = params.toString() ? `?${params.toString()}` : '';
const res = await fetch(`${API_BASE_URL}/api/v1/files${suffix}`, {
headers: {
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
});
if (!res.ok) {
const errorData = await res.json().catch(() => ({}));
throw new Error(errorData.error || `Request failed (${res.status})`);
}
return res.json();
},
};
export async function uploadChatFile(file: File): Promise<{ id: number; original_name: string; mime_type: string }> {