refactor(ui): move MCP settings to dedicated admin tab and increase prod db timeout
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -6,8 +6,9 @@ import { Button } from "@/components/ui/button";
|
|||||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { Loader2, Server, Save } from "lucide-react";
|
import { Loader2, Server, Save, Copy } from "lucide-react";
|
||||||
import { useToast } from "@/hooks/use-toast";
|
import { useToast } from "@/hooks/use-toast";
|
||||||
|
import { apiRequest } from "@/lib/queryClient";
|
||||||
|
|
||||||
export function McpSettingsCard() {
|
export function McpSettingsCard() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -18,6 +19,38 @@ export function McpSettingsCard() {
|
|||||||
mcp_port: "5001" // Default to main app port unless specific override logic is added
|
mcp_port: "5001" // Default to main app port unless specific override logic is added
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Feature 1: Get User for API Key
|
||||||
|
const { data: user } = useQuery<any>({
|
||||||
|
queryKey: ['/api/user']
|
||||||
|
});
|
||||||
|
|
||||||
|
// Feature 2: API Key Mutations
|
||||||
|
const generateApiKeyMutation = useMutation({
|
||||||
|
mutationFn: async () => {
|
||||||
|
const res = await apiRequest("POST", "/api/user/apikey", {});
|
||||||
|
return res.json();
|
||||||
|
},
|
||||||
|
onSuccess: (data) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["/api/user"] });
|
||||||
|
toast({ title: t('settings.mcp.generated') });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const revokeApiKeyMutation = useMutation({
|
||||||
|
mutationFn: async () => {
|
||||||
|
await apiRequest("DELETE", "/api/user/apikey");
|
||||||
|
},
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["/api/user"] });
|
||||||
|
toast({ title: t('settings.mcp.revoked') });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const copyToClipboard = (text: string) => {
|
||||||
|
navigator.clipboard.writeText(text);
|
||||||
|
toast({ title: "Copied!" });
|
||||||
|
}
|
||||||
|
|
||||||
const { data: settings, isLoading } = useQuery<any>({
|
const { data: settings, isLoading } = useQuery<any>({
|
||||||
queryKey: ['/api/admin/settings'],
|
queryKey: ['/api/admin/settings'],
|
||||||
});
|
});
|
||||||
@@ -86,6 +119,55 @@ export function McpSettingsCard() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Status Indicator */}
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="space-y-0.5">
|
||||||
|
<p className="font-medium">{t('settings.mcp.status')}</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2 text-green-500">
|
||||||
|
<div className="w-2 h-2 rounded-full bg-green-500 animate-pulse" />
|
||||||
|
<span className="font-medium">{t('settings.mcp.running')}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Endpoint URL */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
<p className="text-sm font-medium">{t('settings.mcp.url')}</p>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Input readOnly value={`${window.location.protocol}//${window.location.host}/api/mcp/sse`} />
|
||||||
|
<Button variant="outline" size="icon" onClick={() => copyToClipboard(`${window.location.protocol}//${window.location.host}/api/mcp/sse`)}>
|
||||||
|
<Copy className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* API Key Management */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
<p className="text-sm font-medium">{t('settings.mcp.apiKey')}</p>
|
||||||
|
{user?.apiKey ? (
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Input type="password" readOnly value={user.apiKey} />
|
||||||
|
<Button variant="outline" size="icon" onClick={() => copyToClipboard(user.apiKey!)}>
|
||||||
|
<Copy className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
<Button variant="destructive" onClick={() => revokeApiKeyMutation.mutate()} disabled={revokeApiKeyMutation.isPending}>
|
||||||
|
{t('settings.mcp.revoke')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<p className="text-sm text-muted-foreground">{t('settings.mcp.noKey')}</p>
|
||||||
|
<Button onClick={() => generateApiKeyMutation.mutate()} disabled={generateApiKeyMutation.isPending}>
|
||||||
|
{t('settings.mcp.generate')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-muted/50 p-3 rounded-lg text-sm text-muted-foreground">
|
||||||
|
{t('settings.mcp.instructions')}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="grid gap-2">
|
<div className="grid gap-2">
|
||||||
<Label htmlFor="mcp_port">Port (Informational)</Label>
|
<Label htmlFor="mcp_port">Port (Informational)</Label>
|
||||||
<Input
|
<Input
|
||||||
|
|||||||
@@ -15,9 +15,10 @@ services:
|
|||||||
- "${POSTGRES_PORT:-5432}:5432"
|
- "${POSTGRES_PORT:-5432}:5432"
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER}" ]
|
test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER}" ]
|
||||||
interval: 60s
|
interval: 10s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 10
|
retries: 60
|
||||||
|
start_period: 60s
|
||||||
networks:
|
networks:
|
||||||
- taskflow-network
|
- taskflow-network
|
||||||
|
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "rest-express",
|
"name": "rest-express",
|
||||||
"version": "1.0.4",
|
"version": "1.0.5",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "rest-express",
|
"name": "rest-express",
|
||||||
"version": "1.0.4",
|
"version": "1.0.5",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dnd-kit/core": "^6.3.1",
|
"@dnd-kit/core": "^6.3.1",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "rest-express",
|
"name": "rest-express",
|
||||||
"version": "1.0.4",
|
"version": "1.0.5",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
Reference in New Issue
Block a user