mirror of
https://github.com/Buriburizaem0n/admin-frontend-domain.git
synced 2026-02-04 12:40:08 +00:00
fix: i18n (#71)
* fix: block_identifier text * fix: i18n * chore: auto-fix linting and formatting issues * fix: block button * fix: ConfirmBlock text * fix: i18n --------- Co-authored-by: hamster1963 <hamster1963@users.noreply.github.com>
This commit is contained in:
@@ -21,6 +21,12 @@ interface ButtonGroupProps<E, U> {
|
|||||||
delete: { fn: (id: E[]) => Promise<void>; id: E; mutate: KeyedMutator<U> }
|
delete: { fn: (id: E[]) => Promise<void>; id: E; mutate: KeyedMutator<U> }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface BlockButtonGroupProps<E, U> {
|
||||||
|
className?: string
|
||||||
|
children?: React.ReactNode
|
||||||
|
block: { fn: (id: E[]) => Promise<void>; id: E; mutate: KeyedMutator<U> }
|
||||||
|
}
|
||||||
|
|
||||||
export function ActionButtonGroup<E, U>({
|
export function ActionButtonGroup<E, U>({
|
||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
@@ -66,3 +72,49 @@ export function ActionButtonGroup<E, U>({
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function BlockButtonGroup<E, U>({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
block: { fn, id, mutate },
|
||||||
|
}: BlockButtonGroupProps<E, U>) {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
const handleBlock = async () => {
|
||||||
|
try {
|
||||||
|
await fn([id])
|
||||||
|
} catch (error: any) {
|
||||||
|
toast(t("Error"), {
|
||||||
|
description: error.message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
await mutate()
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
{children}
|
||||||
|
<AlertDialog>
|
||||||
|
<AlertDialogTrigger asChild>
|
||||||
|
<IconButton variant="destructive" icon="ban" />
|
||||||
|
</AlertDialogTrigger>
|
||||||
|
<AlertDialogContent className="sm:max-w-lg">
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>{t("ConfirmBlock")}</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>
|
||||||
|
{t("Results.ThisOperationIsUnrecoverable")}
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel>{t("Close")}</AlertDialogCancel>
|
||||||
|
<AlertDialogAction
|
||||||
|
className={buttonVariants({ variant: "destructive" })}
|
||||||
|
onClick={handleBlock}
|
||||||
|
>
|
||||||
|
{t("Confirm")}
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ interface ButtonGroupProps<E, U> {
|
|||||||
delete: { fn: (id: E[]) => Promise<void>; id: E[]; mutate: KeyedMutator<U> }
|
delete: { fn: (id: E[]) => Promise<void>; id: E[]; mutate: KeyedMutator<U> }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ButtonBlockGroupProps<E, U> {
|
||||||
|
className?: string
|
||||||
|
children?: React.ReactNode
|
||||||
|
block: { fn: (id: E[]) => Promise<void>; id: E[]; mutate: KeyedMutator<U> }
|
||||||
|
}
|
||||||
|
|
||||||
export function HeaderButtonGroup<E, U>({
|
export function HeaderButtonGroup<E, U>({
|
||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
@@ -83,3 +89,66 @@ export function HeaderButtonGroup<E, U>({
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function HeaderBlockButtonGroup<E, U>({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
block: { fn, id, mutate },
|
||||||
|
}: ButtonBlockGroupProps<E, U>) {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
const handleBlock = async () => {
|
||||||
|
try {
|
||||||
|
await fn(id)
|
||||||
|
} catch (error: any) {
|
||||||
|
toast(t("Error"), {
|
||||||
|
description: error.message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
await mutate()
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
{id.length < 1 ? (
|
||||||
|
<>
|
||||||
|
<IconButton
|
||||||
|
variant="destructive"
|
||||||
|
icon="ban"
|
||||||
|
onClick={() => {
|
||||||
|
toast(t("Error"), {
|
||||||
|
description: t("Results.NoRowsAreSelected"),
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<AlertDialog>
|
||||||
|
<AlertDialogTrigger asChild>
|
||||||
|
<IconButton variant="destructive" icon="trash" />
|
||||||
|
</AlertDialogTrigger>
|
||||||
|
<AlertDialogContent className="sm:max-w-lg">
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>{t("ConfirmBlock")}</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>
|
||||||
|
{t("Results.ThisOperationIsUnrecoverable")}
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel>{t("Close")}</AlertDialogCancel>
|
||||||
|
<AlertDialogAction
|
||||||
|
className={buttonVariants({ variant: "destructive" })}
|
||||||
|
onClick={handleBlock}
|
||||||
|
>
|
||||||
|
{t("Confirm")}
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Button, ButtonProps } from "@/components/ui/button"
|
import { Button, ButtonProps } from "@/components/ui/button"
|
||||||
import {
|
import {
|
||||||
|
BanIcon,
|
||||||
Check,
|
Check,
|
||||||
CircleArrowUp,
|
CircleArrowUp,
|
||||||
Clipboard,
|
Clipboard,
|
||||||
@@ -29,6 +30,7 @@ export interface IconButtonProps extends ButtonProps {
|
|||||||
| "download"
|
| "download"
|
||||||
| "upload"
|
| "upload"
|
||||||
| "menu"
|
| "menu"
|
||||||
|
| "ban"
|
||||||
}
|
}
|
||||||
|
|
||||||
export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>((props, ref) => {
|
export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>((props, ref) => {
|
||||||
@@ -77,6 +79,9 @@ export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>((props,
|
|||||||
case "menu": {
|
case "menu": {
|
||||||
return <Menu />
|
return <Menu />
|
||||||
}
|
}
|
||||||
|
case "ban": {
|
||||||
|
return <BanIcon />
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})()}
|
})()}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -164,5 +164,15 @@
|
|||||||
"CommunityThemeDescription": "This theme is provided by the community, use at your own risk",
|
"CommunityThemeDescription": "This theme is provided by the community, use at your own risk",
|
||||||
"Cancel": "Cancel",
|
"Cancel": "Cancel",
|
||||||
"EnableDDNS": "Enable DDNS",
|
"EnableDDNS": "Enable DDNS",
|
||||||
"PushSuccessful": "Push if Successful"
|
"PushSuccessful": "Push if Successful",
|
||||||
|
"GrpcAuthFailed": "gRPC authentication failed",
|
||||||
|
"APITokenInvalid": "API token is invalid",
|
||||||
|
"UserInvalid": "User is invalid",
|
||||||
|
"BlockByUser": "Blocked by user",
|
||||||
|
"BlockIdentifier": "Block identifier",
|
||||||
|
"UserId": "User ID",
|
||||||
|
"ConnectedAt": "Connected at",
|
||||||
|
"OnlineUser": "Online User",
|
||||||
|
"Total": "Total",
|
||||||
|
"ConfirmBlock": "Confirm Block"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,5 +164,15 @@
|
|||||||
"CommunityThemeDescription": "社区主题未经官方审计,需自行甄别风险",
|
"CommunityThemeDescription": "社区主题未经官方审计,需自行甄别风险",
|
||||||
"Cancel": "取消",
|
"Cancel": "取消",
|
||||||
"EnableDDNS": "启用 DDNS",
|
"EnableDDNS": "启用 DDNS",
|
||||||
"PushSuccessful": "推送成功的通知"
|
"PushSuccessful": "推送成功的通知",
|
||||||
|
"GrpcAuthFailed": "gRPC 认证失败",
|
||||||
|
"APITokenInvalid": "API 令牌无效",
|
||||||
|
"UserInvalid": "用户无效",
|
||||||
|
"BlockByUser": "被用户封禁",
|
||||||
|
"BlockIdentifier": "封禁标识",
|
||||||
|
"UserId": "用户 ID",
|
||||||
|
"ConnectedAt": "连接时间",
|
||||||
|
"OnlineUser": "在线用户",
|
||||||
|
"Total": "总数",
|
||||||
|
"ConfirmBlock": "确认封禁"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,5 +164,15 @@
|
|||||||
"CommunityThemeDescription": "社群主題未經官方審計,需自行甄別風險",
|
"CommunityThemeDescription": "社群主題未經官方審計,需自行甄別風險",
|
||||||
"Cancel": "取消",
|
"Cancel": "取消",
|
||||||
"EnableDDNS": "啟用 DDNS",
|
"EnableDDNS": "啟用 DDNS",
|
||||||
"PushSuccessful": "推送成功的通知"
|
"PushSuccessful": "推送成功的通知",
|
||||||
|
"GrpcAuthFailed": "gRPC 認證失敗",
|
||||||
|
"APITokenInvalid": "API 令牌無效",
|
||||||
|
"UserInvalid": "使用者無效",
|
||||||
|
"BlockByUser": "被使用者封鎖",
|
||||||
|
"BlockIdentifier": "封鎖標識符",
|
||||||
|
"UserId": "使用者 ID",
|
||||||
|
"ConnectedAt": "連接時間",
|
||||||
|
"OnlineUser": "線上使用者",
|
||||||
|
"Total": "總數",
|
||||||
|
"ConfirmBlock": "確認封鎖"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { swrFetcher } from "@/api/api"
|
import { swrFetcher } from "@/api/api"
|
||||||
import { blockUser } from "@/api/online-user"
|
import { blockUser } from "@/api/online-user"
|
||||||
import { ActionButtonGroup } from "@/components/action-button-group"
|
import { BlockButtonGroup } from "@/components/action-button-group"
|
||||||
import { HeaderButtonGroup } from "@/components/header-button-group"
|
import { HeaderBlockButtonGroup } from "@/components/header-button-group"
|
||||||
import { SettingsTab } from "@/components/settings-tab"
|
import { SettingsTab } from "@/components/settings-tab"
|
||||||
import { Checkbox } from "@/components/ui/checkbox"
|
import { Checkbox } from "@/components/ui/checkbox"
|
||||||
import {
|
import {
|
||||||
@@ -104,16 +104,16 @@ export default function OnlineUserPage() {
|
|||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const s = row.original
|
const s = row.original
|
||||||
return (
|
return (
|
||||||
<ActionButtonGroup
|
<BlockButtonGroup
|
||||||
className="flex gap-2"
|
className="flex gap-2"
|
||||||
delete={{
|
block={{
|
||||||
fn: blockUser,
|
fn: blockUser,
|
||||||
id: s.ip ?? "",
|
id: s.ip ?? "",
|
||||||
mutate: mutate,
|
mutate: mutate,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<></>
|
<></>
|
||||||
</ActionButtonGroup>
|
</BlockButtonGroup>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -242,16 +242,16 @@ export default function OnlineUserPage() {
|
|||||||
<SettingsTab className="mt-6 w-full" />
|
<SettingsTab className="mt-6 w-full" />
|
||||||
<div className="flex mt-4 mb-4">
|
<div className="flex mt-4 mb-4">
|
||||||
{isAdmin && (
|
{isAdmin && (
|
||||||
<HeaderButtonGroup
|
<HeaderBlockButtonGroup
|
||||||
className="flex-2 flex gap-2 ml-auto"
|
className="flex-2 flex gap-2 ml-auto"
|
||||||
delete={{
|
block={{
|
||||||
fn: blockUser,
|
fn: blockUser,
|
||||||
id: selectedRows.map((r) => r.original.ip ?? ""),
|
id: selectedRows.map((r) => r.original.ip ?? ""),
|
||||||
mutate: mutate,
|
mutate: mutate,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<></>
|
<></>
|
||||||
</HeaderButtonGroup>
|
</HeaderBlockButtonGroup>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Table>
|
<Table>
|
||||||
|
|||||||
@@ -96,11 +96,11 @@ export default function WAFPage() {
|
|||||||
cell: ({ row }) => <span>{wafBlockReasons[row.original.block_reason] || ""}</span>,
|
cell: ({ row }) => <span>{wafBlockReasons[row.original.block_reason] || ""}</span>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: t("LastBlockIdentifier"),
|
header: t("BlockIdentifier"),
|
||||||
accessorKey: "lastBlockIdentifier",
|
accessorKey: "BlockIdentifier",
|
||||||
accessorFn: (row) => (
|
accessorFn: (row) => {
|
||||||
<span>{wafBlockIdentifiers[row.block_identifier] || row.block_identifier}</span>
|
return wafBlockIdentifiers[row.block_identifier] || row.block_identifier
|
||||||
),
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: t("LastBlockTime"),
|
header: t("LastBlockTime"),
|
||||||
|
|||||||
Reference in New Issue
Block a user