Improved UI for clients and ensured function of all current APIs
This commit is contained in:
@@ -113,7 +113,7 @@ const BotsManagement: React.FC<BotsManagementProps> = ({ token }) => {
|
||||
guild_ids: newIdData.guild_ids.split(',').map(id => id.trim()).filter(id => id),
|
||||
};
|
||||
const method = editingId ? 'PUT' : 'POST';
|
||||
const url = editingId ? `${API_BASE_URL}/discord_ids/${editingId._id}` : `${API_BASE_URL}/discord_ids/`;
|
||||
const url = editingId ? `${API_BASE_URL}/bots/token/${editingId._id}` : `${API_BASE_URL}/bots/token`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
@@ -147,7 +147,7 @@ const BotsManagement: React.FC<BotsManagementProps> = ({ token }) => {
|
||||
if (!window.confirm('Are you sure you want to delete this Discord ID?')) return;
|
||||
setError('');
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/discord_ids/${id}`, {
|
||||
const response = await fetch(`${API_BASE_URL}/bots/token/${id}`, {
|
||||
method: 'DELETE',
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
@@ -274,7 +274,7 @@ const BotsManagement: React.FC<BotsManagementProps> = ({ token }) => {
|
||||
<TableCell>{dId.discord_id}</TableCell>
|
||||
<TableCell className="truncate max-w-xs">{dId.token ? dId.token.substring(0, 8) + '...' : 'N/A'}</TableCell>
|
||||
<TableCell>{dId.active ? 'Yes' : 'No'}</TableCell>
|
||||
<TableCell>{dId.guild_ids.join(', ')}</TableCell>
|
||||
<TableCell>{dId.guild_ids?.join(', ')}</TableCell>
|
||||
<TableCell>
|
||||
<Button variant="outline" size="sm" className="mr-2"
|
||||
onClick={() => {
|
||||
@@ -284,7 +284,7 @@ const BotsManagement: React.FC<BotsManagementProps> = ({ token }) => {
|
||||
name: dId.name,
|
||||
token: dId.token,
|
||||
active: dId.active,
|
||||
guild_ids: dId.guild_ids.join(', '),
|
||||
guild_ids: dId.guild_ids?.join(', '),
|
||||
});
|
||||
setIsAddIdDialogOpen(true);
|
||||
}}>
|
||||
|
||||
@@ -8,9 +8,10 @@ import { ErrorResponse, NodeStatusResponse, System } from '@/types';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Input } from '@/components/ui/input';
|
||||
|
||||
interface IndividualClientPageProps {
|
||||
clientId: string; // Now received as a prop
|
||||
clientId: string;
|
||||
token: string;
|
||||
}
|
||||
|
||||
@@ -26,6 +27,16 @@ const IndividualClientPage: React.FC<IndividualClientPageProps> = ({ clientId, t
|
||||
const [isSetConfigDialogOpen, setIsSetConfigDialogOpen] = useState<boolean>(false);
|
||||
const [availableSystems, setAvailableSystems] = useState<System[]>([]);
|
||||
|
||||
// Join Discord Popup States
|
||||
const [isJoinDiscordDialogOpen, setIsJoinDiscordDialogOpen] = useState<boolean>(false);
|
||||
const [discordServerId, setDiscordServerId] = useState<string>('');
|
||||
const [discordChannelId, setDiscordChannelId] = useState<string>('');
|
||||
|
||||
// Leave Discord Popup States
|
||||
const [isLeaveDiscordDialogOpen, setIsLeaveDiscordDialogOpen] = useState<boolean>(false);
|
||||
const [leaveGuildId, setLeaveGuildId] = useState<string>('');
|
||||
|
||||
|
||||
const fetchClientStatus = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
@@ -80,7 +91,11 @@ const IndividualClientPage: React.FC<IndividualClientPageProps> = ({ clientId, t
|
||||
fetchSystems(); // Fetch systems when the component mounts or clientId/token changes
|
||||
}, [clientId, token]);
|
||||
|
||||
const handleAction = async (action: 'join' | 'leave' | 'op25_start' | 'op25_stop' | 'op25_set'): Promise<void> => {
|
||||
const handleAction = async (
|
||||
action: 'join' | 'leave' | 'op25_start' | 'op25_stop' | 'op25_set',
|
||||
// Optional parameters for 'join' and 'leave' actions
|
||||
payloadData?: { server_id?: string; channel_id?: string; guild_id?: string }
|
||||
): Promise<void> => {
|
||||
setMessage('');
|
||||
setError('');
|
||||
setLoading(true);
|
||||
@@ -103,6 +118,25 @@ const IndividualClientPage: React.FC<IndividualClientPageProps> = ({ clientId, t
|
||||
httpOptions.body = JSON.stringify({
|
||||
"system_id": selectedSystem
|
||||
});
|
||||
} else if (action === "join") {
|
||||
if (!payloadData?.server_id || !payloadData?.channel_id) {
|
||||
setError("Please provide both Discord Server ID and Channel ID.");
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
httpOptions.body = JSON.stringify({
|
||||
"guild_id": payloadData.server_id,
|
||||
"channel_id": payloadData.channel_id
|
||||
});
|
||||
} else if (action === "leave") {
|
||||
if (!payloadData?.guild_id) {
|
||||
setError("Please provide the Guild ID to leave.");
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
httpOptions.body = JSON.stringify({
|
||||
"guild_id": payloadData.guild_id
|
||||
});
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/nodes/${clientId}/${action}`, httpOptions);
|
||||
@@ -112,7 +146,9 @@ const IndividualClientPage: React.FC<IndividualClientPageProps> = ({ clientId, t
|
||||
if (response.ok) {
|
||||
setMessage(`Client "${clientId}" successfully ${action === 'op25_set' ? 'set config for system ' + selectedSystem : action + 'ed'}.`);
|
||||
fetchClientStatus();
|
||||
setIsSetConfigDialogOpen(false); // Close dialog on success
|
||||
setIsSetConfigDialogOpen(false); // Close set config dialog on success
|
||||
setIsJoinDiscordDialogOpen(false); // Close join discord dialog on success
|
||||
setIsLeaveDiscordDialogOpen(false); // Close leave discord dialog on success
|
||||
} else {
|
||||
const errorData = data as ErrorResponse;
|
||||
setError(`Failed to ${action} client "${clientId}": ${errorData.message || (typeof errorData.detail === 'string' ? errorData.detail : JSON.stringify(errorData.detail)) || response.statusText}`);
|
||||
@@ -125,6 +161,26 @@ const IndividualClientPage: React.FC<IndividualClientPageProps> = ({ clientId, t
|
||||
}
|
||||
};
|
||||
|
||||
const handleJoinClick = () => {
|
||||
setDiscordServerId(''); // Clear previous values
|
||||
setDiscordChannelId(''); // Clear previous values
|
||||
setIsJoinDiscordDialogOpen(true);
|
||||
};
|
||||
|
||||
const handleConfirmJoin = () => {
|
||||
handleAction('join', { server_id: discordServerId, channel_id: discordChannelId });
|
||||
};
|
||||
|
||||
const handleLeaveClick = () => {
|
||||
setLeaveGuildId(''); // Clear previous value
|
||||
setIsLeaveDiscordDialogOpen(true);
|
||||
};
|
||||
|
||||
const handleConfirmLeave = () => {
|
||||
handleAction('leave', { guild_id: leaveGuildId });
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<Card className="w-full max-w-md mx-auto mt-8">
|
||||
<CardHeader>
|
||||
@@ -134,19 +190,19 @@ const IndividualClientPage: React.FC<IndividualClientPageProps> = ({ clientId, t
|
||||
<p>Current Discord Status: {currentClientDiscordStatus}</p>
|
||||
<div className="flex space-x-2">
|
||||
<Button
|
||||
onClick={() => handleAction('join')}
|
||||
onClick={handleJoinClick} // Open dialog for join
|
||||
disabled={loading}
|
||||
className="flex-1"
|
||||
>
|
||||
{loading && message.includes('join') ? 'Joining...' : 'Join Client'}
|
||||
Join Client
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => handleAction('leave')}
|
||||
onClick={handleLeaveClick} // Open dialog for leave
|
||||
disabled={loading}
|
||||
variant="outline"
|
||||
className="flex-1"
|
||||
>
|
||||
{loading && message.includes('leave') ? 'Leaving...' : 'Leave Client'}
|
||||
Leave Client
|
||||
</Button>
|
||||
</div>
|
||||
<p>Current OP25 Status: {currentClientOp25Status}</p>
|
||||
@@ -214,6 +270,74 @@ const IndividualClientPage: React.FC<IndividualClientPageProps> = ({ clientId, t
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Join Discord Dialog */}
|
||||
<Dialog open={isJoinDiscordDialogOpen} onOpenChange={setIsJoinDiscordDialogOpen}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Join Discord Server</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="grid gap-4 py-4">
|
||||
<div className="grid grid-cols-4 items-center gap-4">
|
||||
<Label htmlFor="discord-server-id" className="text-right">Server ID</Label>
|
||||
<Input
|
||||
id="discord-server-id"
|
||||
value={discordServerId}
|
||||
onChange={(e) => setDiscordServerId(e.target.value)}
|
||||
className="col-span-3"
|
||||
placeholder="Enter Discord Server ID"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-4 items-center gap-4">
|
||||
<Label htmlFor="discord-channel-id" className="text-right">Channel ID</Label>
|
||||
<Input
|
||||
id="discord-channel-id"
|
||||
value={discordChannelId}
|
||||
onChange={(e) => setDiscordChannelId(e.target.value)}
|
||||
className="col-span-3"
|
||||
placeholder="Enter Discord Channel ID"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button onClick={handleConfirmJoin} disabled={!discordServerId || !discordChannelId || loading}>
|
||||
{loading ? 'Joining...' : 'Confirm Join'}
|
||||
</Button>
|
||||
<Button variant="outline" onClick={() => setIsJoinDiscordDialogOpen(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Leave Discord Dialog */}
|
||||
<Dialog open={isLeaveDiscordDialogOpen} onOpenChange={setIsLeaveDiscordDialogOpen}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Leave Discord Server</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="grid gap-4 py-4">
|
||||
<div className="grid grid-cols-4 items-center gap-4">
|
||||
<Label htmlFor="leave-guild-id" className="text-right">Guild ID</Label>
|
||||
<Input
|
||||
id="leave-guild-id"
|
||||
value={leaveGuildId}
|
||||
onChange={(e) => setLeaveGuildId(e.target.value)}
|
||||
className="col-span-3"
|
||||
placeholder="Enter Discord Guild ID to Leave"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button onClick={handleConfirmLeave} disabled={!leaveGuildId || loading}>
|
||||
{loading ? 'Leaving...' : 'Confirm Leave'}
|
||||
</Button>
|
||||
<Button variant="outline" onClick={() => setIsLeaveDiscordDialogOpen(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user