more fixes

This commit is contained in:
Lokowitz 2025-05-17 20:04:56 +00:00
parent eff812eaa8
commit d9ee40c898
48 changed files with 122 additions and 135 deletions

View file

@ -385,7 +385,7 @@
"userErrorOrgRemoveDescription": "Beim Entfernen des Benutzers ist ein Fehler aufgetreten.",
"userOrgRemoved": "Benutzer entfernt",
"userOrgRemovedDescription": "Der Benutzer {email} wurde aus der Organisation entfernt.",
"userQuestionOrgRemove": "Sind Sie sicher, dass Sie <b>{email}</b> aus der Organisation entfernen möchten?",
"userQuestionOrgRemove": "Sind Sie sicher, dass Sie {email} aus der Organisation entfernen möchten?",
"userMessageOrgRemove": "Nach dem Entfernen hat dieser Benutzer keinen Zugriff mehr auf die Organisation. Sie können ihn später jederzeit wieder einladen, aber er muss die Einladung erneut annehmen.",
"userMessageOrgConfirm": "Geben Sie zur Bestätigung den Namen des Benutzers unten ein.",
"userRemoveOrgConfirm": "Entfernen des Benutzers bestätigen",
@ -684,7 +684,7 @@
"accessRoleErrorRemove": "Fehler beim Entfernen der Rolle",
"accessRoleErrorRemoveDescription": "Beim Entfernen der Rolle ist ein Fehler aufgetreten.",
"accessRoleName": "Rollenname",
"accessRoleQuestionRemove": "Sie sind dabei, die Rolle <b>{name}</b> zu löschen. Diese Aktion kann nicht rückgängig gemacht werden.",
"accessRoleQuestionRemove": "Sie sind dabei, die Rolle {name} zu löschen. Diese Aktion kann nicht rückgängig gemacht werden.",
"accessRoleRemove": "Rolle entfernen",
"accessRoleRemoveDescription": "Eine Rolle aus der Organisation entfernen",
"accessRoleRemoveSubmit": "Rolle entfernen",
@ -709,7 +709,7 @@
"idpManageDescription": "Identitätsanbieter im System anzeigen und verwalten",
"idpDeletedDescription": "Identitätsanbieter erfolgreich gelöscht",
"idpOidc": "OAuth2/OIDC",
"idpQuestionRemove": "Sind Sie sicher, dass Sie den Identitätsanbieter <b>{name}</b> dauerhaft löschen möchten?",
"idpQuestionRemove": "Sind Sie sicher, dass Sie den Identitätsanbieter {name} dauerhaft löschen möchten?",
"idpMessageRemove": "Dies wird den Identitätsanbieter und alle zugehörigen Konfigurationen entfernen. Benutzer, die sich über diesen Anbieter authentifizieren, können sich nicht mehr anmelden.",
"idpMessageConfirm": "Bitte geben Sie zur Bestätigung den Namen des Identitätsanbieters unten ein.",
"idpConfirmDelete": "Löschen des Identitätsanbieters bestätigen",

View file

@ -27,6 +27,7 @@
"createAnAccount": "Create an Account",
"inviteNotAccepted": "Invite Not Accepted",
"authCreateAccount": "Create an account to get started",
"authNoAccount": "Don't have an account?",
"email": "Email",
"password": "Password",
"confirmPassword": "Confirm Password",
@ -314,6 +315,9 @@
"licenseKeyDeletedDescription": "The license key has been deleted.",
"licenseErrorKeyActivate": "Failed to activate license key",
"licenseErrorKeyActivateDescription": "An error occurred while activating the license key.",
"licenseAbout": "About Licensing",
"communityEdition": "Community Edition",
"licenseAboutDescription": "This is for business and enterprise users who are using Pangolin in a commercial environment. If you are using Pangolin for personal use, you can ignore this section.",
"licenseKeyActivated": "License key activated",
"licenseKeyActivatedDescription": "The license key has been successfully activated.",
"licenseErrorKeyRecheck": "Failed to recheck license keys",
@ -350,6 +354,7 @@
"total": "Total",
"licenseContinuePayment": "Continue to Payment",
"pricingPage": "pricing page",
"pricingPortal": "See Purchase Portal",
"licensePricingPage": "For the most up-to-date pricing and discounts, please visit the ",
"invite": "Invitations",
"inviteRegenerate": "Regenerate Invitation",
@ -385,7 +390,7 @@
"userErrorOrgRemoveDescription": "An error occurred while removing the user.",
"userOrgRemoved": "User removed",
"userOrgRemovedDescription": "The user {email} has been removed from the organization.",
"userQuestionOrgRemove": "Are you sure you want to remove <b>{email}</b> from the organization?",
"userQuestionOrgRemove": "Are you sure you want to remove {email} from the organization?",
"userMessageOrgRemove": "Once removed, this user will no longer have access to the organization. You can always re-invite them later, but they will need to accept the invitation again.",
"userMessageOrgConfirm": "To confirm, please type the name of the of the user below.",
"userRemoveOrgConfirm": "Confirm Remove User",
@ -626,6 +631,7 @@
"resourceErrorWhitelistSave": "Failed to save whitelist",
"resourceErrorWhitelistSaveDescription": "An error occurred while saving the whitelist",
"resourcePasswordSubmit": "Enable Password Protection",
"resourcePasswordProtection": "Password Protection {status}",
"resourcePasswordRemove": "Resource password removed",
"resourcePasswordRemoveDescription": "The resource password has been removed successfully",
"resourcePasswordSetup": "Resource password set",
@ -707,7 +713,7 @@
"idpManageDescription": "View and manage identity providers in the system",
"idpDeletedDescription": "Identity provider deleted successfully",
"idpOidc": "OAuth2/OIDC",
"idpQuestionRemove": "Are you sure you want to permanently delete the identity provider <b>{name}</b>?",
"idpQuestionRemove": "Are you sure you want to permanently delete the identity provider {name}?",
"idpMessageRemove": "This will remove the identity provider and all associated configurations. Users who authenticate through this provider will no longer be able to log in.",
"idpMessageConfirm": "To confirm, please type the name of the identity provider below.",
"idpConfirmDelete": "Confirm Delete Identity Provider",
@ -792,6 +798,7 @@
"orgMappingPathOptional": "Organization Mapping Path (Optional)",
"orgPolicyUpdate": "Update Policy",
"orgPolicyAdd": "Add Policy",
"orgPolicyConfig": "Configure access for an organization",
"idpUpdatedDescription": "Identity provider updated successfully",
"redirectUrl": "Redirect URL",
"redirectUrlAbout": "About Redirect URL",

