diff --git a/client/src/App.tsx b/client/src/App.tsx index cdf2488..0223eec 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -263,7 +263,9 @@ const LobbyView: React.FC = (props: LobbyProps) => { ))} */} - {session && socketUrl && } + {session && socketUrl && lobby && ( + + )} {session && socketUrl && lobby && ( )} diff --git a/client/src/BotConfig.css b/client/src/BotConfig.css index 3c2e93e..7a7666e 100644 --- a/client/src/BotConfig.css +++ b/client/src/BotConfig.css @@ -15,8 +15,15 @@ border-bottom: 1px solid #dee2e6; } +.bot-config-title { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 8px; +} + .bot-config-header h3 { - margin: 0 0 8px 0; + margin: 0; color: #212529; font-size: 1.5rem; } @@ -172,6 +179,30 @@ cursor: not-allowed; } +.config-refresh-button { + padding: 6px 12px; + background: #28a745; + color: white; + border: none; + border-radius: 4px; + font-size: 0.875rem; + font-weight: 500; + cursor: pointer; + transition: background-color 0.15s ease-in-out; + display: flex; + align-items: center; + gap: 4px; +} + +.config-refresh-button:hover:not(:disabled) { + background: #1e7e34; +} + +.config-refresh-button:disabled { + background: #6c757d; + cursor: not-allowed; +} + .bot-config-loading, .bot-config-error, .bot-config-unavailable { diff --git a/client/src/BotConfig.tsx b/client/src/BotConfig.tsx index 18a85cb..2da41ea 100644 --- a/client/src/BotConfig.tsx +++ b/client/src/BotConfig.tsx @@ -7,11 +7,12 @@ */ import React, { useState, useEffect } from 'react'; -import './BotConfig.css'; +import { base } from "./Common"; +import "./BotConfig.css"; interface ConfigParameter { name: string; - type: 'string' | 'number' | 'boolean' | 'select' | 'range'; + type: "string" | "number" | "boolean" | "select" | "range"; label: string; description: string; default_value?: any; @@ -47,58 +48,74 @@ interface BotConfigProps { onConfigUpdate?: (config: BotConfig) => void; } -const BotConfigComponent: React.FC = ({ - botName, - lobbyId, - onConfigUpdate -}) => { +const BotConfigComponent: React.FC = ({ botName, lobbyId, onConfigUpdate }) => { const [schema, setSchema] = useState(null); const [currentConfig, setCurrentConfig] = useState(null); const [configValues, setConfigValues] = useState<{ [key: string]: any }>({}); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [saving, setSaving] = useState(false); + const [refreshing, setRefreshing] = useState(false); // Fetch configuration schema - useEffect(() => { - const fetchSchema = async () => { - try { - setLoading(true); - const response = await fetch(`/api/bots/config/schema/${botName}`); - - if (response.ok) { - const schemaData = await response.json(); - setSchema(schemaData); - - // Initialize config values with defaults - const defaultValues: { [key: string]: any } = {}; - schemaData.parameters.forEach((param: ConfigParameter) => { - if (param.default_value !== undefined) { - defaultValues[param.name] = param.default_value; - } - }); - setConfigValues(defaultValues); - } else if (response.status === 404) { - setError(`Bot "${botName}" does not support configuration`); - } else { - setError('Failed to fetch configuration schema'); - } - } catch (err) { - setError('Network error while fetching configuration schema'); - } finally { - setLoading(false); - } - }; + const fetchSchema = async (forceRefresh = false) => { + try { + setLoading(true); + setError(null); + // Use refresh endpoint if force refresh is requested + const url = forceRefresh + ? `${base}/api/bots/config/schema/${botName}/refresh` + : `${base}/api/bots/config/schema/${botName}`; + + const method = forceRefresh ? "POST" : "GET"; + + const response = await fetch(url, { method }); + + if (response.ok) { + const responseData = await response.json(); + // For refresh endpoint, the schema is in the 'schema' field + const schemaData = forceRefresh ? responseData.schema : responseData; + + setSchema(schemaData); + + // Initialize config values with defaults + const defaultValues: { [key: string]: any } = {}; + schemaData.parameters.forEach((param: ConfigParameter) => { + if (param.default_value !== undefined) { + defaultValues[param.name] = param.default_value; + } + }); + setConfigValues(defaultValues); + } else if (response.status === 404) { + setError(`Bot "${botName}" does not support configuration`); + } else { + setError("Failed to fetch configuration schema"); + } + } catch (err) { + setError("Network error while fetching configuration schema"); + } finally { + setLoading(false); + } + }; + + useEffect(() => { fetchSchema(); }, [botName]); + // Handle schema refresh + const handleRefreshSchema = async () => { + setRefreshing(true); + await fetchSchema(true); + setRefreshing(false); + }; + // Fetch current configuration useEffect(() => { const fetchCurrentConfig = async () => { try { - const response = await fetch(`/api/bots/config/lobby/${lobbyId}/bot/${botName}`); - + const response = await fetch(`${base}/api/bots/config/lobby/${lobbyId}/bot/${botName}`); + if (response.ok) { const config = await response.json(); setCurrentConfig(config); @@ -106,7 +123,7 @@ const BotConfigComponent: React.FC = ({ } // If 404, no existing config - that's fine } catch (err) { - console.warn('Failed to fetch current config:', err); + console.warn("Failed to fetch current config:", err); } }; @@ -116,9 +133,9 @@ const BotConfigComponent: React.FC = ({ }, [botName, lobbyId, schema]); const handleValueChange = (paramName: string, value: any) => { - setConfigValues(prev => ({ + setConfigValues((prev) => ({ ...prev, - [paramName]: value + [paramName]: value, })); }; @@ -127,15 +144,15 @@ const BotConfigComponent: React.FC = ({ setSaving(true); setError(null); - const response = await fetch('/api/bots/config/update', { - method: 'POST', + const response = await fetch(`${base}/api/bots/config/update`, { + method: "POST", headers: { - 'Content-Type': 'application/json', + "Content-Type": "application/json", }, body: JSON.stringify({ bot_name: botName, lobby_id: lobbyId, - config_values: configValues + config_values: configValues, }), }); @@ -147,10 +164,10 @@ const BotConfigComponent: React.FC = ({ onConfigUpdate(result.updated_config); } } else { - setError(result.message || 'Failed to save configuration'); + setError(result.message || "Failed to save configuration"); } } catch (err) { - setError('Network error while saving configuration'); + setError("Network error while saving configuration"); } finally { setSaving(false); } @@ -160,7 +177,7 @@ const BotConfigComponent: React.FC = ({ const value = configValues[param.name]; switch (param.type) { - case 'boolean': + case "boolean": return (
); - case 'select': + case "select": return (