mirror of
https://github.com/Buriburizaem0n/admin-frontend-domain.git
synced 2026-02-04 04:30:06 +00:00
chore: update translations (#101)
* chore: update translations * fix: form values type conversion * feat: terminal fullscreen mode * fix
This commit is contained in:
@@ -82,7 +82,9 @@ const alertRuleFormSchema = z.object({
|
||||
),
|
||||
rules: z.array(ruleSchema),
|
||||
fail_trigger_tasks: z.array(z.number()),
|
||||
fail_trigger_tasks_raw: z.string(),
|
||||
recover_trigger_tasks: z.array(z.number()),
|
||||
recover_trigger_tasks_raw: z.string(),
|
||||
notification_group_id: z.coerce.number().int(),
|
||||
trigger_mode: z.coerce.number().int().min(0),
|
||||
enable: asOptionalField(z.boolean()),
|
||||
@@ -96,13 +98,17 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
|
||||
? {
|
||||
...data,
|
||||
rules_raw: JSON.stringify(data.rules),
|
||||
fail_trigger_tasks_raw: conv.arrToStr(data.fail_trigger_tasks),
|
||||
recover_trigger_tasks_raw: conv.arrToStr(data.recover_trigger_tasks),
|
||||
}
|
||||
: {
|
||||
name: "",
|
||||
rules_raw: "",
|
||||
rules: [],
|
||||
fail_trigger_tasks: [],
|
||||
fail_trigger_tasks_raw: "",
|
||||
recover_trigger_tasks: [],
|
||||
recover_trigger_tasks_raw: "",
|
||||
notification_group_id: 0,
|
||||
trigger_mode: 0,
|
||||
},
|
||||
@@ -115,6 +121,8 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
|
||||
|
||||
const onSubmit = async (values: z.infer<typeof alertRuleFormSchema>) => {
|
||||
values.rules = JSON.parse(values.rules_raw)
|
||||
values.fail_trigger_tasks = conv.strToArr(values.fail_trigger_tasks_raw).map(Number)
|
||||
values.recover_trigger_tasks = conv.strToArr(values.recover_trigger_tasks_raw).map(Number)
|
||||
const { rules_raw, ...requiredFields } = values
|
||||
try {
|
||||
data?.id
|
||||
@@ -227,7 +235,7 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="fail_trigger_tasks"
|
||||
name="fail_trigger_tasks_raw"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
@@ -235,17 +243,7 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
|
||||
t("SeparateWithComma")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="1,2,3"
|
||||
{...field}
|
||||
value={conv.arrToStr(field.value ?? [])}
|
||||
onChange={(e) => {
|
||||
const arr = conv
|
||||
.strToArr(e.target.value)
|
||||
.map(Number)
|
||||
field.onChange(arr)
|
||||
}}
|
||||
/>
|
||||
<Input placeholder="1,2,3" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@@ -253,7 +251,7 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="recover_trigger_tasks"
|
||||
name="recover_trigger_tasks_raw"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
@@ -261,17 +259,7 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
|
||||
t("SeparateWithComma")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="1,2,3"
|
||||
{...field}
|
||||
value={conv.arrToStr(field.value ?? [])}
|
||||
onChange={(e) => {
|
||||
const arr = conv
|
||||
.strToArr(e.target.value)
|
||||
.map(Number)
|
||||
field.onChange(arr)
|
||||
}}
|
||||
/>
|
||||
<Input placeholder="1,2,3" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
||||
@@ -57,6 +57,7 @@ const ddnsFormSchema = z.object({
|
||||
name: z.string().min(1),
|
||||
provider: z.string(),
|
||||
domains: z.array(z.string()),
|
||||
domains_raw: z.string(),
|
||||
access_id: asOptionalField(z.string()),
|
||||
access_secret: asOptionalField(z.string()),
|
||||
webhook_url: asOptionalField(z.string().url()),
|
||||
@@ -71,12 +72,16 @@ export const DDNSCard: React.FC<DDNSCardProps> = ({ data, providers, mutate }) =
|
||||
const form = useForm<z.infer<typeof ddnsFormSchema>>({
|
||||
resolver: zodResolver(ddnsFormSchema),
|
||||
defaultValues: data
|
||||
? data
|
||||
? {
|
||||
...data,
|
||||
domains_raw: conv.arrToStr(data.domains),
|
||||
}
|
||||
: {
|
||||
max_retries: 3,
|
||||
name: "",
|
||||
provider: "dummy",
|
||||
domains: [],
|
||||
domains_raw: "",
|
||||
},
|
||||
resetOptions: {
|
||||
keepDefaultValues: false,
|
||||
@@ -87,6 +92,7 @@ export const DDNSCard: React.FC<DDNSCardProps> = ({ data, providers, mutate }) =
|
||||
|
||||
const onSubmit = async (values: z.infer<typeof ddnsFormSchema>) => {
|
||||
try {
|
||||
values.domains = conv.strToArr(values.domains_raw)
|
||||
data?.id ? await updateDDNSProfile(data.id, values) : await createDDNSProfile(values)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
@@ -156,22 +162,14 @@ export const DDNSCard: React.FC<DDNSCardProps> = ({ data, providers, mutate }) =
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="domains"
|
||||
name="domains_raw"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t("Domains") + t("SeparateWithComma")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="www.example.com"
|
||||
{...field}
|
||||
value={conv.arrToStr(field.value ?? [])}
|
||||
onChange={(e) => {
|
||||
const arr = conv.strToArr(e.target.value)
|
||||
field.onChange(arr)
|
||||
}}
|
||||
/>
|
||||
<Input placeholder="www.example.com" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
||||
@@ -48,13 +48,17 @@ const serverFormSchema = z.object({
|
||||
hide_for_guest: asOptionalField(z.boolean()),
|
||||
enable_ddns: asOptionalField(z.boolean()),
|
||||
ddns_profiles: asOptionalField(z.array(z.number())),
|
||||
ddns_profiles_raw: asOptionalField(z.string()),
|
||||
})
|
||||
|
||||
export const ServerCard: React.FC<ServerCardProps> = ({ data, mutate }) => {
|
||||
const { t } = useTranslation()
|
||||
const form = useForm<z.infer<typeof serverFormSchema>>({
|
||||
resolver: zodResolver(serverFormSchema),
|
||||
defaultValues: data,
|
||||
defaultValues: {
|
||||
...data,
|
||||
ddns_profiles_raw: data.ddns_profiles ? conv.arrToStr(data.ddns_profiles) : undefined,
|
||||
},
|
||||
resetOptions: {
|
||||
keepDefaultValues: false,
|
||||
},
|
||||
@@ -64,6 +68,9 @@ export const ServerCard: React.FC<ServerCardProps> = ({ data, mutate }) => {
|
||||
|
||||
const onSubmit = async (values: z.infer<typeof serverFormSchema>) => {
|
||||
try {
|
||||
values.ddns_profiles = values.ddns_profiles_raw
|
||||
? conv.strToArr(values.ddns_profiles_raw).map(Number)
|
||||
: undefined
|
||||
await updateServer(data!.id!, values)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
@@ -119,24 +126,14 @@ export const ServerCard: React.FC<ServerCardProps> = ({ data, mutate }) => {
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="ddns_profiles"
|
||||
name="ddns_profiles_raw"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t("DDNSProfiles") + t("SeparateWithComma")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="1,2,3"
|
||||
{...field}
|
||||
value={conv.arrToStr(field.value || [])}
|
||||
onChange={(e) => {
|
||||
const arr = conv
|
||||
.strToArr(e.target.value)
|
||||
.map(Number)
|
||||
field.onChange(arr)
|
||||
}}
|
||||
/>
|
||||
<Input placeholder="1,2,3" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
||||
@@ -58,6 +58,7 @@ const serviceFormSchema = z.object({
|
||||
enable_show_in_service: asOptionalField(z.boolean()),
|
||||
enable_trigger_task: asOptionalField(z.boolean()),
|
||||
fail_trigger_tasks: z.array(z.number()),
|
||||
fail_trigger_tasks_raw: z.string(),
|
||||
latency_notify: asOptionalField(z.boolean()),
|
||||
max_latency: z.coerce.number().int().min(0),
|
||||
min_latency: z.coerce.number().int().min(0),
|
||||
@@ -65,6 +66,7 @@ const serviceFormSchema = z.object({
|
||||
notification_group_id: z.coerce.number().int(),
|
||||
notify: asOptionalField(z.boolean()),
|
||||
recover_trigger_tasks: z.array(z.number()),
|
||||
recover_trigger_tasks_raw: z.string(),
|
||||
skip_servers: z.record(z.boolean()),
|
||||
skip_servers_raw: z.array(z.string()),
|
||||
target: z.string(),
|
||||
@@ -78,6 +80,8 @@ export const ServiceCard: React.FC<ServiceCardProps> = ({ data, mutate }) => {
|
||||
defaultValues: data
|
||||
? {
|
||||
...data,
|
||||
fail_trigger_tasks_raw: conv.arrToStr(data.fail_trigger_tasks),
|
||||
recover_trigger_tasks_raw: conv.arrToStr(data.recover_trigger_tasks),
|
||||
skip_servers_raw: conv.recordToStrArr(data.skip_servers ? data.skip_servers : {}),
|
||||
}
|
||||
: {
|
||||
@@ -90,7 +94,9 @@ export const ServiceCard: React.FC<ServiceCardProps> = ({ data, mutate }) => {
|
||||
duration: 30,
|
||||
notification_group_id: 0,
|
||||
fail_trigger_tasks: [],
|
||||
fail_trigger_tasks_raw: "",
|
||||
recover_trigger_tasks: [],
|
||||
recover_trigger_tasks_raw: "",
|
||||
skip_servers: {},
|
||||
skip_servers_raw: [],
|
||||
},
|
||||
@@ -103,6 +109,8 @@ export const ServiceCard: React.FC<ServiceCardProps> = ({ data, mutate }) => {
|
||||
|
||||
const onSubmit = async (values: z.infer<typeof serviceFormSchema>) => {
|
||||
values.skip_servers = conv.arrToRecord(values.skip_servers_raw)
|
||||
values.fail_trigger_tasks = conv.strToArr(values.fail_trigger_tasks_raw).map(Number)
|
||||
values.recover_trigger_tasks = conv.strToArr(values.recover_trigger_tasks_raw).map(Number)
|
||||
const { skip_servers_raw, ...requiredFields } = values
|
||||
try {
|
||||
data?.id
|
||||
@@ -400,7 +408,7 @@ export const ServiceCard: React.FC<ServiceCardProps> = ({ data, mutate }) => {
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="fail_trigger_tasks"
|
||||
name="fail_trigger_tasks_raw"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
@@ -408,17 +416,7 @@ export const ServiceCard: React.FC<ServiceCardProps> = ({ data, mutate }) => {
|
||||
t("SeparateWithComma")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="1,2,3"
|
||||
{...field}
|
||||
value={conv.arrToStr(field.value ?? [])}
|
||||
onChange={(e) => {
|
||||
const arr = conv
|
||||
.strToArr(e.target.value)
|
||||
.map(Number)
|
||||
field.onChange(arr)
|
||||
}}
|
||||
/>
|
||||
<Input placeholder="1,2,3" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@@ -426,7 +424,7 @@ export const ServiceCard: React.FC<ServiceCardProps> = ({ data, mutate }) => {
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="recover_trigger_tasks"
|
||||
name="recover_trigger_tasks_raw"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
@@ -434,17 +432,7 @@ export const ServiceCard: React.FC<ServiceCardProps> = ({ data, mutate }) => {
|
||||
t("SeparateWithComma")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="1,2,3"
|
||||
{...field}
|
||||
value={conv.arrToStr(field.value ?? [])}
|
||||
onChange={(e) => {
|
||||
const arr = conv
|
||||
.strToArr(e.target.value)
|
||||
.map(Number)
|
||||
field.onChange(arr)
|
||||
}}
|
||||
/>
|
||||
<Input placeholder="1,2,3" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
||||
@@ -13,7 +13,7 @@ import { AttachAddon } from "@xterm/addon-attach"
|
||||
import { FitAddon } from "@xterm/addon-fit"
|
||||
import { Terminal } from "@xterm/xterm"
|
||||
import "@xterm/xterm/css/xterm.css"
|
||||
import { useEffect, useMemo, useRef, useState } from "react"
|
||||
import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react"
|
||||
import { useParams } from "react-router-dom"
|
||||
import { toast } from "sonner"
|
||||
|
||||
@@ -26,119 +26,134 @@ interface XtermProps {
|
||||
setClose: React.Dispatch<React.SetStateAction<boolean>>
|
||||
}
|
||||
|
||||
const XtermComponent: React.FC<XtermProps & JSX.IntrinsicElements["div"]> = ({
|
||||
wsUrl,
|
||||
setClose,
|
||||
...props
|
||||
}) => {
|
||||
const terminalIdRef = useRef<HTMLDivElement>(null)
|
||||
const terminalRef = useRef<Terminal | null>(null)
|
||||
const wsRef = useRef<WebSocket | null>(null)
|
||||
const XtermComponent = forwardRef<HTMLDivElement, XtermProps & JSX.IntrinsicElements["div"]>(
|
||||
({ wsUrl, setClose, ...props }, ref) => {
|
||||
const terminalIdRef = useRef<HTMLDivElement>(null)
|
||||
const terminalRef = useRef<Terminal | null>(null)
|
||||
const wsRef = useRef<WebSocket | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
wsRef.current?.close()
|
||||
terminalRef.current?.dispose()
|
||||
}
|
||||
}, [])
|
||||
useImperativeHandle(ref, () => {
|
||||
return {
|
||||
...terminalIdRef.current!,
|
||||
async requestFullscreen() {
|
||||
await terminalIdRef.current?.requestFullscreen()
|
||||
},
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
terminalRef.current = new Terminal({
|
||||
cursorBlink: true,
|
||||
fontSize: 16,
|
||||
})
|
||||
const ws = new WebSocket(wsUrl)
|
||||
wsRef.current = ws
|
||||
ws.binaryType = "arraybuffer"
|
||||
ws.onopen = () => {
|
||||
onResize()
|
||||
}
|
||||
ws.onclose = () => {
|
||||
terminalRef.current?.dispose()
|
||||
setClose(true)
|
||||
}
|
||||
ws.onerror = (e) => {
|
||||
console.error(e)
|
||||
toast("Websocket error", {
|
||||
description: "View console for details.",
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
wsRef.current?.close()
|
||||
terminalRef.current?.dispose()
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
terminalRef.current = new Terminal({
|
||||
cursorBlink: true,
|
||||
fontSize: 16,
|
||||
})
|
||||
}
|
||||
}, [wsUrl])
|
||||
const ws = new WebSocket(wsUrl)
|
||||
wsRef.current = ws
|
||||
ws.binaryType = "arraybuffer"
|
||||
ws.onopen = () => {
|
||||
onResize()
|
||||
}
|
||||
ws.onclose = () => {
|
||||
terminalRef.current?.dispose()
|
||||
setClose(true)
|
||||
}
|
||||
ws.onerror = (e) => {
|
||||
console.error(e)
|
||||
toast("Websocket error", {
|
||||
description: "View console for details.",
|
||||
})
|
||||
}
|
||||
}, [wsUrl])
|
||||
|
||||
const fitAddon = useRef(new FitAddon()).current
|
||||
const sendResize = useRef(false)
|
||||
const fitAddon = useRef(new FitAddon()).current
|
||||
const sendResize = useRef(false)
|
||||
|
||||
const doResize = () => {
|
||||
if (!terminalIdRef.current) return
|
||||
const doResize = () => {
|
||||
if (!terminalIdRef.current) return
|
||||
|
||||
fitAddon.fit()
|
||||
fitAddon.fit()
|
||||
|
||||
const dimensions = fitAddon.proposeDimensions()
|
||||
const dimensions = fitAddon.proposeDimensions()
|
||||
|
||||
if (dimensions) {
|
||||
const prefix = new Int8Array([1])
|
||||
const resizeMessage = new TextEncoder().encode(
|
||||
JSON.stringify({
|
||||
Rows: dimensions.rows,
|
||||
Cols: dimensions.cols,
|
||||
}),
|
||||
)
|
||||
if (dimensions) {
|
||||
const prefix = new Int8Array([1])
|
||||
const resizeMessage = new TextEncoder().encode(
|
||||
JSON.stringify({
|
||||
Rows: dimensions.rows,
|
||||
Cols: dimensions.cols,
|
||||
}),
|
||||
)
|
||||
|
||||
const msg = new Int8Array(prefix.length + resizeMessage.length)
|
||||
msg.set(prefix)
|
||||
msg.set(resizeMessage, prefix.length)
|
||||
const msg = new Int8Array(prefix.length + resizeMessage.length)
|
||||
msg.set(prefix)
|
||||
msg.set(resizeMessage, prefix.length)
|
||||
|
||||
wsRef.current?.send(msg)
|
||||
}
|
||||
}
|
||||
|
||||
const onResize = async () => {
|
||||
if (sendResize.current) return
|
||||
|
||||
sendResize.current = true
|
||||
try {
|
||||
await sleep(1500)
|
||||
doResize()
|
||||
} catch (error) {
|
||||
console.error("resize error", error)
|
||||
} finally {
|
||||
sendResize.current = false
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!wsRef.current || !terminalIdRef.current || !terminalRef.current) return
|
||||
const attachAddon = new AttachAddon(wsRef.current)
|
||||
terminalRef.current.loadAddon(attachAddon)
|
||||
terminalRef.current.loadAddon(fitAddon)
|
||||
terminalRef.current.open(terminalIdRef.current)
|
||||
window.addEventListener("resize", onResize)
|
||||
return () => {
|
||||
window.removeEventListener("resize", onResize)
|
||||
if (wsRef.current) {
|
||||
wsRef.current.close()
|
||||
wsRef.current?.send(msg)
|
||||
}
|
||||
}
|
||||
}, [wsRef.current, terminalRef.current, terminalIdRef.current])
|
||||
|
||||
return <div ref={terminalIdRef} {...props} />
|
||||
}
|
||||
const onResize = async () => {
|
||||
if (sendResize.current) return
|
||||
|
||||
sendResize.current = true
|
||||
try {
|
||||
await sleep(1500)
|
||||
doResize()
|
||||
} catch (error) {
|
||||
console.error("resize error", error)
|
||||
} finally {
|
||||
sendResize.current = false
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!wsRef.current || !terminalIdRef.current || !terminalRef.current) return
|
||||
const attachAddon = new AttachAddon(wsRef.current)
|
||||
terminalRef.current.loadAddon(attachAddon)
|
||||
terminalRef.current.loadAddon(fitAddon)
|
||||
terminalRef.current.open(terminalIdRef.current)
|
||||
window.addEventListener("resize", onResize)
|
||||
return () => {
|
||||
window.removeEventListener("resize", onResize)
|
||||
if (wsRef.current) {
|
||||
wsRef.current.close()
|
||||
}
|
||||
}
|
||||
}, [wsRef.current, terminalRef.current, terminalIdRef.current])
|
||||
|
||||
return <div ref={terminalIdRef} {...props} />
|
||||
},
|
||||
)
|
||||
|
||||
export const TerminalPage = () => {
|
||||
const { id } = useParams<{ id: string }>()
|
||||
const [open, setOpen] = useState(false)
|
||||
const terminal = useTerminal(id ? parseInt(id) : undefined)
|
||||
const terminalIdRef = useRef<HTMLDivElement>(null)
|
||||
return (
|
||||
<div className="px-8">
|
||||
<div className="flex mt-6 mb-4">
|
||||
<h1 className="flex-1 text-3xl font-bold tracking-tight">{`Terminal (${id})`}</h1>
|
||||
<div className="flex-2 flex ml-auto gap-2">
|
||||
<IconButton
|
||||
icon="expand"
|
||||
onClick={async () => {
|
||||
await terminalIdRef.current?.requestFullscreen()
|
||||
}}
|
||||
/>
|
||||
<FMCard id={id} />
|
||||
</div>
|
||||
</div>
|
||||
{terminal?.session_id ? (
|
||||
<XtermComponent
|
||||
className="max-h-[60%] mb-5"
|
||||
ref={terminalIdRef}
|
||||
className="max-h-[60%] mb-5 overflow-auto"
|
||||
wsUrl={`/api/v1/ws/terminal/${terminal?.session_id}`}
|
||||
setClose={setOpen}
|
||||
/>
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
Clipboard,
|
||||
Download,
|
||||
Edit2,
|
||||
Expand,
|
||||
FolderClosed,
|
||||
Menu,
|
||||
Play,
|
||||
@@ -31,6 +32,7 @@ export interface IconButtonProps extends ButtonProps {
|
||||
| "upload"
|
||||
| "menu"
|
||||
| "ban"
|
||||
| "expand"
|
||||
}
|
||||
|
||||
export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>((props, ref) => {
|
||||
@@ -82,6 +84,9 @@ export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>((props,
|
||||
case "ban": {
|
||||
return <BanIcon />
|
||||
}
|
||||
case "expand": {
|
||||
return <Expand />
|
||||
}
|
||||
}
|
||||
})()}
|
||||
</Button>
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
"InstallCommands": "Installationsbefehl",
|
||||
"Actions": "Aktionen",
|
||||
"Weight": "Gewicht (je größer die Zahl, desto höher wird es angezeigt)",
|
||||
"TasksToTriggerOnAlert": "Die Aufgabe, die den Alarm ausgelöst hat",
|
||||
"TasksToTriggerOnAlert": "Aufgaben, die bei Alarm ausgelöst werden sollen",
|
||||
"NotifierGroup": "Benachrichtigungsgruppe",
|
||||
"EditNAT": "NAT-Konfiguration bearbeiten",
|
||||
"BindHostname": "Bind Domain Name",
|
||||
|
||||
@@ -64,12 +64,13 @@
|
||||
"Coverage": "Coverage",
|
||||
"CoverAll": "Cover All",
|
||||
"IgnoreAll": "Ignore All",
|
||||
"OnAlert": "Alarmed Servers",
|
||||
"SpecificServers": "Specific server",
|
||||
"Type": "Type",
|
||||
"Interval": "Interval",
|
||||
"NotifierGroupID": "Notifier Group ID",
|
||||
"Trigger": "On Trigger",
|
||||
"TasksToTriggerOnAlert": "The task that triggered the alert",
|
||||
"TasksToTriggerOnAlert": "Tasks to be triggered on alert",
|
||||
"TasksToTriggerAfterRecovery": "Tasks to be triggered after recovery",
|
||||
"Confirm": "Confirm",
|
||||
"ConfirmDeletion": "Confirm Deletion?",
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"Weight": "Peso (cuanto mayor sea el número, más alto se mostrará)",
|
||||
"DDNSProfiles": "IDs de perfil de DDNS",
|
||||
"Target": "Objetivo",
|
||||
"TasksToTriggerOnAlert": "La tarea que activó la alerta",
|
||||
"TasksToTriggerOnAlert": "Tareas que se activarán en caso de alerta",
|
||||
"Services": "Servicios",
|
||||
"MaximumLatency": "Retraso máximo (ms)",
|
||||
"Server": "Servidor",
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
"Interval": "Intervallo",
|
||||
"NotifierGroupID": "ID del gruppo di notifiche",
|
||||
"Trigger": "Grilletto",
|
||||
"TasksToTriggerOnAlert": "L'attività che ha attivato l'avviso",
|
||||
"TasksToTriggerOnAlert": "Attività da attivare in caso di allarme",
|
||||
"TasksToTriggerAfterRecovery": "Attività da attivare dopo il ripristino",
|
||||
"Confirm": "Confermo",
|
||||
"ConfirmDeletion": "Confermi l'eliminazione?",
|
||||
|
||||
@@ -64,12 +64,13 @@
|
||||
"Coverage": "覆盖范围",
|
||||
"CoverAll": "覆盖全部",
|
||||
"IgnoreAll": "忽略全部",
|
||||
"OnAlert": "告警服务器",
|
||||
"SpecificServers": "特定服务器",
|
||||
"Type": "类型",
|
||||
"Interval": "间隔",
|
||||
"NotifierGroupID": "通知组ID",
|
||||
"Trigger": "触发",
|
||||
"TasksToTriggerOnAlert": "触发警报的任务",
|
||||
"TasksToTriggerOnAlert": "告警时要触发的任务",
|
||||
"TasksToTriggerAfterRecovery": "恢复后要触发的任务",
|
||||
"Confirm": "确认",
|
||||
"ConfirmDeletion": "确认删除?",
|
||||
|
||||
@@ -64,12 +64,13 @@
|
||||
"Coverage": "覆蓋範圍",
|
||||
"CoverAll": "覆蓋全部",
|
||||
"IgnoreAll": "忽略全部",
|
||||
"OnAlert": "告警伺服器",
|
||||
"SpecificServers": "特定伺服器",
|
||||
"Type": "類型",
|
||||
"Interval": "間隔",
|
||||
"NotifierGroupID": "通知群組ID",
|
||||
"Trigger": "觸發",
|
||||
"TasksToTriggerOnAlert": "觸發警報的任務",
|
||||
"TasksToTriggerOnAlert": "告警時要觸發的任務",
|
||||
"TasksToTriggerAfterRecovery": "恢復後要觸發的任務",
|
||||
"Confirm": "確認",
|
||||
"ConfirmDeletion": "確認刪除?",
|
||||
|
||||
@@ -111,13 +111,13 @@ export default function CronPage() {
|
||||
{(() => {
|
||||
switch (s.cover) {
|
||||
case 0: {
|
||||
return <span>Ignore All</span>
|
||||
return <span>{t("IgnoreAll")}</span>
|
||||
}
|
||||
case 1: {
|
||||
return <span>Cover All</span>
|
||||
return <span>{t("CoverAll")}</span>
|
||||
}
|
||||
case 2: {
|
||||
return <span>On alert</span>
|
||||
return <span>{t("OnAlert")}</span>
|
||||
}
|
||||
}
|
||||
})()}
|
||||
@@ -129,6 +129,14 @@ export default function CronPage() {
|
||||
header: t("SpecificServers"),
|
||||
accessorKey: "servers",
|
||||
accessorFn: (row) => row.servers,
|
||||
cell: ({ row }) => {
|
||||
const s = row.original
|
||||
return (
|
||||
<div className="max-w-16 whitespace-normal break-words">
|
||||
<span>{s.servers.join(",")}</span>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
header: t("LastExecution"),
|
||||
|
||||
@@ -78,6 +78,14 @@ export default function NotificationGroupPage() {
|
||||
header: t("Notifier") + "(ID)",
|
||||
accessorKey: "notifications",
|
||||
accessorFn: (row) => row.notifications,
|
||||
cell: ({ row }) => {
|
||||
const s = row.original
|
||||
return (
|
||||
<div className="max-w-48 whitespace-normal break-words">
|
||||
<span>{s.notifications.join(",")}</span>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
|
||||
@@ -78,6 +78,14 @@ export default function ServerGroupPage() {
|
||||
header: t("Server") + "(ID)",
|
||||
accessorKey: "servers",
|
||||
accessorFn: (row) => row.servers,
|
||||
cell: ({ row }) => {
|
||||
const s = row.original
|
||||
return (
|
||||
<div className="max-w-48 whitespace-normal break-words">
|
||||
<span>{s.servers.join(",")}</span>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import animatePlugin from "tailwindcss-animate"
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
darkMode: ["class"],
|
||||
@@ -56,5 +58,5 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require("tailwindcss-animate")],
|
||||
plugins: [animatePlugin],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user