View file

@ -385,7 +385,7 @@
"userErrorOrgRemoveDescription": "Une erreur s'est produite lors de la suppression de l'utilisateur.",
"userOrgRemoved": "Utilisateur supprimé",
"userOrgRemovedDescription": "L'utilisateur {email} a été retiré de l'organisation.",
"userQuestionOrgRemove": "Êtes-vous sûr de vouloir retirer <b>{email}</b> de l'organisation ?",
"userQuestionOrgRemove": "Êtes-vous sûr de vouloir retirer {email} de l'organisation ?",
"userMessageOrgRemove": "Une fois retiré, cet utilisateur n'aura plus accès à l'organisation. Vous pouvez toujours le réinviter plus tard, mais il devra accepter l'invitation à nouveau.",
"userMessageOrgConfirm": "Pour confirmer, veuillez saisir le nom de l'utilisateur ci-dessous.",
"userRemoveOrgConfirm": "Confirmer la suppression de l'utilisateur",
@ -684,7 +684,7 @@
"accessRoleErrorRemove": "Échec de la suppression du rôle",
"accessRoleErrorRemoveDescription": "Une erreur s'est produite lors de la suppression du rôle.",
"accessRoleName": "Nom du rôle",
"accessRoleQuestionRemove": "Vous êtes sur le point de supprimer le rôle <b>{name}</b>. Cette action est irréversible.",
"accessRoleQuestionRemove": "Vous êtes sur le point de supprimer le rôle {name}. Cette action est irréversible.",
"accessRoleRemove": "Supprimer le rôle",
"accessRoleRemoveDescription": "Retirer un rôle de l'organisation",
"accessRoleRemoveSubmit": "Supprimer le rôle",
@ -709,7 +709,7 @@
"idpManageDescription": "Voir et gérer les fournisseurs d'identité dans le système",
"idpDeletedDescription": "Fournisseur d'identité supprimé avec succès",
"idpOidc": "OAuth2/OIDC",
"idpQuestionRemove": "Êtes-vous sûr de vouloir supprimer définitivement le fournisseur d'identité <b>{name}</b> ?",
"idpQuestionRemove": "Êtes-vous sûr de vouloir supprimer définitivement le fournisseur d'identité {name}?",
"idpMessageRemove": "Cela supprimera le fournisseur d'identité et toutes les configurations associées. Les utilisateurs qui s'authentifient via ce fournisseur ne pourront plus se connecter.",
"idpMessageConfirm": "Pour confirmer, veuillez saisir le nom du fournisseur d'identité ci-dessous.",
"idpConfirmDelete": "Confirmer la suppression du fournisseur d'identité",

View file

@ -385,7 +385,7 @@
"userErrorOrgRemoveDescription": "Si è verificato un errore durante la rimozione dell'utente.",
"userOrgRemoved": "Utente rimosso",
"userOrgRemovedDescription": "L'utente {email} è stato rimosso dall'organizzazione.",
"userQuestionOrgRemove": "Sei sicuro di voler rimuovere <b>{email}</b> dall'organizzazione?",
"userQuestionOrgRemove": "Sei sicuro di voler rimuovere {email} dall'organizzazione?",
"userMessageOrgRemove": "Una volta rimosso, questo utente non avrà più accesso all'organizzazione. Puoi sempre reinvitarlo in seguito, ma dovrà accettare nuovamente l'invito.",
"userMessageOrgConfirm": "Per confermare, digita il nome dell'utente qui sotto.",
"userRemoveOrgConfirm": "Conferma Rimozione Utente",
@ -684,7 +684,7 @@
"accessRoleErrorRemove": "Impossibile rimuovere il ruolo",
"accessRoleErrorRemoveDescription": "Si è verificato un errore durante la rimozione del ruolo.",
"accessRoleName": "Nome Del Ruolo",
"accessRoleQuestionRemove": "Stai per eliminare il ruolo <b>{name}</b>. Non puoi annullare questa azione.",
"accessRoleQuestionRemove": "Stai per eliminare il ruolo {name}. Non puoi annullare questa azione.",
"accessRoleRemove": "Rimuovi Ruolo",
"accessRoleRemoveDescription": "Rimuovi un ruolo dall'organizzazione",
"accessRoleRemoveSubmit": "Rimuovi Ruolo",
@ -709,7 +709,7 @@
"idpManageDescription": "Visualizza e gestisci i provider di identità nel sistema",
"idpDeletedDescription": "Provider di identità eliminato con successo",
"idpOidc": "OAuth2/OIDC",
"idpQuestionRemove": "Sei sicuro di voler eliminare definitivamente il provider di identità <b>{name}</b>?",
"idpQuestionRemove": "Sei sicuro di voler eliminare definitivamente il provider di identità {name}?",
"idpMessageRemove": "Questo rimuoverà il provider di identità e tutte le configurazioni associate. Gli utenti che si autenticano tramite questo provider non potranno più accedere.",
"idpMessageConfirm": "Per confermare, digita il nome del provider di identità qui sotto.",
"idpConfirmDelete": "Conferma Eliminazione Provider di Identità",

