Merge pull request #16 from vlalx/i18n_admin_api_keys

i18n in admin/api-keys
This commit is contained in:
Marvin
2025-05-06 14:10:27 +02:00
committed by GitHub
15 changed files with 76 additions and 58 deletions

View File

@@ -286,6 +286,7 @@
"apiKeysDelete": "API-Schlüssel löschen", "apiKeysDelete": "API-Schlüssel löschen",
"apiKeysManage": "API-Schlüssel verwalten", "apiKeysManage": "API-Schlüssel verwalten",
"apiKeysDescription": "API-Schlüssel werden zur Authentifizierung mit der Integrations-API verwendet", "apiKeysDescription": "API-Schlüssel werden zur Authentifizierung mit der Integrations-API verwendet",
"apiKeysSettings": "{apiKeyName} Einstellungen",
"userTitle": "Alle Benutzer verwalten", "userTitle": "Alle Benutzer verwalten",
"userDescription": "Alle Benutzer im System anzeigen und verwalten", "userDescription": "Alle Benutzer im System anzeigen und verwalten",
"userAbount": "Über Benutzerverwaltung", "userAbount": "Über Benutzerverwaltung",

View File

@@ -286,6 +286,7 @@
"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",
"apiKeysSettings": "{apiKeyName} Settings",
"userTitle": "Manage All Users", "userTitle": "Manage All Users",
"userDescription": "View and manage all users in the system", "userDescription": "View and manage all users in the system",
"userAbount": "About User Management", "userAbount": "About User Management",

View File

@@ -286,6 +286,7 @@
"apiKeysDelete": "Supprimer la clé API", "apiKeysDelete": "Supprimer la clé API",
"apiKeysManage": "Gérer les clés API", "apiKeysManage": "Gérer les clés API",
"apiKeysDescription": "Les clés API sont utilisées pour s'authentifier avec l'API d'intégration", "apiKeysDescription": "Les clés API sont utilisées pour s'authentifier avec l'API d'intégration",
"apiKeysSettings": "Paramètres de {apiKeyName}",
"userTitle": "Gérer tous les utilisateurs", "userTitle": "Gérer tous les utilisateurs",
"userDescription": "Voir et gérer tous les utilisateurs du système", "userDescription": "Voir et gérer tous les utilisateurs du système",
"userAbount": "À propos de la gestion des utilisateurs", "userAbount": "À propos de la gestion des utilisateurs",

View File

@@ -286,6 +286,7 @@
"apiKeysDelete": "Elimina Chiave API", "apiKeysDelete": "Elimina Chiave API",
"apiKeysManage": "Gestisci Chiavi API", "apiKeysManage": "Gestisci Chiavi API",
"apiKeysDescription": "Le chiavi API sono utilizzate per autenticarsi con l'API di integrazione", "apiKeysDescription": "Le chiavi API sono utilizzate per autenticarsi con l'API di integrazione",
"apiKeysSettings": "Impostazioni {apiKeyName}",
"userTitle": "Gestisci Tutti Gli Utenti", "userTitle": "Gestisci Tutti Gli Utenti",
"userDescription": "Visualizza e gestisci tutti gli utenti del sistema", "userDescription": "Visualizza e gestisci tutti gli utenti del sistema",
"userAbount": "Informazioni Sulla Gestione Utente", "userAbount": "Informazioni Sulla Gestione Utente",

View File

@@ -286,6 +286,7 @@
"apiKeysDelete": "Usuń klucz API", "apiKeysDelete": "Usuń klucz API",
"apiKeysManage": "Zarządzaj kluczami API", "apiKeysManage": "Zarządzaj kluczami API",
"apiKeysDescription": "Klucze API służą do uwierzytelniania z API integracji", "apiKeysDescription": "Klucze API służą do uwierzytelniania z API integracji",
"apiKeysSettings": "Ustawienia {apiKeyName}",
"userTitle": "Zarządzaj wszystkimi użytkownikami", "userTitle": "Zarządzaj wszystkimi użytkownikami",
"userDescription": "Zobacz i zarządzaj wszystkimi użytkownikami w systemie", "userDescription": "Zobacz i zarządzaj wszystkimi użytkownikami w systemie",
"userAbount": "O zarządzaniu użytkownikami", "userAbount": "O zarządzaniu użytkownikami",

