diff --git a/dashboard/public/locales/en.json b/dashboard/public/locales/en.json index d347a2d..9f560be 100644 --- a/dashboard/public/locales/en.json +++ b/dashboard/public/locales/en.json @@ -121,6 +121,10 @@ }, "nodes": { "settings": { + "no-backend-alert": { + "title": "No backend is configured for this node", + "desc": "Please take required measures and configure a backend for this node." + }, "title": "Nodes Settings", "detail": "Details", "log-container": { diff --git a/dashboard/public/locales/fa.json b/dashboard/public/locales/fa.json index 22b2ef6..c63b5b1 100644 --- a/dashboard/public/locales/fa.json +++ b/dashboard/public/locales/fa.json @@ -117,6 +117,10 @@ }, "nodes": { "settings": { + "no-backend-alert": { + "title": "هیچ بکندی برای این نود تنظیم نشده است.", + "desc": "لطفا اقدامات لازم جهت افزودن بکندی به این نود را انجام دهید." + }, "title": "تنظیمات نود", "detail": "جزئیات", "log-container": { diff --git a/dashboard/src/components/alert-card/index.tsx b/dashboard/src/components/alert-card/index.tsx new file mode 100644 index 0000000..838a604 --- /dev/null +++ b/dashboard/src/components/alert-card/index.tsx @@ -0,0 +1,20 @@ +import { Info, TriangleAlert, OctagonAlert } from 'lucide-react'; +import { + Alert, + AlertDescription, + AlertTitle, +} from '@marzneshin/components'; + +export const AlertCard = ({ title, desc, variant = "default" }: { variant?: "warning" | "default" | "destructive", title: string | JSX.Element, desc: string | JSX.Element }) => { + const Icon = variant === "warning" ? TriangleAlert : (variant === "destructive" ? OctagonAlert : Info) + return ( + + + {title} + + {desc} + + + ) +} + diff --git a/dashboard/src/components/index.ts b/dashboard/src/components/index.ts index 147cac2..168a40b 100644 --- a/dashboard/src/components/index.ts +++ b/dashboard/src/components/index.ts @@ -20,3 +20,4 @@ export * from "./info-table"; export * from "./skeletons"; export * from "./no-propogation-button"; export * from "./form-fields"; +export * from "./alert-card"; diff --git a/dashboard/src/components/ui/alert.tsx b/dashboard/src/components/ui/alert.tsx index 1cda26e..9f22b3a 100644 --- a/dashboard/src/components/ui/alert.tsx +++ b/dashboard/src/components/ui/alert.tsx @@ -4,55 +4,57 @@ import { cva, type VariantProps } from "class-variance-authority" import { cn } from "@marzneshin/utils" const alertVariants = cva( - "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", - { - variants: { - variant: { - default: "bg-background text-foreground", - destructive: - "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", - }, - }, - defaultVariants: { - variant: "default", - }, - } + "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", + { + variants: { + variant: { + default: "bg-background text-foreground", + warning: + "border-yellow/50 text-yellow dark:border-yellow [&>svg]:text-yellow", + destructive: + "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", + }, + }, + defaultVariants: { + variant: "default", + }, + } ) const Alert = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes & VariantProps + HTMLDivElement, + React.HTMLAttributes & VariantProps >(({ className, variant, ...props }, ref) => ( - + )) Alert.displayName = "Alert" const AlertTitle = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes + HTMLParagraphElement, + React.HTMLAttributes >(({ className, ...props }, ref) => ( - + )) AlertTitle.displayName = "AlertTitle" const AlertDescription = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes + HTMLParagraphElement, + React.HTMLAttributes >(({ className, ...props }, ref) => ( - + )) AlertDescription.displayName = "AlertDescription" diff --git a/dashboard/src/features/nodes/dialogs/settings/index.tsx b/dashboard/src/features/nodes/dialogs/settings/index.tsx index 5ceaefd..16424b6 100644 --- a/dashboard/src/features/nodes/dialogs/settings/index.tsx +++ b/dashboard/src/features/nodes/dialogs/settings/index.tsx @@ -1,10 +1,11 @@ import { - type SettingsDialogProps, - SettingsDialog, - Tabs, - TabsContent, - TabsList, - TabsTrigger, + type SettingsDialogProps, + SettingsDialog, + Tabs, + TabsContent, + TabsList, + TabsTrigger, + AlertCard, } from "@marzneshin/components"; import type { FC } from "react"; import { useTranslation } from "react-i18next"; @@ -13,51 +14,59 @@ import { NodesDetailTable } from "../../tables/detail-table"; import { NodeBackendSetting } from "./node-backend-setting"; interface NodesSettingsDialogProps extends SettingsDialogProps { - entity: NodeType; - onClose: () => void; + entity: NodeType; + onClose: () => void; } export const NodesSettingsDialog: FC = ({ - onOpenChange, - open, - entity, - onClose, + onOpenChange, + open, + entity, + onClose, }) => { - const { t } = useTranslation(); + const { t } = useTranslation(); - return ( - - - - {t("page.nodes.settings.detail")} - - - - - - {...entity.backends.map((backend: NodeBackendType) => ( - - {backend.name} - - ))} - - {...entity.backends.map((backend: NodeBackendType) => ( - - - - ))} - - - ); + return ( + + + + {t("page.nodes.settings.detail")} + + + + {entity.backends.length === 0 ? ( + + ) : ( + + + {...entity.backends.map((backend: NodeBackendType) => ( + + {backend.name} + + ))} + + {...entity.backends.map((backend: NodeBackendType) => ( + + + + ))} + + )} + + ); }; diff --git a/dashboard/src/features/users/components/no-service-alert/index.tsx b/dashboard/src/features/users/components/no-service-alert/index.tsx index 0f9f43e..2e00f91 100644 --- a/dashboard/src/features/users/components/no-service-alert/index.tsx +++ b/dashboard/src/features/users/components/no-service-alert/index.tsx @@ -1,25 +1,23 @@ import { useServicesQuery } from '@marzneshin/features/services'; -import { ExclamationTriangleIcon } from '@radix-ui/react-icons'; import { Link } from '@tanstack/react-router' import { useTranslation } from 'react-i18next'; import { - Alert, - AlertDescription, - AlertTitle, + AlertCard, } from '@marzneshin/components'; export const UsersNoServiceAlert = () => { const { t } = useTranslation(); const { data } = useServicesQuery({ page: 1, size: 10 }); return (data && data.pageCount === 0) && ( - - - {t('page.users.services-alert.title')} - - {t('page.users.services-alert.desc')} - {t('page.nodes.certificate-alert.click')} - - + + {t('page.users.services-alert.desc')} + {t('page.nodes.certificate-alert.click')} + > + } + /> ) } diff --git a/dashboard/src/routes/_dashboard/nodes.lazy.tsx b/dashboard/src/routes/_dashboard/nodes.lazy.tsx index f0e8d88..12ede6a 100644 --- a/dashboard/src/routes/_dashboard/nodes.lazy.tsx +++ b/dashboard/src/routes/_dashboard/nodes.lazy.tsx @@ -1,7 +1,5 @@ import { - Alert, - AlertDescription, - AlertTitle, + AlertCard, Card, CardContent, CardFooter, @@ -12,7 +10,6 @@ import { } from '@marzneshin/components'; import { NodesTable } from '@marzneshin/features/nodes'; import { Link, createFileRoute, Outlet } from '@tanstack/react-router' -import { Info } from 'lucide-react'; import { type FC, Suspense } from 'react'; import { useTranslation } from 'react-i18next'; import { SudoRoute } from "@marzneshin/features/sudo-routes"; @@ -34,14 +31,15 @@ export const NodesPage: FC = () => { - - - {t('page.nodes.certificate-alert.title')} - - {t('page.nodes.certificate-alert.desc')} - {t('page.nodes.certificate-alert.click')} - - + + {t('page.nodes.certificate-alert.desc')} + {t('page.nodes.certificate-alert.click')} + > + } + />