Add user edit
This commit is contained in:
parent
3582a0ccd1
commit
7178f3dccb
27 changed files with 475 additions and 132 deletions
|
|
@ -153,6 +153,78 @@ router.post('/admin/users', requireAdmin, async (req, res) => {
|
|||
}
|
||||
});
|
||||
|
||||
// PUT /api/admin/users/:id - update a user
|
||||
router.put('/admin/users/:id', requireAdmin, async (req, res) => {
|
||||
try {
|
||||
const id = parseInt(req.params.id, 10);
|
||||
if (!Number.isFinite(id))
|
||||
return res.status(400).json({ error: 'Invalid user id' });
|
||||
|
||||
const user = await User.findByPk(id);
|
||||
if (!user) return res.status(404).json({ error: 'User not found' });
|
||||
|
||||
const { email, password, name, surname, role } = req.body || {};
|
||||
|
||||
// Update email if provided
|
||||
if (email !== undefined && email !== null) {
|
||||
if (typeof email !== 'string' || !email.includes('@')) {
|
||||
return res.status(400).json({ error: 'Invalid email' });
|
||||
}
|
||||
user.email = email;
|
||||
}
|
||||
|
||||
// Update password if provided
|
||||
if (password && password.trim() !== '') {
|
||||
if (typeof password !== 'string' || password.length < 6) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: 'Password must be at least 6 characters' });
|
||||
}
|
||||
user.password = password;
|
||||
}
|
||||
|
||||
// Update name and surname - handle empty strings properly
|
||||
if (name !== undefined) user.name = name || null;
|
||||
if (surname !== undefined) user.surname = surname || null;
|
||||
|
||||
await user.save();
|
||||
|
||||
// Update role if provided
|
||||
if (role !== undefined) {
|
||||
const makeAdmin = role === 'admin';
|
||||
const [userRole] = await Role.findOrCreate({
|
||||
where: { user_id: user.id },
|
||||
defaults: { user_id: user.id, is_admin: makeAdmin },
|
||||
});
|
||||
if (userRole.is_admin !== makeAdmin) {
|
||||
userRole.is_admin = makeAdmin;
|
||||
await userRole.save();
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch updated role
|
||||
const userRole = await Role.findOne({ where: { user_id: user.id } });
|
||||
|
||||
res.json({
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
surname: user.surname,
|
||||
created_at: user.created_at,
|
||||
role: userRole?.is_admin ? 'admin' : 'user',
|
||||
});
|
||||
} catch (err) {
|
||||
logError('Error updating user:', err);
|
||||
// Unique constraint
|
||||
if (err?.name === 'SequelizeUniqueConstraintError') {
|
||||
return res.status(409).json({ error: 'Email already exists' });
|
||||
}
|
||||
res.status(400).json({
|
||||
error: 'There was a problem updating the user.',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// DELETE /api/admin/users/:id - delete a user, prevent self-delete
|
||||
router.delete('/admin/users/:id', requireAdmin, async (req, res) => {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
import React, { useEffect, useMemo, useState, useRef } from 'react';
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { ChevronDownIcon, CheckIcon } from '@heroicons/react/24/outline';
|
||||
import {
|
||||
ChevronDownIcon,
|
||||
CheckIcon,
|
||||
PencilIcon,
|
||||
TrashIcon,
|
||||
} from '@heroicons/react/24/outline';
|
||||
import ConfirmDialog from '../Shared/ConfirmDialog';
|
||||
|
||||
interface AdminUserItem {
|
||||
id: number;
|
||||
|
|
@ -64,6 +70,49 @@ const createAdminUser = async (
|
|||
return await res.json();
|
||||
};
|
||||
|
||||
const updateAdminUser = async (
|
||||
id: number,
|
||||
email: string,
|
||||
t: any,
|
||||
name?: string,
|
||||
surname?: string,
|
||||
role?: 'admin' | 'user',
|
||||
password?: string
|
||||
): Promise<AdminUserItem> => {
|
||||
const body: any = { email, name, surname, role };
|
||||
if (password) body.password = password;
|
||||
|
||||
const res = await fetch(`/api/admin/users/${id}`, {
|
||||
method: 'PUT',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
if (res.status === 401)
|
||||
throw new Error(
|
||||
t('admin.authenticationRequired', 'Authentication required')
|
||||
);
|
||||
if (res.status === 403) throw new Error(t('admin.forbidden', 'Forbidden'));
|
||||
if (res.status === 409)
|
||||
throw new Error(t('admin.emailAlreadyExists', 'Email already exists'));
|
||||
if (res.status === 404)
|
||||
throw new Error(t('admin.userNotFound', 'User not found'));
|
||||
if (!res.ok) {
|
||||
let message = t('admin.failedToUpdateUser', 'Failed to update user');
|
||||
try {
|
||||
const body = await res.json();
|
||||
if (body?.error) message = body.error;
|
||||
} catch {
|
||||
// ignore non-JSON error bodies
|
||||
}
|
||||
throw new Error(message);
|
||||
}
|
||||
return await res.json();
|
||||
};
|
||||
|
||||
const deleteAdminUser = async (id: number, t: any): Promise<void> => {
|
||||
const res = await fetch(`/api/admin/users/${id}`, {
|
||||
method: 'DELETE',
|
||||
|
|
@ -91,7 +140,9 @@ const AddUserModal: React.FC<{
|
|||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onCreated: (user: AdminUserItem) => void;
|
||||
}> = ({ isOpen, onClose, onCreated }) => {
|
||||
onUpdated: (user: AdminUserItem) => void;
|
||||
editingUser?: AdminUserItem | null;
|
||||
}> = ({ isOpen, onClose, onCreated, onUpdated, editingUser }) => {
|
||||
const { t } = useTranslation();
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
|
|
@ -110,15 +161,23 @@ const AddUserModal: React.FC<{
|
|||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
setEmail('');
|
||||
setPassword('');
|
||||
setName('');
|
||||
setSurname('');
|
||||
setRole('user');
|
||||
if (editingUser) {
|
||||
setEmail(editingUser.email);
|
||||
setPassword('');
|
||||
setName(editingUser.name || '');
|
||||
setSurname(editingUser.surname || '');
|
||||
setRole(editingUser.role);
|
||||
} else {
|
||||
setEmail('');
|
||||
setPassword('');
|
||||
setName('');
|
||||
setSurname('');
|
||||
setRole('user');
|
||||
}
|
||||
setError(null);
|
||||
setIsRoleDropdownOpen(false);
|
||||
}
|
||||
}, [isOpen]);
|
||||
}, [isOpen, editingUser]);
|
||||
|
||||
// Close dropdown when clicking outside
|
||||
useEffect(() => {
|
||||
|
|
@ -144,7 +203,7 @@ const AddUserModal: React.FC<{
|
|||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setError(null);
|
||||
if (!email || !password) {
|
||||
if (!email) {
|
||||
setError(t('errors.required', 'This field is required'));
|
||||
return;
|
||||
}
|
||||
|
|
@ -152,22 +211,45 @@ const AddUserModal: React.FC<{
|
|||
setError(t('errors.invalidEmail', 'Invalid email address'));
|
||||
return;
|
||||
}
|
||||
// Password is required for new users, optional for updates
|
||||
if (!editingUser && !password) {
|
||||
setError(t('errors.required', 'This field is required'));
|
||||
return;
|
||||
}
|
||||
setSubmitting(true);
|
||||
try {
|
||||
const user = await createAdminUser(
|
||||
email,
|
||||
password,
|
||||
t,
|
||||
name,
|
||||
surname,
|
||||
role
|
||||
);
|
||||
onCreated(user);
|
||||
if (editingUser) {
|
||||
const user = await updateAdminUser(
|
||||
editingUser.id,
|
||||
email,
|
||||
t,
|
||||
name,
|
||||
surname,
|
||||
role,
|
||||
password || undefined
|
||||
);
|
||||
onUpdated(user);
|
||||
} else {
|
||||
const user = await createAdminUser(
|
||||
email,
|
||||
password,
|
||||
t,
|
||||
name,
|
||||
surname,
|
||||
role
|
||||
);
|
||||
onCreated(user);
|
||||
}
|
||||
onClose();
|
||||
} catch (err: any) {
|
||||
setError(
|
||||
err.message ||
|
||||
t('admin.failedToCreateUser', 'Failed to create user')
|
||||
(editingUser
|
||||
? t('admin.failedToUpdateUser', 'Failed to update user')
|
||||
: t(
|
||||
'admin.failedToCreateUser',
|
||||
'Failed to create user'
|
||||
))
|
||||
);
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
|
|
@ -184,7 +266,9 @@ const AddUserModal: React.FC<{
|
|||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-4">
|
||||
{t('admin.addUser', 'Add user')}
|
||||
{editingUser
|
||||
? t('admin.editUser', 'Edit user')
|
||||
: t('admin.addUser', 'Add user')}
|
||||
</h3>
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div>
|
||||
|
|
@ -224,13 +308,23 @@ const AddUserModal: React.FC<{
|
|||
<div>
|
||||
<label className="block text-sm text-gray-700 dark:text-gray-300 mb-1">
|
||||
{t('admin.password', 'Password')}
|
||||
{editingUser && (
|
||||
<span className="text-xs text-gray-500 dark:text-gray-400 ml-2">
|
||||
(
|
||||
{t(
|
||||
'admin.passwordOptional',
|
||||
'Leave blank to keep current'
|
||||
)}
|
||||
)
|
||||
</span>
|
||||
)}
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
className="w-full rounded border px-3 py-2 bg-white dark:bg-gray-700 border-gray-300 dark:border-gray-600 text-gray-900 dark:text-gray-100"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
required
|
||||
required={!editingUser}
|
||||
minLength={6}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -321,7 +415,9 @@ const AddUserModal: React.FC<{
|
|||
>
|
||||
{submitting
|
||||
? t('common.saving', 'Saving...')
|
||||
: t('common.create', 'Create')}
|
||||
: editingUser
|
||||
? t('common.save', 'Save')
|
||||
: t('common.create', 'Create')}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
@ -335,12 +431,13 @@ const AdminUsersPage: React.FC = () => {
|
|||
const [users, setUsers] = useState<AdminUserItem[] | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [selectedIds, setSelectedIds] = useState<Set<number>>(new Set());
|
||||
const [addOpen, setAddOpen] = useState(false);
|
||||
const [editingUser, setEditingUser] = useState<AdminUserItem | null>(null);
|
||||
const [userToDelete, setUserToDelete] = useState<AdminUserItem | null>(
|
||||
null
|
||||
);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const selectedCount = selectedIds.size;
|
||||
|
||||
const load = async () => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
|
@ -363,57 +460,24 @@ const AdminUsersPage: React.FC = () => {
|
|||
load();
|
||||
}, []);
|
||||
|
||||
const toggleSelect = (id: number) => {
|
||||
setSelectedIds((prev) => {
|
||||
const next = new Set(prev);
|
||||
if (next.has(id)) next.delete(id);
|
||||
else next.add(id);
|
||||
return next;
|
||||
});
|
||||
};
|
||||
const handleDeleteUser = async () => {
|
||||
if (!userToDelete) return;
|
||||
|
||||
const toggleSelectAll = () => {
|
||||
if (!users) return;
|
||||
setSelectedIds((prev) => {
|
||||
if (prev.size === users.length) return new Set();
|
||||
return new Set(users.map((u) => u.id));
|
||||
});
|
||||
};
|
||||
|
||||
const removeSelected = async () => {
|
||||
if (!users || selectedIds.size === 0) return;
|
||||
const toDelete = Array.from(selectedIds);
|
||||
const remaining: AdminUserItem[] = [];
|
||||
const byId = new Map(users.map((u) => [u.id, u] as const));
|
||||
for (const id of toDelete) {
|
||||
try {
|
||||
await deleteAdminUser(id, t);
|
||||
} catch (err: any) {
|
||||
// Keep the user if deletion failed and surface error inline later
|
||||
console.error(
|
||||
t('admin.failedToDeleteUser', 'Failed to delete user'),
|
||||
id,
|
||||
err?.message
|
||||
);
|
||||
remaining.push(byId.get(id)!);
|
||||
}
|
||||
try {
|
||||
await deleteAdminUser(userToDelete.id, t);
|
||||
setUsers((prev) =>
|
||||
prev ? prev.filter((u) => u.id !== userToDelete.id) : null
|
||||
);
|
||||
setUserToDelete(null);
|
||||
} catch (err: any) {
|
||||
setError(
|
||||
err.message ||
|
||||
t('admin.failedToDeleteUser', 'Failed to delete user')
|
||||
);
|
||||
setUserToDelete(null);
|
||||
}
|
||||
const next = users.filter((u) => !toDelete.includes(u.id));
|
||||
// If any failed, keep them
|
||||
const nextWithFailures = remaining.length
|
||||
? next.concat(
|
||||
remaining.filter((r) => !next.find((n) => n.id === r.id))
|
||||
)
|
||||
: next;
|
||||
setUsers(nextWithFailures);
|
||||
setSelectedIds(new Set());
|
||||
};
|
||||
|
||||
const headerCheckboxChecked = useMemo(() => {
|
||||
if (!users || users.length === 0) return false;
|
||||
return selectedIds.size === users.length;
|
||||
}, [users, selectedIds]);
|
||||
|
||||
return (
|
||||
<div className="flex justify-center px-4 lg:px-2">
|
||||
<div className="w-full max-w-5xl space-y-6">
|
||||
|
|
@ -421,21 +485,15 @@ const AdminUsersPage: React.FC = () => {
|
|||
<h2 className="text-2xl font-light">
|
||||
{t('admin.userManagement', 'User Management')}
|
||||
</h2>
|
||||
<div className="flex items-center space-x-2">
|
||||
<button
|
||||
onClick={() => setAddOpen(true)}
|
||||
className="px-4 py-2 rounded-md bg-blue-600 text-white hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600 focus:outline-none transition duration-150 ease-in-out text-sm"
|
||||
>
|
||||
{t('admin.addUser', 'Add user')}
|
||||
</button>
|
||||
<button
|
||||
onClick={removeSelected}
|
||||
disabled={selectedCount === 0}
|
||||
className="px-4 py-2 rounded-md border border-red-300 dark:border-red-600 text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20 focus:outline-none transition duration-150 ease-in-out text-sm disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{t('admin.remove', 'Remove')}
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => {
|
||||
setEditingUser(null);
|
||||
setAddOpen(true);
|
||||
}}
|
||||
className="px-4 py-2 rounded-md bg-blue-600 text-white hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600 focus:outline-none transition duration-150 ease-in-out text-sm"
|
||||
>
|
||||
{t('admin.addUser', 'Add user')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
|
|
@ -448,14 +506,6 @@ const AdminUsersPage: React.FC = () => {
|
|||
<table className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<thead className="bg-gray-50 dark:bg-gray-900">
|
||||
<tr>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={headerCheckboxChecked}
|
||||
onChange={toggleSelectAll}
|
||||
className="w-4 h-4 rounded border-gray-300 dark:border-gray-600 text-blue-600 focus:ring-blue-500 dark:focus:ring-blue-400 focus:ring-2 bg-white dark:bg-gray-700"
|
||||
/>
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
||||
{t('admin.email', 'Email')}
|
||||
</th>
|
||||
|
|
@ -471,6 +521,9 @@ const AdminUsersPage: React.FC = () => {
|
|||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
||||
{t('admin.role', 'Role')}
|
||||
</th>
|
||||
<th className="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
||||
{t('admin.actions', 'Actions')}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
|
||||
|
|
@ -504,16 +557,6 @@ const AdminUsersPage: React.FC = () => {
|
|||
key={u.id}
|
||||
className="hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors duration-150"
|
||||
>
|
||||
<td className="px-6 py-4 whitespace-nowrap">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedIds.has(u.id)}
|
||||
onChange={() =>
|
||||
toggleSelect(u.id)
|
||||
}
|
||||
className="w-4 h-4 rounded border-gray-300 dark:border-gray-600 text-blue-600 focus:ring-blue-500 dark:focus:ring-blue-400 focus:ring-2 bg-white dark:bg-gray-700"
|
||||
/>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900 dark:text-gray-100">
|
||||
{u.email}
|
||||
</td>
|
||||
|
|
@ -537,6 +580,35 @@ const AdminUsersPage: React.FC = () => {
|
|||
: t('admin.user', 'user')}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||
<div className="flex items-center justify-end space-x-2">
|
||||
<button
|
||||
onClick={() => {
|
||||
setEditingUser(u);
|
||||
setAddOpen(true);
|
||||
}}
|
||||
className="text-blue-600 hover:text-blue-900 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
title={t(
|
||||
'common.edit',
|
||||
'Edit'
|
||||
)}
|
||||
>
|
||||
<PencilIcon className="h-5 w-5" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() =>
|
||||
setUserToDelete(u)
|
||||
}
|
||||
className="text-red-600 hover:text-red-900 dark:text-red-400 dark:hover:text-red-300"
|
||||
title={t(
|
||||
'common.delete',
|
||||
'Delete'
|
||||
)}
|
||||
>
|
||||
<TrashIcon className="h-5 w-5" />
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
|
|
@ -545,11 +617,35 @@ const AdminUsersPage: React.FC = () => {
|
|||
|
||||
<AddUserModal
|
||||
isOpen={addOpen}
|
||||
onClose={() => setAddOpen(false)}
|
||||
onClose={() => {
|
||||
setAddOpen(false);
|
||||
setEditingUser(null);
|
||||
}}
|
||||
onCreated={(user) =>
|
||||
setUsers((prev) => (prev ? [user, ...prev] : [user]))
|
||||
}
|
||||
onUpdated={(user) =>
|
||||
setUsers((prev) =>
|
||||
prev
|
||||
? prev.map((u) => (u.id === user.id ? user : u))
|
||||
: [user]
|
||||
)
|
||||
}
|
||||
editingUser={editingUser}
|
||||
/>
|
||||
|
||||
{userToDelete && (
|
||||
<ConfirmDialog
|
||||
title={t('admin.deleteUser', 'Delete User')}
|
||||
message={t(
|
||||
'admin.confirmDeleteUser',
|
||||
'Are you sure you want to delete {{email}}? This action cannot be undone.',
|
||||
{ email: userToDelete.email }
|
||||
)}
|
||||
onConfirm={handleDeleteUser}
|
||||
onCancel={() => setUserToDelete(null)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "فشل في إنشاء المستخدم",
|
||||
"badRequest": "طلب غير صحيح",
|
||||
"userNotFound": "المستخدم غير موجود",
|
||||
"failedToDeleteUser": "فشل في حذف المستخدم"
|
||||
"failedToDeleteUser": "فشل في حذف المستخدم",
|
||||
"editUser": "تعديل المستخدم",
|
||||
"actions": "الإجراءات",
|
||||
"passwordOptional": "اتركه فارغًا للاحتفاظ بالحالي",
|
||||
"failedToUpdateUser": "فشل في تحديث المستخدم",
|
||||
"confirmDelete": "هل أنت متأكد أنك تريد حذف هذا المستخدم؟",
|
||||
"deleteUser": "حذف المستخدم",
|
||||
"confirmDeleteUser": "هل أنت متأكد أنك تريد حذف {{email}}؟ لا يمكن التراجع عن هذا الإجراء."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "مشاركة المشروع",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "Неуспешно създаване на потребител",
|
||||
"badRequest": "Невалидна заявка",
|
||||
"userNotFound": "Потребителят не е намерен",
|
||||
"failedToDeleteUser": "Неуспешно изтриване на потребител"
|
||||
"failedToDeleteUser": "Неуспешно изтриване на потребител",
|
||||
"editUser": "Редактиране на потребител",
|
||||
"actions": "Действия",
|
||||
"passwordOptional": "Оставете празно, за да запазите текущата",
|
||||
"failedToUpdateUser": "Неуспешно обновяване на потребителя",
|
||||
"confirmDelete": "Сигурни ли сте, че искате да изтриете този потребител?",
|
||||
"deleteUser": "Изтриване на потребител",
|
||||
"confirmDeleteUser": "Сигурни ли сте, че искате да изтриете {{email}}? Това действие не може да бъде отменено."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Сподели проект",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "Kunne ikke oprette bruger",
|
||||
"badRequest": "Ugyldig anmodning",
|
||||
"userNotFound": "Bruger ikke fundet",
|
||||
"failedToDeleteUser": "Kunne ikke slette bruger"
|
||||
"failedToDeleteUser": "Kunne ikke slette bruger",
|
||||
"editUser": "Rediger bruger",
|
||||
"actions": "Handlinger",
|
||||
"passwordOptional": "Lad være tom for at bevare nuværende",
|
||||
"failedToUpdateUser": "Kunne ikke opdatere bruger",
|
||||
"confirmDelete": "Er du sikker på, at du vil slette denne bruger?",
|
||||
"deleteUser": "Slet bruger",
|
||||
"confirmDeleteUser": "Er du sikker på, at du vil slette {{email}}? Denne handling kan ikke fortrydes."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Del projekt",
|
||||
|
|
|
|||
|
|
@ -963,7 +963,14 @@
|
|||
"failedToCreateUser": "Benutzer konnte nicht erstellt werden",
|
||||
"badRequest": "Ungültige Anfrage",
|
||||
"userNotFound": "Benutzer nicht gefunden",
|
||||
"failedToDeleteUser": "Benutzer konnte nicht gelöscht werden"
|
||||
"failedToDeleteUser": "Benutzer konnte nicht gelöscht werden",
|
||||
"editUser": "Benutzer bearbeiten",
|
||||
"actions": "Aktionen",
|
||||
"passwordOptional": "Feld leer lassen, um das aktuelle Passwort beizubehalten",
|
||||
"failedToUpdateUser": "Fehler beim Aktualisieren des Benutzers",
|
||||
"confirmDelete": "Sind Sie sicher, dass Sie diesen Benutzer löschen möchten?",
|
||||
"deleteUser": "Benutzer löschen",
|
||||
"confirmDeleteUser": "Sind Sie sicher, dass Sie {{email}} löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Projekt teilen",
|
||||
|
|
|
|||
|
|
@ -940,15 +940,18 @@
|
|||
"manageUsers": "Διαχείριση χρηστών",
|
||||
"userManagement": "Διαχείριση Χρηστών",
|
||||
"addUser": "Προσθήκη χρήστη",
|
||||
"editUser": "Επεξεργασία χρήστη",
|
||||
"remove": "Αφαίρεση",
|
||||
"email": "Ηλεκτρονικό ταχυδρομείο",
|
||||
"created": "Δημιουργήθηκε",
|
||||
"role": "Ρόλος",
|
||||
"actions": "Ενέργειες",
|
||||
"loadingUsers": "Φόρτωση χρηστών...",
|
||||
"noUsers": "Δεν υπάρχουν χρήστες",
|
||||
"admin": "διαχειριστής",
|
||||
"user": "χρήστης",
|
||||
"password": "Κωδικός πρόσβασης",
|
||||
"passwordOptional": "Αφήστε το κενό για να διατηρήσετε τον τρέχοντα",
|
||||
"name": "Όνομα",
|
||||
"surname": "Επώνυμο",
|
||||
"authenticationRequired": "Απαιτείται αυθεντικοποίηση",
|
||||
|
|
@ -956,9 +959,13 @@
|
|||
"failedToLoadUsers": "Αποτυχία φόρτωσης χρηστών",
|
||||
"emailAlreadyExists": "Το email υπάρχει ήδη",
|
||||
"failedToCreateUser": "Αποτυχία δημιουργίας χρήστη",
|
||||
"failedToUpdateUser": "Αποτυχία ενημέρωσης χρήστη",
|
||||
"badRequest": "Κακή αίτηση",
|
||||
"userNotFound": "Ο χρήστης δεν βρέθηκε",
|
||||
"failedToDeleteUser": "Αποτυχία διαγραφής χρήστη"
|
||||
"failedToDeleteUser": "Αποτυχία διαγραφής χρήστη",
|
||||
"confirmDelete": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτόν τον χρήστη;",
|
||||
"deleteUser": "Διαγραφή Χρήστη",
|
||||
"confirmDeleteUser": "Είστε βέβαιοι ότι θέλετε να διαγράψετε το {{email}}; Αυτή η ενέργεια δεν μπορεί να αναιρεθεί."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Κοινή χρήση έργου",
|
||||
|
|
|
|||
|
|
@ -937,25 +937,32 @@
|
|||
"manageUsers": "Manage users",
|
||||
"userManagement": "User Management",
|
||||
"addUser": "Add user",
|
||||
"editUser": "Edit user",
|
||||
"remove": "Remove",
|
||||
"email": "Email",
|
||||
"name": "Name",
|
||||
"surname": "Surname",
|
||||
"created": "Created",
|
||||
"role": "Role",
|
||||
"actions": "Actions",
|
||||
"loadingUsers": "Loading users...",
|
||||
"noUsers": "No users",
|
||||
"admin": "admin",
|
||||
"user": "user",
|
||||
"password": "Password",
|
||||
"passwordOptional": "Leave blank to keep current",
|
||||
"authenticationRequired": "Authentication required",
|
||||
"forbidden": "Forbidden",
|
||||
"failedToLoadUsers": "Failed to load users",
|
||||
"emailAlreadyExists": "Email already exists",
|
||||
"failedToCreateUser": "Failed to create user",
|
||||
"failedToUpdateUser": "Failed to update user",
|
||||
"badRequest": "Bad request",
|
||||
"userNotFound": "User not found",
|
||||
"failedToDeleteUser": "Failed to delete user"
|
||||
"failedToDeleteUser": "Failed to delete user",
|
||||
"confirmDelete": "Are you sure you want to delete this user?",
|
||||
"deleteUser": "Delete User",
|
||||
"confirmDeleteUser": "Are you sure you want to delete {{email}}? This action cannot be undone."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Share project",
|
||||
|
|
|
|||
|
|
@ -955,7 +955,14 @@
|
|||
"failedToCreateUser": "Error al crear usuario",
|
||||
"badRequest": "Solicitud incorrecta",
|
||||
"userNotFound": "Usuario no encontrado",
|
||||
"failedToDeleteUser": "Error al eliminar usuario"
|
||||
"failedToDeleteUser": "Error al eliminar usuario",
|
||||
"editUser": "Editar usuario",
|
||||
"actions": "Acciones",
|
||||
"passwordOptional": "Dejar en blanco para mantener el actual",
|
||||
"failedToUpdateUser": "Error al actualizar el usuario",
|
||||
"confirmDelete": "¿Está seguro de que desea eliminar este usuario?",
|
||||
"deleteUser": "Eliminar usuario",
|
||||
"confirmDeleteUser": "¿Está seguro de que desea eliminar {{email}}? Esta acción no se puede deshacer."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Compartir proyecto",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "Käyttäjän luominen epäonnistui",
|
||||
"badRequest": "Virheellinen pyyntö",
|
||||
"userNotFound": "Käyttäjää ei löytynyt",
|
||||
"failedToDeleteUser": "Käyttäjän poistaminen epäonnistui"
|
||||
"failedToDeleteUser": "Käyttäjän poistaminen epäonnistui",
|
||||
"editUser": "Muokkaa käyttäjää",
|
||||
"actions": "Toiminnot",
|
||||
"passwordOptional": "Jätä tyhjäksi säilyttääksesi nykyisen",
|
||||
"failedToUpdateUser": "Käyttäjän päivittäminen epäonnistui",
|
||||
"confirmDelete": "Oletko varma, että haluat poistaa tämän käyttäjän?",
|
||||
"deleteUser": "Poista käyttäjä",
|
||||
"confirmDeleteUser": "Oletko varma, että haluat poistaa {{email}}? Tätä toimintoa ei voi peruuttaa."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Jaa projekti",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "Échec de la création de l'utilisateur",
|
||||
"badRequest": "Mauvaise requête",
|
||||
"userNotFound": "Utilisateur non trouvé",
|
||||
"failedToDeleteUser": "Échec de la suppression de l'utilisateur"
|
||||
"failedToDeleteUser": "Échec de la suppression de l'utilisateur",
|
||||
"editUser": "Modifier l'utilisateur",
|
||||
"actions": "Actions",
|
||||
"passwordOptional": "Laissez vide pour conserver l'actuel",
|
||||
"failedToUpdateUser": "Échec de la mise à jour de l'utilisateur",
|
||||
"confirmDelete": "Êtes-vous sûr de vouloir supprimer cet utilisateur ?",
|
||||
"deleteUser": "Supprimer l'utilisateur",
|
||||
"confirmDeleteUser": "Êtes-vous sûr de vouloir supprimer {{email}} ? Cette action ne peut pas être annulée."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Partager le projet",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "Gagal membuat pengguna",
|
||||
"badRequest": "Permintaan tidak valid",
|
||||
"userNotFound": "Pengguna tidak ditemukan",
|
||||
"failedToDeleteUser": "Gagal menghapus pengguna"
|
||||
"failedToDeleteUser": "Gagal menghapus pengguna",
|
||||
"editUser": "Edit pengguna",
|
||||
"actions": "Tindakan",
|
||||
"passwordOptional": "Biarkan kosong untuk mempertahankan yang sekarang",
|
||||
"failedToUpdateUser": "Gagal memperbarui pengguna",
|
||||
"confirmDelete": "Apakah Anda yakin ingin menghapus pengguna ini?",
|
||||
"deleteUser": "Hapus Pengguna",
|
||||
"confirmDeleteUser": "Apakah Anda yakin ingin menghapus {{email}}? Tindakan ini tidak dapat dibatalkan."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Bagikan proyek",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "Impossibile creare l'utente",
|
||||
"badRequest": "Richiesta non valida",
|
||||
"userNotFound": "Utente non trovato",
|
||||
"failedToDeleteUser": "Impossibile eliminare l'utente"
|
||||
"failedToDeleteUser": "Impossibile eliminare l'utente",
|
||||
"editUser": "Modifica utente",
|
||||
"actions": "Azioni",
|
||||
"passwordOptional": "Lascia vuoto per mantenere quello attuale",
|
||||
"failedToUpdateUser": "Impossibile aggiornare l'utente",
|
||||
"confirmDelete": "Sei sicuro di voler eliminare questo utente?",
|
||||
"deleteUser": "Elimina utente",
|
||||
"confirmDeleteUser": "Sei sicuro di voler eliminare {{email}}? Questa azione non può essere annullata."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Condividi progetto",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "ユーザーの作成に失敗しました",
|
||||
"badRequest": "不正なリクエスト",
|
||||
"userNotFound": "ユーザーが見つかりません",
|
||||
"failedToDeleteUser": "ユーザーの削除に失敗しました"
|
||||
"failedToDeleteUser": "ユーザーの削除に失敗しました",
|
||||
"editUser": "ユーザーを編集",
|
||||
"actions": "アクション",
|
||||
"passwordOptional": "現在のままにするには空白のままにしてください",
|
||||
"failedToUpdateUser": "ユーザーの更新に失敗しました",
|
||||
"confirmDelete": "このユーザーを削除してもよろしいですか?",
|
||||
"deleteUser": "ユーザーを削除",
|
||||
"confirmDeleteUser": "{{email}} を削除してもよろしいですか?この操作は元に戻せません。"
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "プロジェクトを共有",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "사용자 생성 실패",
|
||||
"badRequest": "잘못된 요청",
|
||||
"userNotFound": "사용자를 찾을 수 없습니다",
|
||||
"failedToDeleteUser": "사용자 삭제 실패"
|
||||
"failedToDeleteUser": "사용자 삭제 실패",
|
||||
"editUser": "사용자 편집",
|
||||
"actions": "작업",
|
||||
"passwordOptional": "현재 비밀번호를 유지하려면 비워 두세요",
|
||||
"failedToUpdateUser": "사용자 업데이트에 실패했습니다",
|
||||
"confirmDelete": "이 사용자를 삭제하시겠습니까?",
|
||||
"deleteUser": "사용자 삭제",
|
||||
"confirmDeleteUser": "{{email}}을(를) 삭제하시겠습니까? 이 작업은 취소할 수 없습니다."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "프로젝트 공유",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "Kon gebruiker niet aanmaken",
|
||||
"badRequest": "Ongeldig verzoek",
|
||||
"userNotFound": "Gebruiker niet gevonden",
|
||||
"failedToDeleteUser": "Kon gebruiker niet verwijderen"
|
||||
"failedToDeleteUser": "Kon gebruiker niet verwijderen",
|
||||
"editUser": "Bewerk gebruiker",
|
||||
"actions": "Acties",
|
||||
"passwordOptional": "Laat leeg om huidige te behouden",
|
||||
"failedToUpdateUser": "Bijwerken van gebruiker mislukt",
|
||||
"confirmDelete": "Weet u zeker dat u deze gebruiker wilt verwijderen?",
|
||||
"deleteUser": "Verwijder gebruiker",
|
||||
"confirmDeleteUser": "Weet u zeker dat u {{email}} wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Project delen",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "Kunne ikke opprette bruker",
|
||||
"badRequest": "Feil forespørsel",
|
||||
"userNotFound": "Bruker ikke funnet",
|
||||
"failedToDeleteUser": "Kunne ikke slette bruker"
|
||||
"failedToDeleteUser": "Kunne ikke slette bruker",
|
||||
"editUser": "Rediger bruker",
|
||||
"actions": "Handlinger",
|
||||
"passwordOptional": "La stå blankt for å beholde nåværende",
|
||||
"failedToUpdateUser": "Kunne ikke oppdatere bruker",
|
||||
"confirmDelete": "Er du sikker på at du vil slette denne brukeren?",
|
||||
"deleteUser": "Slett bruker",
|
||||
"confirmDeleteUser": "Er du sikker på at du vil slette {{email}}? Denne handlingen kan ikke angres."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Del prosjekt",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "Nie udało się utworzyć użytkownika",
|
||||
"badRequest": "Złe żądanie",
|
||||
"userNotFound": "Użytkownik nie znaleziony",
|
||||
"failedToDeleteUser": "Nie udało się usunąć użytkownika"
|
||||
"failedToDeleteUser": "Nie udało się usunąć użytkownika",
|
||||
"editUser": "Edytuj użytkownika",
|
||||
"actions": "Akcje",
|
||||
"passwordOptional": "Pozostaw puste, aby zachować obecne",
|
||||
"failedToUpdateUser": "Nie udało się zaktualizować użytkownika",
|
||||
"confirmDelete": "Czy na pewno chcesz usunąć tego użytkownika?",
|
||||
"deleteUser": "Usuń użytkownika",
|
||||
"confirmDeleteUser": "Czy na pewno chcesz usunąć {{email}}? Ta akcja nie może być cofnięta."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Udostępnij projekt",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "Falha ao criar usuário",
|
||||
"badRequest": "Requisição inválida",
|
||||
"userNotFound": "Usuário não encontrado",
|
||||
"failedToDeleteUser": "Falha ao deletar usuário"
|
||||
"failedToDeleteUser": "Falha ao deletar usuário",
|
||||
"editUser": "Editar usuário",
|
||||
"actions": "Ações",
|
||||
"passwordOptional": "Deixe em branco para manter o atual",
|
||||
"failedToUpdateUser": "Falha ao atualizar o usuário",
|
||||
"confirmDelete": "Você tem certeza de que deseja excluir este usuário?",
|
||||
"deleteUser": "Excluir Usuário",
|
||||
"confirmDeleteUser": "Você tem certeza de que deseja excluir {{email}}? Esta ação não pode ser desfeita."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Compartilhar projeto",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "Crearea utilizatorului a eșuat",
|
||||
"badRequest": "Cerere incorectă",
|
||||
"userNotFound": "Utilizatorul nu a fost găsit",
|
||||
"failedToDeleteUser": "Ștergerea utilizatorului a eșuat"
|
||||
"failedToDeleteUser": "Ștergerea utilizatorului a eșuat",
|
||||
"editUser": "Editează utilizator",
|
||||
"actions": "Acțiuni",
|
||||
"passwordOptional": "Lăsați gol pentru a păstra actual",
|
||||
"failedToUpdateUser": "Actualizarea utilizatorului a eșuat",
|
||||
"confirmDelete": "Ești sigur că vrei să ștergi acest utilizator?",
|
||||
"deleteUser": "Șterge utilizator",
|
||||
"confirmDeleteUser": "Ești sigur că vrei să ștergi {{email}}? Această acțiune nu poate fi anulată."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Partajați proiectul",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "Не удалось создать пользователя",
|
||||
"badRequest": "Неверный запрос",
|
||||
"userNotFound": "Пользователь не найден",
|
||||
"failedToDeleteUser": "Не удалось удалить пользователя"
|
||||
"failedToDeleteUser": "Не удалось удалить пользователя",
|
||||
"editUser": "Редактировать пользователя",
|
||||
"actions": "Действия",
|
||||
"passwordOptional": "Оставьте пустым, чтобы сохранить текущий",
|
||||
"failedToUpdateUser": "Не удалось обновить пользователя",
|
||||
"confirmDelete": "Вы уверены, что хотите удалить этого пользователя?",
|
||||
"deleteUser": "Удалить пользователя",
|
||||
"confirmDeleteUser": "Вы уверены, что хотите удалить {{email}}? Это действие нельзя отменить."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Поделиться проектом",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "Ustvarjanje uporabnika je spodletelo",
|
||||
"badRequest": "Neveljavna zahteva",
|
||||
"userNotFound": "Uporabnik ni bil najden",
|
||||
"failedToDeleteUser": "Brisanje uporabnika je spodletelo"
|
||||
"failedToDeleteUser": "Brisanje uporabnika je spodletelo",
|
||||
"editUser": "Uredi uporabnika",
|
||||
"actions": "Dejanja",
|
||||
"passwordOptional": "Pustite prazno, da obdržite trenutno",
|
||||
"failedToUpdateUser": "Posodobitev uporabnika ni uspela",
|
||||
"confirmDelete": "Ali ste prepričani, da želite izbrisati tega uporabnika?",
|
||||
"deleteUser": "Izbriši uporabnika",
|
||||
"confirmDeleteUser": "Ali ste prepričani, da želite izbrisati {{email}}? Te akcije ni mogoče razveljaviti."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Deli projekt",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "Misslyckades med att skapa användare",
|
||||
"badRequest": "Felaktig begäran",
|
||||
"userNotFound": "Användare hittades inte",
|
||||
"failedToDeleteUser": "Misslyckades med att ta bort användare"
|
||||
"failedToDeleteUser": "Misslyckades med att ta bort användare",
|
||||
"editUser": "Redigera användare",
|
||||
"actions": "Åtgärder",
|
||||
"passwordOptional": "Lämna tomt för att behålla nuvarande",
|
||||
"failedToUpdateUser": "Misslyckades med att uppdatera användare",
|
||||
"confirmDelete": "Är du säker på att du vill ta bort denna användare?",
|
||||
"deleteUser": "Ta bort användare",
|
||||
"confirmDeleteUser": "Är du säker på att du vill ta bort {{email}}? Denna åtgärd kan inte ångras."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Dela projekt",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "Kullanıcı oluşturulamadı",
|
||||
"badRequest": "Geçersiz istek",
|
||||
"userNotFound": "Kullanıcı bulunamadı",
|
||||
"failedToDeleteUser": "Kullanıcı silinemedi"
|
||||
"failedToDeleteUser": "Kullanıcı silinemedi",
|
||||
"editUser": "Kullanıcıyı Düzenle",
|
||||
"actions": "Eylemler",
|
||||
"passwordOptional": "Mevcut şifreyi korumak için boş bırakın",
|
||||
"failedToUpdateUser": "Kullanıcıyı güncellemeye başarısız olundu",
|
||||
"confirmDelete": "Bu kullanıcıyı silmek istediğinize emin misiniz?",
|
||||
"deleteUser": "Kullanıcıyı Sil",
|
||||
"confirmDeleteUser": "{{email}}'yi silmek istediğinize emin misiniz? Bu işlem geri alınamaz."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Projeyi paylaş",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "Не вдалося створити користувача",
|
||||
"badRequest": "Неправильний запит",
|
||||
"userNotFound": "Користувача не знайдено",
|
||||
"failedToDeleteUser": "Не вдалося видалити користувача"
|
||||
"failedToDeleteUser": "Не вдалося видалити користувача",
|
||||
"editUser": "Редагувати користувача",
|
||||
"actions": "Дії",
|
||||
"passwordOptional": "Залиште порожнім, щоб зберегти поточний",
|
||||
"failedToUpdateUser": "Не вдалося оновити користувача",
|
||||
"confirmDelete": "Ви впевнені, що хочете видалити цього користувача?",
|
||||
"deleteUser": "Видалити користувача",
|
||||
"confirmDeleteUser": "Ви впевнені, що хочете видалити {{email}}? Цю дію не можна скасувати."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Поділитися проектом",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "Không thể tạo người dùng",
|
||||
"badRequest": "Yêu cầu không hợp lệ",
|
||||
"userNotFound": "Không tìm thấy người dùng",
|
||||
"failedToDeleteUser": "Không thể xóa người dùng"
|
||||
"failedToDeleteUser": "Không thể xóa người dùng",
|
||||
"editUser": "Chỉnh sửa người dùng",
|
||||
"actions": "Hành động",
|
||||
"passwordOptional": "Để trống để giữ nguyên",
|
||||
"failedToUpdateUser": "Cập nhật người dùng không thành công",
|
||||
"confirmDelete": "Bạn có chắc chắn muốn xóa người dùng này không?",
|
||||
"deleteUser": "Xóa người dùng",
|
||||
"confirmDeleteUser": "Bạn có chắc chắn muốn xóa {{email}}? Hành động này không thể hoàn tác."
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "Chia sẻ dự án",
|
||||
|
|
|
|||
|
|
@ -954,7 +954,14 @@
|
|||
"failedToCreateUser": "创建用户失败",
|
||||
"badRequest": "错误的请求",
|
||||
"userNotFound": "用户未找到",
|
||||
"failedToDeleteUser": "删除用户失败"
|
||||
"failedToDeleteUser": "删除用户失败",
|
||||
"editUser": "编辑用户",
|
||||
"actions": "操作",
|
||||
"passwordOptional": "留空以保持当前密码",
|
||||
"failedToUpdateUser": "更新用户失败",
|
||||
"confirmDelete": "您确定要删除此用户吗?",
|
||||
"deleteUser": "删除用户",
|
||||
"confirmDeleteUser": "您确定要删除 {{email}} 吗?此操作无法撤销。"
|
||||
},
|
||||
"shares": {
|
||||
"shareProject": "分享项目",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue