fix(bots): channel picker dropdown instead of ID text input

Server selector + channel dropdown for built-in bot config.
No more asking users to paste UUIDs.
This commit is contained in:
2026-07-15 15:02:39 -04:00
parent 97c5d81d70
commit 3fd0b0e9e2
+35 -8
View File
@@ -2,6 +2,7 @@ import { useEffect, useState } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { useBotStore, type Bot } from '../stores/bot.ts'; import { useBotStore, type Bot } from '../stores/bot.ts';
import { useServerStore } from '../stores/server.ts'; import { useServerStore } from '../stores/server.ts';
import { useChannelStore } from '../stores/channel.ts';
// ponytail: config fields per bot type, add new types here // ponytail: config fields per bot type, add new types here
const BOT_TYPE_CONFIGS: Record<string, { label: string; fields: { key: string; label: string; type: 'text' | 'number' | 'channel'; placeholder: string }[] }> = { const BOT_TYPE_CONFIGS: Record<string, { label: string; fields: { key: string; label: string; type: 'text' | 'number' | 'channel'; placeholder: string }[] }> = {
@@ -27,12 +28,15 @@ export function BotManager() {
const servers = useServerStore((s) => s.servers); const servers = useServerStore((s) => s.servers);
const fetchServers = useServerStore((s) => s.fetchServers); const fetchServers = useServerStore((s) => s.fetchServers);
const channelsByServer = useChannelStore((s) => s.channelsByServer);
const fetchChannels = useChannelStore((s) => s.fetchChannels);
const [showCreate, setShowCreate] = useState(false); const [showCreate, setShowCreate] = useState(false);
const [createName, setCreateName] = useState(''); const [createName, setCreateName] = useState('');
const [createDesc, setCreateDesc] = useState(''); const [createDesc, setCreateDesc] = useState('');
const [createType, setCreateType] = useState(''); const [createType, setCreateType] = useState('');
const [createConfig, setCreateConfig] = useState<Record<string, string>>({}); const [createConfig, setCreateConfig] = useState<Record<string, string>>({});
const [channelServerId, setChannelServerId] = useState('');
const [editingId, setEditingId] = useState<string | null>(null); const [editingId, setEditingId] = useState<string | null>(null);
const [editName, setEditName] = useState(''); const [editName, setEditName] = useState('');
const [editDesc, setEditDesc] = useState(''); const [editDesc, setEditDesc] = useState('');
@@ -63,6 +67,7 @@ export function BotManager() {
setCreateDesc(''); setCreateDesc('');
setCreateType(''); setCreateType('');
setCreateConfig({}); setCreateConfig({});
setChannelServerId('');
setShowCreate(false); setShowCreate(false);
} catch { } catch {
// error handled in store // error handled in store
@@ -221,13 +226,35 @@ export function BotManager() {
<div key={field.key}> <div key={field.key}>
<label className="block text-gb-fg-f mb-1 font-mono text-xs">{field.label}:</label> <label className="block text-gb-fg-f mb-1 font-mono text-xs">{field.label}:</label>
{field.type === 'channel' ? ( {field.type === 'channel' ? (
<input <div className="space-y-1">
type="text" <select
value={createConfig[field.key] || ''} value={channelServerId}
onChange={(e) => setCreateConfig((prev) => ({ ...prev, [field.key]: e.target.value }))} onChange={(e) => {
placeholder="channel ID (from URL)" setChannelServerId(e.target.value);
className="terminal-input w-full" setCreateConfig((prev) => ({ ...prev, [field.key]: '' }));
/> if (e.target.value) fetchChannels(e.target.value);
}}
className="terminal-input w-full"
>
<option value="">-- select server first --</option>
{servers.map((s) => (
<option key={s.id} value={s.id}>{s.name}</option>
))}
</select>
<select
value={createConfig[field.key] || ''}
onChange={(e) => setCreateConfig((prev) => ({ ...prev, [field.key]: e.target.value }))}
className="terminal-input w-full"
disabled={!channelServerId}
>
<option value="">-- select channel --</option>
{(channelsByServer[channelServerId] || [])
.filter((c) => c.type === 'text')
.map((c) => (
<option key={c.id} value={c.id}>#{c.name}</option>
))}
</select>
</div>
) : ( ) : (
<input <input
type={field.type} type={field.type}
@@ -245,7 +272,7 @@ export function BotManager() {
</button> </button>
<button <button
type="button" type="button"
onClick={() => { setShowCreate(false); setCreateName(''); setCreateDesc(''); setCreateType(''); setCreateConfig({}); }} onClick={() => { setShowCreate(false); setCreateName(''); setCreateDesc(''); setCreateType(''); setCreateConfig({}); setChannelServerId(''); }}
className="text-gb-fg-f hover:text-gb-aqua font-mono text-sm" className="text-gb-fg-f hover:text-gb-aqua font-mono text-sm"
> >
[CANCEL] [CANCEL]