@micha.bigler/ui-core-micha 3.8.0 → 3.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/WORK_ORDERS.md +2 -0
- package/dist/auth/apiClient.js +8 -0
- package/dist/components/AccessCodeManager.js +5 -5
- package/dist/components/AccessCodeSingleUseToggle.js +3 -2
- package/dist/components/AllowedEmailDomainsManager.js +3 -2
- package/dist/components/AuthFactorRequirementCard.js +3 -2
- package/dist/components/BulkInviteCsvTab.js +3 -2
- package/dist/components/MFAComponent.js +9 -8
- package/dist/components/MfaLoginComponent.js +7 -6
- package/dist/components/PasskeysComponent.js +7 -6
- package/dist/components/ProfileComponent.js +4 -3
- package/dist/components/QrSignupManager.js +4 -3
- package/dist/components/QrSignupValidityManager.js +3 -2
- package/dist/components/RegistrationMethodsManager.js +3 -2
- package/dist/components/SecurityComponent.js +5 -4
- package/dist/components/SupportRecoveryRequestsTab.js +8 -7
- package/dist/components/UserInviteComponent.js +3 -2
- package/dist/components/UserListComponent.js +14 -7
- package/dist/i18n/authTranslations.js +420 -0
- package/dist/pages/AccountPage.js +3 -2
- package/dist/pages/LoginPage.js +10 -9
- package/dist/pages/PasswordChangePage.js +4 -3
- package/dist/pages/PasswordInvitePage.js +7 -6
- package/dist/pages/PasswordResetRequestPage.js +5 -4
- package/dist/pages/SignUpPage.js +7 -6
- package/dist/pages/SignupConfirmPage.js +7 -6
- package/dist/utils/auth-errors.js +45 -8
- package/dist/utils/resolveErrorText.js +24 -0
- package/package.json +1 -1
- package/src/auth/apiClient.jsx +9 -0
- package/src/components/AccessCodeManager.jsx +5 -5
- package/src/components/AccessCodeSingleUseToggle.jsx +3 -2
- package/src/components/AllowedEmailDomainsManager.jsx +3 -2
- package/src/components/AuthFactorRequirementCard.jsx +3 -2
- package/src/components/BulkInviteCsvTab.jsx +3 -2
- package/src/components/MFAComponent.jsx +9 -8
- package/src/components/MfaLoginComponent.jsx +7 -6
- package/src/components/PasskeysComponent.jsx +7 -6
- package/src/components/ProfileComponent.jsx +4 -3
- package/src/components/QrSignupManager.jsx +4 -3
- package/src/components/QrSignupValidityManager.jsx +3 -2
- package/src/components/RegistrationMethodsManager.jsx +3 -2
- package/src/components/SecurityComponent.jsx +5 -4
- package/src/components/SupportRecoveryRequestsTab.jsx +9 -8
- package/src/components/UserInviteComponent.jsx +3 -2
- package/src/components/UserListComponent.jsx +14 -7
- package/src/i18n/authTranslations.ts +421 -0
- package/src/pages/AccountPage.jsx +3 -4
- package/src/pages/LoginPage.jsx +10 -9
- package/src/pages/PasswordChangePage.jsx +4 -3
- package/src/pages/PasswordInvitePage.jsx +7 -6
- package/src/pages/PasswordResetRequestPage.jsx +5 -4
- package/src/pages/SignUpPage.jsx +7 -6
- package/src/pages/SignupConfirmPage.jsx +7 -6
- package/src/utils/auth-errors.js +44 -7
- package/src/utils/resolveErrorText.js +28 -0
- package/tests/AccountPage.test.jsx +27 -20
- package/tests/PasswordInvitePage.test.jsx +28 -21
- package/tests/QrSignupManager.registrationContext.test.jsx +5 -1
- package/tests/SignUpPage.test.jsx +14 -3
- package/tests/UserListComponent.test.jsx +100 -16
- package/tests/apiClientLanguage.test.js +33 -0
- package/tests/authErrors.test.js +31 -0
- package/tests/errorCallSiteGuard.test.js +32 -0
- package/tests/loginPageErrorResolution.test.jsx +102 -0
- package/tests/resolveErrorText.test.js +72 -0
- package/work-orders/UCM-AUTH-10.md +490 -0
- package/work-orders/UCM-AUTH-11.md +185 -0
|
@@ -18,6 +18,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
18
18
|
// WICHTIG: Importiere den Context, um die bereits geladenen Daten zu nutzen
|
|
19
19
|
import { AuthContext } from '../auth/AuthContext';
|
|
20
20
|
import { fetchCookieStatement, fetchPrivacyStatement } from '../auth/authApi';
|
|
21
|
+
import { resolveErrorText } from '../utils/resolveErrorText';
|
|
21
22
|
|
|
22
23
|
export function ProfileComponent({
|
|
23
24
|
onSubmit,
|
|
@@ -29,7 +30,7 @@ export function ProfileComponent({
|
|
|
29
30
|
privacyStatementText = null,
|
|
30
31
|
cookieStatementText = null,
|
|
31
32
|
}) {
|
|
32
|
-
const { t } = useTranslation();
|
|
33
|
+
const { t, i18n } = useTranslation();
|
|
33
34
|
|
|
34
35
|
// WICHTIG: Wir holen den User direkt aus dem globalen State
|
|
35
36
|
// Das verhindert den doppelten Request und den ReferenceError
|
|
@@ -140,7 +141,7 @@ export function ProfileComponent({
|
|
|
140
141
|
} catch (err) {
|
|
141
142
|
// eslint-disable-next-line no-console
|
|
142
143
|
console.error("Profile update error:", err);
|
|
143
|
-
setErrorKey(err
|
|
144
|
+
setErrorKey(resolveErrorText(i18n, err, 'Auth.PROFILE_UPDATE_FAILED'));
|
|
144
145
|
} finally {
|
|
145
146
|
setSaving(false);
|
|
146
147
|
}
|
|
@@ -175,7 +176,7 @@ export function ProfileComponent({
|
|
|
175
176
|
>
|
|
176
177
|
{errorKey && (
|
|
177
178
|
<Alert severity="error">
|
|
178
|
-
{
|
|
179
|
+
{errorKey}
|
|
179
180
|
</Alert>
|
|
180
181
|
)}
|
|
181
182
|
{successKey && (
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { useTranslation } from 'react-i18next';
|
|
11
11
|
import { QRCodeSVG } from 'qrcode.react';
|
|
12
12
|
import { createSignupQr } from '../auth/authApi';
|
|
13
|
+
import { resolveErrorText } from '../utils/resolveErrorText';
|
|
13
14
|
|
|
14
15
|
export const QR_SIGNUP_MANAGER_ALERT_SX = { mb: 2 };
|
|
15
16
|
|
|
@@ -47,7 +48,7 @@ export function QrSignupManager({
|
|
|
47
48
|
registrationContext = null,
|
|
48
49
|
defaultMaxRedemptions = DEFAULT_MAX_REDEMPTIONS,
|
|
49
50
|
}) {
|
|
50
|
-
const { t } = useTranslation();
|
|
51
|
+
const { t, i18n } = useTranslation();
|
|
51
52
|
const qrWrapperRef = useRef(null);
|
|
52
53
|
const [busy, setBusy] = useState(false);
|
|
53
54
|
const [error, setError] = useState('');
|
|
@@ -112,7 +113,7 @@ export function QrSignupManager({
|
|
|
112
113
|
hasGeneratedRef.current = true;
|
|
113
114
|
setSuccess(t('Auth.SIGNUP_QR_CREATE_SUCCESS', 'New QR signup link created.'));
|
|
114
115
|
} catch (err) {
|
|
115
|
-
setError(
|
|
116
|
+
setError(resolveErrorText(i18n, err, 'Auth.SIGNUP_QR_CREATE_FAILED'));
|
|
116
117
|
} finally {
|
|
117
118
|
setBusy(false);
|
|
118
119
|
}
|
|
@@ -158,7 +159,7 @@ export function QrSignupManager({
|
|
|
158
159
|
setSuccess(t('Auth.SIGNUP_QR_CREATE_SUCCESS', 'New QR signup link created.'));
|
|
159
160
|
} catch (err) {
|
|
160
161
|
if (!active) return;
|
|
161
|
-
setError(
|
|
162
|
+
setError(resolveErrorText(i18n, err, 'Auth.SIGNUP_QR_CREATE_FAILED'));
|
|
162
163
|
} finally {
|
|
163
164
|
if (active) {
|
|
164
165
|
setBusy(false);
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from '@mui/material';
|
|
10
10
|
import { useTranslation } from 'react-i18next';
|
|
11
11
|
import { updateAuthPolicy } from '../auth/authApi';
|
|
12
|
+
import { resolveErrorText } from '../utils/resolveErrorText';
|
|
12
13
|
|
|
13
14
|
export const QR_SIGNUP_VALIDITY_ALERT_SX = { mb: 2 };
|
|
14
15
|
export const QR_SIGNUP_VALIDITY_FIELD_SX = { flex: 1 };
|
|
@@ -30,7 +31,7 @@ export function QrSignupValidityManager({
|
|
|
30
31
|
onPolicyChange,
|
|
31
32
|
canEdit = true,
|
|
32
33
|
}) {
|
|
33
|
-
const { t } = useTranslation();
|
|
34
|
+
const { t, i18n } = useTranslation();
|
|
34
35
|
const [currentExpiryDays, setCurrentExpiryDays] = useState(String(expiryDays || DEFAULT_EXPIRY_DAYS));
|
|
35
36
|
const [busy, setBusy] = useState(false);
|
|
36
37
|
const [error, setError] = useState('');
|
|
@@ -53,7 +54,7 @@ export function QrSignupValidityManager({
|
|
|
53
54
|
setSuccess(t('Auth.AUTH_POLICY_SAVE_SUCCESS', 'Authentication settings saved.'));
|
|
54
55
|
if (onPolicyChange) onPolicyChange(next);
|
|
55
56
|
} catch (err) {
|
|
56
|
-
setError(
|
|
57
|
+
setError(resolveErrorText(i18n, err, 'Auth.AUTH_POLICY_UPDATE_FAILED'));
|
|
57
58
|
} finally {
|
|
58
59
|
setBusy(false);
|
|
59
60
|
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from '@mui/material';
|
|
11
11
|
import { useTranslation } from 'react-i18next';
|
|
12
12
|
import { updateAuthPolicy } from '../auth/authApi';
|
|
13
|
+
import { resolveErrorText } from '../utils/resolveErrorText';
|
|
13
14
|
|
|
14
15
|
export const REGISTRATION_METHODS_ALERT_SX = { mb: 2 };
|
|
15
16
|
export const REGISTRATION_METHODS_INFO_SX = { mt: 2 };
|
|
@@ -31,7 +32,7 @@ export function RegistrationMethodsManager({
|
|
|
31
32
|
onPolicyChange,
|
|
32
33
|
canEdit = true,
|
|
33
34
|
}) {
|
|
34
|
-
const { t } = useTranslation();
|
|
35
|
+
const { t, i18n } = useTranslation();
|
|
35
36
|
const [policyState, setPolicyState] = useState(EMPTY_POLICY);
|
|
36
37
|
const [busyField, setBusyField] = useState('');
|
|
37
38
|
const [saveError, setSaveError] = useState('');
|
|
@@ -57,7 +58,7 @@ export function RegistrationMethodsManager({
|
|
|
57
58
|
if (onPolicyChange) onPolicyChange(next);
|
|
58
59
|
} catch (err) {
|
|
59
60
|
setPolicyState((prev) => ({ ...prev, [field]: previous }));
|
|
60
|
-
setSaveError(
|
|
61
|
+
setSaveError(resolveErrorText(i18n, err, 'Auth.AUTH_POLICY_UPDATE_FAILED'));
|
|
61
62
|
} finally {
|
|
62
63
|
setBusyField('');
|
|
63
64
|
}
|
|
@@ -14,6 +14,7 @@ import { MFAComponent } from './MFAComponent';
|
|
|
14
14
|
import { changePassword } from '../auth/authApi';
|
|
15
15
|
import { startSocialLogin } from '../utils/authService';
|
|
16
16
|
import { AuthContext } from '../auth/AuthContext';
|
|
17
|
+
import { resolveErrorText } from '../utils/resolveErrorText';
|
|
17
18
|
|
|
18
19
|
export const SECURITY_ALERT_SX = { mb: 2 };
|
|
19
20
|
export const SECURITY_DIVIDER_SX = { my: 3 };
|
|
@@ -22,7 +23,7 @@ export function SecurityComponent({
|
|
|
22
23
|
fromRecovery = false,
|
|
23
24
|
fromWeakLogin = false,
|
|
24
25
|
}) {
|
|
25
|
-
const { t } = useTranslation();
|
|
26
|
+
const { t, i18n } = useTranslation();
|
|
26
27
|
const { authMethods } = useContext(AuthContext);
|
|
27
28
|
|
|
28
29
|
const [messageKey, setMessageKey] = useState(null);
|
|
@@ -60,7 +61,7 @@ export function SecurityComponent({
|
|
|
60
61
|
callbackUrl: `${window.location.origin}/account?tab=security`,
|
|
61
62
|
});
|
|
62
63
|
} catch (err) {
|
|
63
|
-
setErrorKey(err
|
|
64
|
+
setErrorKey(resolveErrorText(i18n, err, 'Auth.SOCIAL_LOGIN_FAILED'));
|
|
64
65
|
}
|
|
65
66
|
};
|
|
66
67
|
|
|
@@ -71,7 +72,7 @@ export function SecurityComponent({
|
|
|
71
72
|
await changePassword(currentPassword, newPassword);
|
|
72
73
|
setMessageKey('Auth.RESET_PASSWORD_SUCCESS');
|
|
73
74
|
} catch (err) {
|
|
74
|
-
setErrorKey(err
|
|
75
|
+
setErrorKey(resolveErrorText(i18n, err, 'Auth.PASSWORD_CHANGE_FAILED'));
|
|
75
76
|
}
|
|
76
77
|
};
|
|
77
78
|
|
|
@@ -96,7 +97,7 @@ export function SecurityComponent({
|
|
|
96
97
|
)}
|
|
97
98
|
{errorKey && (
|
|
98
99
|
<Alert severity="error" sx={SECURITY_ALERT_SX}>
|
|
99
|
-
{
|
|
100
|
+
{errorKey}
|
|
100
101
|
</Alert>
|
|
101
102
|
)}
|
|
102
103
|
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
} from '@mui/material';
|
|
25
25
|
import CloseIcon from '@mui/icons-material/Close';
|
|
26
26
|
import { useTranslation } from 'react-i18next';
|
|
27
|
+
import { resolveErrorText } from '../utils/resolveErrorText';
|
|
27
28
|
import { AuthContext } from '../auth/AuthContext';
|
|
28
29
|
import {
|
|
29
30
|
approveRecoveryRequest,
|
|
@@ -63,7 +64,7 @@ export function SupportRecoveryRequestsTab() {
|
|
|
63
64
|
const data = await fetchRecoveryRequests(statusFilter);
|
|
64
65
|
setRequests(Array.isArray(data) ? data : []);
|
|
65
66
|
} catch (err) {
|
|
66
|
-
setErrorKey(err
|
|
67
|
+
setErrorKey(resolveErrorText(i18n, err, 'Support.RECOVERY_REQUESTS_LOAD_FAILED'));
|
|
67
68
|
} finally {
|
|
68
69
|
setLoading(false);
|
|
69
70
|
}
|
|
@@ -88,7 +89,7 @@ export function SupportRecoveryRequestsTab() {
|
|
|
88
89
|
});
|
|
89
90
|
setAllUsers(list);
|
|
90
91
|
} catch (err) {
|
|
91
|
-
|
|
92
|
+
setAgentErrorKey(resolveErrorText(i18n, err, 'Auth.USER_LIST_FAILED'));
|
|
92
93
|
} finally {
|
|
93
94
|
setAgentLoading(false);
|
|
94
95
|
}
|
|
@@ -124,7 +125,7 @@ export function SupportRecoveryRequestsTab() {
|
|
|
124
125
|
await loadRequests();
|
|
125
126
|
closeDialog();
|
|
126
127
|
} catch (err) {
|
|
127
|
-
setErrorKey(err
|
|
128
|
+
setErrorKey(resolveErrorText(i18n, err, 'Support.RECOVERY_REQUEST_APPROVE_FAILED'));
|
|
128
129
|
}
|
|
129
130
|
};
|
|
130
131
|
|
|
@@ -136,7 +137,7 @@ export function SupportRecoveryRequestsTab() {
|
|
|
136
137
|
await loadRequests();
|
|
137
138
|
closeDialog();
|
|
138
139
|
} catch (err) {
|
|
139
|
-
setErrorKey(err
|
|
140
|
+
setErrorKey(resolveErrorText(i18n, err, 'Support.RECOVERY_REQUEST_REJECT_FAILED'));
|
|
140
141
|
}
|
|
141
142
|
};
|
|
142
143
|
|
|
@@ -167,7 +168,7 @@ export function SupportRecoveryRequestsTab() {
|
|
|
167
168
|
setSelectedAgentCandidate(null);
|
|
168
169
|
await loadUsers();
|
|
169
170
|
} catch (err) {
|
|
170
|
-
setAgentErrorKey(err
|
|
171
|
+
setAgentErrorKey(resolveErrorText(i18n, err, 'Auth.USER_SUPPORT_UPDATE_FAILED'));
|
|
171
172
|
} finally {
|
|
172
173
|
setAgentActionUserId(null);
|
|
173
174
|
}
|
|
@@ -185,7 +186,7 @@ export function SupportRecoveryRequestsTab() {
|
|
|
185
186
|
}
|
|
186
187
|
await loadUsers();
|
|
187
188
|
} catch (err) {
|
|
188
|
-
setAgentErrorKey(err
|
|
189
|
+
setAgentErrorKey(resolveErrorText(i18n, err, 'Auth.USER_SUPPORT_UPDATE_FAILED'));
|
|
189
190
|
} finally {
|
|
190
191
|
setAgentActionUserId(null);
|
|
191
192
|
}
|
|
@@ -216,7 +217,7 @@ export function SupportRecoveryRequestsTab() {
|
|
|
216
217
|
|
|
217
218
|
{agentErrorKey && (
|
|
218
219
|
<Alert severity="error" sx={SUPPORT_RECOVERY_ALERT_SX}>
|
|
219
|
-
{
|
|
220
|
+
{agentErrorKey}
|
|
220
221
|
</Alert>
|
|
221
222
|
)}
|
|
222
223
|
|
|
@@ -310,7 +311,7 @@ export function SupportRecoveryRequestsTab() {
|
|
|
310
311
|
|
|
311
312
|
{errorKey && (
|
|
312
313
|
<Alert severity="error" sx={SUPPORT_RECOVERY_ALERT_SX}>
|
|
313
|
-
{
|
|
314
|
+
{errorKey}
|
|
314
315
|
</Alert>
|
|
315
316
|
)}
|
|
316
317
|
|
|
@@ -2,6 +2,7 @@ import React, { useState } from 'react';
|
|
|
2
2
|
import { Box, TextField, Button, Typography, Alert, CircularProgress } from '@mui/material';
|
|
3
3
|
import { sendAdminInvite } from '../auth/authApi';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { resolveErrorText } from '../utils/resolveErrorText';
|
|
5
6
|
|
|
6
7
|
export const USER_INVITE_ACTION_SX = {
|
|
7
8
|
minWidth: 120,
|
|
@@ -11,7 +12,7 @@ export const USER_INVITE_ACTION_SX = {
|
|
|
11
12
|
export const USER_INVITE_ALERT_SX = { mb: 2 };
|
|
12
13
|
|
|
13
14
|
export function UserInviteComponent() { // FIX: Removed apiUrl prop
|
|
14
|
-
const { t } = useTranslation();
|
|
15
|
+
const { t, i18n } = useTranslation();
|
|
15
16
|
const [inviteEmail, setInviteEmail] = useState('');
|
|
16
17
|
const [message, setMessage] = useState('');
|
|
17
18
|
const [error, setError] = useState('');
|
|
@@ -31,7 +32,7 @@ export function UserInviteComponent() { // FIX: Removed apiUrl prop
|
|
|
31
32
|
// err.message contains normalized text or code from authApi
|
|
32
33
|
// eslint-disable-next-line no-console
|
|
33
34
|
console.error('Error inviting user:', err);
|
|
34
|
-
setError(
|
|
35
|
+
setError(resolveErrorText(i18n, err, 'Auth.INVITE_FAILED'));
|
|
35
36
|
} finally {
|
|
36
37
|
setLoading(false);
|
|
37
38
|
}
|
|
@@ -24,6 +24,7 @@ import CancelIcon from '@mui/icons-material/Cancel';
|
|
|
24
24
|
import DeleteIcon from '@mui/icons-material/Delete';
|
|
25
25
|
import { useTranslation } from 'react-i18next';
|
|
26
26
|
import { fetchUsersList, deleteUser, updateUserRole } from '../auth/authApi';
|
|
27
|
+
import { resolveErrorText } from '../utils/resolveErrorText';
|
|
27
28
|
|
|
28
29
|
const DEFAULT_ROLES = ['none', 'student', 'teacher', 'admin'];
|
|
29
30
|
|
|
@@ -49,7 +50,7 @@ export function UserListComponent({
|
|
|
49
50
|
canDeleteUser = null,
|
|
50
51
|
onDeleteUser = null,
|
|
51
52
|
}) {
|
|
52
|
-
const { t } = useTranslation();
|
|
53
|
+
const { t, i18n } = useTranslation();
|
|
53
54
|
const [users, setUsers] = useState([]);
|
|
54
55
|
const [loading, setLoading] = useState(true);
|
|
55
56
|
const [error, setError] = useState(null);
|
|
@@ -75,7 +76,7 @@ export function UserListComponent({
|
|
|
75
76
|
});
|
|
76
77
|
setUsers(list);
|
|
77
78
|
} catch (err) {
|
|
78
|
-
setError(err
|
|
79
|
+
setError(resolveErrorText(i18n, err, 'Auth.USER_LIST_FAILED'));
|
|
79
80
|
} finally {
|
|
80
81
|
setLoading(false);
|
|
81
82
|
}
|
|
@@ -99,7 +100,7 @@ export function UserListComponent({
|
|
|
99
100
|
}
|
|
100
101
|
setUsers(prev => prev.filter(u => u.id !== userId));
|
|
101
102
|
} catch (err) {
|
|
102
|
-
alert(
|
|
103
|
+
alert(resolveErrorText(i18n, err, 'Auth.USER_DELETE_FAILED'));
|
|
103
104
|
}
|
|
104
105
|
};
|
|
105
106
|
|
|
@@ -120,7 +121,7 @@ export function UserListComponent({
|
|
|
120
121
|
await loadUsers();
|
|
121
122
|
alert(t('UserList.ROLE_UPDATE_SUCCESS', 'Role updated.'));
|
|
122
123
|
} catch (err) {
|
|
123
|
-
alert(
|
|
124
|
+
alert(resolveErrorText(i18n, err, 'Auth.USER_ROLE_UPDATE_FAILED'));
|
|
124
125
|
}
|
|
125
126
|
};
|
|
126
127
|
|
|
@@ -154,6 +155,11 @@ export function UserListComponent({
|
|
|
154
155
|
return canEdit(targetUser);
|
|
155
156
|
};
|
|
156
157
|
|
|
158
|
+
const isOwnRow = (targetUser) => {
|
|
159
|
+
if (currentUser?.id == null || targetUser?.id == null) return false;
|
|
160
|
+
return String(targetUser.id) === String(currentUser.id);
|
|
161
|
+
};
|
|
162
|
+
|
|
157
163
|
const listContext = useMemo(() => ({
|
|
158
164
|
currentUser,
|
|
159
165
|
extraContext,
|
|
@@ -276,7 +282,7 @@ export function UserListComponent({
|
|
|
276
282
|
});
|
|
277
283
|
} catch (err) {
|
|
278
284
|
// eslint-disable-next-line no-alert
|
|
279
|
-
alert(err
|
|
285
|
+
alert(resolveErrorText(i18n, err, 'Common.OPERATION_FAILED'));
|
|
280
286
|
} finally {
|
|
281
287
|
setRowActionLoading((prev) => ({ ...prev, [actionId]: false }));
|
|
282
288
|
}
|
|
@@ -434,7 +440,7 @@ export function UserListComponent({
|
|
|
434
440
|
);
|
|
435
441
|
})}
|
|
436
442
|
|
|
437
|
-
{showDeleteAction && (
|
|
443
|
+
{showDeleteAction && !isOwnRow(row) && (
|
|
438
444
|
<Tooltip title={t('Common.DELETE', 'Delete')}>
|
|
439
445
|
<span>
|
|
440
446
|
<Button
|
|
@@ -472,6 +478,7 @@ export function UserListComponent({
|
|
|
472
478
|
loadUsers,
|
|
473
479
|
canEdit,
|
|
474
480
|
canDelete,
|
|
481
|
+
isOwnRow,
|
|
475
482
|
]);
|
|
476
483
|
|
|
477
484
|
const sortedUsers = useMemo(() => {
|
|
@@ -514,7 +521,7 @@ export function UserListComponent({
|
|
|
514
521
|
/>
|
|
515
522
|
</Box>
|
|
516
523
|
|
|
517
|
-
{error && <Alert severity="error" sx={USER_LIST_ALERT_SX}>{
|
|
524
|
+
{error && <Alert severity="error" sx={USER_LIST_ALERT_SX}>{error}</Alert>}
|
|
518
525
|
|
|
519
526
|
{loading && (
|
|
520
527
|
<Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}>
|