add admin/user i18n

This commit is contained in:
Lokowitz 2025-05-06 06:49:47 +00:00
parent e38941adf1
commit 4dd9f4736d
4 changed files with 40 additions and 28 deletions

View file

@ -285,5 +285,17 @@
"apiKeysDeleteConfirm": "Confirm Delete API Key", "apiKeysDeleteConfirm": "Confirm Delete API Key",
"apiKeysDelete": "Delete API Key", "apiKeysDelete": "Delete API Key",
"apiKeysManage": "Manage API Keys", "apiKeysManage": "Manage API Keys",
"apiKeysDescription": "API keys are used to authenticate with the integration API" "apiKeysDescription": "API keys are used to authenticate with the integration API",
"userTitle": "Manage All Users",
"userDescription": "View and manage all users in the system",
"userAbount": "About User Management",
"userAbountDescription": "This table displays all root user objects in the system. Each user may belong to multiple organizations. Removing a user from an organization does not delete their root user object - they will remain in the system. To completely remove a user from the system, you must delete their root user object using the delete action in this table.",
"userServer": "Server Users",
"userSearch": "Search server users...",
"userErrorDelete": "Error deleting user",
"userDeleteConfirm": "Confirm Delete User",
"userDeleteServer": "Delete User from Server",
"userMessageRemove": "The user will be removed from all organizations and be completely removed from the server.",
"userMessageConfirm": "To confirm, please type the name of the user below.",
"userQuestionRemove": "Are you sure you want to permanently delete {selectedUser} from the server?"
} }

View file

@ -4,6 +4,7 @@ import {
ColumnDef, ColumnDef,
} from "@tanstack/react-table"; } from "@tanstack/react-table";
import { DataTable } from "@app/components/ui/data-table"; import { DataTable } from "@app/components/ui/data-table";
import { useTranslations } from 'next-intl';
interface DataTableProps<TData, TValue> { interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[]; columns: ColumnDef<TData, TValue>[];
@ -14,12 +15,15 @@ export function UsersDataTable<TData, TValue>({
columns, columns,
data data
}: DataTableProps<TData, TValue>) { }: DataTableProps<TData, TValue>) {
const t = useTranslations();
return ( return (
<DataTable <DataTable
columns={columns} columns={columns}
data={data} data={data}
title="Server Users" title={t('userServer')}
searchPlaceholder="Search server users..." searchPlaceholder={t('userSearch')}
searchColumn="email" searchColumn="email"
/> />
); );

View file

@ -11,6 +11,7 @@ import { toast } from "@app/hooks/useToast";
import { formatAxiosError } from "@app/lib/api"; import { formatAxiosError } from "@app/lib/api";
import { createApiClient } from "@app/lib/api"; import { createApiClient } from "@app/lib/api";
import { useEnvContext } from "@app/hooks/useEnvContext"; import { useEnvContext } from "@app/hooks/useEnvContext";
import { useTranslations } from 'next-intl';
export type GlobalUserRow = { export type GlobalUserRow = {
id: string; id: string;
@ -29,6 +30,7 @@ type Props = {
export default function UsersTable({ users }: Props) { export default function UsersTable({ users }: Props) {
const router = useRouter(); const router = useRouter();
const t = useTranslations();
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [selected, setSelected] = useState<GlobalUserRow | null>(null); const [selected, setSelected] = useState<GlobalUserRow | null>(null);
@ -42,8 +44,8 @@ export default function UsersTable({ users }: Props) {
console.error("Error deleting user", e); console.error("Error deleting user", e);
toast({ toast({
variant: "destructive", variant: "destructive",
title: "Error deleting user", title: t('userErrorDelete'),
description: formatAxiosError(e, "Error deleting user") description: formatAxiosError(e, t('userErrorDelete'))
}); });
}) })
.then(() => { .then(() => {
@ -82,7 +84,7 @@ export default function UsersTable({ users }: Props) {
column.toggleSorting(column.getIsSorted() === "asc") column.toggleSorting(column.getIsSorted() === "asc")
} }
> >
Username {t('username')}
<ArrowUpDown className="ml-2 h-4 w-4" /> <ArrowUpDown className="ml-2 h-4 w-4" />
</Button> </Button>
); );
@ -98,7 +100,7 @@ export default function UsersTable({ users }: Props) {
column.toggleSorting(column.getIsSorted() === "asc") column.toggleSorting(column.getIsSorted() === "asc")
} }
> >
Email {t('email')}
<ArrowUpDown className="ml-2 h-4 w-4" /> <ArrowUpDown className="ml-2 h-4 w-4" />
</Button> </Button>
); );
@ -114,7 +116,7 @@ export default function UsersTable({ users }: Props) {
column.toggleSorting(column.getIsSorted() === "asc") column.toggleSorting(column.getIsSorted() === "asc")
} }
> >
Name {t('name')}
<ArrowUpDown className="ml-2 h-4 w-4" /> <ArrowUpDown className="ml-2 h-4 w-4" />
</Button> </Button>
); );
@ -130,7 +132,7 @@ export default function UsersTable({ users }: Props) {
column.toggleSorting(column.getIsSorted() === "asc") column.toggleSorting(column.getIsSorted() === "asc")
} }
> >
Identity Provider {t('identityProvider')}
<ArrowUpDown className="ml-2 h-4 w-4" /> <ArrowUpDown className="ml-2 h-4 w-4" />
</Button> </Button>
); );
@ -151,7 +153,7 @@ export default function UsersTable({ users }: Props) {
setIsDeleteModalOpen(true); setIsDeleteModalOpen(true);
}} }}
> >
Delete {t('delete')}
</Button> </Button>
</div> </div>
</> </>
@ -172,35 +174,26 @@ export default function UsersTable({ users }: Props) {
dialog={ dialog={
<div className="space-y-4"> <div className="space-y-4">
<p> <p>
Are you sure you want to permanently delete{" "} {t('userQuestionRemove', {selectedUser: selected?.email || selected?.name || selected?.username})}
<b className="break-all">
{selected?.email ||
selected?.name ||
selected?.username}
</b>{" "}
from the server?
</p> </p>
<p> <p>
<b> <b>
The user will be removed from all {t('userMessageRemove')}
organizations and be completely removed from
the server.
</b> </b>
</p> </p>
<p> <p>
To confirm, please type the name of the user {t('userMessageConfirm')}
below.
</p> </p>
</div> </div>
} }
buttonText="Confirm Delete User" buttonText={t('userDeleteConfirm')}
onConfirm={async () => deleteUser(selected!.id)} onConfirm={async () => deleteUser(selected!.id)}
string={ string={
selected.email || selected.name || selected.username selected.email || selected.name || selected.username
} }
title="Delete User from Server" title={t('userDeleteServer')}
/> />
)} )}