View file

@ -385,7 +385,7 @@
"userErrorOrgRemoveDescription": "Wystąpił błąd podczas usuwania użytkownika.",
"userOrgRemoved": "Użytkownik usunięty",
"userOrgRemovedDescription": "Użytkownik {email} został usunięty z organizacji.",
"userQuestionOrgRemove": "Czy na pewno chcesz usunąć <b>{email}</b> z organizacji?",
"userQuestionOrgRemove": "Czy na pewno chcesz usunąć {email} z organizacji?",
"userMessageOrgRemove": "Po usunięciu ten użytkownik nie będzie miał już dostępu do organizacji. Zawsze możesz ponownie go zaprosić później, ale będzie musiał ponownie zaakceptować zaproszenie.",
"userMessageOrgConfirm": "Aby potwierdzić, wpisz nazwę użytkownika poniżej.",
"userRemoveOrgConfirm": "Potwierdź usunięcie użytkownika",
@ -684,7 +684,7 @@
"accessRoleErrorRemove": "Nie udało się usunąć roli",
"accessRoleErrorRemoveDescription": "Wystąpił błąd podczas usuwania roli.",
"accessRoleName": "Nazwa roli",
"accessRoleQuestionRemove": "Zamierzasz usunąć rolę <b>{name}</b>. Tej akcji nie można cofnąć.",
"accessRoleQuestionRemove": "Zamierzasz usunąć rolę {name}. Tej akcji nie można cofnąć.",
"accessRoleRemove": "Usuń rolę",
"accessRoleRemoveDescription": "Usuń rolę z organizacji",
"accessRoleRemoveSubmit": "Usuń rolę",
@ -709,7 +709,7 @@
"idpManageDescription": "Wyświetl i zarządzaj dostawcami tożsamości w systemie",
"idpDeletedDescription": "Dostawca tożsamości został pomyślnie usunięty",
"idpOidc": "OAuth2/OIDC",
"idpQuestionRemove": "Czy na pewno chcesz trwale usunąć dostawcę tożsamości <b>{name}</b>?",
"idpQuestionRemove": "Czy na pewno chcesz trwale usunąć dostawcę tożsamości {name}?",
"idpMessageRemove": "Spowoduje to usunięcie dostawcy tożsamości i wszystkich powiązanych konfiguracji. Użytkownicy uwierzytelniający się przez tego dostawcę nie będą mogli się już zalogować.",
"idpMessageConfirm": "Aby potwierdzić, wpisz nazwę dostawcy tożsamości poniżej.",
"idpConfirmDelete": "Potwierdź usunięcie dostawcy tożsamości",

View file

@ -385,7 +385,7 @@
"userErrorOrgRemoveDescription": "Ocorreu um erro ao remover o usuário.",
"userOrgRemoved": "Usuário removido",
"userOrgRemovedDescription": "O usuário {email} foi removido da organização.",
"userQuestionOrgRemove": "Tem certeza que deseja remover <b>{email}</b> da organização?",
"userQuestionOrgRemove": "Tem certeza que deseja remover {email} da organização?",
"userMessageOrgRemove": "Uma vez removido, este usuário não terá mais acesso à organização. Você sempre pode reconvidá-lo depois, mas eles precisarão aceitar o convite novamente.",
"userMessageOrgConfirm": "Para confirmar, digite o nome do usuário abaixo.",
"userRemoveOrgConfirm": "Confirmar Remoção do Usuário",
@ -684,7 +684,7 @@
"accessRoleErrorRemove": "Falha ao remover função",
"accessRoleErrorRemoveDescription": "Ocorreu um erro ao remover a função.",
"accessRoleName": "Nome da Função",
"accessRoleQuestionRemove": "Você está prestes a excluir a função <b>{name}</b>. Você não pode desfazer esta ação.",
"accessRoleQuestionRemove": "Você está prestes a excluir a função {name}. Você não pode desfazer esta ação.",
"accessRoleRemove": "Remover Função",
"accessRoleRemoveDescription": "Remover uma função da organização",
"accessRoleRemoveSubmit": "Remover Função",
@ -709,7 +709,7 @@
"idpManageDescription": "Visualizar e gerir provedores de identidade no sistema",
"idpDeletedDescription": "Provedor de identidade eliminado com sucesso",
"idpOidc": "OAuth2/OIDC",
"idpQuestionRemove": "Tem certeza que deseja eliminar permanentemente o provedor de identidade <b>{name}</b>?",
"idpQuestionRemove": "Tem certeza que deseja eliminar permanentemente o provedor de identidade {name}?",
"idpMessageRemove": "Isto irá remover o provedor de identidade e todas as configurações associadas. Os utilizadores que se autenticam através deste provedor não poderão mais fazer login.",
"idpMessageConfirm": "Para confirmar, por favor digite o nome do provedor de identidade abaixo.",
"idpConfirmDelete": "Confirmar Eliminação do Provedor de Identidade",

