mirror of
https://github.com/siteboon/claudecodeui.git
synced 2025-12-10 05:59:38 +00:00
fix: settings api calls that would fail.
This commit is contained in:
@@ -528,7 +528,8 @@ router.get('/next/:projectName', async (req, res) => {
|
||||
console.warn('Failed to execute task-master CLI:', cliError.message);
|
||||
|
||||
// Fallback to loading tasks and finding next one locally
|
||||
const tasksResponse = await fetch(`${req.protocol}://${req.get('host')}/api/taskmaster/tasks/${encodeURIComponent(projectName)}`, {
|
||||
// Use localhost to bypass proxy for internal server-to-server calls
|
||||
const tasksResponse = await fetch(`http://localhost:${process.env.PORT || 3001}/api/taskmaster/tasks/${encodeURIComponent(projectName)}`, {
|
||||
headers: {
|
||||
'Authorization': req.headers.authorization
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useState, useEffect } from 'react';
|
||||
import { Button } from './ui/button';
|
||||
import { Input } from './ui/input';
|
||||
import { Key, Plus, Trash2, Eye, EyeOff, Copy, Check, Github } from 'lucide-react';
|
||||
import { authenticatedFetch } from '../utils/api';
|
||||
|
||||
function ApiKeysSettings() {
|
||||
const [apiKeys, setApiKeys] = useState([]);
|
||||
@@ -23,19 +24,14 @@ function ApiKeysSettings() {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const token = localStorage.getItem('auth-token');
|
||||
|
||||
// Fetch API keys
|
||||
const apiKeysRes = await fetch('/api/settings/api-keys', {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
const apiKeysRes = await authenticatedFetch('/api/settings/api-keys');
|
||||
const apiKeysData = await apiKeysRes.json();
|
||||
setApiKeys(apiKeysData.apiKeys || []);
|
||||
|
||||
// Fetch GitHub tokens
|
||||
const githubRes = await fetch('/api/settings/credentials?type=github_token', {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
const githubRes = await authenticatedFetch('/api/settings/credentials?type=github_token');
|
||||
const githubData = await githubRes.json();
|
||||
setGithubTokens(githubData.credentials || []);
|
||||
} catch (error) {
|
||||
@@ -49,13 +45,8 @@ function ApiKeysSettings() {
|
||||
if (!newKeyName.trim()) return;
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
const res = await fetch('/api/settings/api-keys', {
|
||||
const res = await authenticatedFetch('/api/settings/api-keys', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ keyName: newKeyName })
|
||||
});
|
||||
|
||||
@@ -75,10 +66,8 @@ function ApiKeysSettings() {
|
||||
if (!confirm('Are you sure you want to delete this API key?')) return;
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
await fetch(`/api/settings/api-keys/${keyId}`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
await authenticatedFetch(`/api/settings/api-keys/${keyId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
fetchData();
|
||||
} catch (error) {
|
||||
@@ -88,13 +77,8 @@ function ApiKeysSettings() {
|
||||
|
||||
const toggleApiKey = async (keyId, isActive) => {
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
await fetch(`/api/settings/api-keys/${keyId}/toggle`, {
|
||||
await authenticatedFetch(`/api/settings/api-keys/${keyId}/toggle`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ isActive: !isActive })
|
||||
});
|
||||
fetchData();
|
||||
@@ -107,13 +91,8 @@ function ApiKeysSettings() {
|
||||
if (!newTokenName.trim() || !newGithubToken.trim()) return;
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
const res = await fetch('/api/settings/credentials', {
|
||||
const res = await authenticatedFetch('/api/settings/credentials', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
credentialName: newTokenName,
|
||||
credentialType: 'github_token',
|
||||
@@ -137,10 +116,8 @@ function ApiKeysSettings() {
|
||||
if (!confirm('Are you sure you want to delete this GitHub token?')) return;
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
await fetch(`/api/settings/credentials/${tokenId}`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
await authenticatedFetch(`/api/settings/credentials/${tokenId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
fetchData();
|
||||
} catch (error) {
|
||||
@@ -150,13 +127,8 @@ function ApiKeysSettings() {
|
||||
|
||||
const toggleGithubToken = async (tokenId, isActive) => {
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
await fetch(`/api/settings/credentials/${tokenId}/toggle`, {
|
||||
await authenticatedFetch(`/api/settings/credentials/${tokenId}/toggle`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ isActive: !isActive })
|
||||
});
|
||||
fetchData();
|
||||
|
||||
@@ -1728,11 +1728,7 @@ function ChatInterface({ selectedProject, selectedSession, ws, sendMessage, mess
|
||||
// Load Cursor default model from config
|
||||
useEffect(() => {
|
||||
if (provider === 'cursor') {
|
||||
fetch('/api/cursor/config', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${localStorage.getItem('auth-token')}`
|
||||
}
|
||||
})
|
||||
authenticatedFetch('/api/cursor/config')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.success && data.config?.model?.modelId) {
|
||||
@@ -3752,15 +3748,9 @@ function ChatInterface({ selectedProject, selectedSession, ws, sendMessage, mess
|
||||
});
|
||||
|
||||
try {
|
||||
const token = safeLocalStorage.getItem('auth-token');
|
||||
const headers = {};
|
||||
if (token) {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
const response = await fetch(`/api/projects/${selectedProject.name}/upload-images`, {
|
||||
const response = await authenticatedFetch(`/api/projects/${selectedProject.name}/upload-images`, {
|
||||
method: 'POST',
|
||||
headers: headers,
|
||||
headers: {}, // Let browser set Content-Type for FormData
|
||||
body: formData
|
||||
});
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Input } from './ui/input';
|
||||
import { Key, Plus, Trash2, Eye, EyeOff, Copy, Check, Github, ExternalLink } from 'lucide-react';
|
||||
import { useVersionCheck } from '../hooks/useVersionCheck';
|
||||
import { version } from '../../package.json';
|
||||
import { authenticatedFetch } from '../utils/api';
|
||||
|
||||
function CredentialsSettings() {
|
||||
const [apiKeys, setApiKeys] = useState([]);
|
||||
@@ -29,19 +30,14 @@ function CredentialsSettings() {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const token = localStorage.getItem('auth-token');
|
||||
|
||||
// Fetch API keys
|
||||
const apiKeysRes = await fetch('/api/settings/api-keys', {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
const apiKeysRes = await authenticatedFetch('/api/settings/api-keys');
|
||||
const apiKeysData = await apiKeysRes.json();
|
||||
setApiKeys(apiKeysData.apiKeys || []);
|
||||
|
||||
// Fetch GitHub credentials only
|
||||
const credentialsRes = await fetch('/api/settings/credentials?type=github_token', {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
const credentialsRes = await authenticatedFetch('/api/settings/credentials?type=github_token');
|
||||
const credentialsData = await credentialsRes.json();
|
||||
setGithubCredentials(credentialsData.credentials || []);
|
||||
} catch (error) {
|
||||
@@ -55,13 +51,8 @@ function CredentialsSettings() {
|
||||
if (!newKeyName.trim()) return;
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
const res = await fetch('/api/settings/api-keys', {
|
||||
const res = await authenticatedFetch('/api/settings/api-keys', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ keyName: newKeyName })
|
||||
});
|
||||
|
||||
@@ -81,10 +72,8 @@ function CredentialsSettings() {
|
||||
if (!confirm('Are you sure you want to delete this API key?')) return;
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
await fetch(`/api/settings/api-keys/${keyId}`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
await authenticatedFetch(`/api/settings/api-keys/${keyId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
fetchData();
|
||||
} catch (error) {
|
||||
@@ -94,13 +83,8 @@ function CredentialsSettings() {
|
||||
|
||||
const toggleApiKey = async (keyId, isActive) => {
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
await fetch(`/api/settings/api-keys/${keyId}/toggle`, {
|
||||
await authenticatedFetch(`/api/settings/api-keys/${keyId}/toggle`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ isActive: !isActive })
|
||||
});
|
||||
fetchData();
|
||||
@@ -113,13 +97,8 @@ function CredentialsSettings() {
|
||||
if (!newGithubName.trim() || !newGithubToken.trim()) return;
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
const res = await fetch('/api/settings/credentials', {
|
||||
const res = await authenticatedFetch('/api/settings/credentials', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
credentialName: newGithubName,
|
||||
credentialType: 'github_token',
|
||||
@@ -145,10 +124,8 @@ function CredentialsSettings() {
|
||||
if (!confirm('Are you sure you want to delete this GitHub token?')) return;
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
await fetch(`/api/settings/credentials/${credentialId}`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
await authenticatedFetch(`/api/settings/credentials/${credentialId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
fetchData();
|
||||
} catch (error) {
|
||||
@@ -158,13 +135,8 @@ function CredentialsSettings() {
|
||||
|
||||
const toggleGithubCredential = async (credentialId, isActive) => {
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
await fetch(`/api/settings/credentials/${credentialId}/toggle`, {
|
||||
await authenticatedFetch(`/api/settings/credentials/${credentialId}/toggle`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ isActive: !isActive })
|
||||
});
|
||||
fetchData();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Button } from './ui/button';
|
||||
import { X } from 'lucide-react';
|
||||
import { authenticatedFetch } from '../utils/api';
|
||||
|
||||
function ImageViewer({ file, onClose }) {
|
||||
const imagePath = `/api/projects/${file.projectName}/files/content?path=${encodeURIComponent(file.path)}`;
|
||||
@@ -18,16 +19,7 @@ function ImageViewer({ file, onClose }) {
|
||||
setError(null);
|
||||
setImageUrl(null);
|
||||
|
||||
const token = localStorage.getItem('auth-token');
|
||||
if (!token) {
|
||||
setError('Missing authentication token');
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await fetch(imagePath, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
const response = await authenticatedFetch(imagePath, {
|
||||
signal: controller.signal
|
||||
});
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import ClaudeLogo from './ClaudeLogo';
|
||||
import CursorLogo from './CursorLogo';
|
||||
import CredentialsSettings from './CredentialsSettings';
|
||||
import LoginModal from './LoginModal';
|
||||
import { authenticatedFetch } from '../utils/api';
|
||||
|
||||
function Settings({ isOpen, onClose, projects = [], initialTab = 'tools' }) {
|
||||
const { isDarkMode, toggleDarkMode } = useTheme();
|
||||
@@ -135,13 +136,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'tools' }) {
|
||||
// Fetch Cursor MCP servers
|
||||
const fetchCursorMcpServers = async () => {
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
const response = await fetch('/api/cursor/mcp', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
const response = await authenticatedFetch('/api/cursor/mcp');
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
@@ -157,15 +152,8 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'tools' }) {
|
||||
// MCP API functions
|
||||
const fetchMcpServers = async () => {
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
|
||||
// Try to read directly from config files for complete details
|
||||
const configResponse = await fetch('/api/mcp/config/read', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
const configResponse = await authenticatedFetch('/api/mcp/config/read');
|
||||
|
||||
if (configResponse.ok) {
|
||||
const configData = await configResponse.json();
|
||||
@@ -176,12 +164,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'tools' }) {
|
||||
}
|
||||
|
||||
// Fallback to Claude CLI
|
||||
const cliResponse = await fetch('/api/mcp/cli/list', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
const cliResponse = await authenticatedFetch('/api/mcp/cli/list');
|
||||
|
||||
if (cliResponse.ok) {
|
||||
const cliData = await cliResponse.json();
|
||||
@@ -209,12 +192,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'tools' }) {
|
||||
}
|
||||
|
||||
// Final fallback to direct config reading
|
||||
const response = await fetch('/api/mcp/servers?scope=user', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
const response = await authenticatedFetch('/api/mcp/servers?scope=user');
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
@@ -229,20 +207,14 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'tools' }) {
|
||||
|
||||
const saveMcpServer = async (serverData) => {
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
|
||||
if (editingMcpServer) {
|
||||
// For editing, remove old server and add new one
|
||||
await deleteMcpServer(editingMcpServer.id, 'user');
|
||||
}
|
||||
|
||||
// Use Claude CLI to add the server
|
||||
const response = await fetch('/api/mcp/cli/add', {
|
||||
const response = await authenticatedFetch('/api/mcp/cli/add', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: serverData.name,
|
||||
type: serverData.type,
|
||||
@@ -276,15 +248,9 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'tools' }) {
|
||||
|
||||
const deleteMcpServer = async (serverId, scope = 'user') => {
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
|
||||
// Use Claude CLI to remove the server with proper scope
|
||||
const response = await fetch(`/api/mcp/cli/remove/${serverId}?scope=${scope}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
const response = await authenticatedFetch(`/api/mcp/cli/remove/${serverId}?scope=${scope}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
@@ -307,13 +273,8 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'tools' }) {
|
||||
|
||||
const testMcpServer = async (serverId, scope = 'user') => {
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
const response = await fetch(`/api/mcp/servers/${serverId}/test?scope=${scope}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
const response = await authenticatedFetch(`/api/mcp/servers/${serverId}/test?scope=${scope}`, {
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
@@ -332,13 +293,8 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'tools' }) {
|
||||
|
||||
const discoverMcpTools = async (serverId, scope = 'user') => {
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
const response = await fetch(`/api/mcp/servers/${serverId}/tools?scope=${scope}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
const response = await authenticatedFetch(`/api/mcp/servers/${serverId}/tools?scope=${scope}`, {
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
@@ -441,13 +397,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'tools' }) {
|
||||
|
||||
const checkClaudeAuthStatus = async () => {
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
const response = await fetch('/api/cli/claude/status', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
const response = await authenticatedFetch('/api/cli/claude/status');
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
@@ -478,13 +428,7 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'tools' }) {
|
||||
|
||||
const checkCursorAuthStatus = async () => {
|
||||
try {
|
||||
const token = localStorage.getItem('auth-token');
|
||||
const response = await fetch('/api/cli/cursor/status', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
const response = await authenticatedFetch('/api/cli/cursor/status');
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
@@ -647,13 +591,8 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'tools' }) {
|
||||
try {
|
||||
if (mcpFormData.importMode === 'json') {
|
||||
// Use JSON import endpoint
|
||||
const token = localStorage.getItem('auth-token');
|
||||
const response = await fetch('/api/mcp/cli/add-json', {
|
||||
const response = await authenticatedFetch('/api/mcp/cli/add-json', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: mcpFormData.name,
|
||||
jsonConfig: mcpFormData.jsonInput,
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
// Utility function for authenticated API calls
|
||||
export const authenticatedFetch = (url, options = {}) => {
|
||||
const isPlatform = import.meta.env.VITE_IS_PLATFORM === 'true';
|
||||
const token = localStorage.getItem('auth-token');
|
||||
|
||||
const defaultHeaders = {
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
if (token) {
|
||||
if (!isPlatform && token) {
|
||||
defaultHeaders['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user