mirror of
https://github.com/fankes/beszel.git
synced 2025-10-19 09:49:28 +08:00
login i18n & chart loading & fix forgot pass page (#236)
Co-authored-by: hank <hank@henrygd.me>
This commit is contained in:
Binary file not shown.
@@ -32,7 +32,6 @@
|
||||
"cmdk": "^1.0.0",
|
||||
"d3-time": "^3.1.0",
|
||||
"i18next": "^23.16.4",
|
||||
"i18next-browser-languagedetector": "^8.0.0",
|
||||
"lucide-react": "^0.452.0",
|
||||
"nanostores": "^0.11.3",
|
||||
"pocketbase": "^0.21.5",
|
||||
|
@@ -16,6 +16,7 @@ import {
|
||||
import { useCallback, useState } from 'react'
|
||||
import { AuthMethodsList, OAuth2AuthConfig } from 'pocketbase'
|
||||
import { Link } from '../router'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const honeypot = v.literal('')
|
||||
const emailSchema = v.pipe(v.string(), v.email('Invalid email address.'))
|
||||
@@ -63,6 +64,8 @@ export function UserAuthForm({
|
||||
isFirstRun: boolean
|
||||
authMethods: AuthMethodsList
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false)
|
||||
const [isOauthLoading, setIsOauthLoading] = useState<boolean>(false)
|
||||
const [errors, setErrors] = useState<Record<string, string | undefined>>({})
|
||||
@@ -224,7 +227,7 @@ export function UserAuthForm({
|
||||
) : (
|
||||
<LogInIcon className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
{isFirstRun ? 'Create account' : 'Sign in'}
|
||||
{isFirstRun ? t('auth.create_account') : t('auth.sign_in')}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -317,16 +320,16 @@ export function UserAuthForm({
|
||||
<DialogTitle>OAuth 2 / OIDC support</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="text-primary/70 text-[0.95em] contents">
|
||||
<p>Beszel supports OpenID Connect and many OAuth2 authentication providers.</p>
|
||||
<p>{t('auth.openid_des')}</p>
|
||||
<p>
|
||||
Please view the{' '}
|
||||
{t('please_view_the')}{' '}
|
||||
<a
|
||||
href="https://github.com/henrygd/beszel/blob/main/readme.md#oauth--oidc-integration"
|
||||
className={cn(buttonVariants({ variant: 'link' }), 'p-0 h-auto')}
|
||||
>
|
||||
GitHub README
|
||||
</a>{' '}
|
||||
for instructions.
|
||||
{t('for_instructions')}
|
||||
</p>
|
||||
</div>
|
||||
</DialogContent>
|
||||
@@ -338,7 +341,7 @@ export function UserAuthForm({
|
||||
href="/forgot-password"
|
||||
className="text-sm mx-auto hover:text-brand underline underline-offset-4 opacity-70 hover:opacity-100 transition-opacity"
|
||||
>
|
||||
Forgot password?
|
||||
{t('auth.forgot_password')}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
|
@@ -8,6 +8,7 @@ import { cn } from '@/lib/utils'
|
||||
import { pb } from '@/lib/stores'
|
||||
import { Dialog, DialogHeader } from '../ui/dialog'
|
||||
import { DialogContent, DialogTrigger, DialogTitle } from '../ui/dialog'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const showLoginFaliedToast = () => {
|
||||
toast({
|
||||
@@ -18,6 +19,7 @@ const showLoginFaliedToast = () => {
|
||||
}
|
||||
|
||||
export default function ForgotPassword() {
|
||||
const { t } = useTranslation()
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false)
|
||||
const [email, setEmail] = useState('')
|
||||
|
||||
@@ -72,26 +74,25 @@ export default function ForgotPassword() {
|
||||
) : (
|
||||
<SendHorizonalIcon className="mr-2 h-4 w-4" />
|
||||
)}
|
||||
Reset password
|
||||
{t('auth.reset_password')}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<button className="text-sm mx-auto hover:text-brand underline underline-offset-4 opacity-70 hover:opacity-100 transition-opacity">
|
||||
Command line instructions
|
||||
{t('auth.command_line_instructions')}
|
||||
</button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-[33em]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Command line instructions</DialogTitle>
|
||||
<DialogTitle>{t('auth.command_line_instructions')}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<p className="text-primary/70 text-[0.95em] leading-relaxed">
|
||||
If you've lost the password to your admin account, you may reset it using the following
|
||||
command.
|
||||
{t('auth.command_1')}
|
||||
</p>
|
||||
<p className="text-primary/70 text-[0.95em] leading-relaxed">
|
||||
Then log into the backend and reset your user account password in the users table.
|
||||
{t('auth.command_2')}
|
||||
</p>
|
||||
<code className="bg-muted rounded-sm py-0.5 px-2.5 mr-auto text-sm">
|
||||
beszel admin update youremail@example.com newpassword
|
||||
|
@@ -6,8 +6,11 @@ import { useStore } from '@nanostores/react'
|
||||
import ForgotPassword from './forgot-pass-form'
|
||||
import { $router } from '../router'
|
||||
import { AuthMethodsList } from 'pocketbase'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
export default function () {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const page = useStore($router)
|
||||
const [isFirstRun, setFirstRun] = useState(false)
|
||||
const [authMethods, setAuthMethods] = useState<AuthMethodsList>()
|
||||
@@ -30,11 +33,11 @@ export default function () {
|
||||
|
||||
const subtitle = useMemo(() => {
|
||||
if (isFirstRun) {
|
||||
return 'Please create an admin account'
|
||||
return t('auth.create')
|
||||
} else if (page?.path === '/forgot-password') {
|
||||
return 'Enter email address to reset password'
|
||||
return t('auth.reset')
|
||||
} else {
|
||||
return 'Please sign in to your account'
|
||||
return t('auth.login')
|
||||
}
|
||||
}, [isFirstRun, page])
|
||||
|
||||
|
@@ -5,6 +5,7 @@ export const $router = createRouter(
|
||||
home: '/',
|
||||
server: '/system/:name',
|
||||
settings: '/settings/:name?',
|
||||
forgot_password: '/forgot-password',
|
||||
},
|
||||
{ links: false }
|
||||
)
|
||||
|
@@ -112,6 +112,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
const netCardRef = useRef<HTMLDivElement>(null)
|
||||
const [containerFilterBar, setContainerFilterBar] = useState(null as null | JSX.Element)
|
||||
const [bottomSpacing, setBottomSpacing] = useState(0)
|
||||
const [chartLoading, setChartLoading] = useState(false)
|
||||
const isLongerChart = chartTime !== '1h'
|
||||
|
||||
useEffect(() => {
|
||||
@@ -178,10 +179,15 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
if (!system.id || !chartTime) {
|
||||
return
|
||||
}
|
||||
// loading: true
|
||||
setChartLoading(true)
|
||||
Promise.allSettled([
|
||||
getStats<SystemStatsRecord>('system_stats', system, chartTime),
|
||||
getStats<ContainerStatsRecord>('container_stats', system, chartTime),
|
||||
]).then(([systemStats, containerStats]) => {
|
||||
// loading: false
|
||||
setChartLoading(false)
|
||||
|
||||
const { expectedInterval } = chartTimeData[chartTime]
|
||||
// make new system stats
|
||||
const ss_cache_key = `${system.id}_${chartTime}_system_stats`
|
||||
@@ -291,6 +297,9 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
return null
|
||||
}
|
||||
|
||||
// if no data, show empty state
|
||||
const dataEmpty = !chartLoading && chartData.systemStats.length === 0;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div id="chartwrap" className="grid gap-4 mb-10 overflow-x-clip">
|
||||
@@ -375,6 +384,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
{/* main charts */}
|
||||
<div className="grid lg:grid-cols-2 gap-4">
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t('monitor.total_cpu_usage')}
|
||||
description={`${cpuMaxStore[0] && isLongerChart ? t('monitor.max_1_min') : t('monitor.average') } ${t('monitor.cpu_des')}`}
|
||||
@@ -390,6 +400,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
|
||||
{containerFilterBar && (
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t('monitor.docker_cpu_usage')}
|
||||
description={t('monitor.docker_cpu_des')}
|
||||
@@ -400,6 +411,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
)}
|
||||
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t('monitor.total_memory_usage')}
|
||||
description={t('monitor.memory_des')}
|
||||
@@ -409,6 +421,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
|
||||
{containerFilterBar && (
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t('monitor.docker_memory_usage')}
|
||||
description={t('monitor.docker_memory_des')}
|
||||
@@ -418,7 +431,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
</ChartCard>
|
||||
)}
|
||||
|
||||
<ChartCard grid={grid} title={t('monitor.disk_space')} description={t('monitor.disk_des')}>
|
||||
<ChartCard empty={dataEmpty} grid={grid} title={t('monitor.disk_space')} description={t('monitor.disk_des')}>
|
||||
<DiskChart
|
||||
chartData={chartData}
|
||||
dataKey="stats.du"
|
||||
@@ -427,6 +440,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
</ChartCard>
|
||||
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t('monitor.disk_io')}
|
||||
description={t('monitor.disk_io_des')}
|
||||
@@ -440,6 +454,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
</ChartCard>
|
||||
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={t('monitor.bandwidth')}
|
||||
cornerEl={isLongerChart ? <SelectAvgMax store={bandwidthMaxStore} /> : null}
|
||||
@@ -460,6 +475,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
})}
|
||||
>
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
title={t('monitor.docker_network_io')}
|
||||
description={t('monitor.docker_network_io_des')}
|
||||
cornerEl={containerFilterBar}
|
||||
@@ -471,13 +487,13 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
)}
|
||||
|
||||
{(systemStats.at(-1)?.stats.su ?? 0) > 0 && (
|
||||
<ChartCard grid={grid} title={t('monitor.swap_usage')} description={t('monitor.swap_des')}>
|
||||
<ChartCard empty={dataEmpty} grid={grid} title={t('monitor.swap_usage')} description={t('monitor.swap_des')}>
|
||||
<SwapChart chartData={chartData} />
|
||||
</ChartCard>
|
||||
)}
|
||||
|
||||
{systemStats.at(-1)?.stats.t && (
|
||||
<ChartCard grid={grid} title={t('monitor.temperature')} description={t('monitor.temperature_des')}>
|
||||
<ChartCard empty={dataEmpty} grid={grid} title={t('monitor.temperature')} description={t('monitor.temperature_des')}>
|
||||
<TemperatureChart chartData={chartData} />
|
||||
</ChartCard>
|
||||
)}
|
||||
@@ -490,6 +506,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
return (
|
||||
<div key={extraFsName} className="contents">
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={`${extraFsName} ${t('monitor.usage')}`}
|
||||
description={`${t('monitor.disk_usage_of')} ${extraFsName}`}
|
||||
@@ -501,6 +518,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
/>
|
||||
</ChartCard>
|
||||
<ChartCard
|
||||
empty={dataEmpty}
|
||||
grid={grid}
|
||||
title={`${extraFsName} I/O`}
|
||||
description={`${t('monitor.throughput_of')} ${extraFsName}`}
|
||||
@@ -591,12 +609,14 @@ function ChartCard({
|
||||
description,
|
||||
children,
|
||||
grid,
|
||||
empty,
|
||||
cornerEl,
|
||||
}: {
|
||||
title: string
|
||||
description: string
|
||||
children: React.ReactNode
|
||||
grid?: boolean
|
||||
empty?: boolean,
|
||||
cornerEl?: JSX.Element | null
|
||||
}) {
|
||||
const { isIntersecting, ref } = useIntersectionObserver()
|
||||
@@ -616,7 +636,7 @@ function ChartCard({
|
||||
)}
|
||||
</CardHeader>
|
||||
<div className="pl-0 w-[calc(100%-1.6em)] h-52 relative">
|
||||
{<Spinner />}
|
||||
{<Spinner empty={empty} />}
|
||||
{isIntersecting && children}
|
||||
</div>
|
||||
</Card>
|
||||
|
@@ -1,9 +1,12 @@
|
||||
import { LoaderCircleIcon } from 'lucide-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
export default function () {
|
||||
export default function (props: { empty?: boolean }) {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<div className="grid place-content-center h-full absolute inset-0">
|
||||
<div className="flex flex-col items-center justify-center h-full absolute inset-0">
|
||||
<LoaderCircleIcon className="animate-spin h-10 w-10 opacity-60" />
|
||||
{props.empty && <p className={'opacity-60 mt-2'}>{t('monitor.waiting_for')}</p>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
|
||||
import en from '../locales/en/translation.json';
|
||||
import es from '../locales/es/translation.json';
|
||||
@@ -10,8 +9,32 @@ import ru from '../locales/ru/translation.json';
|
||||
import zhHans from '../locales/zh-CN/translation.json';
|
||||
import zhHant from '../locales/zh-HK/translation.json';
|
||||
|
||||
// Custom language detector to use localStorage
|
||||
const languageDetector: any = {
|
||||
type: 'languageDetector',
|
||||
async: true,
|
||||
detect: (callback: (lng: string) => void) => {
|
||||
const savedLanguage = localStorage.getItem('i18nextLng');
|
||||
const fallbackLanguage = (()=>{
|
||||
switch (navigator.language) {
|
||||
case 'zh-CN': case 'zh-SG': case 'zh-MY': case 'zh': case 'zh-Hans':
|
||||
return 'zh-CN';
|
||||
case 'zh-HK': case 'zh-TW': case 'zh-MO': case 'zh-Hant':
|
||||
return 'zh-HK';
|
||||
default:
|
||||
return navigator.language;
|
||||
}
|
||||
})();
|
||||
callback(savedLanguage || fallbackLanguage);
|
||||
},
|
||||
init: () => {},
|
||||
cacheUserLanguage: (lng: string) => {
|
||||
localStorage.setItem('i18nextLng', lng);
|
||||
}
|
||||
};
|
||||
|
||||
i18n
|
||||
.use(LanguageDetector)
|
||||
.use(languageDetector)
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
resources: {
|
||||
|
@@ -173,6 +173,22 @@
|
||||
"temperature_des": "Temperaturen der System-Sensoren",
|
||||
"usage": "Nutzung",
|
||||
"disk_usage_of": "Festplattennutzung von",
|
||||
"throughput_of": "Durchsatz von"
|
||||
"throughput_of": "Durchsatz von",
|
||||
"waiting_for": "Warten auf genügend Datensätze zur Anzeige"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Bitte melden Sie sich bei Ihrem Konto an",
|
||||
"reset": "E-Mail-Adresse eingeben, um das Passwort zurückzusetzen",
|
||||
"create": "Bitte erstellen Sie ein Administratorkonto",
|
||||
"create_account": "Konto erstellen",
|
||||
"sign_in": "Anmelden",
|
||||
"openid_des": "Beszel unterstützt OpenID Connect und viele OAuth2-Authentifizierungsanbieter.",
|
||||
"please_view_the": "Bitte sehen Sie sich die",
|
||||
"for_instructions": "für Anweisungen an.",
|
||||
"forgot_password": "Passwort vergessen?",
|
||||
"reset_password": "Passwort zurücksetzen",
|
||||
"command_line_instructions": "Befehlszeilenanweisungen",
|
||||
"command_1": "Wenn Sie das Passwort für Ihr Administratorkonto verloren haben, können Sie es mit dem folgenden Befehl zurücksetzen.",
|
||||
"command_2": "Melden Sie sich dann im Backend an und setzen Sie das Passwort Ihres Benutzerkontos in der Benutzertabelle zurück."
|
||||
}
|
||||
}
|
@@ -1,178 +1,193 @@
|
||||
{
|
||||
"all_systems": "All Systems",
|
||||
"filter": "Filter...",
|
||||
"copy": "Copy",
|
||||
"add": "Add",
|
||||
"system": "System",
|
||||
"systems": "Systems",
|
||||
"cancel": "Cancel",
|
||||
"continue": "Continue",
|
||||
"home": {
|
||||
"active_alerts": "Active Alerts",
|
||||
"active_des": "Exceeds {{value}}{{unit}} average in last {{minutes}} min",
|
||||
"subtitle_1": "Updated in real time. Click on a system to view information.",
|
||||
"subtitle_2": "to open the command palette."
|
||||
},
|
||||
"systems_table": {
|
||||
"system": "System",
|
||||
"memory": "Memory",
|
||||
"cpu": "CPU",
|
||||
"disk": "Disk",
|
||||
"net": "Net",
|
||||
"agent": "Agent",
|
||||
"no_systems_found": "No systems found.",
|
||||
"open_menu": "Open menu",
|
||||
"resume": "Resume",
|
||||
"pause": "Pause",
|
||||
"copy_host": "Copy host",
|
||||
"delete": "Delete",
|
||||
"delete_confirm": "Are you sure you want to delete {{name}}?",
|
||||
"delete_confirm_des_1": "This action cannot be undone. This will permanently delete all current records for",
|
||||
"delete_confirm_des_2": "from the database."
|
||||
},
|
||||
"alerts": {
|
||||
"title": "Alerts",
|
||||
"subtitle_1": "See",
|
||||
"notification_settings": "notification settings",
|
||||
"subtitle_2": "to configure how you receive alerts.",
|
||||
"overwrite_existing_alerts": "Overwrite existing alerts",
|
||||
"info": {
|
||||
"status": "Status",
|
||||
"status_des": "Triggers when status switches between up and down.",
|
||||
"cpu_usage": "CPU Usage",
|
||||
"cpu_usage_des": "Triggers when CPU usage exceeds a threshold.",
|
||||
"memory_usage": "Memory Usage",
|
||||
"memory_usage_des": "Triggers when memory usage exceeds a threshold.",
|
||||
"disk_usage": "Disk Usage",
|
||||
"disk_usage_des": "Triggers when usage of any disk exceeds a threshold.",
|
||||
"bandwidth": "Bandwidth",
|
||||
"bandwidth_des": "Triggers when combined up/down exceeds a threshold.",
|
||||
"temperature": "Temperature",
|
||||
"temperature_des": "Triggers when any sensor exceeds a threshold."
|
||||
},
|
||||
"average_exceeds": "Average exceeds",
|
||||
"for": "For",
|
||||
"minute": "minute",
|
||||
"minutes": "minutes"
|
||||
},
|
||||
"settings": {
|
||||
"settings": "Settings",
|
||||
"subtitle": "Manage display and notification preferences.",
|
||||
"save_settings": "Save Settings",
|
||||
"export_configuration": "Export configuration",
|
||||
"general": {
|
||||
"title": "General",
|
||||
"subtitle": "Change general application options.",
|
||||
"language": {
|
||||
"title": "Language",
|
||||
"subtitle_1": "Want to help us make our translations even better? Check out",
|
||||
"subtitle_2": "for more details.",
|
||||
"preferred_language": "Preferred Language"
|
||||
},
|
||||
"chart_options": {
|
||||
"title": "Chart options",
|
||||
"subtitle": "Adjust display options for charts.",
|
||||
"default_time_period": "Default time period",
|
||||
"default_time_period_des": "Sets the default time range for charts when a system is viewed."
|
||||
}
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Notifications",
|
||||
"subtitle_1": "Configure how you receive alert notifications.",
|
||||
"subtitle_2": "Looking instead for where to create alerts? Click the bell",
|
||||
"subtitle_3": "icons in the systems table.",
|
||||
"email": {
|
||||
"title": "Email notifications",
|
||||
"please": "Please",
|
||||
"configure_an_SMTP_server": "configure an SMTP server",
|
||||
"to_ensure_alerts_are_delivered": "to ensure alerts are delivered.",
|
||||
"to_email_s": "To email(s)",
|
||||
"enter_email_address": "Enter email address...",
|
||||
"des": "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
},
|
||||
"webhook_push": {
|
||||
"title": "Webhook / Push notifications",
|
||||
"des_1": "Beszel uses",
|
||||
"des_2": "to integrate with popular notification services.",
|
||||
"add_url": "Add URL"
|
||||
}
|
||||
},
|
||||
"yaml_config": {
|
||||
"short_title": "YAML Config",
|
||||
"title": "YAML Configuration",
|
||||
"subtitle": "Export your current systems configuration.",
|
||||
"des_1": "Systems may be managed in a",
|
||||
"des_2": "file inside your data directory.",
|
||||
"des_3": "On each restart, systems in the database will be updated to match the systems defined in the file.",
|
||||
"alert": {
|
||||
"title": "Caution - potential data loss",
|
||||
"des_1": "Existing systems not defined in",
|
||||
"des_2": "will be deleted. Please make regular backups."
|
||||
}
|
||||
},
|
||||
"language": "Language"
|
||||
},
|
||||
"user_dm": {
|
||||
"users": "Users",
|
||||
"logs": "Logs",
|
||||
"backups": "Backups",
|
||||
"auth_providers": "Auth Providers",
|
||||
"log_out": "Log Out"
|
||||
},
|
||||
"themes": {
|
||||
"toggle_theme": "Toggle theme",
|
||||
"light": "Light",
|
||||
"dark": "Dark",
|
||||
"system": "System"
|
||||
},
|
||||
"add_system": {
|
||||
"add_new_system": "Add New System",
|
||||
"binary": "Binary",
|
||||
"dialog_des_1": "The agent must be running on the system to connect. Copy the",
|
||||
"dialog_des_2": "for the agent below.",
|
||||
"name": "Name",
|
||||
"host_ip": "Host / IP",
|
||||
"port": "Port",
|
||||
"public_key": "Public Key",
|
||||
"click_to_copy": "Click to copy",
|
||||
"command": "command",
|
||||
"add_system": "Add system"
|
||||
},
|
||||
"command": {
|
||||
"search": "Search for systems or settings...",
|
||||
"pages_settings": "Pages / Settings",
|
||||
"dashboard": "Dashboard",
|
||||
"documentation": "Documentation",
|
||||
"SMTP_settings": "SMTP settings",
|
||||
"page": "Page",
|
||||
"admin": "Admin"
|
||||
},
|
||||
"monitor": {
|
||||
"toggle_grid": "Toggle grid",
|
||||
"average": "Average",
|
||||
"max_1_min": "Max 1 min ",
|
||||
"total_cpu_usage": "Total CPU Usage",
|
||||
"cpu_des": "system-wide CPU utilization",
|
||||
"docker_cpu_usage": "Docker CPU Usage",
|
||||
"docker_cpu_des": "Average CPU utilization of containers",
|
||||
"total_memory_usage": "Total Memory Usage",
|
||||
"memory_des": "Precise utilization at the recorded time",
|
||||
"docker_memory_usage": "Docker Memory Usage",
|
||||
"docker_memory_des": "Memory usage of docker containers",
|
||||
"disk_space": "Disk Space",
|
||||
"disk_des": "Usage of root partition",
|
||||
"disk_io": "Disk I/O",
|
||||
"disk_io_des": "Throughput of root filesystem",
|
||||
"bandwidth": "Bandwidth",
|
||||
"bandwidth_des": "Network traffic of public interfaces",
|
||||
"docker_network_io": "Docker Network I/O",
|
||||
"docker_network_io_des": "Network traffic of docker containers",
|
||||
"swap_usage": "Swap Usage",
|
||||
"swap_des": "Swap space used by the system",
|
||||
"temperature": "Temperature",
|
||||
"temperature_des": "Temperatures of system sensors",
|
||||
"usage": "Usage",
|
||||
"disk_usage_of": "Disk usage of",
|
||||
"throughput_of": "Throughput of"
|
||||
}
|
||||
"all_systems": "All Systems",
|
||||
"filter": "Filter...",
|
||||
"copy": "Copy",
|
||||
"add": "Add",
|
||||
"system": "System",
|
||||
"systems": "Systems",
|
||||
"cancel": "Cancel",
|
||||
"continue": "Continue",
|
||||
"home": {
|
||||
"active_alerts": "Active Alerts",
|
||||
"active_des": "Exceeds {{value}}{{unit}} average in last {{minutes}} minutes",
|
||||
"subtitle_1": "Updated in real time. Click on a system to view information.",
|
||||
},
|
||||
"systems_table": {
|
||||
"system": "System",
|
||||
"memory": "Memory",
|
||||
"cpu": "CPU",
|
||||
"disk": "Disk",
|
||||
"net": "Net",
|
||||
"agent": "Agent",
|
||||
"no_systems_found": "No systems found.",
|
||||
"open_menu": "Open menu",
|
||||
"resume": "Resume",
|
||||
"pause": "Pause",
|
||||
"copy_host": "Copy host",
|
||||
"delete": "Delete",
|
||||
"delete_confirm": "Are you sure you want to delete {{name}}?",
|
||||
"delete_confirm_des_1": "This action cannot be undone. This will permanently delete all current records for",
|
||||
"delete_confirm_des_2": "from the database."
|
||||
},
|
||||
"alerts": {
|
||||
"title": "Alerts",
|
||||
"subtitle_1": "See",
|
||||
"notification_settings": "notification settings",
|
||||
"subtitle_2": "to configure how you receive alerts.",
|
||||
"overwrite_existing_alerts": "Overwrite existing alerts",
|
||||
"info": {
|
||||
"status": "Status",
|
||||
"status_des": "Triggers when status switches between up and down.",
|
||||
"cpu_usage": "CPU Usage",
|
||||
"cpu_usage_des": "Triggers when CPU usage exceeds a threshold.",
|
||||
"memory_usage": "Memory Usage",
|
||||
"memory_usage_des": "Triggers when memory usage exceeds a threshold.",
|
||||
"disk_usage": "Disk Usage",
|
||||
"disk_usage_des": "Triggers when usage of any disk exceeds a threshold.",
|
||||
"bandwidth": "Bandwidth",
|
||||
"bandwidth_des": "Triggers when combined up/down exceeds a threshold.",
|
||||
"temperature": "Temperature",
|
||||
"temperature_des": "Triggers when any sensor exceeds a threshold."
|
||||
},
|
||||
"average_exceeds": "Average exceeds",
|
||||
"for": "For",
|
||||
"minute": "minute",
|
||||
"minutes": "minutes"
|
||||
},
|
||||
"settings": {
|
||||
"settings": "Settings",
|
||||
"subtitle": "Manage display and notification preferences.",
|
||||
"save_settings": "Save Settings",
|
||||
"export_configuration": "Export configuration",
|
||||
"general": {
|
||||
"title": "General",
|
||||
"subtitle": "Change general application options.",
|
||||
"language": {
|
||||
"title": "Language",
|
||||
"subtitle_1": "Want to help us make our translations even better? Check out",
|
||||
"subtitle_2": "for more details.",
|
||||
"preferred_language": "Preferred Language"
|
||||
},
|
||||
"chart_options": {
|
||||
"title": "Chart options",
|
||||
"subtitle": "Adjust display options for charts.",
|
||||
"default_time_period": "Default time period",
|
||||
"default_time_period_des": "Sets the default time range for charts when a system is viewed."
|
||||
}
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Notifications",
|
||||
"subtitle_1": "Configure how you receive alert notifications.",
|
||||
"subtitle_2": "Looking instead for where to create alerts? Click the bell",
|
||||
"subtitle_3": "icons in the systems table.",
|
||||
"email": {
|
||||
"title": "Email notifications",
|
||||
"please": "Please",
|
||||
"configure_an_SMTP_server": "configure an SMTP server",
|
||||
"to_ensure_alerts_are_delivered": "to ensure alerts are delivered.",
|
||||
"to_email_s": "To email(s)",
|
||||
"enter_email_address": "Enter email address...",
|
||||
"des": "Save address using enter key or comma. Leave blank to disable email notifications."
|
||||
},
|
||||
"webhook_push": {
|
||||
"title": "Webhook / Push notifications",
|
||||
"des_1": "Beszel uses",
|
||||
"des_2": "to integrate with popular notification services.",
|
||||
"add_url": "Add URL"
|
||||
}
|
||||
},
|
||||
"yaml_config": {
|
||||
"short_title": "YAML Config",
|
||||
"title": "YAML Configuration",
|
||||
"subtitle": "Export your current systems configuration.",
|
||||
"des_1": "Systems may be managed in a",
|
||||
"des_2": "file inside your data directory.",
|
||||
"des_3": "On each restart, systems in the database will be updated to match the systems defined in the file.",
|
||||
"alert": {
|
||||
"title": "Caution - potential data loss",
|
||||
"des_1": "Existing systems not defined in",
|
||||
"des_2": "will be deleted. Please make regular backups."
|
||||
}
|
||||
},
|
||||
"language": "Language"
|
||||
},
|
||||
"user_dm": {
|
||||
"users": "Users",
|
||||
"logs": "Logs",
|
||||
"backups": "Backups",
|
||||
"auth_providers": "Auth Providers",
|
||||
"log_out": "Log Out"
|
||||
},
|
||||
"themes": {
|
||||
"toggle_theme": "Toggle theme",
|
||||
"light": "Light",
|
||||
"dark": "Dark",
|
||||
"system": "System"
|
||||
},
|
||||
"add_system": {
|
||||
"add_new_system": "Add New System",
|
||||
"binary": "Binary",
|
||||
"dialog_des_1": "The agent must be running on the system to connect. Copy the",
|
||||
"dialog_des_2": "for the agent below.",
|
||||
"name": "Name",
|
||||
"host_ip": "Host / IP",
|
||||
"port": "Port",
|
||||
"public_key": "Public Key",
|
||||
"click_to_copy": "Click to copy",
|
||||
"command": "command",
|
||||
"add_system": "Add system"
|
||||
},
|
||||
"command": {
|
||||
"search": "Search for systems or settings...",
|
||||
"pages_settings": "Pages / Settings",
|
||||
"dashboard": "Dashboard",
|
||||
"documentation": "Documentation",
|
||||
"SMTP_settings": "SMTP settings",
|
||||
"page": "Page",
|
||||
"admin": "Admin"
|
||||
},
|
||||
"monitor": {
|
||||
"toggle_grid": "Toggle grid",
|
||||
"average": "Average",
|
||||
"max_1_min": "Max 1 min ",
|
||||
"total_cpu_usage": "Total CPU Usage",
|
||||
"cpu_des": "system-wide CPU utilization",
|
||||
"docker_cpu_usage": "Docker CPU Usage",
|
||||
"docker_cpu_des": "Average CPU utilization of containers",
|
||||
"total_memory_usage": "Total Memory Usage",
|
||||
"memory_des": "Precise utilization at the recorded time",
|
||||
"docker_memory_usage": "Docker Memory Usage",
|
||||
"docker_memory_des": "Memory usage of docker containers",
|
||||
"disk_space": "Disk Space",
|
||||
"disk_des": "Usage of root partition",
|
||||
"disk_io": "Disk I/O",
|
||||
"disk_io_des": "Throughput of root filesystem",
|
||||
"bandwidth": "Bandwidth",
|
||||
"bandwidth_des": "Network traffic of public interfaces",
|
||||
"docker_network_io": "Docker Network I/O",
|
||||
"docker_network_io_des": "Network traffic of docker containers",
|
||||
"swap_usage": "Swap Usage",
|
||||
"swap_des": "Swap space used by the system",
|
||||
"temperature": "Temperature",
|
||||
"temperature_des": "Temperatures of system sensors",
|
||||
"usage": "Usage",
|
||||
"disk_usage_of": "Disk usage of",
|
||||
"throughput_of": "Throughput of",
|
||||
"waiting_for": "Waiting for enough records to display"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Please sign in to your account",
|
||||
"reset": "Enter email address to reset password",
|
||||
"create": "Please create an admin account",
|
||||
"create_account": "Create account",
|
||||
"sign_in": "Sign in",
|
||||
"openid_des": "Beszel supports OpenID Connect and many OAuth2 authentication providers.",
|
||||
"please_view_the": "Please view the",
|
||||
"for_instructions": "for instructions.",
|
||||
"forgot_password": "Forgot password?",
|
||||
"reset_password": "Reset Password",
|
||||
"command_line_instructions": "Command line instructions",
|
||||
"command_1": "If you've lost the password to your admin account, you may reset it using the following command.",
|
||||
"command_2": "Then log into the backend and reset your user account password in the users table."
|
||||
}
|
||||
}
|
||||
|
@@ -173,6 +173,22 @@
|
||||
"temperature_des": "Temperaturas de los sensores del sistema",
|
||||
"usage": "Uso",
|
||||
"disk_usage_of": "Uso de disco de",
|
||||
"throughput_of": "Rendimiento de"
|
||||
"throughput_of": "Rendimiento de",
|
||||
"waiting_for": "Esperando suficientes registros para mostrar"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Por favor, inicie sesión en su cuenta",
|
||||
"reset": "Ingrese la dirección de correo electrónico para restablecer la contraseña",
|
||||
"create": "Por favor, cree una cuenta de administrador",
|
||||
"create_account": "Crear cuenta",
|
||||
"sign_in": "Iniciar sesión",
|
||||
"openid_des": "Beszel admite OpenID Connect y muchos proveedores de autenticación OAuth2.",
|
||||
"please_view_the": "Por favor, consulte el",
|
||||
"for_instructions": "para obtener instrucciones.",
|
||||
"forgot_password": "¿Olvidó su contraseña?",
|
||||
"reset_password": "Restablecer contraseña",
|
||||
"command_line_instructions": "Instrucciones de línea de comandos",
|
||||
"command_1": "Si ha perdido la contraseña de su cuenta de administrador, puede restablecerla usando el siguiente comando.",
|
||||
"command_2": "Luego inicie sesión en el backend y restablezca la contraseña de su cuenta de usuario en la tabla de usuarios."
|
||||
}
|
||||
}
|
@@ -173,6 +173,22 @@
|
||||
"temperature_des": "Températures des capteurs du système",
|
||||
"usage": "Utilisation",
|
||||
"disk_usage_of": "Utilisation du disque de",
|
||||
"throughput_of": "Débit de"
|
||||
"throughput_of": "Débit de",
|
||||
"waiting_for": "En attente de suffisamment d'enregistrements pour afficher"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Veuillez vous connecter à votre compte",
|
||||
"reset": "Entrez l'adresse e-mail pour réinitialiser le mot de passe",
|
||||
"create": "Veuillez créer un compte administrateur",
|
||||
"create_account": "Créer un compte",
|
||||
"sign_in": "Se connecter",
|
||||
"openid_des": "Beszel prend en charge OpenID Connect et de nombreux fournisseurs d'authentification OAuth2.",
|
||||
"please_view_the": "Veuillez consulter le",
|
||||
"for_instructions": "pour les instructions.",
|
||||
"forgot_password": "Mot de passe oublié ?",
|
||||
"reset_password": "Réinitialiser le mot de passe",
|
||||
"command_line_instructions": "Instructions en ligne de commande",
|
||||
"command_1": "Si vous avez perdu le mot de passe de votre compte administrateur, vous pouvez le réinitialiser en utilisant la commande suivante.",
|
||||
"command_2": "Ensuite, connectez-vous au backend et réinitialisez le mot de passe de votre compte utilisateur dans la table des utilisateurs."
|
||||
}
|
||||
}
|
@@ -173,6 +173,22 @@
|
||||
"temperature_des": "Температуры датчиков системы",
|
||||
"usage": "Использование",
|
||||
"disk_usage_of": "Использование диска",
|
||||
"throughput_of": "Пропускная способность"
|
||||
"throughput_of": "Пропускная способность",
|
||||
"waiting_for": "Ожидание достаточного количества записей для отображения"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Пожалуйста, войдите в свою учетную запись",
|
||||
"reset": "Введите адрес электронной почты для сброса пароля",
|
||||
"create": "Пожалуйста, создайте учетную запись администратора",
|
||||
"create_account": "Создать учетную запись",
|
||||
"sign_in": "Войти",
|
||||
"openid_des": "Beszel поддерживает OpenID Connect и многих поставщиков аутентификации OAuth2.",
|
||||
"please_view_the": "Пожалуйста, ознакомьтесь с",
|
||||
"for_instructions": "для получения инструкций.",
|
||||
"forgot_password": "Забыли пароль?",
|
||||
"reset_password": "Сбросить пароль",
|
||||
"command_line_instructions": "Инструкции по командной строке",
|
||||
"command_1": "Если вы потеряли пароль от своей учетной записи администратора, вы можете сбросить его, используя следующую команду.",
|
||||
"command_2": "Затем войдите в бэкэнд и сбросьте пароль своей учетной записи пользователя в таблице пользователей."
|
||||
}
|
||||
}
|
@@ -173,6 +173,22 @@
|
||||
"temperature_des": "系统传感器的温度",
|
||||
"usage": "使用率",
|
||||
"disk_usage_of": "的磁盘使用率",
|
||||
"throughput_of": "的吞吐量"
|
||||
"throughput_of": "的吞吐量",
|
||||
"waiting_for": "等待足够的记录以显示"
|
||||
},
|
||||
"auth": {
|
||||
"login": "请登入你的账户",
|
||||
"reset": "输入邮箱来重设密码",
|
||||
"create": "请创建管理员账户",
|
||||
"create_account": "创建账户",
|
||||
"sign_in": "登入",
|
||||
"openid_des": "Beszel 支持 OpenID Connect 和许多 OAuth2 认证提供商。",
|
||||
"please_view_the": "请检视",
|
||||
"for_instructions": "以获取更多信息。",
|
||||
"forgot_password": "忘记密码?",
|
||||
"reset_password": "重设密码",
|
||||
"command_line_instructions": "了解命令行指令",
|
||||
"command_1": "如果您忘记了管理员账户的密码,可以使用以下命令重置。",
|
||||
"command_2": "然后登录到后台,在用户表中重置您的用户账户密码。"
|
||||
}
|
||||
}
|
@@ -173,6 +173,22 @@
|
||||
"temperature_des": "系統感應器的溫度",
|
||||
"usage": "使用率",
|
||||
"disk_usage_of": "的磁碟使用率",
|
||||
"throughput_of": "的吞吐量"
|
||||
"throughput_of": "的吞吐量",
|
||||
"waiting_for": "等待足夠的記錄以顯示"
|
||||
},
|
||||
"auth": {
|
||||
"login": "請登入你的賬戶",
|
||||
"reset": "輸入電郵來重設密碼",
|
||||
"create": "請創建管理員賬戶",
|
||||
"create_account": "創建賬戶",
|
||||
"sign_in": "登入",
|
||||
"openid_des": "Beszel 支持 OpenID Connect 和許多 OAuth2 認證提供商。",
|
||||
"please_view_the": "請檢視",
|
||||
"for_instructions": "以獲取更多信息。",
|
||||
"forgot_password": "忘記密碼?",
|
||||
"reset_password": "重設密碼",
|
||||
"command_line_instructions": "了解命令行指令",
|
||||
"command_1": "如果您忘記了管理員賬戶的密碼,可以使用以下命令重置。",
|
||||
"command_2": "然後登入到後台,在用戶表中重置您的用戶賬戶密碼。"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user