View file

@ -385,7 +385,7 @@
"userErrorOrgRemoveDescription": "An error occurred while removing the user.",
"userOrgRemoved": "User removed",
"userOrgRemovedDescription": "The user {email} has been removed from the organization.",
"userQuestionOrgRemove": "Are you sure you want to remove <b>{email}</b> from the organization?",
"userQuestionOrgRemove": "Are you sure you want to remove {email} from the organization?",
"userMessageOrgRemove": "Once removed, this user will no longer have access to the organization. You can always re-invite them later, but they will need to accept the invitation again.",
"userMessageOrgConfirm": "To confirm, please type the name of the of the user below.",
"userRemoveOrgConfirm": "Confirm Remove User",
@ -709,7 +709,7 @@
"idpManageDescription": "View and manage identity providers in the system",
"idpDeletedDescription": "Identity provider deleted successfully",
"idpOidc": "OAuth2/OIDC",
"idpQuestionRemove": "Are you sure you want to permanently delete the identity provider <b>{name}</b>?",
"idpQuestionRemove": "Are you sure you want to permanently delete the identity provider {name}?",
"idpMessageRemove": "This will remove the identity provider and all associated configurations. Users who authenticate through this provider will no longer be able to log in.",
"idpMessageConfirm": "To confirm, please type the name of the identity provider below.",
"idpConfirmDelete": "Confirm Delete Identity Provider",

View file