View File

@@ -286,6 +286,7 @@
"apiKeysDelete": "Excluir Chave API", "apiKeysDelete": "Excluir Chave API",
"apiKeysManage": "Gerenciar Chaves API", "apiKeysManage": "Gerenciar Chaves API",
"apiKeysDescription": "As chaves API são usadas para autenticar com a API de integração", "apiKeysDescription": "As chaves API são usadas para autenticar com a API de integração",
"apiKeysSettings": "Configurações de {apiKeyName}",
"userTitle": "Gerenciar Todos os Usuários", "userTitle": "Gerenciar Todos os Usuários",
"userDescription": "Visualizar e gerenciar todos os usuários no sistema", "userDescription": "Visualizar e gerenciar todos os usuários no sistema",
"userAbount": "Sobre a Gestão de Usuário", "userAbount": "Sobre a Gestão de Usuário",

View File

@@ -286,6 +286,7 @@
"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",
"apiKeysSettings": "{apiKeyName} Settings",
"userTitle": "Manage All Users", "userTitle": "Manage All Users",
"userDescription": "View and manage all users in the system", "userDescription": "View and manage all users in the system",
"userAbount": "About User Management", "userAbount": "About User Management",

View File

@@ -101,7 +101,7 @@ export default function OrgApiKeysTable({
setIsDeleteModalOpen(true); setIsDeleteModalOpen(true);
}} }}
> >
<span className="text-red-500">Delete</span> <span className="text-red-500">{t('delete')}</span>
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>

View File

@@ -55,7 +55,7 @@ export default async function SettingsLayout(props: SettingsLayoutProps) {
return ( return (
<> <>
<SettingsSectionTitle title={`${apiKey?.name} Settings`} /> <SettingsSectionTitle title={t('apiKeysSettings', {apiKeyName: apiKey?.name})} />
<ApiKeyProvider apiKey={apiKey}> <ApiKeyProvider apiKey={apiKey}>
<HorizontalTabs items={navItems}>{children}</HorizontalTabs> <HorizontalTabs items={navItems}>{children}</HorizontalTabs>

View File

@@ -32,6 +32,7 @@ import { Input } from "@app/components/ui/input";
import { DataTablePagination } from "@app/components/DataTablePagination"; import { DataTablePagination } from "@app/components/DataTablePagination";
import { Plus, Search } from "lucide-react"; import { Plus, Search } from "lucide-react";
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>[];
@@ -44,15 +45,17 @@ export function ApiKeysDataTable<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="API Keys" title={t('apiKeys')}
searchPlaceholder="Search API keys..." searchPlaceholder={t('searchApiKeys')}
searchColumn="name" searchColumn="name"
onAdd={addApiKey} onAdd={addApiKey}
addButtonText="Generate API Key" addButtonText={t('apiKeysAdd')}
/> />
); );
} }

View File

@@ -24,6 +24,7 @@ import { createApiClient } from "@app/lib/api";
import { useEnvContext } from "@app/hooks/useEnvContext"; import { useEnvContext } from "@app/hooks/useEnvContext";
import moment from "moment"; import moment from "moment";
import { ApiKeysDataTable } from "./ApiKeysDataTable"; import { ApiKeysDataTable } from "./ApiKeysDataTable";
import { useTranslations } from "next-intl";
export type ApiKeyRow = { export type ApiKeyRow = {
id: string; id: string;
@@ -45,14 +46,16 @@ export default function ApiKeysTable({ apiKeys }: ApiKeyTableProps) {
const api = createApiClient(useEnvContext()); const api = createApiClient(useEnvContext());
const t = useTranslations();
const deleteSite = (apiKeyId: string) => { const deleteSite = (apiKeyId: string) => {
api.delete(`/api-key/${apiKeyId}`) api.delete(`/api-key/${apiKeyId}`)
.catch((e) => { .catch((e) => {
console.error("Error deleting API key", e); console.error(t('apiKeysErrorDelete'), e);
toast({ toast({
variant: "destructive", variant: "destructive",
title: "Error deleting API key", title: t('apiKeysErrorDelete'),
description: formatAxiosError(e, "Error deleting API key") description: formatAxiosError(e, t('apiKeysErrorDeleteMessage'))
}); });
}) })
.then(() => { .then(() => {
@@ -86,7 +89,7 @@ export default function ApiKeysTable({ apiKeys }: ApiKeyTableProps) {
setSelected(apiKeyROw); setSelected(apiKeyROw);
}} }}
> >
<span>View settings</span> <span>{t('viewSettings')}</span>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
onClick={() => { onClick={() => {
@@ -94,7 +97,7 @@ export default function ApiKeysTable({ apiKeys }: ApiKeyTableProps) {
setIsDeleteModalOpen(true); setIsDeleteModalOpen(true);
}} }}
> >
<span className="text-red-500">Delete</span> <span className="text-red-500">{t('delete')}</span>
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
@@ -111,7 +114,7 @@ export default function ApiKeysTable({ apiKeys }: ApiKeyTableProps) {
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>
); );
@@ -141,7 +144,7 @@ export default function ApiKeysTable({ apiKeys }: ApiKeyTableProps) {
<div className="flex items-center justify-end"> <div className="flex items-center justify-end">
<Link href={`/admin/api-keys/${r.id}`}> <Link href={`/admin/api-keys/${r.id}`}>
<Button variant={"outlinePrimary"} className="ml-2"> <Button variant={"outlinePrimary"} className="ml-2">
Edit {t('edit')}
<ArrowRight className="ml-2 w-4 h-4" /> <ArrowRight className="ml-2 w-4 h-4" />
</Button> </Button>
</Link> </Link>
@@ -163,27 +166,24 @@ export default function ApiKeysTable({ apiKeys }: ApiKeyTableProps) {
dialog={ dialog={
<div className="space-y-4"> <div className="space-y-4">
<p> <p>
Are you sure you want to remove the API key{" "} {t('apiKeysQuestionRemove', {selectedApiKey: selected?.name || selected?.id})}
<b>{selected?.name || selected?.id}</b>?
</p> </p>
<p> <p>
<b> <b>
Once removed, the API key will no longer be {t('apiKeysMessageRemove')}
able to be used.
</b> </b>
</p> </p>
<p> <p>
To confirm, please type the name of the API key {t('apiKeysMessageConfirm')}
below.
</p> </p>
</div> </div>
} }
buttonText="Confirm Delete API Key" buttonText={t('apiKeysDeleteConfirm')}
onConfirm={async () => deleteSite(selected!.id)} onConfirm={async () => deleteSite(selected!.id)}
string={selected.name} string={selected.name}
title="Delete API Key" title={t('apiKeysDelete')}
/> />
)} )}

View File

@@ -20,6 +20,7 @@ import {
import { GetApiKeyResponse } from "@server/routers/apiKeys"; import { GetApiKeyResponse } from "@server/routers/apiKeys";
import ApiKeyProvider from "@app/providers/ApiKeyProvider"; import ApiKeyProvider from "@app/providers/ApiKeyProvider";
import { HorizontalTabs } from "@app/components/HorizontalTabs"; import { HorizontalTabs } from "@app/components/HorizontalTabs";
import { useTranslations } from "next-intl";
interface SettingsLayoutProps { interface SettingsLayoutProps {
children: React.ReactNode; children: React.ReactNode;
@@ -29,6 +30,8 @@ interface SettingsLayoutProps {
export default async function SettingsLayout(props: SettingsLayoutProps) { export default async function SettingsLayout(props: SettingsLayoutProps) {
const params = await props.params; const params = await props.params;
const t = useTranslations();
const { children } = props; const { children } = props;
let apiKey = null; let apiKey = null;
@@ -45,14 +48,14 @@ export default async function SettingsLayout(props: SettingsLayoutProps) {
const navItems = [ const navItems = [
{ {
title: "Permissions", title: t('apiKeysPermissionsTitle'),
href: "/admin/api-keys/{apiKeyId}/permissions" href: "/admin/api-keys/{apiKeyId}/permissions"
} }
]; ];
return ( return (
<> <>
<SettingsSectionTitle title={`${apiKey?.name} Settings`} /> <SettingsSectionTitle title={t('apiKeysSettings', {apiKeyName: apiKey?.name})} />
<ApiKeyProvider apiKey={apiKey}> <ApiKeyProvider apiKey={apiKey}>
<HorizontalTabs items={navItems}>{children}</HorizontalTabs> <HorizontalTabs items={navItems}>{children}</HorizontalTabs>

View File

@@ -23,12 +23,15 @@ import { ListApiKeyActionsResponse } from "@server/routers/apiKeys";
import { AxiosResponse } from "axios"; import { AxiosResponse } from "axios";
import { useParams } from "next/navigation"; import { useParams } from "next/navigation";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useTranslations } from "next-intl";
export default function Page() { export default function Page() {
const { env } = useEnvContext(); const { env } = useEnvContext();
const api = createApiClient({ env }); const api = createApiClient({ env });
const { apiKeyId } = useParams(); const { apiKeyId } = useParams();
const t = useTranslations();
const [loadingPage, setLoadingPage] = useState<boolean>(true); const [loadingPage, setLoadingPage] = useState<boolean>(true);
const [selectedPermissions, setSelectedPermissions] = useState< const [selectedPermissions, setSelectedPermissions] = useState<
Record<string, boolean> Record<string, boolean>
@@ -47,10 +50,10 @@ export default function Page() {
.catch((e) => { .catch((e) => {
toast({ toast({
variant: "destructive", variant: "destructive",
title: "Error loading API key actions", title: t('apiKeysPermissionsErrorLoadingActions'),
description: formatAxiosError( description: formatAxiosError(
e, e,
"Error loading API key actions" t('apiKeysPermissionsErrorLoadingActions')
) )
}); });
}); });
@@ -81,18 +84,18 @@ export default function Page() {
) )
}) })
.catch((e) => { .catch((e) => {
console.error("Error setting permissions", e); console.error(t('apiKeysPermissionsErrorUpdate'), e);
toast({ toast({
variant: "destructive", variant: "destructive",
title: "Error setting permissions", title: t('apiKeysPermissionsErrorUpdate'),
description: formatAxiosError(e) description: formatAxiosError(e)
}); });
}); });
if (actionsRes && actionsRes.status === 200) { if (actionsRes && actionsRes.status === 200) {
toast({ toast({
title: "Permissions updated", title: t('apiKeysPermissionsUpdated'),
description: "The permissions have been updated." description: t('apiKeysPermissionsUpdatedDescription')
}); });
} }
@@ -106,10 +109,10 @@ export default function Page() {
<SettingsSection> <SettingsSection>
<SettingsSectionHeader> <SettingsSectionHeader>
<SettingsSectionTitle> <SettingsSectionTitle>
Permissions {t('apiKeysPermissionsTitle')}
</SettingsSectionTitle> </SettingsSectionTitle>
<SettingsSectionDescription> <SettingsSectionDescription>
Determine what this API key can do {t('apiKeysPermissionsGeneralSettingsDescription')}
</SettingsSectionDescription> </SettingsSectionDescription>
</SettingsSectionHeader> </SettingsSectionHeader>
<SettingsSectionBody> <SettingsSectionBody>
@@ -127,7 +130,7 @@ export default function Page() {
loading={loadingSavePermissions} loading={loadingSavePermissions}
disabled={loadingSavePermissions} disabled={loadingSavePermissions}
> >
Save Permissions {t('apiKeysPermissionsSave')}
</Button> </Button>
</SettingsSectionFooter> </SettingsSectionFooter>
</SettingsSectionBody> </SettingsSectionBody>

View File

@@ -59,15 +59,18 @@ import CopyToClipboard from "@app/components/CopyToClipboard";
import moment from "moment"; import moment from "moment";
import CopyTextBox from "@app/components/CopyTextBox"; import CopyTextBox from "@app/components/CopyTextBox";
import PermissionsSelectBox from "@app/components/PermissionsSelectBox"; import PermissionsSelectBox from "@app/components/PermissionsSelectBox";
import { useTranslations } from "next-intl";
const t = useTranslations();
const createFormSchema = z.object({ const createFormSchema = z.object({
name: z name: z
.string() .string()
.min(2, { .min(2, {
message: "Name must be at least 2 characters." message: t('apiKeysNameMin')
}) })
.max(255, { .max(255, {
message: "Name must not be longer than 255 characters." message: t('apiKeysNameMax')
}) })
}); });
@@ -82,7 +85,7 @@ const copiedFormSchema = z
return data.copied; return data.copied;
}, },
{ {
message: "You must confirm that you have copied the API key.", message: t('apiKeysConfirmCopy2'),
path: ["copied"] path: ["copied"]
} }
); );
@@ -127,7 +130,7 @@ export default function Page() {
.catch((e) => { .catch((e) => {
toast({ toast({
variant: "destructive", variant: "destructive",
title: "Error creating API key", title: t('apiKeysErrorCreate'),
description: formatAxiosError(e) description: formatAxiosError(e)
}); });
}); });
@@ -148,10 +151,10 @@ export default function Page() {
) )
}) })
.catch((e) => { .catch((e) => {
console.error("Error setting permissions", e); console.error(t('apiKeysErrorSetPermission'), e);
toast({ toast({
variant: "destructive", variant: "destructive",
title: "Error setting permissions", title: t('apiKeysErrorSetPermission'),
description: formatAxiosError(e) description: formatAxiosError(e)
}); });
}); });
@@ -184,8 +187,8 @@ export default function Page() {
<> <>
<div className="flex justify-between"> <div className="flex justify-between">
<HeaderTitle <HeaderTitle
title="Generate API Key" title={t('apiKeysCreate')}
description="Generate a new root access API key" description={t('apiKeysCreateDescription')}
/> />
<Button <Button
variant="outline" variant="outline"
@@ -205,7 +208,7 @@ export default function Page() {
<SettingsSection> <SettingsSection>
<SettingsSectionHeader> <SettingsSectionHeader>
<SettingsSectionTitle> <SettingsSectionTitle>
API Key Information {t('apiKeysTitle')}
</SettingsSectionTitle> </SettingsSectionTitle>
</SettingsSectionHeader> </SettingsSectionHeader>
<SettingsSectionBody> <SettingsSectionBody>
@@ -221,7 +224,7 @@ export default function Page() {
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel> <FormLabel>
Name {t('name')}
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input <Input
@@ -242,10 +245,10 @@ export default function Page() {
<SettingsSection> <SettingsSection>
<SettingsSectionHeader> <SettingsSectionHeader>
<SettingsSectionTitle> <SettingsSectionTitle>
Permissions {t('apiKeysGeneralSettings')}
</SettingsSectionTitle> </SettingsSectionTitle>
<SettingsSectionDescription> <SettingsSectionDescription>
Determine what this API key can do {t('apiKeysGeneralSettingsDescription')}
</SettingsSectionDescription> </SettingsSectionDescription>
</SettingsSectionHeader> </SettingsSectionHeader>
<SettingsSectionBody> <SettingsSectionBody>
@@ -265,14 +268,14 @@ export default function Page() {
<SettingsSection> <SettingsSection>
<SettingsSectionHeader> <SettingsSectionHeader>
<SettingsSectionTitle> <SettingsSectionTitle>
Your API Key {t('apiKeysList')}
</SettingsSectionTitle> </SettingsSectionTitle>
</SettingsSectionHeader> </SettingsSectionHeader>
<SettingsSectionBody> <SettingsSectionBody>
<InfoSections cols={2}> <InfoSections cols={2}>
<InfoSection> <InfoSection>
<InfoSectionTitle> <InfoSectionTitle>
Name {t('name')}
</InfoSectionTitle> </InfoSectionTitle>
<InfoSectionContent> <InfoSectionContent>
<CopyToClipboard <CopyToClipboard
@@ -282,7 +285,7 @@ export default function Page() {
</InfoSection> </InfoSection>
<InfoSection> <InfoSection>
<InfoSectionTitle> <InfoSectionTitle>
Created {t('created')}
</InfoSectionTitle> </InfoSectionTitle>
<InfoSectionContent> <InfoSectionContent>
{moment( {moment(
@@ -295,17 +298,15 @@ export default function Page() {
<Alert variant="neutral"> <Alert variant="neutral">
<InfoIcon className="h-4 w-4" /> <InfoIcon className="h-4 w-4" />
<AlertTitle className="font-semibold"> <AlertTitle className="font-semibold">
Save Your API Key {t('apiKeysSave')}
</AlertTitle> </AlertTitle>
<AlertDescription> <AlertDescription>
You will only be able to see this {t('apiKeysSaveDescription')}
once. Make sure to copy it to a
secure place.
</AlertDescription> </AlertDescription>
</Alert> </Alert>
<h4 className="font-semibold"> <h4 className="font-semibold">
Your API key is: {t('apiKeysInfo')}
</h4> </h4>
<CopyTextBox <CopyTextBox
@@ -343,8 +344,7 @@ export default function Page() {
htmlFor="terms" htmlFor="terms"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
> >
I have copied {t('apiKeysConfirmCopy')}
the API key
</label> </label>
</div> </div>
<FormMessage /> <FormMessage />
@@ -368,7 +368,7 @@ export default function Page() {
router.push(`/admin/api-keys`); router.push(`/admin/api-keys`);
}} }}
> >
Cancel {t('cancel')}
</Button> </Button>
)} )}
{!apiKey && ( {!apiKey && (
@@ -380,7 +380,7 @@ export default function Page() {
form.handleSubmit(onSubmit)(); form.handleSubmit(onSubmit)();
}} }}
> >
Generate {t('generate')}
</Button> </Button>
)} )}
@@ -391,7 +391,7 @@ export default function Page() {
copiedForm.handleSubmit(onCopiedSubmit)(); copiedForm.handleSubmit(onCopiedSubmit)();
}} }}
> >
Done {t('done')}
</Button> </Button>
)} )}
</div> </div>

