Applicatin & Server Settings

This commit is contained in:
headlesdev 2025-05-26 12:26:39 +02:00
parent 338c1922d0
commit 61a9442443
3 changed files with 465 additions and 19 deletions

View File

@ -5,7 +5,7 @@ import { z } from "zod/v4"
const schema = z.object({
enabled: z.boolean(),
statusChange: z.boolean(),
latencyLimit: z.number().min(0).max(100),
latencyLimit: z.number().min(0).max(10000),
notificationTextStatus: z.string(),
notificationTextLatency: z.string(),
notificationLatency: z.boolean(),

View File

@ -1,25 +1,427 @@
"use client";
"use client"
import { useState } from "react";
import { useEffect, useState } from "react"
import useNotifications from "@/hooks/useNotifications"
import { CircleHelp, Server, Smartphone } from "lucide-react"
interface NotificationSettingsProps {
onError: (message: string) => void;
onSuccess: (message: string) => void;
onError: (message: string) => void
onSuccess: (message: string) => void
}
export const NotificationSettings = ({ onError, onSuccess }: NotificationSettingsProps) => {
const [enabled, setEnabled] = useState(false);
const {
getNotificationApplicationsSettings,
getNotificationServerSettings,
editNotificationApplicationsSettings,
editNotificationServerSettings,
} = useNotifications()
const [applicationsSettings, setApplicationsSettings] = useState<any>(null)
const [serverSettings, setServerSettings] = useState<any>(null)
return (
<div>
<div className="w-full bg-base-200 p-4 rounded-2xl border border-stone-800">
<div className="flex items-center justify-between">
<div>
<h2 className="text-lg font-bold">Notification Settings</h2>
<p className="text-sm opacity-70">Manage your notification settings</p>
</div>
</div>
</div>
</div>
const fetchNotificationSettings = async () => {
const applicationsSettings = await getNotificationApplicationsSettings()
const serverSettings = await getNotificationServerSettings()
setServerSettings(
serverSettings || {
enabled: false,
statusChange: false,
cpuLimit: 0,
gpuLimit: 0,
memoryLimit: 0,
diskLimit: 0,
temperatureLimit: 0,
notificationTextStatus: "",
notificationTextCpu: "",
notificationTextGpu: "",
notificationTextMemory: "",
notificationTextDisk: "",
notificationTextTemperature: "",
notificationCpu: false,
notificationGpu: false,
notificationMemory: false,
notificationDisk: false,
notificationTemperature: false,
},
)
}
setApplicationsSettings(
applicationsSettings || {
enabled: false,
statusChange: false,
latencyLimit: 0,
notificationTextStatus: "",
notificationTextLatency: "",
notificationLatency: false,
},
)
}
useEffect(() => {
fetchNotificationSettings()
}, [])
const saveNotificationSettings = async () => {
await editNotificationServerSettings(serverSettings)
await editNotificationApplicationsSettings(applicationsSettings)
}
const ResourceThresholdRow = ({
label,
checked,
onCheckedChange,
value,
onValueChange,
unit,
message,
onMessageChange,
disabled,
}: {
label: string
checked: boolean
onCheckedChange: () => void
value: number
onValueChange: (value: string) => void
unit: string
message: string
onMessageChange: (value: string) => void
disabled: boolean
}) => (
<div className="card bg-base-100 shadow-sm border border-base-300">
<div className="card-body p-4">
<div className="flex flex-col lg:flex-row lg:items-center gap-4">
<div className="flex items-center gap-3 lg:w-48">
<input
type="checkbox"
className="checkbox checkbox-primary checkbox-sm"
checked={checked}
onChange={onCheckedChange}
disabled={disabled}
/>
<span className="font-medium text-sm">{label}</span>
</div>
<div className="flex items-center gap-2 lg:w-32">
<input
type="number"
className="input input-bordered input-sm w-20"
value={value}
onChange={(e) => onValueChange(e.target.value)}
disabled={disabled}
/>
<span className="text-sm text-base-content/70">{unit}</span>
</div>
<div className="flex items-center gap-2 flex-1">
<input
type="text"
className="input input-bordered input-sm flex-1"
placeholder={`${label} alert message...`}
value={message}
onChange={(e) => onMessageChange(e.target.value)}
disabled={disabled}
/>
<div className="tooltip" data-tip="Notification message template">
<CircleHelp className="w-4 h-4 text-base-content/50" />
</div>
</div>
</div>
</div>
</div>
)
return (
<div>
<div className="w-full bg-base-200 p-4 rounded-2xl border border-stone-800">
{/* Header */}
<div className="text-center lg:text-left">
<h2 className="text-lg font-bold">Notification Settings</h2>
<p className="text-sm opacity-70">Configure monitoring alerts for your servers and applications</p>
</div>
{/* Main Content */}
<div className="grid gap-6 mt-4">
{/* Server Monitoring Section */}
<div className="card bg-base-100 shadow-lg border border-base-300">
<div className="card-body">
<div className="flex items-center gap-3 mb-6">
<div className="p-2 bg-primary/10 rounded-lg">
<Server className="w-6 h-6 text-primary" />
</div>
<div>
<h3 className="text-lg font-bold">Server Monitoring</h3>
<p className="text-sm opacity-70">Monitor server resources and performance</p>
</div>
</div>
{/* Master Toggle */}
<div className="card bg-base-200 mb-6">
<div className="card-body p-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<input
type="checkbox"
className="toggle toggle-primary toggle-lg"
checked={serverSettings?.enabled}
onChange={() => setServerSettings({ ...serverSettings, enabled: !serverSettings.enabled })}
/>
<div>
<h3 className="font-semibold">Enable Server Monitoring</h3>
<p className="text-sm text-base-content/70">Turn on global server monitoring</p>
</div>
</div>
<div className={`badge ${serverSettings?.enabled ? "badge-success" : "badge-neutral"}`}>
{serverSettings?.enabled ? "Active" : "Inactive"}
</div>
</div>
</div>
</div>
{/* Status Change Alerts */}
<div className={`space-y-4 ${!serverSettings?.enabled ? "opacity-50" : ""}`}>
<div className="card bg-base-200">
<div className="card-body p-4">
<div className="flex flex-col lg:flex-row lg:items-center gap-4">
<div className="flex items-center gap-3 lg:flex-1">
<input
type="checkbox"
className="checkbox checkbox-primary"
checked={serverSettings?.statusChange}
onChange={() =>
setServerSettings({ ...serverSettings, statusChange: !serverSettings.statusChange })
}
disabled={!serverSettings?.enabled}
/>
<div>
<span className="font-medium">Status Change Alerts</span>
<p className="text-xs text-base-content/70">Get notified when server status changes</p>
</div>
</div>
<div className="flex items-center gap-2 lg:flex-1">
<input
type="text"
className="input input-bordered input-sm flex-1"
placeholder="Status change notification message..."
value={serverSettings?.notificationTextStatus}
onChange={(e) =>
setServerSettings({ ...serverSettings, notificationTextStatus: e.target.value })
}
disabled={!serverSettings?.enabled}
/>
<div className="tooltip" data-tip="Notification message template">
<CircleHelp className="w-4 h-4 text-base-content/50" />
</div>
</div>
</div>
</div>
</div>
{/* Resource Thresholds */}
<div className="space-y-4">
<div className="flex items-center gap-2 mb-4">
<h4 className="text-base font-semibold">Resource Thresholds</h4>
<div className="badge badge-outline badge-sm">Configure limits</div>
</div>
<div className="space-y-3">
<ResourceThresholdRow
label="CPU Usage"
checked={serverSettings?.notificationCpu}
onCheckedChange={() =>
setServerSettings({ ...serverSettings, notificationCpu: !serverSettings.notificationCpu })
}
value={serverSettings?.cpuLimit}
onValueChange={(value) => setServerSettings({ ...serverSettings, cpuLimit: value })}
unit="%"
message={serverSettings?.notificationTextCpu}
onMessageChange={(value) => setServerSettings({ ...serverSettings, notificationTextCpu: value })}
disabled={!serverSettings?.enabled}
/>
<ResourceThresholdRow
label="GPU Usage"
checked={serverSettings?.notificationGpu}
onCheckedChange={() =>
setServerSettings({ ...serverSettings, notificationGpu: !serverSettings.notificationGpu })
}
value={serverSettings?.gpuLimit}
onValueChange={(value) => setServerSettings({ ...serverSettings, gpuLimit: value })}
unit="%"
message={serverSettings?.notificationTextGpu}
onMessageChange={(value) => setServerSettings({ ...serverSettings, notificationTextGpu: value })}
disabled={!serverSettings?.enabled}
/>
<ResourceThresholdRow
label="Memory Usage"
checked={serverSettings?.notificationMemory}
onCheckedChange={() =>
setServerSettings({ ...serverSettings, notificationMemory: !serverSettings.notificationMemory })
}
value={serverSettings?.memoryLimit}
onValueChange={(value) => setServerSettings({ ...serverSettings, memoryLimit: value })}
unit="GB"
message={serverSettings?.notificationTextMemory}
onMessageChange={(value) => setServerSettings({ ...serverSettings, notificationTextMemory: value })}
disabled={!serverSettings?.enabled}
/>
<ResourceThresholdRow
label="Disk Usage"
checked={serverSettings?.notificationDisk}
onCheckedChange={() =>
setServerSettings({ ...serverSettings, notificationDisk: !serverSettings.notificationDisk })
}
value={serverSettings?.diskLimit}
onValueChange={(value) => setServerSettings({ ...serverSettings, diskLimit: value })}
unit="%"
message={serverSettings?.notificationTextDisk}
onMessageChange={(value) => setServerSettings({ ...serverSettings, notificationTextDisk: value })}
disabled={!serverSettings?.enabled}
/>
<ResourceThresholdRow
label="Temperature"
checked={serverSettings?.notificationTemperature}
onCheckedChange={() =>
setServerSettings({
...serverSettings,
notificationTemperature: !serverSettings.notificationTemperature,
})
}
value={serverSettings?.temperatureLimit}
onValueChange={(value) => setServerSettings({ ...serverSettings, temperatureLimit: value })}
unit="°C"
message={serverSettings?.notificationTextTemperature}
onMessageChange={(value) =>
setServerSettings({ ...serverSettings, notificationTextTemperature: value })
}
disabled={!serverSettings?.enabled}
/>
</div>
</div>
</div>
</div>
</div>
{/* Application Monitoring Section */}
<div className="card bg-base-100 shadow-lg border border-base-300">
<div className="card-body">
<div className="flex items-center gap-3 mb-6">
<div className="p-2 bg-secondary/10 rounded-lg">
<Smartphone className="w-6 h-6 text-secondary" />
</div>
<div>
<h3 className="text-lg font-bold">Application Monitoring</h3>
<p className="text-sm opacity-70">Monitor application performance and availability</p>
</div>
</div>
{/* Master Toggle */}
<div className="card bg-base-200 mb-6">
<div className="card-body p-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<input
type="checkbox"
className="toggle toggle-secondary toggle-lg"
checked={applicationsSettings?.enabled}
onChange={() =>
setApplicationsSettings({ ...applicationsSettings, enabled: !applicationsSettings.enabled })
}
/>
<div>
<h3 className="font-semibold">Enable Application Monitoring</h3>
<p className="text-sm text-base-content/70">Turn on global application monitoring</p>
</div>
</div>
<div className={`badge ${applicationsSettings?.enabled ? "badge-success" : "badge-neutral"}`}>
{applicationsSettings?.enabled ? "Active" : "Inactive"}
</div>
</div>
</div>
</div>
{/* Application Settings */}
<div className={`space-y-4 ${!applicationsSettings?.enabled ? "opacity-50" : ""}`}>
{/* Status Change Alerts */}
<div className="card bg-base-200">
<div className="card-body p-4">
<div className="flex flex-col lg:flex-row lg:items-center gap-4">
<div className="flex items-center gap-3 lg:flex-1">
<input
type="checkbox"
className="checkbox checkbox-secondary"
checked={applicationsSettings?.statusChange}
onChange={() =>
setApplicationsSettings({
...applicationsSettings,
statusChange: !applicationsSettings.statusChange,
})
}
disabled={!applicationsSettings?.enabled}
/>
<div>
<span className="font-medium">Status Change Alerts</span>
<p className="text-xs text-base-content/70">Get notified when application status changes</p>
</div>
</div>
<div className="flex items-center gap-2 lg:flex-1">
<input
type="text"
className="input input-bordered input-sm flex-1"
placeholder="Status change notification message..."
value={applicationsSettings?.notificationTextStatus}
onChange={(e) =>
setApplicationsSettings({ ...applicationsSettings, notificationTextStatus: e.target.value })
}
disabled={!applicationsSettings?.enabled}
/>
<div className="tooltip" data-tip="Notification message template">
<CircleHelp className="w-4 h-4 text-base-content/50" />
</div>
</div>
</div>
</div>
</div>
{/* Latency Threshold */}
<div className="space-y-4">
<div className="flex items-center gap-2 mb-4">
<h4 className="text-base font-semibold">Performance Thresholds</h4>
<div className="badge badge-outline badge-sm">Configure limits</div>
</div>
<ResourceThresholdRow
label="Latency Threshold"
checked={applicationsSettings?.notificationLatency}
onCheckedChange={() =>
setApplicationsSettings({
...applicationsSettings,
notificationLatency: !applicationsSettings.notificationLatency,
})
}
value={applicationsSettings?.latencyLimit}
onValueChange={(value) => setApplicationsSettings({ ...applicationsSettings, latencyLimit: Number(value) })}
unit="ms"
message={applicationsSettings?.notificationTextLatency}
onMessageChange={(value) =>
setApplicationsSettings({ ...applicationsSettings, notificationTextLatency: value })
}
disabled={!applicationsSettings?.enabled}
/>
</div>
</div>
</div>
</div>
{/* Action Buttons */}
<div className="flex flex-col sm:flex-row gap-3 justify-end">
<button className="btn btn-primary" onClick={saveNotificationSettings}>Save Settings</button>
</div>
</div>
</div>
</div>
)
}

View File

@ -74,6 +74,46 @@ const useNotifications = () => {
});
}
const getNotificationApplicationsSettings = (): Promise<string> | string => {
return axios.get('/api/notifications/settings_applications_get')
.then((response) => {
return response.data.notification;
})
.catch(err => {
throw err.response?.data?.error || 'An error occurred';
});
}
const getNotificationServerSettings = (): Promise<string> | string => {
return axios.get('/api/notifications/settings_server_get')
.then((response) => {
return response.data.notification;
})
.catch(err => {
throw err.response?.data?.error || 'An error occurred';
});
}
const editNotificationApplicationsSettings = (settings: any): Promise<string> | string => {
return axios.post('/api/notifications/settings_applications_edit', settings)
.then((response) => {
return response.data.notificationSettings;
})
.catch(err => {
throw err.response?.data?.error || 'An error occurred';
});
}
const editNotificationServerSettings = (settings: any): Promise<string> | string => {
return axios.post('/api/notifications/settings_server_edit', settings)
.then((response) => {
return response.data.notificationSettings;
})
.catch(err => {
throw err.response?.data?.error || 'An error occurred';
});
}
return {
notifications,
loading,
@ -82,7 +122,11 @@ const useNotifications = () => {
loadNotifications,
testNotification,
getNotificationTest,
notificationTest
notificationTest,
getNotificationApplicationsSettings,
getNotificationServerSettings,
editNotificationApplicationsSettings,
editNotificationServerSettings
};
}