@ -14,6 +14,7 @@ export default function AccessPageHeaderAndNav({
hasInvitations
}: AccessPageHeaderAndNavProps) {
const t = useTranslations();
const navItems = [
{
title: t('users'),

View file

@ -123,7 +123,7 @@ export default function RegenerateInvitationForm({
onRegenerate({
id: invitation.id,
email: invitation.email,
expiresAt: res.data.data.expiresAt ?? "",
expiresAt: res.data.data.expiresAt,
role: invitation.role,
roleId: invitation.roleId
});

View file

@ -19,6 +19,7 @@ export const dynamic = "force-dynamic";
export default async function InvitationsPage(props: InvitationsPageProps) {
const params = await props.params;
const t = await getTranslations();
const getUser = cache(verifySession);
const user = await getUser();
@ -72,8 +73,6 @@ export default async function InvitationsPage(props: InvitationsPageProps) {
};
});
const t = await getTranslations();
return (
<>
<SettingsSectionTitle

View file

@ -222,7 +222,7 @@ export default function UsersTable({ users: u }: UsersTableProps) {
toast({
variant: "default",
title: t('userOrgRemoved'),
description: t('userOrgRemovedDescription', {email: selectedUser.email || ''})
description: t('userOrgRemovedDescription', {email: selectedUser.email})
});
setUsers((prev) =>
@ -244,7 +244,7 @@ export default function UsersTable({ users: u }: UsersTableProps) {
dialog={
<div className="space-y-4">
<p>
{t('userQuestionOrgRemove', {email: selectedUser?.email || selectedUser?.name || selectedUser?.username || ''})}
{t('userQuestionOrgRemove', {email: selectedUser?.email || selectedUser?.name || selectedUser?.username})}
</p>
<p>

View file

@ -92,6 +92,7 @@ export default function Page() {
const api = createApiClient({ env });
const { orgId } = useParams();
const router = useRouter();
const t = useTranslations();
const [loadingPage, setLoadingPage] = useState(true);
const [createLoading, setCreateLoading] = useState(false);
@ -114,8 +115,6 @@ export default function Page() {
}
});
const t = useTranslations();
async function onSubmit(data: CreateFormValues) {
setCreateLoading(true);

View file

@ -60,6 +60,7 @@ export default function GeneralPage() {
const { org } = useOrgContext();
const api = createApiClient(useEnvContext());
const { user } = useUserContext();
const t = useTranslations();
const [loadingDelete, setLoadingDelete] = useState(false);
const [loadingSave, setLoadingSave] = useState(false);
@ -151,8 +152,6 @@ export default function GeneralPage() {
});
}
const t = useTranslations();
return (
<SettingsContainer>
<ConfirmDeleteDialog

View file

@ -9,7 +9,6 @@ import {
SelectTrigger,
SelectValue
} from "@/components/ui/select";
import { useTranslations } from "next-intl";
interface DomainOption {
baseDomain: string;
@ -24,12 +23,10 @@ interface CustomDomainInputProps {
onChange?: (value: string, selectedDomainId: string) => void;
}
const t = useTranslations();
export default function CustomDomainInput({
domainOptions,
selectedDomainId,
placeholder = t('subdomain'),
placeholder = "Subdomain",
value: defaultValue,
onChange
}: CustomDomainInputProps) {

View file

@ -57,6 +57,7 @@ export default function SetResourcePasswordForm({
onSetPassword
}: SetPasswordFormProps) {
const api = createApiClient(useEnvContext());
const t = useTranslations();
const [loading, setLoading] = useState(false);
@ -65,8 +66,6 @@ export default function SetResourcePasswordForm({
defaultValues
});
const t = useTranslations();
useEffect(() => {
if (!open) {
return;

View file

@ -83,6 +83,7 @@ export default function ResourceAuthenticationPage() {
const api = createApiClient({ env });
const router = useRouter();
const t = useTranslations();
const [pageLoading, setPageLoading] = useState(true);
@ -130,8 +131,6 @@ export default function ResourceAuthenticationPage() {
defaultValues: { emails: [] }
});
const t = useTranslations();
useEffect(() => {
const fetchData = async () => {
try {
@ -565,8 +564,7 @@ export default function ResourceAuthenticationPage() {
>
<Key />
<span>
Password Protection{" "}
{authInfo.password ? t('enabled') : t('disabled')}
{t('resourcePasswordProtection', {status: authInfo.password? t('enabled') : t('disabled')})}
</span>
</div>
<Button

View file

@ -927,6 +927,7 @@ function isIPInSubnet(subnet: string, ip: string): boolean {
// Split subnet into IP and mask parts
const [subnetIP, maskBits] = subnet.split("/");
const mask = parseInt(maskBits);
const t = useTranslations();
if (mask < 0 || mask > 32) {
throw new Error(t('subnetMaskErrorInvalid'));
@ -946,6 +947,8 @@ function isIPInSubnet(subnet: string, ip: string): boolean {
function ipToNumber(ip: string): number {
// Validate IP address format
const parts = ip.split(".");
const t = useTranslations();
if (parts.length !== 4) {
throw new Error(t('ipAddressErrorInvalidFormat'));
}

View file

@ -88,17 +88,15 @@ type LocalRule = ArrayElement<ListResourceRulesResponse["rules"]> & {
updated?: boolean;
};
const t = useTranslations();
const RuleAction = {
ACCEPT: t('alwaysAllow'),
DROP: t('alwaysDeny')
ACCEPT: "Always Allow",
DROP: "Always Deny"
} as const;
const RuleMatch = {
PATH: t('path'),
PATH: "Path",
IP: "IP",
CIDR: t('ipAddressRange')
CIDR: "IP Range"
} as const;
export default function ResourceRules(props: {
@ -113,6 +111,7 @@ export default function ResourceRules(props: {
const [pageLoading, setPageLoading] = useState(true);
const [rulesEnabled, setRulesEnabled] = useState(resource.applyRules);
const router = useRouter();
const t = useTranslations();
const addRuleForm = useForm({
resolver: zodResolver(addRuleSchema),

View file

@ -199,10 +199,10 @@ export default function Page() {
.catch((e) => {
toast({
variant: "destructive",
title: "Error creating resource",
title: t('resourceErrorCreate'),
description: formatAxiosError(
e,
"An error occurred when creating the resource"
t('resourceErrorCreateDescription')
)
});
});
@ -219,11 +219,11 @@ export default function Page() {
}
}
} catch (e) {
console.error("Error creating resource:", e);
console.error(t('resourceErrorCreateMessage'), e);
toast({
variant: "destructive",
title: "Error creating resource",
description: "An unexpected error occurred"
title: t('resourceErrorCreate'),
description:t('resourceErrorCreateMessageDescription')
});
}

View file

@ -144,10 +144,10 @@ export default function CreateShareLinkForm({
console.error(e);
toast({
variant: "destructive",
title: "Failed to fetch resources",
title: t('shareErrorFetchResource'),
description: formatAxiosError(
e,
"An error occurred while fetching the resources"
t('shareErrorFetchResourceDescription')
)
});
});
@ -211,10 +211,10 @@ export default function CreateShareLinkForm({
console.error(e);
toast({
variant: "destructive",
title: "Failed to create share link",
title: t('shareErrorCreate'),
description: formatAxiosError(
e,
"An error occurred while creating the share link"
t('shareErrorCreateDescription')
)
});
});

View file

@ -42,6 +42,7 @@ export function ApiKeysDataTable<TData, TValue>({
}: DataTableProps<TData, TValue>) {
const t = useTranslations();
return (
<DataTable
columns={columns}

View file

@ -79,18 +79,18 @@ export default function Page() {
)
})
.catch((e) => {
console.error("Error setting permissions", e);
console.error(t('apiKeysErrorSetPermission'), e);
toast({
variant: "destructive",
title: "Error setting permissions",
title: t('apiKeysErrorSetPermission'),
description: formatAxiosError(e)
});
});
if (actionsRes && actionsRes.status === 200) {
toast({
title: "Permissions updated",
description: "The permissions have been updated."
title: t('apiKeysPermissionsUpdated'),
description: t('apiKeysPermissionsUpdatedDescription')
});
}

View file

@ -89,6 +89,7 @@ export default function Page() {
const { env } = useEnvContext();
const api = createApiClient({ env });
const router = useRouter();
const t = useTranslations();
const [loadingPage, setLoadingPage] = useState(true);
const [createLoading, setCreateLoading] = useState(false);
@ -111,8 +112,6 @@ export default function Page() {
}
});
const t = useTranslations();
async function onSubmit(data: CreateFormValues) {
setCreateLoading(true);

View file

@ -4,7 +4,7 @@ import { AxiosResponse } from "axios";
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
import { ListRootApiKeysResponse } from "@server/routers/apiKeys";
import ApiKeysTable, { ApiKeyRow } from "./ApiKeysTable";
import { useTranslations } from "next-intl";
import { getTranslations } from 'next-intl/server';
type ApiKeyPageProps = {};
@ -12,7 +12,6 @@ export const dynamic = "force-dynamic";
export default async function ApiKeysPage(props: ApiKeyPageProps) {
let apiKeys: ListRootApiKeysResponse["apiKeys"] = [];
const t = useTranslations();
try {
const res = await internal.get<AxiosResponse<ListRootApiKeysResponse>>(
`/api-keys`,
@ -30,6 +29,8 @@ export default async function ApiKeysPage(props: ApiKeyPageProps) {
};
});
const t = await getTranslations();
return (
<>
<SettingsSectionTitle

View file

@ -146,14 +146,14 @@ export default function GeneralPage() {
if (res.status === 200) {
toast({
title: "Success",
description: "Identity provider updated successfully"
title: t('success'),
description: t('idpUpdatedDescription')
});
router.refresh();
}
} catch (e) {
toast({
title: "Error",
title: t('error'),
description: formatAxiosError(e),
variant: "destructive"
});
@ -372,7 +372,6 @@ export default function GeneralPage() {
{t('idpJmespathAbout')}
</AlertTitle>
<AlertDescription>
{/*TODO(vlalx): Validate replacing */}
{t('idpJmespathAboutDescription')}
<a
href="https://jmespath.org"

View file

@ -25,6 +25,7 @@ interface SettingsLayoutProps {
export default async function SettingsLayout(props: SettingsLayoutProps) {
const params = await props.params;
const { children } = props;
const t = await getTranslations();
let idp = null;
try {
@ -37,8 +38,6 @@ export default async function SettingsLayout(props: SettingsLayoutProps) {
redirect("/admin/idp");
}
const t = await getTranslations();
const navItems: HorizontalTabs = [
{
title: t('general'),

View file

@ -15,7 +15,9 @@ export function PolicyDataTable<TData, TValue>({
data,
onAdd
}: DataTableProps<TData, TValue>) {
const t = useTranslations();
return (
<DataTable
columns={columns}

View file

@ -89,6 +89,7 @@ export default function PoliciesPage() {
const api = createApiClient({ env });
const router = useRouter();
const { idpId } = useParams();
const t = useTranslations();
const [pageLoading, setPageLoading] = useState(true);
const [addPolicyLoading, setAddPolicyLoading] = useState(false);
@ -118,8 +119,6 @@ export default function PoliciesPage() {
}
});
const t = useTranslations();
const loadIdp = async () => {
try {
const res = await api.get<AxiosResponse<GetIdpResponse>>(
@ -450,7 +449,7 @@ export default function PoliciesPage() {
: t('orgPoliciesAdd')}
</CredenzaTitle>
<CredenzaDescription>
Configure access for an organization
{t('orgPolicyConfig')}
</CredenzaDescription>
</CredenzaHeader>
<CredenzaBody>

View file

@ -77,6 +77,7 @@ export default function Page() {
const router = useRouter();
const [createLoading, setCreateLoading] = useState(false);
const { isUnlocked } = useLicenseStatusContext();
const t = useTranslations();
const form = useForm<CreateIdpFormValues>({
resolver: zodResolver(createIdpFormSchema),
@ -95,8 +96,6 @@ export default function Page() {
}
});
const t = useTranslations();
async function onSubmit(data: CreateIdpFormValues) {
setCreateLoading(true);
@ -370,7 +369,6 @@ export default function Page() {
{t('idpJmespathAbout')}
</AlertTitle>
<AlertDescription>
{/*TODO(vlalx): Validate replacing */}
{t('idpJmespathAboutDescription')}{" "}
<a
href="https://jmespath.org"

View file

@ -10,7 +10,6 @@ import { AxiosResponse } from "axios";
import { authCookieHeader } from "@app/lib/api/cookies";
import { Layout } from "@app/components/Layout";
import { adminNavItems } from "../navigation";
import { useTranslations } from "next-intl";
export const dynamic = "force-dynamic";

View file

@ -122,7 +122,7 @@ export function SitePriceCalculator({
<Button variant="outline">{t('cancel')}</Button>
</CredenzaClose>
<Button onClick={continueToPayment}>
See Purchase Portal
{t('pricingPortal')}
</Button>
</CredenzaFooter>
</CredenzaContent>

View file

@ -130,10 +130,10 @@ export default function LicensePage() {
}
} catch (e) {
toast({
title: "Failed to load license keys",
title: t('licenseErrorKeyLoad'),
description: formatAxiosError(
e,
"An error occurred loading license keys."
t('licenseErrorKeyLoadDescription')
)
});
}
@ -149,16 +149,16 @@ export default function LicensePage() {
}
await loadLicenseKeys();
toast({
title: "License key deleted",
description: "The license key has been deleted."
title: t('licenseKeyDeleted'),
description: t('licenseKeyDeletedDescription')
});
setIsDeleteModalOpen(false);
} catch (e) {
toast({
title: "Failed to delete license key",
title: t('licenseErrorKeyDelete'),
description: formatAxiosError(
e,
"An error occurred deleting license key."
t('licenseErrorKeyDeleteDescription')
)
});
} finally {
@ -175,15 +175,15 @@ export default function LicensePage() {
}
await loadLicenseKeys();
toast({
title: "License keys rechecked",
description: "All license keys have been rechecked"
title: t('licenseErrorKeyRechecked'),
description: t('licenseErrorKeyRecheckedDescription')
});
} catch (e) {
toast({
title: "Failed to recheck license keys",
title: t('licenseErrorKeyRecheck'),
description: formatAxiosError(
e,
"An error occurred rechecking license keys."
t('licenseErrorKeyRecheckDescription')
)
});
} finally {
@ -202,8 +202,8 @@ export default function LicensePage() {
}
toast({
title: "License key activated",
description: "The license key has been successfully activated."
title: t('licenseKeyActivated'),
description: t('licenseKeyActivatedDescription')
});
setIsCreateModalOpen(false);
@ -212,10 +212,10 @@ export default function LicensePage() {
} catch (e) {
toast({
variant: "destructive",
title: "Failed to activate license key",
title: t('licenseErrorKeyActivate'),
description: formatAxiosError(
e,
"An error occurred while activating the license key."
t('licenseErrorKeyActivateDescription')
)
});
} finally {
@ -360,12 +360,10 @@ export default function LicensePage() {
<Alert variant="neutral" className="mb-6">
<InfoIcon className="h-4 w-4" />
<AlertTitle className="font-semibold">
About Licensing
{t('licenseAbout')}
</AlertTitle>
<AlertDescription>
This is for business and enterprise users who are using
Pangolin in a commercial environment. If you are using
Pangolin for personal use, you can ignore this section.
{t('licenseAboutDescription')}
</AlertDescription>
</Alert>
@ -397,12 +395,12 @@ export default function LicensePage() {
<div className="space-y-2">
{supporterStatus?.visible ? (
<div className="text-2xl">
Community Edition
{t('communityEdition')}
</div>
) : (
<div className="text-2xl flex items-center gap-2 text-pink-500">
<Heart />
Community Edition
{t('communityEdition')}
</div>
)}
</div>

View file

@ -3,7 +3,7 @@ import ValidateOidcToken from "./ValidateOidcToken";
import { idp } from "@server/db/schemas";
import db from "@server/db";
import { eq } from "drizzle-orm";
import { useTranslations } from "next-intl";
import { getTranslations } from 'next-intl/server';
export default async function Page(props: {
params: Promise<{ orgId: string; idpId: string }>;
@ -14,6 +14,7 @@ export default async function Page(props: {
}) {
const params = await props.params;
const searchParams = await props.searchParams;
const t = await getTranslations();
const allCookies = await cookies();
const stateCookie = allCookies.get("p_oidc_state")?.value;
@ -24,8 +25,6 @@ export default async function Page(props: {
.from(idp)
.where(eq(idp.idpId, parseInt(params.idpId!)));
const t = useTranslations();
if (!idpRes) {
return <div>{t('idpErrorNotFound')}</div>;
}

View file

@ -73,7 +73,7 @@ export default async function AuthLayout({ children }: AuthLayoutProps) {
aria-label="GitHub"
className="flex items-center space-x-2 whitespace-nowrap"
>
<span>Community Edition</span>
<span>{t('communityEdition')}</span>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"

View file

@ -63,7 +63,7 @@ export default async function Page(props: {
{(!signUpDisabled || isInvite) && (
<p className="text-center text-muted-foreground mt-4">
Don't have an account?{" "}
{t('authNoAccount')}{" "}
<Link
href={
!redirectUrl

View file

@ -138,8 +138,8 @@ export default function ResetPasswordForm({
} as RequestPasswordResetBody
)
.catch((e) => {
setError(formatAxiosError(e, "An error occurred"));
console.error("Failed to request reset:", e);
setError(formatAxiosError(e, t('errorOccurred')));
console.error(t('passwordErrorRequestReset'), e);
setIsSubmitting(false);
});
@ -168,8 +168,8 @@ export default function ResetPasswordForm({
} as ResetPasswordBody
)
.catch((e) => {
setError(formatAxiosError(e, "An error occurred"));
console.error("Failed to reset password:", e);
setError(formatAxiosError(e, t('errorOccurred')));
console.error(t('passwordErrorReset'), e);
setIsSubmitting(false);
});
@ -185,7 +185,7 @@ export default function ResetPasswordForm({
return;
}
setSuccessMessage("Password reset successfully! Back to log in...");
setSuccessMessage(t('passwordResetSuccess'));
setTimeout(() => {
if (redirect) {

View file

@ -4,7 +4,7 @@ import { cache } from "react";
import ResetPasswordForm from "./ResetPasswordForm";
import Link from "next/link";
import { cleanRedirect } from "@app/lib/cleanRedirect";
import { useTranslations } from "next-intl";
import { getTranslations } from 'next-intl/server';
export const dynamic = "force-dynamic";
@ -18,6 +18,7 @@ export default async function Page(props: {
const searchParams = await props.searchParams;
const getUser = cache(verifySession);
const user = await getUser();
const t = await getTranslations();
if (user) {
redirect("/");
@ -28,8 +29,6 @@ export default async function Page(props: {
redirectUrl = cleanRedirect(searchParams.redirect);
}
const t = useTranslations();
return (
<>
<ResetPasswordForm

View file

@ -102,7 +102,7 @@ export default function AccessToken({
);
}
} catch (e) {
console.error("Error checking access token", e);
console.error(t('accessTokenError'), e);
} finally {
setLoading(false);
}

View file

@ -87,6 +87,7 @@ type ResourceAuthPortalProps = {
export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
const router = useRouter();
const t = useTranslations();
const getNumMethods = () => {
let colLength = 0;
@ -171,8 +172,6 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
return fullUrl.toString();
}
const t = useTranslations();
const onWhitelistSubmit = (values: any) => {
setLoadingLogin(true);
api.post<AxiosResponse<AuthWithWhitelistResponse>>(

View file

@ -10,6 +10,7 @@ import Link from "next/link";
import { useTranslations } from "next-intl";
export default async function ResourceNotFound() {
const t = useTranslations();
return (

View file

@ -87,7 +87,7 @@ export default function SignupForm({
.catch((e) => {
console.error(e);
setError(
formatAxiosError(e, "An error occurred while signing up")
formatAxiosError(e, t('signupError'))
);
});

View file

@ -6,7 +6,7 @@ import { Mail } from "lucide-react";
import Link from "next/link";
import { redirect } from "next/navigation";
import { cache } from "react";
import { useTranslations } from "next-intl";
import { getTranslations } from 'next-intl/server';
export const dynamic = "force-dynamic";
@ -16,13 +16,12 @@ export default async function Page(props: {
const searchParams = await props.searchParams;
const getUser = cache(verifySession);
const user = await getUser();
const t = await getTranslations();
const env = pullEnv();
const isInvite = searchParams?.redirect?.includes("/invite");
const t = useTranslations();
if (env.flags.disableSignupWithoutInvite && !isInvite) {
redirect("/");
}

View file

@ -56,6 +56,7 @@ export default function VerifyEmailForm({
redirect,
}: VerifyEmailFormProps) {
const router = useRouter();
const t = useTranslations();
const [error, setError] = useState<string | null>(null);
const [successMessage, setSuccessMessage] = useState<string | null>(null);
@ -72,8 +73,6 @@ export default function VerifyEmailForm({
},
});
const t = useTranslations();
async function onSubmit(data: z.infer<typeof FormSchema>) {
setIsSubmitting(true);
@ -82,15 +81,15 @@ export default function VerifyEmailForm({
code: data.pin,
})
.catch((e) => {
setError(formatAxiosError(e, "An error occurred"));
console.error("Failed to verify email:", e);
setError(formatAxiosError(e, t('errorOccurred')));
console.error(t('emailErrorVerify'), e);
setIsSubmitting(false);
});
if (res && res.data?.data?.valid) {
setError(null);
setSuccessMessage(
"Email successfully verified! Redirecting you..."
t('emailVerified')
);
setTimeout(() => {
if (redirect) {
@ -108,16 +107,16 @@ export default function VerifyEmailForm({
setIsResending(true);
const res = await api.post("/auth/verify-email/request").catch((e) => {
setError(formatAxiosError(e, "An error occurred"));
console.error("Failed to resend verification code:", e);
setError(formatAxiosError(e, t('errorOccurred')));
console.error(t('verificationCodeErrorResend'), e);
});
if (res) {
setError(null);
toast({
variant: "default",
title: "Verification code resent",
description: "We've resent a verification code to your email address. Please check your inbox.",
title: t('verificationCodeResend'),
description: t('verificationCodeResendDescription'),
});
}

View file

@ -6,6 +6,7 @@ import { Star } from "lucide-react";
import { useTranslations } from 'next-intl';
export default function SupporterMessage({ tier }: { tier: string }) {
const t = useTranslations();
return (

View file

@ -6,9 +6,7 @@ import { AxiosResponse } from "axios";
import { redirect } from "next/navigation";
import InviteStatusCard from "./InviteStatusCard";
import { formatAxiosError } from "@app/lib/api";
import { useTranslations } from "next-intl";
;
import { getTranslations } from 'next-intl/server';
export default async function InvitePage(props: {
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
@ -22,8 +20,7 @@ export default async function InvitePage(props: {
}
const user = await verifySession();
const t = useTranslations();
const t = await getTranslations();
const parts = tokenParam.split("-");
if (parts.length !== 2) {

View file

@ -10,7 +10,6 @@ import {
KeyRound,
TicketCheck
} from "lucide-react";
import { useTranslations } from "next-intl";
export const orgLangingNavItems: SidebarNavItem[] = [
{

View file

@ -11,7 +11,6 @@ import { ListUserOrgsResponse } from "@server/routers/org";
import { internal } from "@app/lib/api";
import { AxiosResponse } from "axios";
import { authCookieHeader } from "@app/lib/api/cookies";
import { useTranslations } from "next-intl";
export const metadata: Metadata = {
title: `Setup - Pangolin`,

View file

@ -45,6 +45,7 @@ const orgSchema = z.object({
export default function StepperForm() {
const [currentStep, setCurrentStep] = useState<Step>("org");
const [orgIdTaken, setOrgIdTaken] = useState(false);
const t = useTranslations();
const [loading, setLoading] = useState(false);
const [isChecked, setIsChecked] = useState(false);
@ -106,15 +107,13 @@ export default function StepperForm() {
} catch (e) {
console.error(e);
setError(
formatAxiosError(e, "An error occurred while creating org")
formatAxiosError(e, t('orgErrorCreate'))
);
}
setLoading(false);
}
const t = useTranslations();
return (
<>
<Card>