View File

@@ -9,6 +9,7 @@ import { AxiosResponse } from "axios";
import SettingsSectionTitle from "@app/components/SettingsSectionTitle"; import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
import { ListRootApiKeysResponse } from "@server/routers/apiKeys"; import { ListRootApiKeysResponse } from "@server/routers/apiKeys";
import ApiKeysTable, { ApiKeyRow } from "./ApiKeysTable"; import ApiKeysTable, { ApiKeyRow } from "./ApiKeysTable";
import { useTranslations } from "next-intl";
type ApiKeyPageProps = {}; type ApiKeyPageProps = {};
@@ -16,6 +17,7 @@ export const dynamic = "force-dynamic";
export default async function ApiKeysPage(props: ApiKeyPageProps) { export default async function ApiKeysPage(props: ApiKeyPageProps) {
let apiKeys: ListRootApiKeysResponse["apiKeys"] = []; let apiKeys: ListRootApiKeysResponse["apiKeys"] = [];
const t = useTranslations();
try { try {
const res = await internal.get<AxiosResponse<ListRootApiKeysResponse>>( const res = await internal.get<AxiosResponse<ListRootApiKeysResponse>>(
`/api-keys`, `/api-keys`,
@@ -36,8 +38,8 @@ export default async function ApiKeysPage(props: ApiKeyPageProps) {
return ( return (
<> <>
<SettingsSectionTitle <SettingsSectionTitle
title="Manage API Keys" title={t('apiKeysManage')}
description="API keys are used to authenticate with the integration API" description={t('apiKeysDescription')}
/> />
<ApiKeysTable apiKeys={rows} /> <ApiKeysTable apiKeys={rows} />