View file

@ -6,6 +6,7 @@ import { AdminListUsersResponse } from "@server/routers/user/adminListUsers";
import UsersTable, { GlobalUserRow } from "./AdminUsersTable"; import UsersTable, { GlobalUserRow } from "./AdminUsersTable";
import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert"; import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert";
import { InfoIcon } from "lucide-react"; import { InfoIcon } from "lucide-react";
import { getTranslations } from 'next-intl/server';
type PageProps = { type PageProps = {
params: Promise<{ orgId: string }>; params: Promise<{ orgId: string }>;
@ -39,17 +40,19 @@ export default async function UsersPage(props: PageProps) {
}; };
}); });
const t = await getTranslations();
return ( return (
<> <>
<SettingsSectionTitle <SettingsSectionTitle
title="Manage All Users" title={t('userTitle')}
description="View and manage all users in the system" description={t('userDescription')}
/> />
<Alert variant="neutral" className="mb-6"> <Alert variant="neutral" className="mb-6">
<InfoIcon className="h-4 w-4" /> <InfoIcon className="h-4 w-4" />
<AlertTitle className="font-semibold">About User Management</AlertTitle> <AlertTitle className="font-semibold">{t('userAbount')}</AlertTitle>
<AlertDescription> <AlertDescription>
This table displays all root user objects in the system. Each user may belong to multiple organizations. Removing a user from an organization does not delete their root user object - they will remain in the system. To completely remove a user from the system, you must delete their root user object using the delete action in this table. {t('userAbountDescription')}
</AlertDescription> </AlertDescription>
</Alert> </Alert>
<UsersTable users={userRows} /> <UsersTable users={userRows} />