Fix spelling error

This commit is contained in:
LukeGus
2025-09-02 16:56:28 -05:00
parent 59cc469a44
commit 38436e3cb5

View File

@@ -26,7 +26,6 @@ import {
removeAdminStatus, removeAdminStatus,
deleteUser deleteUser
} from "@/ui/main-axios.ts"; } from "@/ui/main-axios.ts";
import {useTranslation} from "react-i18next";
function getCookie(name: string) { function getCookie(name: string) {
return document.cookie.split('; ').reduce((r, v) => { return document.cookie.split('; ').reduce((r, v) => {
@@ -41,7 +40,6 @@ interface AdminSettingsProps {
export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.ReactElement { export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.ReactElement {
const {state: sidebarState} = useSidebar(); const {state: sidebarState} = useSidebar();
const {t} = useTranslation();
const [allowRegistration, setAllowRegistration] = React.useState(true); const [allowRegistration, setAllowRegistration] = React.useState(true);
const [regLoading, setRegLoading] = React.useState(false); const [regLoading, setRegLoading] = React.useState(false);
@@ -137,7 +135,7 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
await updateOIDCConfig(oidcConfig); await updateOIDCConfig(oidcConfig);
setOidcSuccess("OIDC configuration updated successfully!"); setOidcSuccess("OIDC configuration updated successfully!");
} catch (err: any) { } catch (err: any) {
setOidcError(err?.response?.data?.error || t('interface.failedToUpdateOidcConfig')); setOidcError(err?.response?.data?.error || "Failed to update OIDC configuration");
} finally { } finally {
setOidcLoading(false); setOidcLoading(false);
} }
@@ -160,7 +158,7 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
setNewAdminUsername(""); setNewAdminUsername("");
fetchUsers(); fetchUsers();
} catch (err: any) { } catch (err: any) {
setMakeAdminError(err?.response?.data?.error || t('interface.failedToMakeUserAdmin')); setMakeAdminError(err?.response?.data?.error || "Failed to make user admin");
} finally { } finally {
setMakeAdminLoading(false); setMakeAdminLoading(false);
} }
@@ -202,7 +200,7 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
className="bg-[#18181b] text-white rounded-lg border-2 border-[#303032] overflow-hidden"> className="bg-[#18181b] text-white rounded-lg border-2 border-[#303032] overflow-hidden">
<div className="h-full w-full flex flex-col"> <div className="h-full w-full flex flex-col">
<div className="flex items-center justify-between px-3 pt-2 pb-2"> <div className="flex items-center justify-between px-3 pt-2 pb-2">
<h1 className="font-bold text-lg">{t('admin.title')}</h1> <h1 className="font-bold text-lg">Admin Settings</h1>
</div> </div>
<Separator className="p-0.25 w-full"/> <Separator className="p-0.25 w-full"/>
@@ -211,98 +209,99 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
<TabsList className="mb-4 bg-[#18181b] border-2 border-[#303032]"> <TabsList className="mb-4 bg-[#18181b] border-2 border-[#303032]">
<TabsTrigger value="registration" className="flex items-center gap-2"> <TabsTrigger value="registration" className="flex items-center gap-2">
<Users className="h-4 w-4"/> <Users className="h-4 w-4"/>
{t('common.settings')} General
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="oidc" className="flex items-center gap-2"> <TabsTrigger value="oidc" className="flex items-center gap-2">
<Shield className="h-4 w-4"/> <Shield className="h-4 w-4"/>
{t('admin.oidcSettings')} OIDC
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="users" className="flex items-center gap-2"> <TabsTrigger value="users" className="flex items-center gap-2">
<Users className="h-4 w-4"/> <Users className="h-4 w-4"/>
{t('admin.users')} Users
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="admins" className="flex items-center gap-2"> <TabsTrigger value="admins" className="flex items-center gap-2">
<Shield className="h-4 w-4"/> <Shield className="h-4 w-4"/>
{t('nav.admin')} Admins
</TabsTrigger> </TabsTrigger>
</TabsList> </TabsList>
<TabsContent value="registration" className="space-y-6"> <TabsContent value="registration" className="space-y-6">
<div className="space-y-4"> <div className="space-y-4">
<h3 className="text-lg font-semibold">{t('admin.userManagement')}</h3> <h3 className="text-lg font-semibold">User Registration</h3>
<label className="flex items-center gap-2"> <label className="flex items-center gap-2">
<Checkbox checked={allowRegistration} onCheckedChange={handleToggleRegistration} <Checkbox checked={allowRegistration} onCheckedChange={handleToggleRegistration}
disabled={regLoading}/> disabled={regLoading}/>
{t('admin.allowRegistration')} Allow new account registration
</label> </label>
</div> </div>
</TabsContent> </TabsContent>
<TabsContent value="oidc" className="space-y-6"> <TabsContent value="oidc" className="space-y-6">
<div className="space-y-4"> <div className="space-y-4">
<h3 className="text-lg font-semibold">{t('admin.externalAuthentication')}</h3> <h3 className="text-lg font-semibold">External Authentication (OIDC)</h3>
<p className="text-sm text-muted-foreground">{t('admin.configureExternalProvider')}</p> <p className="text-sm text-muted-foreground">Configure external identity provider for
OIDC/OAuth2 authentication.</p>
{oidcError && ( {oidcError && (
<Alert variant="destructive"> <Alert variant="destructive">
<AlertTitle>{t('common.error')}</AlertTitle> <AlertTitle>Error</AlertTitle>
<AlertDescription>{oidcError}</AlertDescription> <AlertDescription>{oidcError}</AlertDescription>
</Alert> </Alert>
)} )}
<form onSubmit={handleOIDCConfigSubmit} className="space-y-4"> <form onSubmit={handleOIDCConfigSubmit} className="space-y-4">
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="client_id">{t('admin.clientId')}</Label> <Label htmlFor="client_id">Client ID</Label>
<Input id="client_id" value={oidcConfig.client_id} <Input id="client_id" value={oidcConfig.client_id}
onChange={(e) => handleOIDCConfigChange('client_id', e.target.value)} onChange={(e) => handleOIDCConfigChange('client_id', e.target.value)}
placeholder={t('placeholders.clientId')} required/> placeholder="your-client-id" required/>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="client_secret">{t('admin.clientSecret')}</Label> <Label htmlFor="client_secret">Client Secret</Label>
<Input id="client_secret" type="password" value={oidcConfig.client_secret} <Input id="client_secret" type="password" value={oidcConfig.client_secret}
onChange={(e) => handleOIDCConfigChange('client_secret', e.target.value)} onChange={(e) => handleOIDCConfigChange('client_secret', e.target.value)}
placeholder={t('placeholders.clientSecret')} required/> placeholder="your-client-secret" required/>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="authorization_url">{t('admin.authorizationUrl')}</Label> <Label htmlFor="authorization_url">Authorization URL</Label>
<Input id="authorization_url" value={oidcConfig.authorization_url} <Input id="authorization_url" value={oidcConfig.authorization_url}
onChange={(e) => handleOIDCConfigChange('authorization_url', e.target.value)} onChange={(e) => handleOIDCConfigChange('authorization_url', e.target.value)}
placeholder={t('placeholders.authUrl')} placeholder="https://your-provider.com/application/o/authorize/"
required/> required/>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="issuer_url">{t('admin.issuerUrl')}</Label> <Label htmlFor="issuer_url">Issuer URL</Label>
<Input id="issuer_url" value={oidcConfig.issuer_url} <Input id="issuer_url" value={oidcConfig.issuer_url}
onChange={(e) => handleOIDCConfigChange('issuer_url', e.target.value)} onChange={(e) => handleOIDCConfigChange('issuer_url', e.target.value)}
placeholder={t('placeholders.redirectUrl')} required/> placeholder="https://your-provider.com/application/o/termix/" required/>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="token_url">{t('admin.tokenUrl')}</Label> <Label htmlFor="token_url">Token URL</Label>
<Input id="token_url" value={oidcConfig.token_url} <Input id="token_url" value={oidcConfig.token_url}
onChange={(e) => handleOIDCConfigChange('token_url', e.target.value)} onChange={(e) => handleOIDCConfigChange('token_url', e.target.value)}
placeholder={t('placeholders.tokenUrl')} required/> placeholder="https://your-provider.com/application/o/token/" required/>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="identifier_path">{t('admin.userIdentifierPath')}</Label> <Label htmlFor="identifier_path">User Identifier Path</Label>
<Input id="identifier_path" value={oidcConfig.identifier_path} <Input id="identifier_path" value={oidcConfig.identifier_path}
onChange={(e) => handleOIDCConfigChange('identifier_path', e.target.value)} onChange={(e) => handleOIDCConfigChange('identifier_path', e.target.value)}
placeholder={t('placeholders.userIdField')} required/> placeholder="sub" required/>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="name_path">{t('admin.displayNamePath')}</Label> <Label htmlFor="name_path">Display Name Path</Label>
<Input id="name_path" value={oidcConfig.name_path} <Input id="name_path" value={oidcConfig.name_path}
onChange={(e) => handleOIDCConfigChange('name_path', e.target.value)} onChange={(e) => handleOIDCConfigChange('name_path', e.target.value)}
placeholder={t('placeholders.usernameField')} required/> placeholder="name" required/>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="scopes">{t('admin.scopes')}</Label> <Label htmlFor="scopes">Scopes</Label>
<Input id="scopes" value={oidcConfig.scopes} <Input id="scopes" value={oidcConfig.scopes}
onChange={(e) => handleOIDCConfigChange('scopes', (e.target as HTMLInputElement).value)} onChange={(e) => handleOIDCConfigChange('scopes', (e.target as HTMLInputElement).value)}
placeholder={t('placeholders.scopes')} required/> placeholder="openid email profile" required/>
</div> </div>
<div className="flex gap-2 pt-2"> <div className="flex gap-2 pt-2">
<Button type="submit" className="flex-1" <Button type="submit" className="flex-1"
disabled={oidcLoading}>{oidcLoading ? t('admin.saving') : t('admin.saveConfiguration')}</Button> disabled={oidcLoading}>{oidcLoading ? "Saving..." : "Save Configuration"}</Button>
<Button type="button" variant="outline" onClick={() => setOidcConfig({ <Button type="button" variant="outline" onClick={() => setOidcConfig({
client_id: '', client_id: '',
client_secret: '', client_secret: '',
@@ -312,12 +311,12 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
identifier_path: 'sub', identifier_path: 'sub',
name_path: 'name', name_path: 'name',
scopes: 'openid email profile' scopes: 'openid email profile'
})}>{t('admin.reset')}</Button> })}>Reset</Button>
</div> </div>
{oidcSuccess && ( {oidcSuccess && (
<Alert> <Alert>
<AlertTitle>{t('admin.success')}</AlertTitle> <AlertTitle>Success</AlertTitle>
<AlertDescription>{oidcSuccess}</AlertDescription> <AlertDescription>{oidcSuccess}</AlertDescription>
</Alert> </Alert>
)} )}
@@ -328,20 +327,20 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
<TabsContent value="users" className="space-y-6"> <TabsContent value="users" className="space-y-6">
<div className="space-y-4"> <div className="space-y-4">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<h3 className="text-lg font-semibold">{t('admin.userManagement')}</h3> <h3 className="text-lg font-semibold">User Management</h3>
<Button onClick={fetchUsers} disabled={usersLoading} variant="outline" <Button onClick={fetchUsers} disabled={usersLoading} variant="outline"
size="sm">{usersLoading ? t('admin.loading') : t('admin.refresh')}</Button> size="sm">{usersLoading ? "Loading..." : "Refresh"}</Button>
</div> </div>
{usersLoading ? ( {usersLoading ? (
<div className="text-center py-8 text-muted-foreground">{t('admin.loadingUsers')}</div> <div className="text-center py-8 text-muted-foreground">Loading users...</div>
) : ( ) : (
<div className="border rounded-md overflow-hidden"> <div className="border rounded-md overflow-hidden">
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="px-4">{t('admin.username')}</TableHead> <TableHead className="px-4">Username</TableHead>
<TableHead className="px-4">{t('admin.type')}</TableHead> <TableHead className="px-4">Type</TableHead>
<TableHead className="px-4">{t('admin.actions')}</TableHead> <TableHead className="px-4">Actions</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
@@ -351,11 +350,11 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
{user.username} {user.username}
{user.is_admin && ( {user.is_admin && (
<span <span
className="ml-2 inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-muted/50 text-muted-foreground border border-border">{t('admin.adminBadge')}</span> className="ml-2 inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-muted/50 text-muted-foreground border border-border">Admin</span>
)} )}
</TableCell> </TableCell>
<TableCell <TableCell
className="px-4">{user.is_oidc ? t('admin.external') : t('admin.local')}</TableCell> className="px-4">{user.is_oidc ? "External" : "Local"}</TableCell>
<TableCell className="px-4"> <TableCell className="px-4">
<Button variant="ghost" size="sm" <Button variant="ghost" size="sm"
onClick={() => deleteUser(user.username)} onClick={() => deleteUser(user.username)}
@@ -375,29 +374,29 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
<TabsContent value="admins" className="space-y-6"> <TabsContent value="admins" className="space-y-6">
<div className="space-y-6"> <div className="space-y-6">
<h3 className="text-lg font-semibold">{t('admin.adminManagement')}</h3> <h3 className="text-lg font-semibold">Admin Management</h3>
<div className="space-y-4 p-6 border rounded-md bg-muted/50"> <div className="space-y-4 p-6 border rounded-md bg-muted/50">
<h4 className="font-medium">{t('admin.makeUserAdmin')}</h4> <h4 className="font-medium">Make User Admin</h4>
<form onSubmit={makeUserAdmin} className="space-y-4"> <form onSubmit={makeUserAdmin} className="space-y-4">
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="new-admin-username">{t('admin.username')}</Label> <Label htmlFor="new-admin-username">Username</Label>
<div className="flex gap-2"> <div className="flex gap-2">
<Input id="new-admin-username" value={newAdminUsername} <Input id="new-admin-username" value={newAdminUsername}
onChange={(e) => setNewAdminUsername(e.target.value)} onChange={(e) => setNewAdminUsername(e.target.value)}
placeholder={t('placeholders.enterUsername')} required/> placeholder="Enter username to make admin" required/>
<Button type="submit" <Button type="submit"
disabled={makeAdminLoading || !newAdminUsername.trim()}>{makeAdminLoading ? t('admin.adding') : t('admin.makeAdmin')}</Button> disabled={makeAdminLoading || !newAdminUsername.trim()}>{makeAdminLoading ? "Adding..." : "Make Admin"}</Button>
</div> </div>
</div> </div>
{makeAdminError && ( {makeAdminError && (
<Alert variant="destructive"> <Alert variant="destructive">
<AlertTitle>{t('common.error')}</AlertTitle> <AlertTitle>Error</AlertTitle>
<AlertDescription>{makeAdminError}</AlertDescription> <AlertDescription>{makeAdminError}</AlertDescription>
</Alert> </Alert>
)} )}
{makeAdminSuccess && ( {makeAdminSuccess && (
<Alert> <Alert>
<AlertTitle>{t('admin.success')}</AlertTitle> <AlertTitle>Success</AlertTitle>
<AlertDescription>{makeAdminSuccess}</AlertDescription> <AlertDescription>{makeAdminSuccess}</AlertDescription>
</Alert> </Alert>
)} )}
@@ -405,14 +404,14 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
</div> </div>
<div className="space-y-4"> <div className="space-y-4">
<h4 className="font-medium">{t('admin.currentAdmins')}</h4> <h4 className="font-medium">Current Admins</h4>
<div className="border rounded-md overflow-hidden"> <div className="border rounded-md overflow-hidden">
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="px-4">{t('admin.username')}</TableHead> <TableHead className="px-4">Username</TableHead>
<TableHead className="px-4">{t('admin.type')}</TableHead> <TableHead className="px-4">Type</TableHead>
<TableHead className="px-4">{t('admin.actions')}</TableHead> <TableHead className="px-4">Actions</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
@@ -424,13 +423,13 @@ export function AdminSettings({isTopbarOpen = true}: AdminSettingsProps): React.
className="ml-2 inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-muted/50 text-muted-foreground border border-border">Admin</span> className="ml-2 inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-muted/50 text-muted-foreground border border-border">Admin</span>
</TableCell> </TableCell>
<TableCell <TableCell
className="px-4">{admin.is_oidc ? t('admin.external') : t('admin.local')}</TableCell> className="px-4">{admin.is_oidc ? "External" : "Local"}</TableCell>
<TableCell className="px-4"> <TableCell className="px-4">
<Button variant="ghost" size="sm" <Button variant="ghost" size="sm"
onClick={() => removeAdminStatus(admin.username)} onClick={() => removeAdminStatus(admin.username)}
className="text-orange-600 hover:text-orange-700 hover:bg-orange-50"> className="text-orange-600 hover:text-orange-700 hover:bg-orange-50">
<Shield className="h-4 w-4"/> <Shield className="h-4 w-4"/>
{t('admin.removeAdminButton')} Remove Admin
</Button> </Button>
</TableCell> </TableCell>
</TableRow> </TableRow>