- McpEnvVar: infisical_value → coolify_value + has_duplicates - McpEnvResponse: drop Infisical metadata fields - EnvVarRow: 'Coolify:' label, 'ערוך ב-Coolify' external link - DriftBadge: infisicalAvailable → coolifyAvailable - EnvironmentTab: Coolify app badge, duplicates count
124 lines
4.1 KiB
TypeScript
124 lines
4.1 KiB
TypeScript
"use client";
|
||
|
||
import { useState } from "react";
|
||
import { ExternalLink, Save, Lock } from "lucide-react";
|
||
import { Button } from "@/components/ui/button";
|
||
import { Badge } from "@/components/ui/badge";
|
||
import type { McpEnvVar } from "@/lib/api/settings";
|
||
import { useUpdateMcpEnv } from "@/lib/api/settings";
|
||
import { toast } from "sonner";
|
||
import { DriftBadge } from "./drift-badge";
|
||
import { EnvVarEditor } from "./env-var-editor";
|
||
|
||
type Props = {
|
||
spec: McpEnvVar;
|
||
coolifyAppUuid: string;
|
||
coolifyAvailable: boolean;
|
||
onPendingRedeploy: () => void;
|
||
};
|
||
|
||
export function EnvVarRow({
|
||
spec,
|
||
coolifyAppUuid,
|
||
coolifyAvailable,
|
||
onPendingRedeploy,
|
||
}: Props) {
|
||
const [draft, setDraft] = useState<string>(spec.coolify_value ?? "");
|
||
const update = useUpdateMcpEnv();
|
||
const dirty = draft !== (spec.coolify_value ?? "");
|
||
|
||
function handleSave() {
|
||
update.mutate(
|
||
{ key: spec.key, value: draft },
|
||
{
|
||
onSuccess: (res) => {
|
||
toast.success(res.message);
|
||
onPendingRedeploy();
|
||
},
|
||
onError: (err) => toast.error(`שגיאה: ${err.message}`),
|
||
},
|
||
);
|
||
}
|
||
|
||
const coolifyEnvUrl =
|
||
`https://coolify.nautilus.marcusgroup.org/project/applications/${coolifyAppUuid}/environment-variables`;
|
||
|
||
return (
|
||
<div className="rounded-md border border-rule p-4 bg-rule-soft/20 hover:bg-rule-soft/40 transition-colors">
|
||
<div className="flex items-start justify-between gap-3 mb-3">
|
||
<div className="flex-1 min-w-0">
|
||
<div className="flex items-center gap-2 flex-wrap">
|
||
<code className="font-mono text-sm font-medium text-navy" dir="ltr">
|
||
{spec.key}
|
||
</code>
|
||
<Badge variant="outline" className="text-[0.7rem]">
|
||
{spec.type}
|
||
</Badge>
|
||
{spec.is_secret && (
|
||
<Badge variant="outline" className="text-[0.7rem] text-warn border-warn/40 gap-1">
|
||
<Lock className="w-3 h-3" />
|
||
secret
|
||
</Badge>
|
||
)}
|
||
<DriftBadge drift={spec.drift} coolifyAvailable={coolifyAvailable} />
|
||
{spec.has_duplicates && (
|
||
<Badge variant="outline" className="text-[0.7rem] text-warn border-warn/40">
|
||
duplicates
|
||
</Badge>
|
||
)}
|
||
</div>
|
||
<p className="text-sm text-ink-muted mt-1">{spec.description}</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 text-sm">
|
||
<div className="flex items-center gap-2">
|
||
<span className="text-[0.72rem] text-ink-muted w-20">Coolify:</span>
|
||
{spec.is_editable ? (
|
||
<EnvVarEditor
|
||
spec={spec}
|
||
value={draft}
|
||
onChange={setDraft}
|
||
disabled={update.isPending}
|
||
/>
|
||
) : (
|
||
<span className="font-mono text-ink" dir="ltr">
|
||
{spec.coolify_value ?? <em className="text-ink-muted">— לא מוגדר —</em>}
|
||
</span>
|
||
)}
|
||
</div>
|
||
<div className="flex items-center gap-2">
|
||
<span className="text-[0.72rem] text-ink-muted w-20">Container:</span>
|
||
<span className="font-mono text-ink" dir="ltr">
|
||
{spec.container_value ?? <em className="text-ink-muted">— לא מוגדר —</em>}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="flex items-center justify-end gap-2 mt-3">
|
||
{!spec.is_editable && (
|
||
<a
|
||
href={coolifyEnvUrl}
|
||
target="_blank"
|
||
rel="noopener noreferrer"
|
||
className="text-[0.78rem] text-gold-deep hover:underline flex items-center gap-1"
|
||
>
|
||
ערוך ב-Coolify
|
||
<ExternalLink className="w-3 h-3" />
|
||
</a>
|
||
)}
|
||
{spec.is_editable && (
|
||
<Button
|
||
size="sm"
|
||
onClick={handleSave}
|
||
disabled={!dirty || update.isPending}
|
||
>
|
||
<Save className="w-3.5 h-3.5" data-icon="inline-start" />
|
||
{update.isPending ? "שומר..." : "שמור"}
|
||
</Button>
|
||
)}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|