0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-03-10 22:22:45 -05:00

feat(console): create user by multiple identifiers (#3694)

This commit is contained in:
Xiao Yijun 2023-04-14 17:48:49 +08:00 committed by GitHub
parent 5553425fcd
commit c5eb3a2ba7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
54 changed files with 302 additions and 58 deletions

View file

@ -0,0 +1,6 @@
---
"@logto/console": minor
"@logto/phrases": minor
---
support create user by multiple identifiers

View file

@ -12,13 +12,14 @@
.infoLine {
display: flex;
align-items: center;
font: var(--font-body-2);
&:not(:last-child) {
margin-bottom: _.unit(2);
}
.infoContent {
font-weight: bold;
font: var(--font-label-2);
padding-left: _.unit(1);
}

View file

@ -1,4 +1,6 @@
import type { AdminConsoleKey } from '@logto/phrases';
import { type User } from '@logto/schemas';
import { conditionalArray } from '@silverhand/essentials';
import { useState } from 'react';
import { toast } from 'react-hot-toast';
import { useTranslation } from 'react-i18next';
@ -13,7 +15,7 @@ import * as modalStyles from '@/scss/modal.module.scss';
import * as styles from './index.module.scss';
type Props = {
username: string;
user: User;
password: string;
title: AdminConsoleKey;
onClose: () => void;
@ -23,7 +25,7 @@ type Props = {
};
function UserAccountInformation({
username,
user,
password,
title,
onClose,
@ -33,16 +35,21 @@ function UserAccountInformation({
}: Props) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const [passwordVisible, setPasswordVisible] = useState(false);
const { primaryEmail, primaryPhone, username } = user;
const handleCopy = async () => {
if (!password) {
return null;
}
await navigator.clipboard.writeText(
`${t('user_details.created_username')} ${username}\n${
passwordLabel ?? t('user_details.created_password')
} ${password}`
);
const content = conditionalArray(
primaryEmail && `${t('user_details.created_email')} ${primaryEmail}`,
primaryPhone && `${t('user_details.created_phone')} ${primaryPhone}`,
username && `${t('user_details.created_username')} ${username}`,
`${passwordLabel ?? t('user_details.created_password')} ${password}`
).join('\n');
await navigator.clipboard.writeText(content);
toast.success(t('general.copied'));
};
@ -71,10 +78,24 @@ function UserAccountInformation({
>
<div>{t('user_details.created_guide')}</div>
<div className={styles.info}>
<div className={styles.infoLine}>
<div>{t('user_details.created_username')}</div>
<div className={styles.infoContent}>{username}</div>
</div>
{username && (
<div className={styles.infoLine}>
<div>{t('user_details.created_username')}</div>
<div className={styles.infoContent}>{username}</div>
</div>
)}
{primaryEmail && (
<div className={styles.infoLine}>
<div>{t('user_details.created_email')}</div>
<div className={styles.infoContent}>{primaryEmail}</div>
</div>
)}
{primaryPhone && (
<div className={styles.infoLine}>
<div>{t('user_details.created_phone')}</div>
<div className={styles.infoContent}>{primaryPhone}</div>
</div>
)}
<div className={styles.infoLine}>
<div>{passwordLabel ?? t('user_details.created_password')}</div>
<div className={styles.infoContent}>

View file

@ -11,6 +11,7 @@ import TextInput from '@/components/TextInput';
import { Tooltip } from '@/components/Tip';
import useApi from '@/hooks/use-api';
import { onKeyDownHandler } from '@/utils/a11y';
import { parsePhoneNumber } from '@/utils/phone';
import * as styles from './index.module.scss';
@ -58,9 +59,7 @@ function SenderTester({ connectorFactoryId, connectorType, className, parse }: P
const data = {
config: parse(),
...(isSms
? { phone: sendTo.replace(/[ ()-]/g, '').replace(/\+/g, '00') }
: { email: sendTo }),
...(isSms ? { phone: parsePhoneNumber(sendTo) } : { email: sendTo }),
};
await api.post(`api/connectors/${connectorFactoryId}/test`, { json: data }).json();

View file

@ -233,7 +233,7 @@ function UserDetails() {
{resetResult && (
<UserAccountInformation
title="user_details.reset_password.congratulations"
username={data.username ?? '-'}
user={data}
password={resetResult}
passwordLabel={t('user_details.reset_password.new_password')}
onClose={() => {

View file

@ -0,0 +1,7 @@
@use '@/scss/underscore' as _;
.error {
font: var(--font-body-2);
color: var(--color-error);
margin-top: _.unit(6);
}

View file

@ -1,5 +1,6 @@
import { usernameRegEx } from '@logto/core-kit';
import type { User } from '@logto/schemas';
import { emailRegEx, phoneInputRegEx, usernameRegEx } from '@logto/core-kit';
import type { CreateUser, User } from '@logto/schemas';
import { conditional } from '@silverhand/essentials';
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
@ -13,13 +14,12 @@ import TextInput from '@/components/TextInput';
import UserAccountInformation from '@/components/UserAccountInformation';
import useApi from '@/hooks/use-api';
import * as modalStyles from '@/scss/modal.module.scss';
import { parsePhoneNumber } from '@/utils/phone';
import * as styles from './index.module.scss';
import { createInitialPassword } from './utils';
type FormData = {
username: string;
name: string;
};
type FormData = Pick<CreateUser, 'name' | 'username' | 'primaryEmail' | 'primaryPhone'>;
type CreatedUserInfo = {
user: User;
@ -36,23 +36,60 @@ function CreateForm({ onClose, onCreate }: Props) {
const { search } = useLocation();
const navigate = useNavigate();
const [createdUserInfo, setCreatedUserInfo] = useState<CreatedUserInfo>();
const [missingIdentifierError, setMissingIdentifierError] = useState<string>();
const {
handleSubmit,
register,
formState: { isSubmitting, errors },
formState: { isSubmitting, errors, submitCount },
getValues,
} = useForm<FormData>();
const api = useApi();
const hasIdentifier = () => {
const { username, primaryEmail, primaryPhone } = getValues();
return Boolean(username) || Boolean(primaryEmail) || Boolean(primaryPhone);
};
const revalidateForm = () => {
if (submitCount) {
if (hasIdentifier()) {
setMissingIdentifierError(undefined);
} else {
setMissingIdentifierError(t('users.error_missing_identifier'));
}
}
};
const onSubmit = handleSubmit(async (data) => {
if (isSubmitting) {
return;
}
setMissingIdentifierError(undefined);
if (!hasIdentifier()) {
setMissingIdentifierError(t('users.error_missing_identifier'));
return;
}
const password = createInitialPassword();
const createdUser = await api.post('api/users', { json: { ...data, password } }).json<User>();
const { primaryPhone } = data;
const userData = {
...data,
password,
...conditional(primaryPhone && { primaryPhone: parsePhoneNumber(primaryPhone) }),
};
// Filter out empty values
const payload = Object.fromEntries(
Object.entries(userData).filter(([, value]) => Boolean(value))
);
const createdUser = await api.post('api/users', { json: payload }).json<User>();
setCreatedUserInfo({
user: createdUser,
@ -65,7 +102,7 @@ function CreateForm({ onClose, onCreate }: Props) {
return createdUserInfo ? (
<UserAccountInformation
title="user_details.created_title"
username={createdUserInfo.user.username ?? '-'}
user={createdUserInfo.user}
password={createdUserInfo.password}
confirmButtonTitle="users.check_user_detail"
onClose={() => {
@ -85,6 +122,7 @@ function CreateForm({ onClose, onCreate }: Props) {
>
<ModalLayout
title="users.create"
subtitle="users.create_subtitle"
footer={
<Button
disabled={isSubmitting}
@ -98,24 +136,53 @@ function CreateForm({ onClose, onCreate }: Props) {
onClose={onClose}
>
<form>
<FormField isRequired title="users.create_form_username">
<FormField title="user_details.field_email">
<TextInput
{...register('primaryEmail', {
pattern: {
value: emailRegEx,
message: t('errors.email_pattern_error'),
},
onChange: () => {
revalidateForm();
},
})}
placeholder={t('users.placeholder_email')}
error={errors.primaryEmail?.message ?? Boolean(missingIdentifierError)}
/>
</FormField>
<FormField title="user_details.field_phone">
<TextInput
{...register('primaryPhone', {
pattern: {
value: phoneInputRegEx,
message: t('errors.phone_pattern_error'),
},
onChange: () => {
revalidateForm();
},
})}
placeholder={t('users.placeholder_phone')}
error={errors.primaryPhone?.message ?? Boolean(missingIdentifierError)}
/>
</FormField>
<FormField title="user_details.field_username">
<TextInput
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus
{...register('username', {
required: true,
pattern: {
value: usernameRegEx,
message: t('errors.username_pattern_error'),
},
onChange: () => {
revalidateForm();
},
})}
error={errors.username?.message}
placeholder={t('users.placeholder_username')}
error={errors.username?.message ?? Boolean(missingIdentifierError)}
/>
</FormField>
<FormField title="users.create_form_name">
<TextInput {...register('name')} error={errors.name?.message} />
</FormField>
</form>
{missingIdentifierError && <div className={styles.error}>{missingIdentifierError}</div>}
</ModalLayout>
</Modal>
);

View file

@ -0,0 +1,2 @@
export const parsePhoneNumber = (phone: string) =>
phone.replace(/[ ()-]/g, '').replace(/\+/g, '00');

View file

@ -103,11 +103,7 @@ export const createUserLibrary = (queries: Queries) => {
},
excludeUserId?: string
) => {
const { username, primaryEmail, primaryPhone } = identifiers;
if (username && (await hasUser(username, excludeUserId))) {
throw new RequestError({ code: 'user.username_already_in_use', status: 422 });
}
const { primaryEmail, primaryPhone, username } = identifiers;
if (primaryEmail && (await hasUserWithEmail(primaryEmail, excludeUserId))) {
throw new RequestError({ code: 'user.email_already_in_use', status: 422 });
@ -116,6 +112,10 @@ export const createUserLibrary = (queries: Queries) => {
if (primaryPhone && (await hasUserWithPhone(primaryPhone, excludeUserId))) {
throw new RequestError({ code: 'user.phone_already_in_use', status: 422 });
}
if (username && (await hasUser(username, excludeUserId))) {
throw new RequestError({ code: 'user.username_already_in_use', status: 422 });
}
};
const findUsersByRoleName = async (roleName: string) => {

View file

@ -15,6 +15,8 @@ const errors = {
'Der Benutzername sollte nur Buchstaben, Zahlen oder Unterstriche enthalten und nicht mit einer Zahl beginnen.',
password_pattern_error:
'Das Passwort benötigt mindestens {{min}} Zeichen und enthält eine Mischung aus Buchstaben, Zahlen und Symbolen.',
email_pattern_error: 'Die E-Mail-Adresse ist ungültig.',
phone_pattern_error: 'Die Telefonnummer ist ungültig.',
insecure_contexts: 'Unsichere Kontexte (nicht-HTTPS) werden nicht unterstützt.',
unexpected_error: 'Ein unerwarteter Fehler ist aufgetreten',
not_found: '404 not found',

View file

@ -2,7 +2,9 @@ const user_details = {
page_title: 'Benutzerdetails',
back_to_users: 'Zurück zur Benutzerverwaltung',
created_title: 'Der Benutzer wurde erfolgreich erstellt',
created_guide: 'Sende dem Benutzer folgende Anmeldeinformationen',
created_guide: 'Hier sind die Informationen, um dem Benutzer bei der Anmeldung zu helfen.',
created_email: 'E-Mail-Adresse:',
created_phone: 'Telefonnummer:',
created_username: 'Benutzername:',
created_password: 'Passwort:',
menu_delete: 'Löschen',

View file

@ -4,15 +4,21 @@ const users = {
subtitle:
'Verwalten von Benutzeridentitäten, einschließlich des Anlegens von Benutzern, Bearbeiten von Benutzerinformationen, Anzeigen von Benutzer-Logs, Zurücksetzen von Passwörtern und Löschen von Benutzern',
create: 'Benutzer hinzufügen',
user_name: 'Benutzer',
create_subtitle: 'Um fortzufahren, geben Sie bitte mindestens eines der folgenden Felder an.',
error_missing_identifier:
'Sie müssen mindestens einen Identifikator eingeben, um einen Benutzer anzulegen',
user_name: 'Benutzername',
application_name: 'Anwendungsname',
latest_sign_in: 'Letzte Anmeldung',
create_form_username: 'Benutzername',
create_form_password: 'Passwort',
create_form_name: 'Name',
placeholder_email: 'ihremail@domain.com',
placeholder_username: 'Ihr Benutzername',
placeholder_phone: '+1 555-123-4567',
unnamed: 'Unbenannt',
search: 'Suche nach Name, E-Mail, Telefon oder Benutzername',
check_user_detail: 'Benutzerdetail prüfen',
check_user_detail: 'Benutzerdetails überprüfen',
placeholder_title: 'Benutzerverwaltung',
placeholder_description:
'Jeder Benutzer hat ein Profil mit allen Benutzerinformationen. Es besteht aus grundlegenden Daten, sozialen Identitäten und benutzerdefinierten Daten.',

View file

@ -15,6 +15,8 @@ const errors = {
'Username should only contain letters, numbers, or underscore and should not start with a number.',
password_pattern_error:
'Password requires a minimum of {{min}} characters and contains a mix of letters, numbers, and symbols.',
email_pattern_error: 'The email address is invalid.',
phone_pattern_error: 'The phone number is invalid.',
insecure_contexts: 'Insecure contexts (non-HTTPS) are not supported.',
unexpected_error: 'An unexpected error occurred.',
not_found: '404 not found',

View file

@ -2,7 +2,9 @@ const user_details = {
page_title: 'User details',
back_to_users: 'Back to User Management',
created_title: 'This user has been successfully created',
created_guide: 'You can send the following log in information to the user',
created_guide: 'Heres the information to assist the user with their sign-in process.',
created_email: 'Email address:',
created_phone: 'Phone number:',
created_username: 'Username:',
created_password: 'Password:',
menu_delete: 'Delete',

View file

@ -4,12 +4,17 @@ const users = {
subtitle:
'Manage user identities including creating users, editing user information, viewing user logs, password resets and deleting users',
create: 'Add User',
create_subtitle: 'Provide at least one of the following fields to proceed.',
error_missing_identifier: 'You must provide at least one identifier to create a user.',
user_name: 'User',
application_name: 'From application',
latest_sign_in: 'Latest sign in',
create_form_username: 'Username',
create_form_password: 'Password',
create_form_name: 'Full name',
placeholder_email: 'youremail@domain.com',
placeholder_username: 'Your username',
placeholder_phone: '+1 555-123-4567',
unnamed: 'Unnamed',
search: 'Search by name, email, phone or username',
check_user_detail: 'Check user detail',

View file

@ -15,6 +15,8 @@ const errors = {
'El nombre de usuario solo debe contener letras, números o guiones bajos y no debe comenzar con un número.',
password_pattern_error:
'La contraseña requiere un mínimo de {{min}} caracteres y contiene una combinación de letras, números y símbolos.',
email_pattern_error: 'La dirección de correo electrónico no es válida.',
phone_pattern_error: 'El número de teléfono no es válido.',
insecure_contexts: 'Los contextos inseguros (no HTTPS) no son compatibles.',
unexpected_error: 'Ocurrió un error inesperado.',
not_found: '404 no encontrado',

View file

@ -2,7 +2,10 @@ const user_details = {
page_title: 'Detalles de usuario',
back_to_users: 'Volver a la gestión de usuarios',
created_title: 'Usuario creado con éxito',
created_guide: 'Puede enviar al usuario la siguiente información de inicio de sesión',
created_guide:
'Aquí está la información para ayudar al usuario con su proceso de inicio de sesión.',
created_email: 'Dirección de correo electrónico:',
created_phone: 'Número de teléfono:',
created_username: 'Nombre de usuario:',
created_password: 'Contraseña:',
menu_delete: 'Eliminar',

View file

@ -5,11 +5,16 @@ const users = {
'Administrar identidades de usuario, incluyendo la creación de usuarios, la edición de información de usuario, la visualización de registros de usuario, la restablecimiento de contraseña y la eliminación de usuarios',
create: 'Agregar usuario',
user_name: 'Usuario',
create_subtitle: 'Proporcione al menos uno de los siguientes campos para continuar.',
error_missing_identifier: 'Debe proporcionar al menos un identificador para crear un usuario.',
application_name: 'De la aplicación',
latest_sign_in: 'Último inicio de sesión',
create_form_username: 'Nombre de usuario',
create_form_password: 'Contraseña',
create_form_name: 'Nombre completo',
placeholder_email: 'tucorreo@dominio.com',
placeholder_username: 'Tu nombre de usuario',
placeholder_phone: '+51 912 345 678',
unnamed: 'Sin nombre',
search: 'Buscar por nombre, correo electrónico, teléfono o nombre de usuario',
check_user_detail: 'Ver detalles del usuario',

View file

@ -15,6 +15,8 @@ const errors = {
"Le nom d'utilisateur ne doit contenir que des lettres, des chiffres ou des traits de soulignement et ne doit pas commencer par un chiffre.",
password_pattern_error:
'Le mot de passe nécessite un minimum de {{min}} caractères et contient un mélange de lettres, de chiffres et de symboles.',
email_pattern_error: "L'adresse e-mail n'est pas valide.",
phone_pattern_error: 'Le numéro de téléphone nest pas valide.',
insecure_contexts: 'Les contextes non sécurisés (non HTTPS) ne sont pas pris en charge.',
unexpected_error: "Une erreur inattendue s'est produite",
not_found: '404 non trouvé',

View file

@ -2,7 +2,9 @@ const user_details = {
page_title: "Détails de l'utilisateur",
back_to_users: 'Retour à la gestion des utilisateurs',
created_title: 'Cet utilisateur a été créé avec succès',
created_guide: "Vous pouvez envoyer à l'utilisateur les informations de connexion suivantes",
created_guide: "Voici les informations pour aider l'utilisateur à se connecter.",
created_email: 'Adresse email :',
created_phone: 'Numéro de téléphone :',
created_username: "Nom d'utilisateur :",
created_password: 'Mot de passe :',
menu_delete: 'Supprimer',

View file

@ -4,12 +4,17 @@ const users = {
subtitle:
"Gérer les identités des utilisateurs, y compris la création d'utilisateurs, la modification des informations sur les utilisateurs, la consultation des journaux des utilisateurs, la réinitialisation des mots de passe et la suppression des utilisateurs.",
create: 'Ajouter un utilisateur',
create_subtitle: "Fournir au moins l'un des champs suivants pour continuer.",
error_missing_identifier: 'Vous devez saisir au moins un identifiant pour créer un utilisateur.',
user_name: 'Utilisateur',
application_name: "De l'application",
latest_sign_in: 'Dernière connexion',
create_form_username: "Nom d'utilisateur",
create_form_password: 'Mot de passe',
create_form_name: 'Nom complet',
placeholder_email: 'votreemail@domaine.com',
placeholder_username: "Votre nom d'utilisateur",
placeholder_phone: '+1 555-123-4567',
unnamed: 'Sans nom',
search: "Rechercher par nom, email, téléphone ou nom d'utilisateur",
check_user_detail: "Vérifier les détails de l'utilisateur",

View file

@ -15,6 +15,8 @@ const errors = {
'Il nome utente dovrebbe contenere solo lettere, numeri, o trattini bassi e non dovrebbe iniziare con un numero.',
password_pattern_error:
'La password richiede un minimo di {{min}} caratteri e contiene una combinazione di lettere, numeri e simboli.',
email_pattern_error: "L'indirizzo email non è valido.",
phone_pattern_error: 'Il numero di telefono non è valido.',
insecure_contexts: 'I contesti non sicuri (non HTTPS) non sono supportati.',
unexpected_error: 'Si è verificato un errore inaspettato.',
not_found: '404 non trovato',

View file

@ -2,7 +2,9 @@ const user_details = {
page_title: 'Dettagli utente',
back_to_users: 'Torna alla gestione utenti',
created_title: 'Questo utente è stato creato con successo',
created_guide: "Puoi inviare le seguenti informazioni di accesso all'utente",
created_guide: 'Ecco le informazioni per aiutare lutente con il processo di accesso.',
created_email: 'Indirizzo email:',
created_phone: 'Numero di telefono:',
created_username: 'Nome utente:',
created_password: 'Password:',
menu_delete: 'Elimina',

View file

@ -4,12 +4,17 @@ const users = {
subtitle:
"Gestisci le identità degli utenti, inclusa la creazione di utenti, la modifica delle informazioni degli utenti, la visualizzazione dei log degli utenti, il ripristino delle password e l'eliminazione degli utenti",
create: 'Aggiungi utente',
create_subtitle: 'Fornire almeno uno dei seguenti campi per procedere.',
error_missing_identifier: 'Devi fornire almeno un identificatore per creare un utente.',
user_name: 'Utente',
application_name: "Dall'applicazione",
latest_sign_in: 'Ultimo accesso',
create_form_username: 'Nome utente',
create_form_password: 'Password',
create_form_name: 'Nome completo',
placeholder_email: 'tuaemail@dominio.com',
placeholder_username: 'Il tuo nome utente',
placeholder_phone: '+39 123-456-7890',
unnamed: 'Senza nome',
search: 'Cerca per nome, email, telefono o nome utente',
check_user_detail: "Controlla i dettagli dell'utente",

View file

@ -15,6 +15,8 @@ const errors = {
'ユーザー名には、文字、数字、またはアンダースコアしか含めることができず、数字で始めることはできません。',
password_pattern_error:
'パスワードには、{{min}}文字以上の文字列と文字、数字、およびシンボルが必要です。',
email_pattern_error: 'メールアドレスが無効です。',
phone_pattern_error: '電話番号が無効です。',
insecure_contexts: '安全でないコンテキストンHTTPはサポートされていません。',
unexpected_error: '予期しないエラーが発生しました。',
not_found: '404が見つかりません',

View file

@ -2,7 +2,9 @@ const user_details = {
page_title: 'ユーザーの詳細',
back_to_users: 'ユーザー管理に戻る',
created_title: 'このユーザーは正常に作成されました',
created_guide: '以下のログイン情報をユーザーに送信できます',
created_guide: 'ユーザーがサインインプロセスを支援するための情報です。',
created_email: 'メールアドレス:',
created_phone: '電話番号:',
created_username: 'ユーザー名:',
created_password: 'パスワード:',
menu_delete: '削除',

View file

@ -4,12 +4,18 @@ const users = {
subtitle:
'ユーザーのアイデンティティを管理する、ユーザーの作成、情報の編集、ユーザーログの表示、パスワードのリセットおよびユーザーの削除を含む',
create: 'ユーザーを追加する',
create_subtitle: '少なくとも1つの以下のフィールドを提供してください。',
error_missing_identifier:
'ユーザーを作成するには、少なくとも1つの識別子を指定する必要があります。',
user_name: 'ユーザー名',
application_name: 'アプリケーションから',
latest_sign_in: '最新のサインイン',
create_form_username: 'ユーザー名',
create_form_password: 'パスワード',
create_form_name: 'フルネーム',
placeholder_email: 'youremail@domain.com',
placeholder_username: 'あなたのユーザー名',
placeholder_phone: '+1 555-123-4567',
unnamed: '名前がありません',
search: '名前、メール、電話、またはユーザー名で検索',
check_user_detail: 'ユーザー詳細を確認する',

View file

@ -14,6 +14,8 @@ const errors = {
username_pattern_error:
'아이디는 반드시 문자, 숫자, _ 만으로 이루어져야 하며, 숫자로 시작하면 안 돼요.',
password_pattern_error: '비밀번호에는 최소 {{min}}자의 문자, 숫자, 특수문자가 포함되어야 해요.',
email_pattern_error: '이메일 형식이 유효하지 않아요.',
phone_pattern_error: '전화번호 형식이 유효하지 않아요.',
insecure_contexts: '비보안 연결(non-HTTPS)는 지원하지 않아요.',
unexpected_error: '알 수 없는 오류가 발생했어요.',
not_found: '404 찾을 수 없음',

View file

@ -2,7 +2,9 @@ const user_details = {
page_title: '사용자 세부 정보',
back_to_users: '사용자 관리로 돌아가기',
created_title: '새로운 사용자가 생성되었어요.',
created_guide: '생성된 정보를 해당 사용자에게 알려주세요.',
created_guide: '사용자가 로그인하는데 도움이 되는 정보를 확인해보세요.',
created_email: '이메일 주소:',
created_phone: '휴대전화 번호:',
created_username: '사용자 이름:',
created_password: '비밀번호:',
menu_delete: '삭제',

View file

@ -3,12 +3,17 @@ const users = {
title: '사용자 관리',
subtitle: '사용자의 신원을 추가, 삭제, 수정, 조회하여 관리해보세요.',
create: '사용자 추가',
create_subtitle: '다음 중 적어도 하나의 필드를 제공해주세요.',
error_missing_identifier: '사용자를 생성하려면 적어도 하나의 식별자를 제공해야 합니다.',
user_name: '사용자',
application_name: '어플리케이션으로부터',
latest_sign_in: '최근 로그인 시각',
create_form_username: '사용자 이름',
create_form_password: '비밀번호',
create_form_name: '이름',
placeholder_email: 'youremail@domain.com',
placeholder_username: '사용자 이름',
placeholder_phone: '+1 555-123-4567',
unnamed: '이름없음',
search: '이름, 이메일, 전화번호, ID로 검색',
check_user_detail: '사용자 상세정보 확인',

View file

@ -15,6 +15,8 @@ const errors = {
'Nazwa użytkownika powinna zawierać tylko litery, cyfry lub znak podkreślenia i nie powinna zaczynać się od cyfry.',
password_pattern_error:
'Hasło wymaga minimum {{min}} znaków i zawiera kombinację liter, cyfr i symboli.',
email_pattern_error: 'Adres e-mail jest nieprawidłowy.',
phone_pattern_error: 'Numer telefonu jest nieprawidłowy.',
insecure_contexts: 'Nieobsługiwane są niebezpieczne konteksty (non-HTTPS).',
unexpected_error: 'Wystąpił nieoczekiwany błąd.',
not_found: '404 nie znaleziono',

View file

@ -2,7 +2,9 @@ const user_details = {
page_title: 'Szczegóły użytkownika',
back_to_users: 'Powrót do zarządzania użytkownikami',
created_title: 'Ten użytkownik został pomyślnie utworzony',
created_guide: 'Możesz wysłać następujące informacje o logowaniu do użytkownika',
created_guide: 'Oto informacje, które pomogą użytkownikowi w procesie logowania.',
created_email: 'Adres email:',
created_phone: 'Numer telefonu:',
created_username: 'Nazwa użytkownika:',
created_password: 'Hasło:',
menu_delete: 'Usuń',

View file

@ -4,12 +4,18 @@ const users = {
subtitle:
'Zarządzaj tożsamościami użytkowników, w tym tworzeniem użytkowników, edycją informacji o użytkownikach, przeglądaniem dzienników użytkowników, resetowaniem hasła i usuwaniem użytkowników.',
create: 'Dodaj użytkownika',
create_subtitle: 'Podaj co najmniej jedno z poniższych pól, aby kontynuować.',
error_missing_identifier:
'Aby utworzyć użytkownika, musisz podać co najmniej jeden identyfikator.',
user_name: 'Użytkownik',
application_name: 'Z aplikacji',
latest_sign_in: 'Najnowsze logowanie',
create_form_username: 'Nazwa użytkownika',
create_form_password: 'Hasło',
create_form_name: 'Imię i nazwisko',
placeholder_email: 'twojemail@domena.com',
placeholder_username: 'Twoja nazwa użytkownika',
placeholder_phone: '+48 555-123-4567',
unnamed: 'Bez nazwy',
search: 'Wyszukaj według nazwy, e-maila, numeru telefonu lub nazwy użytkownika',
check_user_detail: 'Sprawdź szczegóły użytkownika',

View file

@ -15,6 +15,8 @@ const errors = {
'O nome de usuário deve conter apenas letras, números ou sublinhado e não deve começar com um número.',
password_pattern_error:
'A senha requer um mínimo de {{min}} caracteres e contém uma mistura de letras, números e símbolos.',
email_pattern_error: 'O endereço de e-mail é inválido.',
phone_pattern_error: 'O número de telefone é inválido.',
insecure_contexts: 'Contextos inseguros (não-HTTPS) não são suportados.',
unexpected_error: 'Um erro inesperado ocorreu',
not_found: '404 não encontrado',

View file

@ -2,7 +2,9 @@ const user_details = {
page_title: 'Detalhes do usuário',
back_to_users: 'Voltar para gerenciamento de usuários',
created_title: 'Este usuário foi criado com sucesso',
created_guide: 'Você pode enviar as seguintes informações de login para o usuário',
created_guide: 'Aqui está a informação para ajudar o usuário com o processo de login.',
created_email: 'Endereço de e-mail:',
created_phone: 'Número de telefone:',
created_username: 'Nome de usuário:',
created_password: 'Senha:',
menu_delete: 'Excluir',

View file

@ -4,12 +4,17 @@ const users = {
subtitle:
'Gerenciar identidades de usuários, visualização de logs de usuários, redefinições de senha e exclusão de usuários',
create: 'Adicionar usuário',
user_name: 'Usuário',
create_subtitle: 'Fornecer pelo menos um dos seguintes campos para prosseguir.',
error_missing_identifier: 'Você deve fornecer pelo menos um identificador para criar um usuário.',
user_name: 'Nome de usuário',
application_name: 'Aplicativo',
latest_sign_in: 'Último login',
create_form_username: 'Nome de usuário',
create_form_password: 'Senha',
create_form_name: 'Nome completo',
placeholder_email: 'seuemail@dominio.com',
placeholder_username: 'Seu nome de usuário',
placeholder_phone: '+55 11 1234-5678',
unnamed: 'Sem nome',
search: 'Busca por nome, e-mail, telefone ou nome de usuário',
check_user_detail: 'Detalhes do usuário',

View file

@ -15,6 +15,8 @@ const errors = {
'O nome de utilizador deve conter apenas letras, números ou underscores e não deve começar com um número.',
password_pattern_error:
'A password deve conter pelo menos {{min}} caracteres e ter uma combinação de letras, números e símbolos.',
email_pattern_error: 'O endereço de e-mail é inválido.',
phone_pattern_error: 'O número de telefone é inválido.',
insecure_contexts: 'Contextos inseguros (não HTTPS) não são compatíveis.',
unexpected_error: 'Ocorreu um erro inesperado',
not_found: '404 not found',

View file

@ -2,7 +2,9 @@ const user_details = {
page_title: 'Detalhes do utilizador',
back_to_users: 'Voltar a gestão de utilizadores',
created_title: 'Este utilizador foi criado com sucesso',
created_guide: 'Pode enviar as seguintes informações de login para o utilizador',
created_guide: 'Aqui está a informação para ajudar o utilizador no processo de login.',
created_email: 'Endereço de email:',
created_phone: 'Número de telefone:',
created_username: 'Utilizador:',
created_password: 'Palavra-passe:',
menu_delete: 'eliminar',

View file

@ -4,12 +4,17 @@ const users = {
subtitle:
'Gerencie os utilizadores, incluindo a criação, edição de informações, visualização de logs, recuperações de password e exclusões',
create: 'Adicionar usuário',
create_subtitle: 'Fornecer pelo menos um dos seguintes campos para proceder.',
error_missing_identifier: 'Tem de fornecer pelo menos um identificador para criar um utilizador.',
user_name: 'Utilizador',
application_name: 'Do app',
application_name: 'Do aplicativo',
latest_sign_in: 'Último login',
create_form_username: 'Utilizador',
create_form_password: 'Password',
create_form_password: 'Palavra-passe',
create_form_name: 'Nome completo',
placeholder_email: 'seuemail@dominio.com',
placeholder_username: 'Seu nome de utilizador',
placeholder_phone: '+1 555-123-4567',
unnamed: 'Sem nome',
search: 'Procurar por nome, email, telefone ou nome de utilizador',
check_user_detail: 'Ver detalhes do utilizador',

View file

@ -15,6 +15,8 @@ const errors = {
'Имя пользователя должно состоять только из букв, цифр или подчеркивания и не должно начинаться с цифры.',
password_pattern_error:
'Пароль должен содержать не менее {{min}} символов и состоять из букв, цифр и символов.',
email_pattern_error: 'Адрес электронной почты недействителен.',
phone_pattern_error: 'Номер телефона недействителен.',
insecure_contexts: 'Небезопасные контексты (нет HTTPS) не поддерживаются.',
unexpected_error: 'Произошла непредвиденная ошибка.',
not_found: '404 не найдено',

View file

@ -2,7 +2,9 @@ const user_details = {
page_title: 'Детали пользователя',
back_to_users: 'Вернуться к управлению пользователями',
created_title: 'Этот пользователь был успешно создан',
created_guide: 'Вы можете отправить следующую информацию для входа пользователю',
created_guide: 'Вот информация, которая поможет пользователю в процессе входа в систему.',
created_email: 'Адрес электронной почты:',
created_phone: 'Номер телефона:',
created_username: 'Имя пользователя:',
created_password: 'Пароль:',
menu_delete: 'Удалить',

View file

@ -4,12 +4,18 @@ const users = {
subtitle:
'Управление идентификацией пользователей, включая создание пользователей, редактирование информации о пользователях, просмотр журналов пользователей, сброс пароля и удаление пользователей',
create: 'Добавить пользователя',
create_subtitle: 'Введите хотя бы одно из следующих полей для продолжения.',
error_missing_identifier:
'Чтобы создать пользователя, вам нужно указать хотя бы один идентификатор.',
user_name: 'Пользователь',
application_name: 'От приложения',
latest_sign_in: 'Последний вход',
create_form_username: 'Имя пользователя',
create_form_password: 'Пароль',
create_form_name: 'Полное имя',
placeholder_email: 'youremail@domain.com',
placeholder_username: 'Ваше имя пользователя',
placeholder_phone: '+1 555-123-4567',
unnamed: 'Без имени',
search: 'Поиск по имени, электронной почте, телефону или имени пользователя',
check_user_detail: 'Просмотреть информацию о пользователе',

View file

@ -15,6 +15,8 @@ const errors = {
'Kullanıcı adı yalnızca harf, sayı veya alt çizgi içermeli ve bir sayı ile başlamamalıdır.',
password_pattern_error:
'Şifre en az {{min}} karakter ve harfler, sayılar ve simgelerin bir karışımını içermelidir.',
email_pattern_error: 'E-posta adresi geçersiz.',
phone_pattern_error: 'Telefon numarası geçersiz.',
insecure_contexts: 'Güvenli olmayan bağlamlar (HTTPS olmayan) desteklenmez.',
unexpected_error: 'Beklenmedik bir hata oluştu',
not_found: '404 bulunamadı',

View file

@ -2,7 +2,9 @@ const user_details = {
page_title: 'Kullanıcı detayları',
back_to_users: 'Kullanıcı Yönetimine Geri Dön',
created_title: 'Bu kullanıcı başarıyla oluşturuldu',
created_guide: 'Kullanıcıya aşağıdaki oturum açma bilgilerini gönderebilirsiniz',
created_guide: 'Kullanıcının oturum açma sürecinde yardımcı olacak bilgiler burada.',
created_email: 'E-posta adresi:',
created_phone: 'Telefon numarası:',
created_username: 'Kullanıcı Adı:',
created_password: 'Şifre:',
menu_delete: 'Sil',

View file

@ -4,12 +4,18 @@ const users = {
subtitle:
'Kullanıcı oluşturma, kullanıcı bilgilerini düzenleme, kullanıcı kayıtlarını görüntüleme, parola sıfırlama ve kullanıcıları silme dahil olmak üzere kullanıcı kimliklerini yönetin',
create: 'Kullanıcı ekle',
create_subtitle: 'Devam etmek için en az bir alanı sağlayın.',
error_missing_identifier:
'Bir kullanıcı oluşturmak için en az bir tanımlayıcı sağlamanız gerekir.',
user_name: 'Kullanıcı',
application_name: 'Uygulamadan',
latest_sign_in: 'En son oturum açma',
create_form_username: 'Kullanıcı Adı',
create_form_password: 'Şifre',
create_form_name: 'Ad Soyad',
placeholder_email: 'youremail@domain.com',
placeholder_username: 'Kullanıcı adınız',
placeholder_phone: '+1 555-123-4567',
unnamed: 'İsimsiz',
search: 'İsim, email, telefon veya kullanıcı adına göre arama',
check_user_detail: 'Kullanıcı detaylarını kontrol et',

View file

@ -13,6 +13,8 @@ const errors = {
more_details: '查看详情',
username_pattern_error: '用户名只能包含英文字母、数字或下划线,且不以数字开头。',
password_pattern_error: '密码至少需要 {{min}} 个字符,且必须包含字母、数字和符号。',
email_pattern_error: '邮箱地址无效',
phone_pattern_error: '手机号码无效',
insecure_contexts: '不支持不安全的上下文(非 HTTPS。',
unexpected_error: '发生未知错误',
not_found: '404 找不到资源',

View file

@ -2,7 +2,9 @@ const user_details = {
page_title: '用户详情',
back_to_users: '返回用户管理',
created_title: '用户创建成功',
created_guide: '你可以将以下登录信息发送给用户',
created_guide: '这是用户登录过程中的信息。',
created_email: '邮箱地址:',
created_phone: '手机号码:',
created_username: '用户名:',
created_password: '密码:',
menu_delete: '删除用户',

View file

@ -3,12 +3,17 @@ const users = {
title: '用户管理',
subtitle: '管理你的用户,包括创建新用户,编辑用户资料,查看用户日志,以及重新设置密码和删除用户',
create: '添加用户',
create_subtitle: '提供以下至少一项字段才能继续。',
error_missing_identifier: '你必须提供至少一个注册标识来创建用户。',
user_name: '用户',
application_name: '注册应用',
latest_sign_in: '最后登录',
create_form_username: '用户名',
create_form_password: '密码',
create_form_name: '姓名',
placeholder_email: 'youremail@domain.com',
placeholder_username: '你的用户名',
placeholder_phone: '+1 555-123-4567',
unnamed: '未命名',
search: '按姓名、电子邮件、电话或用户名搜索',
check_user_detail: '查看用户详情',

View file

@ -13,6 +13,8 @@ const errors = {
more_details: '查看詳情',
username_pattern_error: '用戶名只能包含英文字母、數字或下劃線,且不以數字開頭。',
password_pattern_error: '密碼至少需要 {{min}} 個字符,且必須包含字母、數字和符號。',
email_pattern_error: '郵箱地址無效',
phone_pattern_error: '手機號碼無效',
insecure_contexts: '不支持不安全的上下文(非 HTTPS。',
unexpected_error: '發生未知錯誤',
not_found: '404 找不到資源',

View file

@ -2,7 +2,9 @@ const user_details = {
page_title: '用戶詳情',
back_to_users: '返回用戶管理',
created_title: '用戶創建成功',
created_guide: '你可以將以下登錄信息發送給用戶',
created_guide: '這是用戶登錄過程中的信息。',
created_email: '電子郵箱地址:',
created_phone: '手機號碼:',
created_username: '用戶名:',
created_password: '密碼:',
menu_delete: '刪除用戶',

View file

@ -3,12 +3,17 @@ const users = {
title: '用戶管理',
subtitle: '管理你的用戶,包括創建新用戶,編輯用戶資料,查看用戶日誌,以及重新設置密碼和刪除用戶',
create: '添加用戶',
create_subtitle: '至少提供以下其中一個字段以繼續進行。',
error_missing_identifier: '你必須提供至少一個註冊標識來創建用戶。',
user_name: '用戶',
application_name: '註冊應用',
latest_sign_in: '最後登錄',
create_form_username: '用戶名',
create_form_password: '密碼',
create_form_name: '姓名',
placeholder_email: 'youremail@domain.com',
placeholder_username: '你的用戶名',
placeholder_phone: '+1 555-123-4567',
unnamed: '未命名',
search: '按姓名、電子郵件、電話或用戶名搜索',
check_user_detail: '查看用戶詳情',

View file

@ -13,6 +13,8 @@ const errors = {
more_details: '查看詳情',
username_pattern_error: '用戶名只能包含英文字母、數字或下劃線,且不以數字開頭。',
password_pattern_error: '密碼至少需要{{min}}個字符,且必須包含字母、數字和符號。',
email_pattern_error: '郵箱地址無效',
phone_pattern_error: '手機號碼無效',
insecure_contexts: '不支援不安全的上下文(非 HTTPS。',
unexpected_error: '發生未知錯誤',
not_found: '404 找不到資源',

View file

@ -2,7 +2,9 @@ const user_details = {
page_title: '用戶詳情',
back_to_users: '返回用戶管理',
created_title: '用戶創建成功',
created_guide: '你可以將以下登入資訊發送給用戶',
created_guide: '這是用戶登錄過程中的信息。',
created_email: '電子郵箱地址:',
created_phone: '手機號碼:',
created_username: '用戶名:',
created_password: '密碼:',
menu_delete: '刪除用戶',

View file

@ -3,12 +3,17 @@ const users = {
title: '用戶管理',
subtitle: '管理你的用戶,包括創建新用戶,編輯用戶資料,查看用戶日誌,以及重新設置密碼和刪除用戶',
create: '添加用戶',
create_subtitle: '請至少提供以下其中一個欄位以繼續操作。',
error_missing_identifier: '你必須提供至少一個註冊標識來創建用戶。',
user_name: '用戶',
application_name: '註冊應用',
latest_sign_in: '最後登錄',
create_form_username: '用戶名',
create_form_password: '密碼',
create_form_name: '姓名',
placeholder_email: 'youremail@domain.com',
placeholder_username: '你的用戶名',
placeholder_phone: '+1 555-123-4567',
unnamed: '未命名',
search: '按姓名、電子郵件、電話或用戶名搜索',
check_user_detail: '查看用戶詳情',