diff --git a/AppImage/components/notification-settings.tsx b/AppImage/components/notification-settings.tsx index eb3c6576..3467f624 100644 --- a/AppImage/components/notification-settings.tsx +++ b/AppImage/components/notification-settings.tsx @@ -9,13 +9,13 @@ import { Label } from "./ui/label" import { Badge } from "./ui/badge" import { Button } from "./ui/button" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select" -import { Dialog, DialogContent, DialogHeader, DialogTitle } from "./ui/dialog" +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "./ui/dialog" import { fetchApi } from "../lib/api-config" import { Bell, BellOff, Send, CheckCircle2, XCircle, Loader2, AlertTriangle, Info, Settings2, Zap, Eye, EyeOff, Trash2, ChevronDown, ChevronUp, ChevronRight, TestTube2, Mail, Webhook, - Copy, Server, Shield, ExternalLink, RefreshCw + Copy, Server, Shield, ExternalLink, RefreshCw, Download, Upload } from "lucide-react" interface ChannelConfig { @@ -63,6 +63,8 @@ interface NotificationConfig { ai_language: string ai_ollama_url: string ai_openai_base_url: string + ai_prompt_mode: string // 'default' or 'custom' + ai_custom_prompt: string // User's custom prompt channel_ai_detail: Record hostname: string webhook_secret: string @@ -180,6 +182,23 @@ const AI_DETAIL_LEVELS = [ { value: "detailed", label: "Detailed", desc: "Complete technical details" }, ] +// Example custom prompt for users to adapt +const EXAMPLE_CUSTOM_PROMPT = `You are a notification formatter for ProxMenux Monitor. + +Your task is to translate and format server notifications. + +RULES: +1. Translate to the user's language +2. Use plain text only (no markdown) +3. Be concise and factual +4. Do not add recommendations + +OUTPUT FORMAT: +[TITLE] +your title here +[BODY] +your message here` + const DEFAULT_CONFIG: NotificationConfig = { enabled: false, channels: { @@ -222,6 +241,8 @@ const DEFAULT_CONFIG: NotificationConfig = { ai_language: "en", ai_ollama_url: "http://localhost:11434", ai_openai_base_url: "", + ai_prompt_mode: "default", + ai_custom_prompt: "", channel_ai_detail: { telegram: "brief", gotify: "brief", @@ -259,6 +280,7 @@ export function NotificationSettings() { const [aiTestResult, setAiTestResult] = useState<{ success: boolean; message: string; model?: string } | null>(null) const [providerModels, setProviderModels] = useState([]) const [loadingProviderModels, setLoadingProviderModels] = useState(false) + const [showCustomPromptInfo, setShowCustomPromptInfo] = useState(false) const [webhookSetup, setWebhookSetup] = useState<{ status: "idle" | "running" | "success" | "failed" fallback_commands: string[] @@ -269,7 +291,7 @@ export function NotificationSettings() { try { const data = await fetchApi<{ success: boolean; config: NotificationConfig }>("/api/notifications/settings") if (data.success && data.config) { - // Ensure ai_api_keys and ai_models objects exist (fallback for older configs) + // Ensure ai_api_keys, ai_models, and prompt settings exist (fallback for older configs) const configWithDefaults = { ...data.config, ai_api_keys: data.config.ai_api_keys || { @@ -287,7 +309,9 @@ export function NotificationSettings() { anthropic: "", openai: "", openrouter: "", - } + }, + ai_prompt_mode: data.config.ai_prompt_mode || "default", + ai_custom_prompt: data.config.ai_custom_prompt || "", } // If ai_model exists but ai_models doesn't have it, save it if (configWithDefaults.ai_model && !configWithDefaults.ai_models[configWithDefaults.ai_provider]) { @@ -1669,80 +1693,173 @@ export function NotificationSettings() { - {/* Test Connection button */} - - - {/* Test result */} - {aiTestResult && ( -
- {aiTestResult.success - ? - : - } -

- {aiTestResult.message} - {aiTestResult.model && ` (${aiTestResult.model})`} -

-
- )} - - {/* Per-channel detail level */} + {/* Prompt Mode section */}
- -
- {CHANNEL_TYPES.map(ch => ( -
- {ch} - -
- ))} +
+ +
+ + {/* Default mode: Detail Level per Channel */} + {(config.ai_prompt_mode || "default") === "default" && ( +
+ +
+ {CHANNEL_TYPES.map(ch => ( +
+ {ch} + +
+ ))} +
+
+ +

+ AI translates and formats notifications to your selected language. Each channel can have different detail levels. +

+
+
+ )} + + {/* Custom mode: Editable prompt textarea */} + {config.ai_prompt_mode === "custom" && ( +
+
+ +