@micha.bigler/ui-core-micha 1.4.27 → 1.4.29
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/dist/auth/AuthContext.js +3 -1
- package/dist/components/SecurityComponent.js +1 -1
- package/dist/components/UserInviteComponent.js +6 -5
- package/dist/components/UserListComponent.js +12 -11
- package/package.json +1 -1
- package/src/auth/AuthContext.jsx +3 -1
- package/src/components/SecurityComponent.jsx +1 -1
- package/src/components/UserInviteComponent.jsx +6 -5
- package/src/components/UserListComponent.jsx +12 -12
package/dist/auth/AuthContext.js
CHANGED
|
@@ -25,7 +25,9 @@ export const AuthProvider = ({ children }) => {
|
|
|
25
25
|
last_name: data.last_name,
|
|
26
26
|
role: data.role,
|
|
27
27
|
is_superuser: data.is_superuser,
|
|
28
|
-
security_state: data.security_state,
|
|
28
|
+
security_state: data.security_state,
|
|
29
|
+
available_roles: data.available_roles,
|
|
30
|
+
ui_permissions: data.ui_permissions,
|
|
29
31
|
});
|
|
30
32
|
}
|
|
31
33
|
}
|
|
@@ -38,4 +38,4 @@ const SecurityComponent = ({ fromRecovery = false, fromWeakLogin = false, // opt
|
|
|
38
38
|
};
|
|
39
39
|
return (_jsxs(Box, { children: [fromRecovery && (_jsx(Alert, { severity: "warning", sx: { mb: 2 }, children: t('Security.RECOVERY_LOGIN_WARNING') })), fromWeakLogin && (_jsx(Alert, { severity: "warning", sx: { mb: 2 }, children: t('Security.WEAK_LOGIN_WARNING') })), messageKey && (_jsx(Alert, { severity: "success", sx: { mb: 2 }, children: t(messageKey) })), errorKey && (_jsx(Alert, { severity: "error", sx: { mb: 2 }, children: t(errorKey) })), _jsx(Typography, { variant: "h6", gutterBottom: true, children: t('Security.LOGIN_PASSWORD_LABEL') }), _jsx(PasswordChangeForm, { onSubmit: handlePasswordChange }), _jsx(Divider, { sx: { my: 3 } }), _jsx(Typography, { variant: "h6", gutterBottom: true, children: t('Security.SOCIAL_SECTION_TITLE') }), _jsx(Typography, { variant: "body2", sx: { mb: 1 }, children: t('Security.SOCIAL_SECTION_DESCRIPTION') }), _jsx(SocialLoginButtons, { onProviderClick: handleSocialClick }), _jsx(Divider, { sx: { my: 3 } }), _jsx(PasskeysComponent, {}), _jsx(Divider, { sx: { my: 3 } }), _jsx(MFAComponent, {})] }));
|
|
40
40
|
};
|
|
41
|
-
export
|
|
41
|
+
export { SecurityComponent };
|
|
@@ -3,7 +3,7 @@ import React, { useState } from 'react';
|
|
|
3
3
|
import { Box, TextField, Button, Typography, Alert, CircularProgress } from '@mui/material';
|
|
4
4
|
import { requestInviteWithCode } from '../auth/authApi';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
|
-
export function UserInviteComponent(
|
|
6
|
+
export function UserInviteComponent() {
|
|
7
7
|
const { t } = useTranslation();
|
|
8
8
|
const [inviteEmail, setInviteEmail] = useState('');
|
|
9
9
|
const [message, setMessage] = useState('');
|
|
@@ -16,15 +16,16 @@ export function UserInviteComponent({ apiUrl = '/api/users/' }) {
|
|
|
16
16
|
return;
|
|
17
17
|
setLoading(true);
|
|
18
18
|
try {
|
|
19
|
-
//
|
|
20
|
-
|
|
19
|
+
// FIX: 2nd parameter is accessCode. For admin invites without code, we pass null.
|
|
20
|
+
// Previously, 'apiUrl' was passed here incorrectly.
|
|
21
|
+
const data = await requestInviteWithCode(inviteEmail, null);
|
|
21
22
|
setInviteEmail('');
|
|
22
23
|
setMessage(data.detail || t('Auth.INVITE_SENT_SUCCESS', 'Invitation sent.'));
|
|
23
24
|
}
|
|
24
25
|
catch (err) {
|
|
25
|
-
// err.message
|
|
26
|
+
// err.message contains normalized text or code from authApi
|
|
27
|
+
// eslint-disable-next-line no-console
|
|
26
28
|
console.error('Error inviting user:', err);
|
|
27
|
-
// Fallback Text, falls der Key nicht übersetzt ist
|
|
28
29
|
setError(t(err.code) || err.message || t('Auth.INVITE_FAILED'));
|
|
29
30
|
}
|
|
30
31
|
finally {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React, { useState, useEffect } from 'react';
|
|
3
|
-
import { Box, Typography, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, FormControl,
|
|
3
|
+
import { Box, Typography, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, FormControl, Select, MenuItem, Button, IconButton, Tooltip, CircularProgress, Alert } from '@mui/material';
|
|
4
4
|
import DeleteIcon from '@mui/icons-material/Delete';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
import { fetchUsersList, deleteUser, updateUserRole, updateUserSupportStatus } from '../auth/authApi';
|
|
7
7
|
const DEFAULT_ROLES = ['none', 'student', 'teacher', 'admin'];
|
|
8
|
-
export function UserListComponent({ roles = DEFAULT_ROLES,
|
|
8
|
+
export function UserListComponent({ roles = DEFAULT_ROLES, currentUser }) {
|
|
9
9
|
const { t } = useTranslation();
|
|
10
10
|
const [users, setUsers] = useState([]);
|
|
11
11
|
const [loading, setLoading] = useState(true);
|
|
@@ -14,11 +14,12 @@ export function UserListComponent({ roles = DEFAULT_ROLES, apiUrl = '/api/users/
|
|
|
14
14
|
setLoading(true);
|
|
15
15
|
setError(null);
|
|
16
16
|
try {
|
|
17
|
-
|
|
17
|
+
// FIX: Removed apiUrl parameter.
|
|
18
|
+
// fetchUsersList uses USERS_BASE from authConfig internally.
|
|
19
|
+
const data = await fetchUsersList();
|
|
18
20
|
setUsers(data);
|
|
19
21
|
}
|
|
20
22
|
catch (err) {
|
|
21
|
-
// err.code ist dank normaliseApiError verfügbar
|
|
22
23
|
setError(err.code || 'Auth.USER_LIST_FAILED');
|
|
23
24
|
}
|
|
24
25
|
finally {
|
|
@@ -28,13 +29,13 @@ export function UserListComponent({ roles = DEFAULT_ROLES, apiUrl = '/api/users/
|
|
|
28
29
|
useEffect(() => {
|
|
29
30
|
loadUsers();
|
|
30
31
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
31
|
-
}, [
|
|
32
|
+
}, []); // Dependency on apiUrl removed
|
|
32
33
|
const handleDelete = async (userId) => {
|
|
33
34
|
if (!window.confirm(t('UserList.DELETE_CONFIRM', 'Are you sure you want to delete this user?')))
|
|
34
35
|
return;
|
|
35
36
|
try {
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
// FIX: Removed apiUrl parameter.
|
|
38
|
+
await deleteUser(userId);
|
|
38
39
|
setUsers(prev => prev.filter(u => u.id !== userId));
|
|
39
40
|
}
|
|
40
41
|
catch (err) {
|
|
@@ -43,8 +44,8 @@ export function UserListComponent({ roles = DEFAULT_ROLES, apiUrl = '/api/users/
|
|
|
43
44
|
};
|
|
44
45
|
const handleChangeRole = async (userId, newRole) => {
|
|
45
46
|
try {
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
// FIX: Removed apiUrl parameter.
|
|
48
|
+
await updateUserRole(userId, newRole);
|
|
48
49
|
loadUsers();
|
|
49
50
|
}
|
|
50
51
|
catch (err) {
|
|
@@ -53,7 +54,8 @@ export function UserListComponent({ roles = DEFAULT_ROLES, apiUrl = '/api/users/
|
|
|
53
54
|
};
|
|
54
55
|
const handleToggleSupporter = async (userId, newValue) => {
|
|
55
56
|
try {
|
|
56
|
-
|
|
57
|
+
// FIX: Removed apiUrl parameter.
|
|
58
|
+
await updateUserSupportStatus(userId, newValue);
|
|
57
59
|
loadUsers();
|
|
58
60
|
}
|
|
59
61
|
catch (err) {
|
|
@@ -69,7 +71,6 @@ export function UserListComponent({ roles = DEFAULT_ROLES, apiUrl = '/api/users/
|
|
|
69
71
|
const targetRole = targetUser.role || 'none';
|
|
70
72
|
if (myRole === 'admin')
|
|
71
73
|
return true;
|
|
72
|
-
// Beispiel Logik: Lehrer dürfen Schüler bearbeiten
|
|
73
74
|
if (myRole === 'teacher') {
|
|
74
75
|
if (targetUser.id === currentUser.id)
|
|
75
76
|
return false;
|
package/package.json
CHANGED
package/src/auth/AuthContext.jsx
CHANGED
|
@@ -37,7 +37,9 @@ export const AuthProvider = ({ children }) => {
|
|
|
37
37
|
last_name: data.last_name,
|
|
38
38
|
role: data.role,
|
|
39
39
|
is_superuser: data.is_superuser,
|
|
40
|
-
security_state: data.security_state,
|
|
40
|
+
security_state: data.security_state,
|
|
41
|
+
available_roles: data.available_roles,
|
|
42
|
+
ui_permissions: data.ui_permissions,
|
|
41
43
|
});
|
|
42
44
|
}
|
|
43
45
|
} catch (err) {
|
|
@@ -3,7 +3,7 @@ import { Box, TextField, Button, Typography, Alert, CircularProgress } from '@mu
|
|
|
3
3
|
import { requestInviteWithCode } from '../auth/authApi';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
|
|
6
|
-
export function UserInviteComponent({
|
|
6
|
+
export function UserInviteComponent() { // FIX: Removed apiUrl prop
|
|
7
7
|
const { t } = useTranslation();
|
|
8
8
|
const [inviteEmail, setInviteEmail] = useState('');
|
|
9
9
|
const [message, setMessage] = useState('');
|
|
@@ -17,15 +17,16 @@ export function UserInviteComponent({ apiUrl = '/api/users/' }) {
|
|
|
17
17
|
|
|
18
18
|
setLoading(true);
|
|
19
19
|
try {
|
|
20
|
-
//
|
|
21
|
-
|
|
20
|
+
// FIX: 2nd parameter is accessCode. For admin invites without code, we pass null.
|
|
21
|
+
// Previously, 'apiUrl' was passed here incorrectly.
|
|
22
|
+
const data = await requestInviteWithCode(inviteEmail, null);
|
|
22
23
|
|
|
23
24
|
setInviteEmail('');
|
|
24
25
|
setMessage(data.detail || t('Auth.INVITE_SENT_SUCCESS', 'Invitation sent.'));
|
|
25
26
|
} catch (err) {
|
|
26
|
-
// err.message
|
|
27
|
+
// err.message contains normalized text or code from authApi
|
|
28
|
+
// eslint-disable-next-line no-console
|
|
27
29
|
console.error('Error inviting user:', err);
|
|
28
|
-
// Fallback Text, falls der Key nicht übersetzt ist
|
|
29
30
|
setError(t(err.code) || err.message || t('Auth.INVITE_FAILED'));
|
|
30
31
|
} finally {
|
|
31
32
|
setLoading(false);
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Box, Typography, Table, TableBody, TableCell, TableContainer,
|
|
4
|
-
TableHead, TableRow, Paper, FormControl,
|
|
4
|
+
TableHead, TableRow, Paper, FormControl, Select,
|
|
5
5
|
MenuItem, Button, IconButton, Tooltip, CircularProgress, Alert
|
|
6
6
|
} from '@mui/material';
|
|
7
7
|
import DeleteIcon from '@mui/icons-material/Delete';
|
|
8
8
|
import { useTranslation } from 'react-i18next';
|
|
9
|
-
import { fetchUsersList, deleteUser, updateUserRole, updateUserSupportStatus } from '../auth/authApi';
|
|
9
|
+
import { fetchUsersList, deleteUser, updateUserRole, updateUserSupportStatus } from '../auth/authApi';
|
|
10
10
|
|
|
11
11
|
const DEFAULT_ROLES = ['none', 'student', 'teacher', 'admin'];
|
|
12
12
|
|
|
13
13
|
export function UserListComponent({
|
|
14
14
|
roles = DEFAULT_ROLES,
|
|
15
|
-
apiUrl = '/api/users/',
|
|
16
15
|
currentUser
|
|
17
16
|
}) {
|
|
18
17
|
const { t } = useTranslation();
|
|
@@ -24,10 +23,11 @@ export function UserListComponent({
|
|
|
24
23
|
setLoading(true);
|
|
25
24
|
setError(null);
|
|
26
25
|
try {
|
|
27
|
-
|
|
26
|
+
// FIX: Removed apiUrl parameter.
|
|
27
|
+
// fetchUsersList uses USERS_BASE from authConfig internally.
|
|
28
|
+
const data = await fetchUsersList();
|
|
28
29
|
setUsers(data);
|
|
29
30
|
} catch (err) {
|
|
30
|
-
// err.code ist dank normaliseApiError verfügbar
|
|
31
31
|
setError(err.code || 'Auth.USER_LIST_FAILED');
|
|
32
32
|
} finally {
|
|
33
33
|
setLoading(false);
|
|
@@ -37,13 +37,13 @@ export function UserListComponent({
|
|
|
37
37
|
useEffect(() => {
|
|
38
38
|
loadUsers();
|
|
39
39
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
40
|
-
}, [
|
|
40
|
+
}, []); // Dependency on apiUrl removed
|
|
41
41
|
|
|
42
42
|
const handleDelete = async (userId) => {
|
|
43
43
|
if (!window.confirm(t('UserList.DELETE_CONFIRM', 'Are you sure you want to delete this user?'))) return;
|
|
44
44
|
try {
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
// FIX: Removed apiUrl parameter.
|
|
46
|
+
await deleteUser(userId);
|
|
47
47
|
setUsers(prev => prev.filter(u => u.id !== userId));
|
|
48
48
|
} catch (err) {
|
|
49
49
|
alert(t(err.code || 'Auth.USER_DELETE_FAILED'));
|
|
@@ -52,8 +52,8 @@ export function UserListComponent({
|
|
|
52
52
|
|
|
53
53
|
const handleChangeRole = async (userId, newRole) => {
|
|
54
54
|
try {
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
// FIX: Removed apiUrl parameter.
|
|
56
|
+
await updateUserRole(userId, newRole);
|
|
57
57
|
loadUsers();
|
|
58
58
|
} catch (err) {
|
|
59
59
|
alert(t(err.code || 'Auth.USER_ROLE_UPDATE_FAILED'));
|
|
@@ -62,7 +62,8 @@ export function UserListComponent({
|
|
|
62
62
|
|
|
63
63
|
const handleToggleSupporter = async (userId, newValue) => {
|
|
64
64
|
try {
|
|
65
|
-
|
|
65
|
+
// FIX: Removed apiUrl parameter.
|
|
66
|
+
await updateUserSupportStatus(userId, newValue);
|
|
66
67
|
loadUsers();
|
|
67
68
|
} catch (err) {
|
|
68
69
|
alert(t(err.code || 'Auth.USER_UPDATE_FAILED'));
|
|
@@ -78,7 +79,6 @@ export function UserListComponent({
|
|
|
78
79
|
|
|
79
80
|
if (myRole === 'admin') return true;
|
|
80
81
|
|
|
81
|
-
// Beispiel Logik: Lehrer dürfen Schüler bearbeiten
|
|
82
82
|
if (myRole === 'teacher') {
|
|
83
83
|
if (targetUser.id === currentUser.id) return false;
|
|
84
84
|
if (['teacher', 'admin', 'supervisor'].includes(targetRole)) return false;
|