mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-02 17:14:55 +02:00
more i18n
This commit is contained in:
parent
7eb08474ff
commit
059081ad8b
12 changed files with 122 additions and 62 deletions
|
@ -10,7 +10,7 @@
|
|||
"setupCreateSite": "Create Site",
|
||||
"setupCreateResources": "Create Resources",
|
||||
"setupOrgName": "Organization Name",
|
||||
"setupDisplayName": "This is the display name for your organization.",
|
||||
"orgDisplayName": "This is the display name of your organization.",
|
||||
"setupOrgId": "Organization ID",
|
||||
"setupIdentifierMessage": "This is the unique identifier for your organization. This is separate from the display name.",
|
||||
"setupErrorIdentifier": "Organization ID is already taken. Please choose a different one.",
|
||||
|
@ -150,5 +150,46 @@
|
|||
"proxy": "Proxy",
|
||||
"rules": "Rules",
|
||||
"resourceSettingDescription": "Configure the settings on your resource",
|
||||
"resourceSetting": "{resourceName} Settings"
|
||||
"resourceSetting": "{resourceName} Settings",
|
||||
"alwaysAllow": "Always Allow",
|
||||
"alwaysDeny": "Always Deny",
|
||||
"orgSettingsDescription": "Configure your organization's general settings",
|
||||
"orgGeneralSettings": "Organization Settings",
|
||||
"orgGeneralSettingsDescription": "Manage your organization details and configuration",
|
||||
"orgGeneralSave": "Save General Settings",
|
||||
"orgDangerZone": "Danger Zone",
|
||||
"orgDangerZoneDescription": "Once you delete this org, there is no going back. Please be certain.",
|
||||
"orgDelete": "Delete Organization",
|
||||
"orgDeleteConfirm": "Confirm Delete Organization",
|
||||
"orgMessageRemove": "This action is irreversible and will delete all associated data.",
|
||||
"orgMessageConfirm": "To confirm, please type the name of the organization below.",
|
||||
"orgQuestionRemove": "Are you sure you want to remove the organization {selectedOrg}?",
|
||||
"orgUpdated": "Organization updated",
|
||||
"orgUpdatedDescription": "The organization has been updated.",
|
||||
"orgErrorUpdate": "Failed to update organization",
|
||||
"orgErrorUpdateMessage": "An error occurred while updating the organization.",
|
||||
"orgErrorFetch": "Failed to fetch organizations",
|
||||
"orgErrorFetchMessage": "An error occurred while listing your organizations",
|
||||
"orgErrorDelete": "Failed to delete organization",
|
||||
"orgErrorDeleteMessage": "An error occurred while deleting the organization.",
|
||||
"orgDeleted": "Organization deleted",
|
||||
"orgDeletedMessage": "The organization and its data has been deleted.",
|
||||
"accessUsersManage": "Manage Users",
|
||||
"accessUsersDescription": "Invite users and add them to roles to manage access to your organization",
|
||||
"accessUsersSearch": "Search users...",
|
||||
"accessUserCreate": "Create User",
|
||||
"accessUserRemove": "Remove User",
|
||||
"username": "Username",
|
||||
"identityProvider": "Identity Provider",
|
||||
"role": "Role",
|
||||
"accessRoleNameRequired": "Name is required",
|
||||
"accessRolesManage": "Manage Roles",
|
||||
"accessRolesDescription": "Configure roles to manage access to your organization",
|
||||
"accessRolesSearch": "Search roles...",
|
||||
"accessRolesAdd": "Add Role",
|
||||
"accessRoleDelete": "Delete Role",
|
||||
"description": "Description",
|
||||
"inviteTitle": "Open Invitations",
|
||||
"inviteDescription": "Manage your invitations to other users",
|
||||
"inviteSearch": "Search invitations..."
|
||||
}
|
|
@ -4,6 +4,7 @@ import {
|
|||
ColumnDef,
|
||||
} from "@tanstack/react-table";
|
||||
import { DataTable } from "@app/components/ui/data-table";
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
interface DataTableProps<TData, TValue> {
|
||||
columns: ColumnDef<TData, TValue>[];
|
||||
|
@ -14,12 +15,15 @@ export function InvitationsDataTable<TData, TValue>({
|
|||
columns,
|
||||
data
|
||||
}: DataTableProps<TData, TValue>) {
|
||||
|
||||
const t = useTranslations();
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={data}
|
||||
title="Invitations"
|
||||
searchPlaceholder="Search invitations..."
|
||||
searchPlaceholder={t('inviteSearch')}
|
||||
searchColumn="email"
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -9,6 +9,7 @@ import UserProvider from "@app/providers/UserProvider";
|
|||
import { verifySession } from "@app/lib/auth/verifySession";
|
||||
import AccessPageHeaderAndNav from "../AccessPageHeaderAndNav";
|
||||
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
|
||||
type InvitationsPageProps = {
|
||||
params: Promise<{ orgId: string }>;
|
||||
|
@ -71,11 +72,13 @@ export default async function InvitationsPage(props: InvitationsPageProps) {
|
|||
};
|
||||
});
|
||||
|
||||
const t = await getTranslations();
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsSectionTitle
|
||||
title="Open Invitations"
|
||||
description="Manage your invitations to other users"
|
||||
title={t('inviteTitle')}
|
||||
description={t('inviteDescription')}
|
||||
/>
|
||||
<UserProvider user={user!}>
|
||||
<OrgProvider org={org}>
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
ColumnDef,
|
||||
} from "@tanstack/react-table";
|
||||
import { DataTable } from "@app/components/ui/data-table";
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
interface DataTableProps<TData, TValue> {
|
||||
columns: ColumnDef<TData, TValue>[];
|
||||
|
@ -16,15 +17,18 @@ export function RolesDataTable<TData, TValue>({
|
|||
data,
|
||||
createRole
|
||||
}: DataTableProps<TData, TValue>) {
|
||||
|
||||
const t = useTranslations();
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={data}
|
||||
title="Roles"
|
||||
searchPlaceholder="Search roles..."
|
||||
searchPlaceholder={t('accessRolesSearch')}
|
||||
searchColumn="name"
|
||||
onAdd={createRole}
|
||||
addButtonText="Add Role"
|
||||
addButtonText={t('accessRolesAdd')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import CreateRoleForm from "./CreateRoleForm";
|
|||
import DeleteRoleForm from "./DeleteRoleForm";
|
||||
import { createApiClient } from "@app/lib/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export type RoleRow = Role;
|
||||
|
||||
|
@ -38,6 +39,8 @@ export default function UsersTable({ roles: r }: RolesTableProps) {
|
|||
|
||||
const { org } = useOrgContext();
|
||||
|
||||
const t = useTranslations();
|
||||
|
||||
const columns: ColumnDef<RoleRow>[] = [
|
||||
{
|
||||
id: "actions",
|
||||
|
@ -58,7 +61,7 @@ export default function UsersTable({ roles: r }: RolesTableProps) {
|
|||
className="h-8 w-8 p-0"
|
||||
>
|
||||
<span className="sr-only">
|
||||
Open menu
|
||||
{t('openMenu')}
|
||||
</span>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</Button>
|
||||
|
@ -71,7 +74,7 @@ export default function UsersTable({ roles: r }: RolesTableProps) {
|
|||
}}
|
||||
>
|
||||
<span className="text-red-500">
|
||||
Delete Role
|
||||
{t('accessRoleDelete')}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
|
@ -92,7 +95,7 @@ export default function UsersTable({ roles: r }: RolesTableProps) {
|
|||
column.toggleSorting(column.getIsSorted() === "asc")
|
||||
}
|
||||
>
|
||||
Name
|
||||
{t('name')}
|
||||
<ArrowUpDown className="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
);
|
||||
|
@ -100,7 +103,7 @@ export default function UsersTable({ roles: r }: RolesTableProps) {
|
|||
},
|
||||
{
|
||||
accessorKey: "description",
|
||||
header: "Description"
|
||||
header: t('description')
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import RolesTable, { RoleRow } from "./RolesTable";
|
|||
import { SidebarSettings } from "@app/components/SidebarSettings";
|
||||
import AccessPageHeaderAndNav from "../AccessPageHeaderAndNav";
|
||||
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
|
||||
type RolesPageProps = {
|
||||
params: Promise<{ orgId: string }>;
|
||||
|
@ -62,12 +63,13 @@ export default async function RolesPage(props: RolesPageProps) {
|
|||
}
|
||||
|
||||
const roleRows: RoleRow[] = roles;
|
||||
const t = await getTranslations();
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsSectionTitle
|
||||
title="Manage Roles"
|
||||
description="Configure roles to manage access to your organization"
|
||||
title={t('accessRolesManage')}
|
||||
description={t('accessRolesDescription')}
|
||||
/>
|
||||
<OrgProvider org={org}>
|
||||
<RolesTable roles={roleRows} />
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
ColumnDef,
|
||||
} from "@tanstack/react-table";
|
||||
import { DataTable } from "@app/components/ui/data-table";
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
interface DataTableProps<TData, TValue> {
|
||||
columns: ColumnDef<TData, TValue>[];
|
||||
|
@ -16,15 +17,18 @@ export function UsersDataTable<TData, TValue>({
|
|||
data,
|
||||
inviteUser
|
||||
}: DataTableProps<TData, TValue>) {
|
||||
|
||||
const t = useTranslations();
|
||||
|
||||
return (
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={data}
|
||||
title="Users"
|
||||
searchPlaceholder="Search users..."
|
||||
searchPlaceholder={t('accessUsersSearch')}
|
||||
searchColumn="email"
|
||||
onAdd={inviteUser}
|
||||
addButtonText="Create User"
|
||||
addButtonText={t('accessUserCreate')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import { formatAxiosError } from "@app/lib/api";
|
|||
import { createApiClient } from "@app/lib/api";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
import { useUserContext } from "@app/hooks/useUserContext";
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export type UserRow = {
|
||||
id: string;
|
||||
|
@ -47,6 +48,7 @@ export default function UsersTable({ users: u }: UsersTableProps) {
|
|||
const api = createApiClient(useEnvContext());
|
||||
const { user, updateUser } = useUserContext();
|
||||
const { org } = useOrgContext();
|
||||
const t = useTranslations();
|
||||
|
||||
const columns: ColumnDef<UserRow>[] = [
|
||||
{
|
||||
|
@ -68,7 +70,7 @@ export default function UsersTable({ users: u }: UsersTableProps) {
|
|||
className="h-8 w-8 p-0"
|
||||
>
|
||||
<span className="sr-only">
|
||||
Open menu
|
||||
{t('openMenu')}
|
||||
</span>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</Button>
|
||||
|
@ -79,7 +81,7 @@ export default function UsersTable({ users: u }: UsersTableProps) {
|
|||
className="block w-full"
|
||||
>
|
||||
<DropdownMenuItem>
|
||||
Manage User
|
||||
{t('accessUsersManage')}
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
{`${userRow.username}-${userRow.idpId}` !==
|
||||
|
@ -95,7 +97,7 @@ export default function UsersTable({ users: u }: UsersTableProps) {
|
|||
}}
|
||||
>
|
||||
<span className="text-red-500">
|
||||
Remove User
|
||||
{t('accessUserRemove')}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
|
@ -118,7 +120,7 @@ export default function UsersTable({ users: u }: UsersTableProps) {
|
|||
column.toggleSorting(column.getIsSorted() === "asc")
|
||||
}
|
||||
>
|
||||
Username
|
||||
{t('username')}
|
||||
<ArrowUpDown className="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
);
|
||||
|
@ -134,7 +136,7 @@ export default function UsersTable({ users: u }: UsersTableProps) {
|
|||
column.toggleSorting(column.getIsSorted() === "asc")
|
||||
}
|
||||
>
|
||||
Identity Provider
|
||||
{t('identityProvider')}
|
||||
<ArrowUpDown className="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
);
|
||||
|
@ -150,7 +152,7 @@ export default function UsersTable({ users: u }: UsersTableProps) {
|
|||
column.toggleSorting(column.getIsSorted() === "asc")
|
||||
}
|
||||
>
|
||||
Role
|
||||
{t('role')}
|
||||
<ArrowUpDown className="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
);
|
||||
|
|
|
@ -10,6 +10,7 @@ import UserProvider from "@app/providers/UserProvider";
|
|||
import { verifySession } from "@app/lib/auth/verifySession";
|
||||
import AccessPageHeaderAndNav from "../AccessPageHeaderAndNav";
|
||||
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
|
||||
type UsersPageProps = {
|
||||
params: Promise<{ orgId: string }>;
|
||||
|
@ -83,11 +84,13 @@ export default async function UsersPage(props: UsersPageProps) {
|
|||
};
|
||||
});
|
||||
|
||||
const t = await getTranslations();
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsSectionTitle
|
||||
title="Manage Users"
|
||||
description="Invite users and add them to roles to manage access to your organization"
|
||||
title={t('accessUsersManage')}
|
||||
description={t('accessUsersDescription')}
|
||||
/>
|
||||
<UserProvider user={user!}>
|
||||
<OrgProvider org={org}>
|
||||
|
|
|
@ -10,6 +10,7 @@ import { GetOrgUserResponse } from "@server/routers/user";
|
|||
import { AxiosResponse } from "axios";
|
||||
import { redirect } from "next/navigation";
|
||||
import { cache } from "react";
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
|
||||
type GeneralSettingsProps = {
|
||||
children: React.ReactNode;
|
||||
|
@ -57,9 +58,11 @@ export default async function GeneralSettingsPage({
|
|||
redirect(`/${orgId}`);
|
||||
}
|
||||
|
||||
const t = await getTranslations();
|
||||
|
||||
const navItems = [
|
||||
{
|
||||
title: "General",
|
||||
title: t('general'),
|
||||
href: `/{orgId}/settings/general`,
|
||||
},
|
||||
];
|
||||
|
@ -69,8 +72,8 @@ export default async function GeneralSettingsPage({
|
|||
<OrgProvider org={org}>
|
||||
<OrgUserProvider orgUser={orgUser}>
|
||||
<SettingsSectionTitle
|
||||
title="General"
|
||||
description="Configure your organization's general settings"
|
||||
title={t('general')}
|
||||
description={t('orgSettingsDescription')}
|
||||
/>
|
||||
|
||||
<HorizontalTabs items={navItems}>
|
||||
|
|
|
@ -44,6 +44,7 @@ import {
|
|||
SettingsSectionFooter
|
||||
} from "@app/components/Settings";
|
||||
import { useUserContext } from "@app/hooks/useUserContext";
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
const GeneralFormSchema = z.object({
|
||||
name: z.string()
|
||||
|
@ -79,8 +80,8 @@ export default function GeneralPage() {
|
|||
);
|
||||
|
||||
toast({
|
||||
title: "Organization deleted",
|
||||
description: "The organization and its data has been deleted."
|
||||
title: t('orgDeleted'),
|
||||
description: t('orgDeletedMessage')
|
||||
});
|
||||
|
||||
if (res.status === 200) {
|
||||
|
@ -90,11 +91,8 @@ export default function GeneralPage() {
|
|||
console.error(err);
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to delete org",
|
||||
description: formatAxiosError(
|
||||
err,
|
||||
"An error occurred while deleting the org."
|
||||
)
|
||||
title: t('orgErrorDelete'),
|
||||
description: formatAxiosError(err,t('orgErrorDeleteMessage'))
|
||||
});
|
||||
} finally {
|
||||
setLoadingDelete(false);
|
||||
|
@ -121,11 +119,8 @@ export default function GeneralPage() {
|
|||
console.error(err);
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to fetch orgs",
|
||||
description: formatAxiosError(
|
||||
err,
|
||||
"An error occurred while listing your orgs"
|
||||
)
|
||||
title: t('orgErrorFetch'),
|
||||
description: formatAxiosError(err,t('orgErrorFetchMessage'))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -138,8 +133,8 @@ export default function GeneralPage() {
|
|||
})
|
||||
.then(() => {
|
||||
toast({
|
||||
title: "Organization updated",
|
||||
description: "The organization has been updated."
|
||||
title: t('orgUpdated'),
|
||||
description: t('orgUpdatedDescription')
|
||||
});
|
||||
|
||||
router.refresh();
|
||||
|
@ -147,11 +142,8 @@ export default function GeneralPage() {
|
|||
.catch((e) => {
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Failed to update org",
|
||||
description: formatAxiosError(
|
||||
e,
|
||||
"An error occurred while updating the org."
|
||||
)
|
||||
title: t('orgErrorUpdate'),
|
||||
description: formatAxiosError(e,t('orgErrorUpdateMessage'))
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
|
@ -159,6 +151,8 @@ export default function GeneralPage() {
|
|||
});
|
||||
}
|
||||
|
||||
const t = useTranslations();
|
||||
|
||||
return (
|
||||
<SettingsContainer>
|
||||
<ConfirmDeleteDialog
|
||||
|
@ -169,31 +163,29 @@ export default function GeneralPage() {
|
|||
dialog={
|
||||
<div>
|
||||
<p className="mb-2">
|
||||
Are you sure you want to delete the organization{" "}
|
||||
<b>{org?.org.name}?</b>
|
||||
{t('orgQuestionRemove', {selectedOrg: org?.org.name})}
|
||||
</p>
|
||||
<p className="mb-2">
|
||||
This action is irreversible and will delete all
|
||||
associated data.
|
||||
{t('orgMessageRemove')}
|
||||
</p>
|
||||
<p>
|
||||
To confirm, type the name of the organization below.
|
||||
{t('orgMessageConfirm')}
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
buttonText="Confirm Delete Organization"
|
||||
buttonText={t('orgDeleteConfirm')}
|
||||
onConfirm={deleteOrg}
|
||||
string={org?.org.name || ""}
|
||||
title="Delete Organization"
|
||||
title={t('orgDelete')}
|
||||
/>
|
||||
|
||||
<SettingsSection>
|
||||
<SettingsSectionHeader>
|
||||
<SettingsSectionTitle>
|
||||
Organization Settings
|
||||
{t('orgGeneralSettings')}
|
||||
</SettingsSectionTitle>
|
||||
<SettingsSectionDescription>
|
||||
Manage your organization details and configuration
|
||||
{t('orgGeneralSettingsDescription')}
|
||||
</SettingsSectionDescription>
|
||||
</SettingsSectionHeader>
|
||||
|
||||
|
@ -210,14 +202,13 @@ export default function GeneralPage() {
|
|||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormLabel>{t('name')}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormDescription>
|
||||
This is the display name of the
|
||||
organization.
|
||||
{t('orgDisplayName')}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
|
@ -234,17 +225,16 @@ export default function GeneralPage() {
|
|||
loading={loadingSave}
|
||||
disabled={loadingSave}
|
||||
>
|
||||
Save General Settings
|
||||
{t('orgGeneralSave')}
|
||||
</Button>
|
||||
</SettingsSectionFooter>
|
||||
</SettingsSection>
|
||||
|
||||
<SettingsSection>
|
||||
<SettingsSectionHeader>
|
||||
<SettingsSectionTitle>Danger Zone</SettingsSectionTitle>
|
||||
<SettingsSectionTitle>{t('orgDangerZone')}</SettingsSectionTitle>
|
||||
<SettingsSectionDescription>
|
||||
Once you delete this org, there is no going back. Please
|
||||
be certain.
|
||||
{t('orgDangerZoneDescription')}
|
||||
</SettingsSectionDescription>
|
||||
</SettingsSectionHeader>
|
||||
|
||||
|
@ -256,7 +246,7 @@ export default function GeneralPage() {
|
|||
loading={loadingDelete}
|
||||
disabled={loadingDelete}
|
||||
>
|
||||
Delete Organization Data
|
||||
{t('orgDelete')}
|
||||
</Button>
|
||||
</SettingsSectionFooter>
|
||||
</SettingsSection>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
"use client";
|
||||
|
||||
import { useEffect, useState, use } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue